portable-agent-layer 0.88.0 → 0.89.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -5
- package/assets/agents/gemini-researcher.md +13 -0
- package/assets/agents/grok-researcher.md +13 -0
- package/assets/agents/multi-perspective-researcher.md +12 -0
- package/assets/agents/perplexity-researcher.md +13 -0
- package/assets/agents/skill-author.md +17 -0
- package/assets/agents/subagent-author.md +18 -1
- package/assets/skills/create-subagent/SKILL.md +3 -2
- package/assets/skills/create-subagent/authoring-guide.md +16 -0
- package/assets/templates/PAL/MEMORY_SYSTEM.md +1 -1
- package/assets/templates/PAL/README.md +6 -5
- package/assets/templates/PAL/SYSTEM_ARCHITECTURE.md +4 -1
- package/assets/templates/hooks.antigravity.json +42 -0
- package/assets/templates/settings.antigravity.json +44 -0
- package/package.json +1 -1
- package/src/cli/builtin-tools.ts +28 -23
- package/src/cli/doctor/agents.ts +64 -64
- package/src/cli/identity.ts +26 -20
- package/src/cli/index.ts +109 -312
- package/src/cli/knowledge.ts +160 -201
- package/src/cli/ledger-command.ts +69 -0
- package/src/cli/ledger.ts +20 -101
- package/src/cli/personal-context.ts +15 -12
- package/src/cli/rule.ts +29 -29
- package/src/cli/server.ts +33 -52
- package/src/cli/session-agent.ts +7 -9
- package/src/cli/skill.ts +73 -64
- package/src/cli/subagent.ts +51 -58
- package/src/cli/tree.ts +177 -0
- package/src/hooks/InvocationContext.ts +26 -0
- package/src/hooks/LedgerCommit.ts +4 -2
- package/src/hooks/LedgerSnapshot.ts +2 -0
- package/src/hooks/SecurityValidator.ts +2 -0
- package/src/hooks/StopOrchestrator.ts +12 -2
- package/src/hooks/UserPromptOrchestrator.ts +3 -15
- package/src/hooks/handlers/context-digests.ts +21 -21
- package/src/hooks/handlers/inject-retrieval.ts +7 -5
- package/src/hooks/handlers/readme-sync.ts +6 -2
- package/src/hooks/handlers/session-name.ts +3 -12
- package/src/hooks/lib/agent-definition.ts +6 -16
- package/src/hooks/lib/agent-registry.ts +88 -0
- package/src/hooks/lib/agent.ts +47 -23
- package/src/hooks/lib/antigravity-inference.ts +84 -0
- package/src/hooks/lib/antigravity-transcript.ts +129 -0
- package/src/hooks/lib/claim-check.ts +13 -2
- package/src/hooks/lib/claim-log.ts +5 -1
- package/src/hooks/lib/claude-md.ts +21 -1
- package/src/hooks/lib/context.ts +5 -1
- package/src/hooks/lib/hook-turn.ts +25 -2
- package/src/hooks/lib/inference.ts +77 -1
- package/src/hooks/lib/invocation-context.ts +99 -0
- package/src/hooks/lib/ledger-hook.ts +14 -6
- package/src/hooks/lib/models.ts +34 -17
- package/src/hooks/lib/paths.ts +39 -6
- package/src/hooks/lib/prompt-capture.ts +28 -0
- package/src/hooks/lib/prompt-text.ts +1 -0
- package/src/hooks/lib/readme-sync.ts +3 -31
- package/src/hooks/lib/security-gate.ts +10 -3
- package/src/hooks/lib/semi-static.ts +13 -3
- package/src/hooks/lib/session-context.ts +3 -1
- package/src/hooks/lib/session-names.ts +20 -4
- package/src/hooks/lib/stop.ts +1 -0
- package/src/hooks/lib/transcript.ts +6 -3
- package/src/targets/agent-render.ts +3 -3
- package/src/targets/antigravity/install.ts +68 -0
- package/src/targets/antigravity/uninstall.ts +66 -0
- package/src/targets/lib.ts +81 -64
- package/src/targets/opencode/install.ts +2 -0
- package/src/targets/opencode/permission.ts +39 -0
- package/src/targets/opencode/uninstall.ts +9 -8
- package/src/tools/agent/algorithm-reflect.ts +70 -62
- package/src/tools/agent/algorithm-synthesize.ts +39 -14
- package/src/tools/agent/analyze.ts +31 -36
- package/src/tools/agent/handoff-note.ts +51 -54
- package/src/tools/agent/interaction.ts +32 -28
- package/src/tools/agent/project.ts +300 -287
- package/src/tools/agent/relationship-note.ts +40 -36
- package/src/tools/agent/relationship-reflect.ts +23 -32
- package/src/tools/agent/synthesize.ts +26 -27
- package/src/tools/agent/thread.ts +42 -51
- package/src/tools/agent/wisdom-frame.ts +45 -38
- package/src/tools/control-room/server.ts +0 -2
- package/src/tools/control-room/ui/dist/assets/{index-BZMDzWFa.js → index-mFpXpiBj.js} +1 -1
- package/src/tools/control-room/ui/dist/index.html +1 -1
- package/src/tools/control-room/ui/screens/log.tsx +10 -1
- package/src/tools/lib/command.ts +275 -0
- package/src/tools/subagent-doctor.ts +74 -9
- package/src/tools/token-cost.ts +18 -17
|
@@ -18,56 +18,60 @@
|
|
|
18
18
|
* Which flags make which notes is in lib/note-flags.ts.
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
-
import { parseArgs } from "node:util";
|
|
22
21
|
import { appendNotes } from "../../hooks/lib/relationship";
|
|
22
|
+
import { leaf, runCommand, UsageError } from "../lib/command";
|
|
23
23
|
import { emit } from "../lib/emit";
|
|
24
|
-
import { notesFromFlags } from "../lib/note-flags";
|
|
24
|
+
import { type NoteFlags, notesFromFlags } from "../lib/note-flags";
|
|
25
25
|
import { scriptArgs } from "../lib/script-args";
|
|
26
26
|
|
|
27
|
-
const
|
|
28
|
-
RelationshipNote — Append W/O/Session entries to today's relationship log
|
|
27
|
+
const DETAILS = `Multiple flags may be combined in one call. At least one of --o, --w, --b is required.
|
|
29
28
|
|
|
30
|
-
|
|
29
|
+
Examples:
|
|
31
30
|
pal cli relationship-note --o "User prefers X" --confidence 0.80
|
|
32
31
|
pal cli relationship-note --w "User is building X in TypeScript"
|
|
33
32
|
pal cli relationship-note --b "Debugged the cache split logic"
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
--o TEXT Opinion/behavioral observation about the user
|
|
37
|
-
--confidence N Confidence for --o (0.0–1.0, default 0.75)
|
|
38
|
-
--w TEXT World fact about the user's situation
|
|
39
|
-
--b TEXT Session diary — what the assistant did (first-person)
|
|
34
|
+
Output: appends to memory/relationship/YYYY-MM/YYYY-MM-DD.md`;
|
|
40
35
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
options: {
|
|
50
|
-
o: { type: "string", multiple: true },
|
|
51
|
-
w: { type: "string", multiple: true },
|
|
52
|
-
b: { type: "string" },
|
|
53
|
-
confidence: { type: "string" },
|
|
54
|
-
help: { type: "boolean", short: "h" },
|
|
36
|
+
export const command = leaf({
|
|
37
|
+
summary: "Append W/O/Session entries to today's relationship log",
|
|
38
|
+
options: {
|
|
39
|
+
o: {
|
|
40
|
+
type: "string",
|
|
41
|
+
multiple: true,
|
|
42
|
+
value: "<text>",
|
|
43
|
+
description: "Opinion/behavioral observation about the user (repeatable)",
|
|
55
44
|
},
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
45
|
+
confidence: {
|
|
46
|
+
type: "string",
|
|
47
|
+
value: "<n>",
|
|
48
|
+
description: "Confidence for --o (0.0–1.0, default 0.75)",
|
|
49
|
+
},
|
|
50
|
+
w: {
|
|
51
|
+
type: "string",
|
|
52
|
+
multiple: true,
|
|
53
|
+
value: "<text>",
|
|
54
|
+
description: "World fact about the user's situation (repeatable)",
|
|
55
|
+
},
|
|
56
|
+
b: {
|
|
57
|
+
type: "string",
|
|
58
|
+
value: "<text>",
|
|
59
|
+
description: "Session diary — what the assistant did (first-person)",
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
details: DETAILS,
|
|
63
|
+
run: ({ values }) => appendFromFlags(values),
|
|
64
|
+
});
|
|
62
65
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
process.exit(1);
|
|
67
|
-
}
|
|
66
|
+
export function run(argv: string[] = scriptArgs()): Promise<number> {
|
|
67
|
+
return runCommand(command, argv, ["pal", "cli", "relationship-note"]);
|
|
68
|
+
}
|
|
68
69
|
|
|
70
|
+
function appendFromFlags(flags: NoteFlags): undefined {
|
|
71
|
+
const result = notesFromFlags(flags);
|
|
72
|
+
if ("error" in result) throw new UsageError(result.error);
|
|
69
73
|
const { file, written } = appendNotes(result.notes);
|
|
70
74
|
emit.receipt(file, { written, deduped: result.notes.length - written });
|
|
71
75
|
}
|
|
72
76
|
|
|
73
|
-
if (import.meta.main) run();
|
|
77
|
+
if (import.meta.main) process.exit(await run());
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
|
|
16
16
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
17
17
|
import { resolve } from "node:path";
|
|
18
|
-
import { parseArgs } from "node:util";
|
|
19
18
|
import { readOpinions, saveOpinion, setLastReflectDate } from "../../hooks/lib/opinions";
|
|
20
19
|
import { palHome } from "../../hooks/lib/paths";
|
|
20
|
+
import { leaf, runCommand } from "../lib/command";
|
|
21
21
|
import { emit } from "../lib/emit";
|
|
22
22
|
import {
|
|
23
23
|
consoleLines,
|
|
@@ -30,21 +30,27 @@ import {
|
|
|
30
30
|
} from "../lib/relationship-reflect";
|
|
31
31
|
import { scriptArgs } from "../lib/script-args";
|
|
32
32
|
|
|
33
|
-
const
|
|
34
|
-
RelationshipReflect — Periodic reflection + opinion promotion
|
|
35
|
-
|
|
36
|
-
Reads recent relationship notes and ratings. Promotes recurring
|
|
33
|
+
const DETAILS = `Reads recent relationship notes and ratings. Promotes recurring
|
|
37
34
|
observations (O type) into tracked opinions with confidence scoring.
|
|
38
|
-
|
|
39
|
-
Usage:
|
|
40
|
-
pal cli relationship-reflect Reflect on last 7 days (default)
|
|
41
|
-
pal cli relationship-reflect --month Reflect on last 30 days
|
|
42
|
-
pal cli relationship-reflect --dry-run Preview without writing
|
|
35
|
+
With no flags, reflects on the last 7 days.
|
|
43
36
|
|
|
44
37
|
Output:
|
|
45
38
|
- Updates memory/relationship/opinions.json (confidence tracking)
|
|
46
|
-
- Creates reflection report in memory/relationship/reflections
|
|
47
|
-
|
|
39
|
+
- Creates reflection report in memory/relationship/reflections/`;
|
|
40
|
+
|
|
41
|
+
export const command = leaf({
|
|
42
|
+
summary: "Periodic reflection + opinion promotion",
|
|
43
|
+
options: {
|
|
44
|
+
month: { type: "boolean", description: "Reflect on last 30 days" },
|
|
45
|
+
"dry-run": { type: "boolean", description: "Preview without writing" },
|
|
46
|
+
},
|
|
47
|
+
details: DETAILS,
|
|
48
|
+
run: ({ values }) => reflect(values.month ?? false, values["dry-run"] ?? false),
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
export function run(argv: string[] = scriptArgs()): Promise<number> {
|
|
52
|
+
return runCommand(command, argv, ["pal", "cli", "relationship-reflect"]);
|
|
53
|
+
}
|
|
48
54
|
|
|
49
55
|
const relationshipDir = () => resolve(palHome(), "memory", "relationship");
|
|
50
56
|
const ratingsFile = () => resolve(palHome(), "memory", "signals", "ratings.jsonl");
|
|
@@ -57,24 +63,9 @@ function saveReport(report: string, period: string): string {
|
|
|
57
63
|
return filepath;
|
|
58
64
|
}
|
|
59
65
|
|
|
60
|
-
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
options: {
|
|
64
|
-
month: { type: "boolean" },
|
|
65
|
-
"dry-run": { type: "boolean" },
|
|
66
|
-
help: { type: "boolean", short: "h" },
|
|
67
|
-
},
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
if (values.help) {
|
|
71
|
-
console.log(HELP);
|
|
72
|
-
process.exit(0);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const daysBack = values.month ? 30 : 7;
|
|
76
|
-
const period = values.month ? "Monthly" : "Weekly";
|
|
77
|
-
const dryRun = values["dry-run"] ?? false;
|
|
66
|
+
function reflect(month: boolean, dryRun: boolean): undefined {
|
|
67
|
+
const daysBack = month ? 30 : 7;
|
|
68
|
+
const period = month ? "Monthly" : "Weekly";
|
|
78
69
|
|
|
79
70
|
const notes = loadNotes(relationshipDir(), daysBack);
|
|
80
71
|
const ratings = loadRatings(ratingsFile(), daysBack);
|
|
@@ -84,7 +75,7 @@ export function run(argv: string[] = scriptArgs()) {
|
|
|
84
75
|
|
|
85
76
|
if (notes.length === 0 && ratings.length === 0) {
|
|
86
77
|
emit.ok("No data to analyze");
|
|
87
|
-
|
|
78
|
+
return;
|
|
88
79
|
}
|
|
89
80
|
|
|
90
81
|
const plan = planPromotions(notes, readOpinions());
|
|
@@ -109,4 +100,4 @@ export function run(argv: string[] = scriptArgs()) {
|
|
|
109
100
|
for (const line of highConfidenceLines(readOpinions())) emit.ok(line);
|
|
110
101
|
}
|
|
111
102
|
|
|
112
|
-
if (import.meta.main) run();
|
|
103
|
+
if (import.meta.main) process.exit(await run());
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
|
|
16
16
|
import { existsSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
17
17
|
import { resolve } from "node:path";
|
|
18
|
-
import { parseArgs } from "node:util";
|
|
19
18
|
import { ensureDir, paths } from "../../hooks/lib/paths";
|
|
19
|
+
import { leaf, runCommand, UsageError } from "../lib/command";
|
|
20
20
|
import { scriptArgs } from "../lib/script-args";
|
|
21
21
|
import { readJsonl } from "../lib/self-model";
|
|
22
22
|
|
|
@@ -304,33 +304,33 @@ export function synthesize(days: number): SynthesisState {
|
|
|
304
304
|
|
|
305
305
|
// ── CLI ──
|
|
306
306
|
|
|
307
|
-
export
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
307
|
+
export const command = leaf({
|
|
308
|
+
summary: "Aggregate recent PAL activity into compact state",
|
|
309
|
+
options: {
|
|
310
|
+
days: {
|
|
311
|
+
type: "string",
|
|
312
|
+
default: "7",
|
|
313
|
+
value: "<n>",
|
|
314
|
+
description: "Lookback window (default: 7)",
|
|
314
315
|
},
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
--days Lookback window (default: 7)
|
|
326
|
-
--force Skip 24h guard
|
|
316
|
+
force: { type: "boolean", description: "Skip 24h guard" },
|
|
317
|
+
},
|
|
318
|
+
details: "Output: ~/.pal/memory/state/synthesis.json",
|
|
319
|
+
run: ({ values }) =>
|
|
320
|
+
synthesizeUnlessFresh(lookbackDays(values.days), values.force ?? false),
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
export function run(argv: string[] = scriptArgs()): Promise<number> {
|
|
324
|
+
return runCommand(command, argv, ["pal", "cli", "synthesize"]);
|
|
325
|
+
}
|
|
327
326
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
327
|
+
function lookbackDays(raw: string): number {
|
|
328
|
+
const days = parseInt(raw, 10);
|
|
329
|
+
if (Number.isNaN(days)) throw new UsageError(`--days must be a number of days: ${raw}`);
|
|
330
|
+
return days;
|
|
331
|
+
}
|
|
332
332
|
|
|
333
|
-
|
|
333
|
+
function synthesizeUnlessFresh(days: number, force: boolean): undefined {
|
|
334
334
|
if (!shouldRun(force)) {
|
|
335
335
|
console.log(
|
|
336
336
|
JSON.stringify({
|
|
@@ -341,7 +341,6 @@ Output: ~/.pal/memory/state/synthesis.json
|
|
|
341
341
|
return;
|
|
342
342
|
}
|
|
343
343
|
|
|
344
|
-
const days = parseInt(values.days ?? "7", 10);
|
|
345
344
|
const state = synthesize(days);
|
|
346
345
|
const sp = synthesisPath();
|
|
347
346
|
|
|
@@ -363,4 +362,4 @@ Output: ~/.pal/memory/state/synthesis.json
|
|
|
363
362
|
);
|
|
364
363
|
}
|
|
365
364
|
|
|
366
|
-
if (import.meta.main) run();
|
|
365
|
+
if (import.meta.main) process.exit(await run());
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* pal cli thread --list [--all]
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import {
|
|
14
|
+
import { leaf, runCommand, UsageError } from "../lib/command";
|
|
15
15
|
import { emit } from "../lib/emit";
|
|
16
16
|
import { scriptArgs } from "../lib/script-args";
|
|
17
17
|
import {
|
|
@@ -23,20 +23,41 @@ import {
|
|
|
23
23
|
writeThreads,
|
|
24
24
|
} from "../lib/thread";
|
|
25
25
|
|
|
26
|
-
const
|
|
27
|
-
|
|
26
|
+
const DETAILS = `Modes (one of --add, --resolve, --list is required):
|
|
27
|
+
pal cli thread --add --title "..." [--context "..."]
|
|
28
|
+
pal cli thread --resolve --id <id>
|
|
29
|
+
pal cli thread --list [--all]`;
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
export const command = leaf({
|
|
32
|
+
summary: "Manage open threads across sessions",
|
|
33
|
+
options: {
|
|
34
|
+
add: { type: "boolean", description: "Open a new thread (needs --title)" },
|
|
35
|
+
resolve: { type: "boolean", description: "Mark a thread resolved (needs --id)" },
|
|
36
|
+
list: { type: "boolean", description: "Print open threads as JSON" },
|
|
37
|
+
title: { type: "string", value: "<text>", description: "Title of the thread to add" },
|
|
38
|
+
context: {
|
|
39
|
+
type: "string",
|
|
40
|
+
value: "<text>",
|
|
41
|
+
description: "Why it matters, what needs to happen (with --add)",
|
|
42
|
+
},
|
|
43
|
+
id: { type: "string", value: "<id>", description: "Id of the thread to resolve" },
|
|
44
|
+
all: { type: "boolean", description: "Include resolved threads (with --list)" },
|
|
45
|
+
},
|
|
46
|
+
details: DETAILS,
|
|
47
|
+
run: ({ values }) => {
|
|
48
|
+
if (values.add) return add(values.title, values.context);
|
|
49
|
+
if (values.resolve) return markResolved(values.id);
|
|
50
|
+
if (values.list) return list(values.all ?? false);
|
|
51
|
+
throw new UsageError("one of --add, --resolve, --list is required");
|
|
52
|
+
},
|
|
53
|
+
});
|
|
34
54
|
|
|
35
|
-
function
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
55
|
+
export function run(argv: string[] = scriptArgs()): Promise<number> {
|
|
56
|
+
return runCommand(command, argv, ["pal", "cli", "thread"]);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function add(title: string | undefined, context: string | undefined): undefined {
|
|
60
|
+
if (!title) throw new UsageError("--add needs --title");
|
|
40
61
|
const thread = addThread(title, context ?? "");
|
|
41
62
|
emit.receipt(threadsFile(), {
|
|
42
63
|
id: thread.id,
|
|
@@ -45,52 +66,22 @@ function add(title: string | undefined, context: string | undefined) {
|
|
|
45
66
|
});
|
|
46
67
|
}
|
|
47
68
|
|
|
48
|
-
function markResolved(id: string | undefined) {
|
|
49
|
-
if (!id)
|
|
50
|
-
console.error("--id required");
|
|
51
|
-
process.exit(1);
|
|
52
|
-
}
|
|
69
|
+
function markResolved(id: string | undefined): number {
|
|
70
|
+
if (!id) throw new UsageError("--resolve needs --id");
|
|
53
71
|
const file = threadsFile();
|
|
54
72
|
const resolution = resolveThreadIn(readThreads(file), id, new Date());
|
|
55
73
|
if (!resolution) {
|
|
56
74
|
console.error(`Thread not found: ${id}`);
|
|
57
|
-
|
|
75
|
+
return 1;
|
|
58
76
|
}
|
|
59
77
|
writeThreads(resolution.threads, file);
|
|
60
78
|
emit.receipt(file, { id, status: "resolved", title: resolution.thread.title });
|
|
79
|
+
return 0;
|
|
61
80
|
}
|
|
62
81
|
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
options: {
|
|
67
|
-
add: { type: "boolean" },
|
|
68
|
-
resolve: { type: "boolean" },
|
|
69
|
-
list: { type: "boolean" },
|
|
70
|
-
title: { type: "string" },
|
|
71
|
-
context: { type: "string" },
|
|
72
|
-
id: { type: "string" },
|
|
73
|
-
all: { type: "boolean" },
|
|
74
|
-
help: { type: "boolean", short: "h" },
|
|
75
|
-
},
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
let cmd: string | null = null;
|
|
79
|
-
if (values.add) cmd = "add";
|
|
80
|
-
else if (values.resolve) cmd = "resolve";
|
|
81
|
-
else if (values.list) cmd = "list";
|
|
82
|
-
|
|
83
|
-
if (values.help || !cmd) {
|
|
84
|
-
console.log(HELP);
|
|
85
|
-
process.exit(cmd ? 0 : 1);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (cmd === "add") add(values.title, values.context);
|
|
89
|
-
if (cmd === "resolve") markResolved(values.id);
|
|
90
|
-
if (cmd === "list") {
|
|
91
|
-
const threads = visibleThreads(readThreads(), values.all ?? false);
|
|
92
|
-
emit.data(JSON.stringify({ count: threads.length, threads }, null, 2));
|
|
93
|
-
}
|
|
82
|
+
function list(includeResolved: boolean): undefined {
|
|
83
|
+
const threads = visibleThreads(readThreads(), includeResolved);
|
|
84
|
+
emit.data(JSON.stringify({ count: threads.length, threads }, null, 2));
|
|
94
85
|
}
|
|
95
86
|
|
|
96
|
-
if (import.meta.main) run();
|
|
87
|
+
if (import.meta.main) process.exit(await run());
|
|
@@ -7,18 +7,13 @@
|
|
|
7
7
|
* evolution log. Principles are marked [CRYSTAL: N%] manually when
|
|
8
8
|
* confidence is high enough.
|
|
9
9
|
*
|
|
10
|
-
* Usage:
|
|
11
|
-
* bun run tool:wisdom-frame --domain communication --observation "prefers bullet points"
|
|
12
|
-
* bun run tool:wisdom-frame --domain development --observation "refactoring without tests caused regressions" --type anti-pattern
|
|
13
|
-
* bun run tool:wisdom-frame --domain workflow --observation "always run type-check after edits" --type principle
|
|
14
|
-
*
|
|
15
|
-
* Types: principle, contextual-rule, anti-pattern, evolution (default)
|
|
10
|
+
* Usage: pal cli wisdom-frame --domain <domain> --observation "…" [--type <type>]
|
|
16
11
|
*/
|
|
17
12
|
|
|
18
13
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
19
14
|
import { resolve } from "node:path";
|
|
20
|
-
import { parseArgs } from "node:util";
|
|
21
15
|
import { paths } from "../../hooks/lib/paths";
|
|
16
|
+
import { leaf, runCommand, UsageError } from "../lib/command";
|
|
22
17
|
import { emit } from "../lib/emit";
|
|
23
18
|
import { scriptArgs } from "../lib/script-args";
|
|
24
19
|
|
|
@@ -193,23 +188,7 @@ ${antiPatternEntry}
|
|
|
193
188
|
|
|
194
189
|
// ── CLI ──
|
|
195
190
|
|
|
196
|
-
|
|
197
|
-
const { values } = parseArgs({
|
|
198
|
-
args: argv,
|
|
199
|
-
options: {
|
|
200
|
-
domain: { type: "string", short: "d" },
|
|
201
|
-
observation: { type: "string", short: "o" },
|
|
202
|
-
type: { type: "string", short: "t" },
|
|
203
|
-
help: { type: "boolean", short: "h" },
|
|
204
|
-
},
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
if (values.help) {
|
|
208
|
-
console.log(`
|
|
209
|
-
WisdomFrameUpdater — Update wisdom frames with observations
|
|
210
|
-
|
|
211
|
-
Usage:
|
|
212
|
-
bun run tool:wisdom-frame --domain <domain> --observation "text" [--type <type>]
|
|
191
|
+
const DETAILS = `Required: --domain and --observation.
|
|
213
192
|
|
|
214
193
|
Domains:
|
|
215
194
|
development, workflow, communication, infrastructure, integration, or any custom domain
|
|
@@ -221,21 +200,49 @@ Types:
|
|
|
221
200
|
evolution General observation (default)
|
|
222
201
|
|
|
223
202
|
Examples:
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
203
|
+
pal cli wisdom-frame -d workflow -o "always run type-check after edits"
|
|
204
|
+
pal cli wisdom-frame -d development -o "mocking DB hides migration bugs" -t anti-pattern
|
|
205
|
+
pal cli wisdom-frame -d communication -o "user prefers terse summaries" -t principle`;
|
|
206
|
+
|
|
207
|
+
export const command = leaf({
|
|
208
|
+
summary: "Update wisdom frames with observations",
|
|
209
|
+
options: {
|
|
210
|
+
domain: {
|
|
211
|
+
type: "string",
|
|
212
|
+
short: "d",
|
|
213
|
+
value: "<domain>",
|
|
214
|
+
description: "Frame to update; created if it does not exist",
|
|
215
|
+
},
|
|
216
|
+
observation: {
|
|
217
|
+
type: "string",
|
|
218
|
+
short: "o",
|
|
219
|
+
value: "<text>",
|
|
220
|
+
description: "The observation to record",
|
|
221
|
+
},
|
|
222
|
+
type: {
|
|
223
|
+
type: "string",
|
|
224
|
+
short: "t",
|
|
225
|
+
value: "<type>",
|
|
226
|
+
description: "Observation type (default: evolution)",
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
details: DETAILS,
|
|
230
|
+
run: ({ values }) => {
|
|
231
|
+
const { domain, observation } = values;
|
|
232
|
+
if (!domain || !observation) {
|
|
233
|
+
throw new UsageError("--domain and --observation are required");
|
|
234
|
+
}
|
|
235
|
+
return recordObservation(domain, observation, values.type || "evolution");
|
|
236
|
+
},
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
export function run(argv: string[] = scriptArgs()): Promise<number> {
|
|
240
|
+
return runCommand(command, argv, ["pal", "cli", "wisdom-frame"]);
|
|
241
|
+
}
|
|
235
242
|
|
|
236
|
-
|
|
237
|
-
const result = updateFrame(
|
|
243
|
+
function recordObservation(domain: string, observation: string, type: string): undefined {
|
|
244
|
+
const result = updateFrame(domain, observation, type as ObservationType);
|
|
238
245
|
emit.receipt(result.framePath, { domain: result.domain, type: result.type });
|
|
239
246
|
}
|
|
240
247
|
|
|
241
|
-
if (import.meta.main) run();
|
|
248
|
+
if (import.meta.main) process.exit(await run());
|
|
@@ -34,8 +34,6 @@ import {
|
|
|
34
34
|
writeInstallSettings,
|
|
35
35
|
} from "./writes";
|
|
36
36
|
|
|
37
|
-
export { DEFAULT_PORT, LOOPBACK };
|
|
38
|
-
|
|
39
37
|
/**
|
|
40
38
|
* Every path the single-page app owns. Listed rather than wildcarded, because a
|
|
41
39
|
* blanket "/*" outranks the fetch handler and would swallow /api as well.
|