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
|
@@ -6,85 +6,93 @@
|
|
|
6
6
|
* Records algorithm performance data after each LEARN phase.
|
|
7
7
|
* Creates a queryable dataset for improving the algorithm over time.
|
|
8
8
|
*
|
|
9
|
-
* Usage:
|
|
10
|
-
* bun run tool:algorithm-reflect --task "description" --criteria 5 --passed 4 --failed 1 --sentiment 7 \
|
|
11
|
-
* --q1 "Should have read the file before planning" \
|
|
12
|
-
* --q2 "Could have parallelized the explore agents" \
|
|
13
|
-
* --q3 "Missed the implicit constraint about cross-platform"
|
|
9
|
+
* Usage: pal cli algorithm-reflect --task "…" --q1 "…" --q2 "…" --q3 "…" [options]
|
|
14
10
|
*/
|
|
15
11
|
|
|
16
12
|
import { appendFileSync } from "node:fs";
|
|
17
|
-
import { parseArgs } from "node:util";
|
|
18
13
|
import { paths } from "../../hooks/lib/paths";
|
|
19
14
|
import { buildReflection, intOr, reflectionLine } from "../lib/algorithm-reflect";
|
|
15
|
+
import { leaf, runCommand, UsageError } from "../lib/command";
|
|
20
16
|
import { emit } from "../lib/emit";
|
|
21
17
|
import { scriptArgs } from "../lib/script-args";
|
|
22
18
|
|
|
23
|
-
const
|
|
24
|
-
AlgorithmReflect — Log algorithm performance after LEARN phase
|
|
19
|
+
const DETAILS = `Required: --task, --q1, --q2, --q3.
|
|
25
20
|
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
Example:
|
|
22
|
+
pal cli algorithm-reflect --task "description" --criteria N --passed N --failed N --sentiment 1-10 \\
|
|
28
23
|
--q1 "self reflection" --q2 "algorithm reflection" --q3 "AI reflection"
|
|
29
24
|
|
|
30
|
-
|
|
31
|
-
--task Brief task description
|
|
32
|
-
--criteria Total criteria count
|
|
33
|
-
--passed Criteria passed
|
|
34
|
-
--failed Criteria failed
|
|
35
|
-
--sentiment Implied satisfaction 1-10
|
|
36
|
-
--q1 Q1 — Self: what I'd do differently
|
|
37
|
-
--q2 Q2 — Algorithm: structural improvement
|
|
38
|
-
--q3 Q3 — AI: reasoning blind spot
|
|
39
|
-
--scope general (default) | task-specific — is the algorithm idea reusable or task-bound?
|
|
25
|
+
Output: algorithm-reflections.jsonl in memory/learning/reflections/`;
|
|
40
26
|
|
|
41
|
-
|
|
42
|
-
`;
|
|
27
|
+
const REQUIRED = ["task", "q1", "q2", "q3"] as const;
|
|
43
28
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
passed: { type: "string" },
|
|
56
|
-
failed: { type: "string" },
|
|
57
|
-
sentiment: { type: "string" },
|
|
58
|
-
q1: { type: "string" },
|
|
59
|
-
q2: { type: "string" },
|
|
60
|
-
q3: { type: "string" },
|
|
61
|
-
scope: { type: "string" },
|
|
62
|
-
help: { type: "boolean", short: "h" },
|
|
29
|
+
export const command = leaf({
|
|
30
|
+
summary: "Log algorithm performance after the LEARN phase",
|
|
31
|
+
options: {
|
|
32
|
+
task: { type: "string", value: "<text>", description: "Brief task description" },
|
|
33
|
+
criteria: { type: "string", value: "<n>", description: "Total criteria count" },
|
|
34
|
+
passed: { type: "string", value: "<n>", description: "Criteria passed" },
|
|
35
|
+
failed: { type: "string", value: "<n>", description: "Criteria failed" },
|
|
36
|
+
sentiment: {
|
|
37
|
+
type: "string",
|
|
38
|
+
value: "<1-10>",
|
|
39
|
+
description: "Implied satisfaction 1-10",
|
|
63
40
|
},
|
|
64
|
-
|
|
41
|
+
q1: {
|
|
42
|
+
type: "string",
|
|
43
|
+
value: "<text>",
|
|
44
|
+
description: "Q1 — Self: what I'd do differently",
|
|
45
|
+
},
|
|
46
|
+
q2: {
|
|
47
|
+
type: "string",
|
|
48
|
+
value: "<text>",
|
|
49
|
+
description: "Q2 — Algorithm: structural improvement",
|
|
50
|
+
},
|
|
51
|
+
q3: { type: "string", value: "<text>", description: "Q3 — AI: reasoning blind spot" },
|
|
52
|
+
scope: {
|
|
53
|
+
type: "string",
|
|
54
|
+
value: "<scope>",
|
|
55
|
+
description:
|
|
56
|
+
"general (default) | task-specific — is the algorithm idea reusable or task-bound?",
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
details: DETAILS,
|
|
60
|
+
run: ({ values }) => {
|
|
61
|
+
const { task, q1, q2, q3 } = values;
|
|
62
|
+
if (!task || !q1 || !q2 || !q3) throw new UsageError(missingRequired(values));
|
|
63
|
+
return appendReflection(
|
|
64
|
+
buildReflection({
|
|
65
|
+
task,
|
|
66
|
+
q1,
|
|
67
|
+
q2,
|
|
68
|
+
q3,
|
|
69
|
+
criteria_count: intOr(values.criteria, 0),
|
|
70
|
+
criteria_passed: intOr(values.passed, 0),
|
|
71
|
+
criteria_failed: intOr(values.failed, 0),
|
|
72
|
+
sentiment: intOr(values.sentiment, 5),
|
|
73
|
+
scope: values.scope,
|
|
74
|
+
})
|
|
75
|
+
);
|
|
76
|
+
},
|
|
77
|
+
});
|
|
65
78
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
79
|
+
export function run(argv: string[] = scriptArgs()): Promise<number> {
|
|
80
|
+
return runCommand(command, argv, ["pal", "cli", "algorithm-reflect"]);
|
|
81
|
+
}
|
|
70
82
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
83
|
+
function missingRequired(
|
|
84
|
+
values: Partial<Record<(typeof REQUIRED)[number], string>>
|
|
85
|
+
): string {
|
|
86
|
+
const missing = REQUIRED.filter((name) => !values[name]).map((name) => `--${name}`);
|
|
87
|
+
return `missing ${missing.join(", ")}`;
|
|
88
|
+
}
|
|
75
89
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
q3: values.q3,
|
|
81
|
-
criteria_count: intOr(values.criteria, 0),
|
|
82
|
-
criteria_passed: intOr(values.passed, 0),
|
|
83
|
-
criteria_failed: intOr(values.failed, 0),
|
|
84
|
-
sentiment: intOr(values.sentiment, 5),
|
|
85
|
-
scope: values.scope,
|
|
86
|
-
});
|
|
90
|
+
function reflectionsPath(): string {
|
|
91
|
+
paths.reflections();
|
|
92
|
+
return paths.reflectionsFile();
|
|
93
|
+
}
|
|
87
94
|
|
|
95
|
+
function appendReflection(reflection: ReturnType<typeof buildReflection>): undefined {
|
|
88
96
|
const path = reflectionsPath();
|
|
89
97
|
appendFileSync(path, reflectionLine(reflection), "utf-8");
|
|
90
98
|
emit.receipt(path, {
|
|
@@ -94,4 +102,4 @@ export function run(argv: string[] = scriptArgs()) {
|
|
|
94
102
|
});
|
|
95
103
|
}
|
|
96
104
|
|
|
97
|
-
if (import.meta.main) run();
|
|
105
|
+
if (import.meta.main) process.exit(await run());
|
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
* invisible even when (especially when) the keyword sort misses or mis-sorts it.
|
|
15
15
|
*
|
|
16
16
|
* Library: import { synthesizeAlgorithm, formatAlgorithmReport } from ".../algorithm-synthesize"
|
|
17
|
-
* Script:
|
|
17
|
+
* Script: pal cli algorithm-synthesize [--since <ISO>] [--json]
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import { parseArgs } from "node:util";
|
|
21
20
|
import { readReflections } from "../../hooks/lib/learning-store";
|
|
22
21
|
import { paths } from "../../hooks/lib/paths";
|
|
22
|
+
import { leaf, runCommand, UsageError } from "../lib/command";
|
|
23
23
|
import { scriptArgs } from "../lib/script-args";
|
|
24
24
|
|
|
25
25
|
/** Algorithm areas a Q2 idea can target, mapped to ALGORITHM.md structure. */
|
|
@@ -203,19 +203,44 @@ export function formatAlgorithmReport(s: AlgorithmSynthesis): string {
|
|
|
203
203
|
return lines.join("\n");
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
206
|
+
const DETAILS = `Reads the Q2 field ("what a smarter algorithm would have done") of every
|
|
207
|
+
algorithm reflection and pre-sorts it into candidate areas of ALGORITHM.md. The
|
|
208
|
+
buckets are a keyword hint only: every Q2 they miss is listed in full under
|
|
209
|
+
"Unbucketed", and task-specific Q2s are listed separately.`;
|
|
210
|
+
|
|
211
|
+
export const command = leaf({
|
|
212
|
+
summary: "Cluster algorithm reflections into candidate ALGORITHM.md changes",
|
|
213
|
+
options: {
|
|
214
|
+
since: {
|
|
215
|
+
type: "string",
|
|
216
|
+
value: "<iso-date>",
|
|
217
|
+
description: "Only reflections from this date on (default: all time)",
|
|
212
218
|
},
|
|
213
|
-
|
|
214
|
-
|
|
219
|
+
json: {
|
|
220
|
+
type: "boolean",
|
|
221
|
+
default: false,
|
|
222
|
+
description: "Print the full synthesis as JSON instead of the report",
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
details: DETAILS,
|
|
226
|
+
run: ({ values }) => printSynthesis(sinceDate(values.since), values.json),
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
export function run(argv: string[] = scriptArgs()): Promise<number> {
|
|
230
|
+
return runCommand(command, argv, ["pal", "cli", "algorithm-synthesize"]);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function sinceDate(raw: string | undefined): Date | undefined {
|
|
234
|
+
if (raw === undefined) return undefined;
|
|
235
|
+
const since = new Date(raw);
|
|
236
|
+
if (Number.isNaN(since.getTime()))
|
|
237
|
+
throw new UsageError(`--since is not a date: ${raw}`);
|
|
238
|
+
return since;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function printSynthesis(since: Date | undefined, asJson: boolean): undefined {
|
|
215
242
|
const result = synthesizeAlgorithm(since);
|
|
216
|
-
console.log(
|
|
217
|
-
values.json ? JSON.stringify(result, null, 2) : formatAlgorithmReport(result)
|
|
218
|
-
);
|
|
243
|
+
console.log(asJson ? JSON.stringify(result, null, 2) : formatAlgorithmReport(result));
|
|
219
244
|
}
|
|
220
245
|
|
|
221
|
-
if (import.meta.main) run();
|
|
246
|
+
if (import.meta.main) process.exit(await run());
|
|
@@ -7,53 +7,48 @@
|
|
|
7
7
|
*
|
|
8
8
|
* What the report says is in lib/analyze-report.ts.
|
|
9
9
|
*
|
|
10
|
-
* Usage:
|
|
10
|
+
* Usage: pal cli analyze [--actionable]
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { parseArgs } from "node:util";
|
|
14
13
|
import { writeLastAnalyzeDate } from "../../hooks/lib/analyze-nudge";
|
|
15
14
|
import { analyze } from "../../hooks/lib/graduation";
|
|
16
15
|
import { reportLines } from "../lib/analyze-report";
|
|
16
|
+
import { leaf, runCommand } from "../lib/command";
|
|
17
17
|
import { scriptArgs } from "../lib/script-args";
|
|
18
18
|
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
`;
|
|
39
|
-
|
|
40
|
-
export async function run(argv: string[] = scriptArgs()) {
|
|
41
|
-
const { values } = parseArgs({
|
|
42
|
-
args: argv,
|
|
43
|
-
options: {
|
|
44
|
-
help: { type: "boolean", short: "h" },
|
|
45
|
-
actionable: { type: "boolean", short: "a" },
|
|
19
|
+
const DETAILS = `Reads all captured failures (rating ≤3) and session learnings,
|
|
20
|
+
groups recurring patterns via Dice similarity on context text,
|
|
21
|
+
and summarizes rating trends.
|
|
22
|
+
|
|
23
|
+
Sections:
|
|
24
|
+
Ratings Overall average, low/high counts
|
|
25
|
+
Graduation Patterns with 3+ occurrences → ready to crystallize
|
|
26
|
+
Emerging Patterns with 2 occurrences → one more to graduate
|
|
27
|
+
|
|
28
|
+
To crystallize a graduated pattern, add it to the target wisdom frame:
|
|
29
|
+
- Your principle here [CRYSTAL: 85%]`;
|
|
30
|
+
|
|
31
|
+
export const command = leaf({
|
|
32
|
+
summary: "PAL Learning Analysis — unified graduation + ratings report",
|
|
33
|
+
options: {
|
|
34
|
+
actionable: {
|
|
35
|
+
type: "boolean",
|
|
36
|
+
short: "a",
|
|
37
|
+
description: "Generate actionable recommendations via Haiku inference",
|
|
46
38
|
},
|
|
47
|
-
}
|
|
39
|
+
},
|
|
40
|
+
details: DETAILS,
|
|
41
|
+
run: ({ values }) => printAnalysis(values.actionable),
|
|
42
|
+
});
|
|
48
43
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
44
|
+
export function run(argv: string[] = scriptArgs()): Promise<number> {
|
|
45
|
+
return runCommand(command, argv, ["pal", "cli", "analyze"]);
|
|
46
|
+
}
|
|
53
47
|
|
|
54
|
-
|
|
48
|
+
async function printAnalysis(actionable: boolean | undefined): Promise<undefined> {
|
|
49
|
+
const result = await analyze({ actionable });
|
|
55
50
|
for (const line of reportLines(result)) console.log(line);
|
|
56
51
|
writeLastAnalyzeDate(new Date().toISOString());
|
|
57
52
|
}
|
|
58
53
|
|
|
59
|
-
if (import.meta.main) await run();
|
|
54
|
+
if (import.meta.main) process.exit(await run());
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { writeFileSync } from "node:fs";
|
|
14
|
-
import {
|
|
14
|
+
import { leaf, runCommand, UsageError } from "../lib/command";
|
|
15
15
|
import { emit } from "../lib/emit";
|
|
16
16
|
import {
|
|
17
17
|
handoffFile,
|
|
@@ -22,68 +22,65 @@ import {
|
|
|
22
22
|
} from "../lib/handoff-note";
|
|
23
23
|
import { scriptArgs } from "../lib/script-args";
|
|
24
24
|
|
|
25
|
-
const
|
|
26
|
-
HandoffNote — Write a handoff note for the current project
|
|
25
|
+
const DETAILS = `Required: --title and --text, or --done to close.
|
|
27
26
|
|
|
28
|
-
|
|
27
|
+
Examples:
|
|
29
28
|
pal cli handoff-note --title "what we were doing" --text "what remains"
|
|
30
29
|
pal cli handoff-note --done # mark session completed
|
|
31
30
|
|
|
32
|
-
|
|
33
|
-
--title Brief title of what was being worked on (5-10 words)
|
|
34
|
-
--text What remains unfinished — decisions made, next steps, blockers
|
|
35
|
-
--waiting What this needs from you before it can move (a decision, an answer, access)
|
|
36
|
-
--done Mark as completed; suppresses "pick up where you left off" injection
|
|
31
|
+
Output: writes to memory/state/last-handoff.json keyed by cwd`;
|
|
37
32
|
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
export const command = leaf({
|
|
34
|
+
summary: "Write a handoff note for the current project",
|
|
35
|
+
options: {
|
|
36
|
+
title: {
|
|
37
|
+
type: "string",
|
|
38
|
+
value: "<text>",
|
|
39
|
+
description: "Brief title of what was being worked on (5-10 words)",
|
|
40
|
+
},
|
|
41
|
+
text: {
|
|
42
|
+
type: "string",
|
|
43
|
+
value: "<text>",
|
|
44
|
+
description: "What remains unfinished — decisions made, next steps, blockers",
|
|
45
|
+
},
|
|
46
|
+
waiting: {
|
|
47
|
+
type: "string",
|
|
48
|
+
value: "<text>",
|
|
49
|
+
description:
|
|
50
|
+
"What this needs from you before it can move (a decision, an answer, access)",
|
|
51
|
+
},
|
|
52
|
+
done: {
|
|
53
|
+
type: "boolean",
|
|
54
|
+
description: `Mark as completed; suppresses "pick up where you left off" injection`,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
details: DETAILS,
|
|
58
|
+
run: ({ values }) => {
|
|
59
|
+
const { title, text, waiting, done } = values;
|
|
60
|
+
if (done) {
|
|
61
|
+
return saveNote({
|
|
62
|
+
cwd: process.cwd(),
|
|
63
|
+
title: title || "session",
|
|
64
|
+
text: text || "",
|
|
65
|
+
done: true,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
if (!title || !text) {
|
|
69
|
+
throw new UsageError("--title and --text are required (or --done to close)");
|
|
70
|
+
}
|
|
71
|
+
return saveNote({ cwd: process.cwd(), title, text, done: false, waitingOn: waiting });
|
|
72
|
+
},
|
|
73
|
+
});
|
|
40
74
|
|
|
41
|
-
function
|
|
75
|
+
export function run(argv: string[] = scriptArgs()): Promise<number> {
|
|
76
|
+
return runCommand(command, argv, ["pal", "cli", "handoff-note"]);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function saveNote(note: NoteInput): undefined {
|
|
42
80
|
const file = handoffFile();
|
|
43
81
|
const store = recordNote(readHandoffs(file), note, new Date());
|
|
44
82
|
writeFileSync(file, JSON.stringify(store, null, 2), "utf-8");
|
|
45
83
|
emit.receipt(file, { status: statusOf(note), entries: Object.keys(store).length });
|
|
46
84
|
}
|
|
47
85
|
|
|
48
|
-
|
|
49
|
-
const { values } = parseArgs({
|
|
50
|
-
args: argv,
|
|
51
|
-
options: {
|
|
52
|
-
title: { type: "string" },
|
|
53
|
-
text: { type: "string" },
|
|
54
|
-
waiting: { type: "string" },
|
|
55
|
-
done: { type: "boolean" },
|
|
56
|
-
help: { type: "boolean", short: "h" },
|
|
57
|
-
},
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
if (values.help) {
|
|
61
|
-
console.log(HELP);
|
|
62
|
-
process.exit(0);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (values.done) {
|
|
66
|
-
saveNote({
|
|
67
|
-
cwd: process.cwd(),
|
|
68
|
-
title: values.title || "session",
|
|
69
|
-
text: values.text || "",
|
|
70
|
-
done: true,
|
|
71
|
-
});
|
|
72
|
-
process.exit(0);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (!values.title || !values.text) {
|
|
76
|
-
console.error("Required: --title and --text (or --done to close)");
|
|
77
|
-
process.exit(1);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
saveNote({
|
|
81
|
-
cwd: process.cwd(),
|
|
82
|
-
title: values.title,
|
|
83
|
-
text: values.text,
|
|
84
|
-
done: false,
|
|
85
|
-
waitingOn: values.waiting,
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (import.meta.main) run();
|
|
86
|
+
if (import.meta.main) process.exit(await run());
|
|
@@ -6,42 +6,46 @@
|
|
|
6
6
|
* Usage: pal cli interaction report [--days N]
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { parseArgs } from "node:util";
|
|
10
9
|
import { claimChecksSince } from "../../hooks/lib/claim-log";
|
|
11
10
|
import { turnsSince } from "../../hooks/lib/interaction";
|
|
11
|
+
import { group, leaf, runCommand, UsageError } from "../lib/command";
|
|
12
12
|
import { claimCheckLines, reportLines, summarize } from "../lib/interaction-report";
|
|
13
13
|
import { scriptArgs } from "../lib/script-args";
|
|
14
14
|
|
|
15
|
-
const
|
|
16
|
-
|
|
15
|
+
const DETAILS = `Reads the measured turns in memory/signals/interaction/ (features only, no
|
|
16
|
+
text) and prints turns, channels, reactions, the hints sent, per agent the
|
|
17
|
+
turns, replies filed and hints sent, and for each label (short, long, fast,
|
|
18
|
+
skimming, friction) how the replies written while it was active compare with
|
|
19
|
+
the replies written while none was. Last, the replies that claimed a result
|
|
20
|
+
(memory/signals/claim-checks/), and which of them had no command behind the
|
|
21
|
+
claim or were sent back.`;
|
|
17
22
|
|
|
18
|
-
|
|
19
|
-
text) and prints turns, channels, reactions, the hints sent, per agent the
|
|
20
|
-
turns, replies filed and hints sent, and for each
|
|
21
|
-
label (short, long, fast, skimming, friction) how the replies written while
|
|
22
|
-
it was active compare with the replies written while none was. Last, the
|
|
23
|
-
replies that claimed a result (memory/signals/claim-checks/), and which of
|
|
24
|
-
them had no command behind the claim or were sent back.
|
|
23
|
+
const DAY_MS = 86_400_000;
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
export const command = group({
|
|
26
|
+
summary: "How the user's turns went, and whether replies changed under each label",
|
|
27
|
+
commands: {
|
|
28
|
+
report: leaf({
|
|
29
|
+
summary: "Print the interaction report",
|
|
30
|
+
options: {
|
|
31
|
+
days: {
|
|
32
|
+
type: "string",
|
|
33
|
+
value: "<n>",
|
|
34
|
+
description: "Days to look back (default 7)",
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
details: DETAILS,
|
|
38
|
+
run: ({ values }) => printReport(Number(values.days ?? "7")),
|
|
39
|
+
}),
|
|
40
|
+
},
|
|
41
|
+
});
|
|
28
42
|
|
|
29
|
-
|
|
43
|
+
export function run(argv: string[] = scriptArgs()): Promise<number> {
|
|
44
|
+
return runCommand(command, argv, ["pal", "cli", "interaction"]);
|
|
45
|
+
}
|
|
30
46
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
args: argv,
|
|
34
|
-
allowPositionals: true,
|
|
35
|
-
options: {
|
|
36
|
-
help: { type: "boolean", short: "h" },
|
|
37
|
-
days: { type: "string", default: "7" },
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
const days = Number(values.days);
|
|
41
|
-
if (values.help || positionals[0] !== "report" || !(days > 0)) {
|
|
42
|
-
console.log(HELP);
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
47
|
+
function printReport(days: number): undefined {
|
|
48
|
+
if (!(days > 0)) throw new UsageError("--days must be a positive number");
|
|
45
49
|
const since = new Date(Date.now() - days * DAY_MS);
|
|
46
50
|
const events = turnsSince(since);
|
|
47
51
|
const claims = claimCheckLines(claimChecksSince(since));
|
|
@@ -49,4 +53,4 @@ export function run(argv: string[] = scriptArgs()) {
|
|
|
49
53
|
console.log(line);
|
|
50
54
|
}
|
|
51
55
|
|
|
52
|
-
if (import.meta.main) run();
|
|
56
|
+
if (import.meta.main) process.exit(await run());
|