mirror of
https://github.com/garrytan/gbrain.git
synced 2026-08-15 17:32:37 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
65f7a1c5c9 |
+15
-8
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* Subcommands:
|
||||
* takes <slug> — list takes for a page
|
||||
* takes list — list all active takes (#2079)
|
||||
* takes search "<query>" [--who h] — keyword search across all takes
|
||||
* takes add <slug> ...flags — append a take (markdown + DB)
|
||||
* takes update <slug> --row N ...flags — update mutable fields
|
||||
@@ -129,11 +130,10 @@ function writeBody(path: string, body: string): void {
|
||||
// --- Subcommands ---
|
||||
|
||||
async function cmdList(engine: BrainEngine, args: string[]): Promise<void> {
|
||||
const slug = args[0];
|
||||
if (!slug) {
|
||||
console.error('Usage: gbrain takes <slug> [--json]');
|
||||
process.exit(1);
|
||||
}
|
||||
// #2079: slug is optional. `gbrain takes list` (no slug) lists ALL active
|
||||
// takes — CLI parity with the takes_list operation. A leading flag is not
|
||||
// a slug.
|
||||
const slug = args[0] && !args[0].startsWith('-') ? args[0] : undefined;
|
||||
const json = flagPresent(args, '--json');
|
||||
const holder = flagValue(args, '--who');
|
||||
const kind = flagValue(args, '--kind') as string | undefined;
|
||||
@@ -153,17 +153,19 @@ async function cmdList(engine: BrainEngine, args: string[]): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
const scope = slug ?? 'this brain';
|
||||
if (takes.length === 0) {
|
||||
console.log(`No takes on ${slug}.`);
|
||||
console.log(`No takes on ${scope}.`);
|
||||
return;
|
||||
}
|
||||
console.log(`# Takes on ${slug}\n`);
|
||||
console.log(`# Takes on ${scope}\n`);
|
||||
for (const t of takes) {
|
||||
const tag = t.active ? '' : ' [superseded]';
|
||||
const w = Number(t.weight).toFixed(2);
|
||||
const since = t.since_date ?? '';
|
||||
const src = t.source ? ` — ${t.source}` : '';
|
||||
console.log(`#${t.row_num} [${t.kind} • ${t.holder} • w=${w}${since ? ` • ${since}` : ''}]${tag}\n ${t.claim}${src}\n`);
|
||||
const where = slug ? '' : `${t.page_slug} `;
|
||||
console.log(`${where}#${t.row_num} [${t.kind} • ${t.holder} • w=${w}${since ? ` • ${since}` : ''}]${tag}\n ${t.claim}${src}\n`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -555,6 +557,8 @@ export async function runTakes(engine: BrainEngine, args: string[]): Promise<voi
|
||||
Subcommands:
|
||||
takes <slug> [--json] [--who h] [--kind k] [--sort weight|since_date|created_at] [--expired]
|
||||
List takes for a page
|
||||
takes list [--json] [--who h] [--kind k] [--sort ...] [--expired]
|
||||
List all active takes across the brain (#2079)
|
||||
takes search "<query>" [--limit N] [--json]
|
||||
Keyword search across all takes
|
||||
takes add <slug> --claim "..." --kind <fact|take|bet|hunch> --who <holder>
|
||||
@@ -584,6 +588,9 @@ Common flags:
|
||||
const rest = args.slice(1);
|
||||
|
||||
switch (sub) {
|
||||
// #2079: `takes list` used to be parsed as page slug "list" and printed
|
||||
// "No takes on list." — reading exactly like an empty takes table.
|
||||
case 'list': return cmdList(engine, rest);
|
||||
case 'search': return cmdSearch(engine, rest);
|
||||
case 'add': return cmdAdd(engine, rest, await resolveTakesSourceId(engine));
|
||||
case 'update': return cmdUpdate(engine, rest, await resolveTakesSourceId(engine));
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* #2079 — `gbrain takes list` used to parse "list" as a PAGE SLUG: cmdList
|
||||
* looked up a page named "list" and printed "No takes on list." even when the
|
||||
* brain held many takes — reading exactly like an empty takes table, so
|
||||
* agents concluded there were no takes and moved on.
|
||||
*
|
||||
* Fix: `list` is a real subcommand (CLI parity with the takes_list op).
|
||||
* Bare `takes <slug>` still lists per-page.
|
||||
*/
|
||||
|
||||
import { afterAll, beforeAll, describe, expect, test } from 'bun:test';
|
||||
import { PGLiteEngine } from '../src/core/pglite-engine.ts';
|
||||
import { runTakes } from '../src/commands/takes.ts';
|
||||
|
||||
let engine: PGLiteEngine;
|
||||
|
||||
async function captureStdout(fn: () => Promise<void>): Promise<string> {
|
||||
const lines: string[] = [];
|
||||
const orig = console.log;
|
||||
console.log = (...args: unknown[]) => { lines.push(args.join(' ')); };
|
||||
try {
|
||||
await fn();
|
||||
} finally {
|
||||
console.log = orig;
|
||||
}
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
engine = new PGLiteEngine();
|
||||
await engine.connect({});
|
||||
await engine.initSchema();
|
||||
await engine.putPage('companies/acme-example', {
|
||||
type: 'company',
|
||||
title: 'Acme Example',
|
||||
compiled_truth: 'Acme Example is a test company.',
|
||||
});
|
||||
const [row] = await engine.executeRaw<{ id: number }>(
|
||||
`SELECT id FROM pages WHERE slug = 'companies/acme-example'`,
|
||||
);
|
||||
await engine.addTakesBatch([{
|
||||
page_id: row.id,
|
||||
row_num: 1,
|
||||
claim: 'Acme will ship the widget by Q3.',
|
||||
kind: 'bet',
|
||||
holder: 'self',
|
||||
weight: 0.7,
|
||||
}]);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await engine.disconnect();
|
||||
});
|
||||
|
||||
describe('gbrain takes list (#2079)', () => {
|
||||
test('`takes list` lists all takes instead of slug-ifying "list"', async () => {
|
||||
const out = await captureStdout(() => runTakes(engine, ['list']));
|
||||
expect(out).not.toContain('No takes on list.');
|
||||
expect(out).toContain('Acme will ship the widget by Q3.');
|
||||
expect(out).toContain('companies/acme-example');
|
||||
});
|
||||
|
||||
test('`takes list --json` returns the full take rows', async () => {
|
||||
const out = await captureStdout(() => runTakes(engine, ['list', '--json']));
|
||||
const parsed = JSON.parse(out);
|
||||
expect(Array.isArray(parsed)).toBe(true);
|
||||
expect(parsed.length).toBe(1);
|
||||
expect(parsed[0].claim).toContain('Acme will ship');
|
||||
});
|
||||
|
||||
test('per-page form still works: `takes <slug>`', async () => {
|
||||
const out = await captureStdout(() => runTakes(engine, ['companies/acme-example']));
|
||||
expect(out).toContain('# Takes on companies/acme-example');
|
||||
expect(out).toContain('Acme will ship the widget by Q3.');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user