portable-agent-layer 0.35.0 → 0.36.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.
Files changed (37) hide show
  1. package/README.md +1 -1
  2. package/assets/skills/projects/SKILL.md +0 -1
  3. package/assets/skills/telos/SKILL.md +7 -52
  4. package/assets/templates/PAL/ALGORITHM.md +28 -3
  5. package/assets/templates/PAL/PROJECT_LIFECYCLE.md +48 -0
  6. package/assets/templates/PAL/README.md +1 -1
  7. package/assets/templates/PAL/STEERING_RULES.md +4 -0
  8. package/assets/templates/PAL/SYSTEM_ARCHITECTURE.md +32 -17
  9. package/assets/templates/PAL/WORK_TRACKING.md +1 -1
  10. package/assets/templates/pal-settings.json +1 -3
  11. package/assets/templates/settings.claude.json +2 -1
  12. package/package.json +1 -1
  13. package/src/cli/setup-telos.ts +12 -79
  14. package/src/hooks/LoadContext.ts +22 -10
  15. package/src/hooks/handlers/context-digests.ts +74 -0
  16. package/src/hooks/handlers/session-intelligence.ts +9 -86
  17. package/src/hooks/lib/claude-md.ts +69 -14
  18. package/src/hooks/lib/context.ts +57 -139
  19. package/src/hooks/lib/relationship.ts +3 -3
  20. package/src/hooks/lib/security.ts +2 -0
  21. package/src/hooks/lib/semi-static.ts +186 -0
  22. package/src/hooks/lib/setup.ts +0 -5
  23. package/src/hooks/lib/stop.ts +3 -0
  24. package/src/targets/claude/uninstall.ts +1 -1
  25. package/src/targets/copilot/install.ts +39 -8
  26. package/src/targets/copilot/uninstall.ts +58 -17
  27. package/src/targets/cursor/install.ts +8 -0
  28. package/src/targets/cursor/uninstall.ts +18 -1
  29. package/src/targets/lib.ts +26 -0
  30. package/src/targets/opencode/install.ts +29 -1
  31. package/src/targets/opencode/plugin.ts +1 -1
  32. package/src/targets/opencode/uninstall.ts +30 -3
  33. package/src/tools/agent/handoff-note.ts +116 -0
  34. package/src/tools/agent/relationship-note.ts +51 -0
  35. package/src/tools/relationship-reflect.ts +2 -2
  36. package/src/tools/self-model.ts +4 -4
  37. package/assets/templates/telos/PROJECTS.md +0 -7
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * HandoffNote — Write or clear a handoff note for the current project.
4
+ *
5
+ * Called in the ALGORITHM LEARN phase when work is unfinished.
6
+ * Written by Claude in-session — no inference call needed.
7
+ *
8
+ * Usage:
9
+ * bun ~/.pal/tools/handoff-note.ts --title "what we were doing" --text "what remains + next steps"
10
+ * bun ~/.pal/tools/handoff-note.ts --done # mark completed, suppress next-session injection
11
+ */
12
+
13
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
14
+ import { resolve } from "node:path";
15
+ import { parseArgs } from "node:util";
16
+ import { ensureDir, paths } from "../../hooks/lib/paths";
17
+
18
+ interface HandoffEntry {
19
+ timestamp: string;
20
+ title: string;
21
+ status: "in-progress" | "completed";
22
+ handoff: string;
23
+ artifacts: string[];
24
+ }
25
+
26
+ function handoffPath(): string {
27
+ return resolve(ensureDir(paths.state()), "last-handoff.json");
28
+ }
29
+
30
+ function readHandoffs(): Record<string, HandoffEntry> {
31
+ const p = handoffPath();
32
+ if (!existsSync(p)) return {};
33
+ try {
34
+ return JSON.parse(readFileSync(p, "utf-8"));
35
+ } catch {
36
+ return {};
37
+ }
38
+ }
39
+
40
+ function writeHandoffs(handoffs: Record<string, HandoffEntry>): void {
41
+ const entries = Object.entries(handoffs);
42
+ const trimmed = entries.length > 20 ? Object.fromEntries(entries.slice(-20)) : handoffs;
43
+ writeFileSync(handoffPath(), JSON.stringify(trimmed, null, 2), "utf-8");
44
+ }
45
+
46
+ export function writeHandoffNote(
47
+ cwd: string,
48
+ title: string,
49
+ text: string,
50
+ done: boolean
51
+ ): { success: boolean; message: string } {
52
+ const handoffs = readHandoffs();
53
+ handoffs[cwd] = {
54
+ timestamp: new Date().toISOString(),
55
+ title,
56
+ status: done ? "completed" : "in-progress",
57
+ handoff: text,
58
+ artifacts: [],
59
+ };
60
+ writeHandoffs(handoffs);
61
+ return {
62
+ success: true,
63
+ message: done ? "Handoff cleared (marked completed)" : "Handoff note written",
64
+ };
65
+ }
66
+
67
+ function run() {
68
+ const { values } = parseArgs({
69
+ args: Bun.argv.slice(2),
70
+ options: {
71
+ title: { type: "string" },
72
+ text: { type: "string" },
73
+ done: { type: "boolean" },
74
+ help: { type: "boolean", short: "h" },
75
+ },
76
+ });
77
+
78
+ if (values.help) {
79
+ console.log(`
80
+ HandoffNote — Write a handoff note for the current project
81
+
82
+ Usage:
83
+ bun ~/.pal/tools/handoff-note.ts --title "what we were doing" --text "what remains"
84
+ bun ~/.pal/tools/handoff-note.ts --done # mark session completed
85
+
86
+ Arguments:
87
+ --title Brief title of what was being worked on (5-10 words)
88
+ --text What remains unfinished — decisions made, next steps, blockers
89
+ --done Mark as completed; suppresses "pick up where you left off" injection
90
+
91
+ Output: writes to memory/state/last-handoff.json keyed by cwd
92
+ `);
93
+ process.exit(0);
94
+ }
95
+
96
+ if (values.done) {
97
+ const result = writeHandoffNote(
98
+ process.cwd(),
99
+ values.title || "session",
100
+ values.text || "",
101
+ true
102
+ );
103
+ console.log(JSON.stringify(result, null, 2));
104
+ process.exit(0);
105
+ }
106
+
107
+ if (!values.title || !values.text) {
108
+ console.error("Required: --title and --text (or --done to close)");
109
+ process.exit(1);
110
+ }
111
+
112
+ const result = writeHandoffNote(process.cwd(), values.title, values.text, false);
113
+ console.log(JSON.stringify(result, null, 2));
114
+ }
115
+
116
+ if (import.meta.main) run();
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * RelationshipNote — Write a B entry to today's relationship log.
4
+ *
5
+ * Called in the ALGORITHM LEARN phase. Claude writes the B entry directly
6
+ * from full session context — no inference call needed.
7
+ *
8
+ * Usage:
9
+ * bun ~/.pal/tools/relationship-note.ts --b "what I did this session"
10
+ */
11
+
12
+ import { parseArgs } from "node:util";
13
+ import { appendNotes } from "../../hooks/lib/relationship";
14
+
15
+ function run() {
16
+ const { values } = parseArgs({
17
+ args: Bun.argv.slice(2),
18
+ options: {
19
+ b: { type: "string" },
20
+ help: { type: "boolean", short: "h" },
21
+ },
22
+ });
23
+
24
+ if (values.help) {
25
+ console.log(`
26
+ RelationshipNote — Append a B entry to today's relationship log
27
+
28
+ Usage:
29
+ bun ~/.pal/tools/relationship-note.ts --b "description"
30
+
31
+ Arguments:
32
+ --b What happened this session (1-2 sentences, first-person, specific)
33
+
34
+ Output: appends to memory/relationship/YYYY-MM/YYYY-MM-DD.md
35
+ `);
36
+ process.exit(0);
37
+ }
38
+
39
+ if (!values.b) {
40
+ console.error("Required: --b");
41
+ process.exit(1);
42
+ }
43
+
44
+ appendNotes([{ type: "Session", text: values.b }]);
45
+
46
+ console.log(
47
+ JSON.stringify({ success: true, message: "Relationship note written" }, null, 2)
48
+ );
49
+ }
50
+
51
+ if (import.meta.main) run();
@@ -37,7 +37,7 @@ interface Rating {
37
37
  }
38
38
 
39
39
  interface ParsedNote {
40
- type: "W" | "O" | "B";
40
+ type: "W" | "O" | "Session";
41
41
  text: string;
42
42
  confidence?: number;
43
43
  date: string;
@@ -94,7 +94,7 @@ export function loadNotes(daysBack: number): ParsedNote[] {
94
94
  const obMatch = line.match(/^- ([OB])\(c=([\d.]+)\):\s*(.+)$/);
95
95
  if (obMatch) {
96
96
  notes.push({
97
- type: obMatch[1] as "O" | "B",
97
+ type: obMatch[1] as "O" | "Session",
98
98
  confidence: Number.parseFloat(obMatch[2]),
99
99
  text: obMatch[3],
100
100
  date: dateStr,
@@ -71,7 +71,7 @@ interface AlgorithmReflection {
71
71
  }
72
72
 
73
73
  interface RelationshipNote {
74
- type: "O" | "W" | "B";
74
+ type: "O" | "W" | "Session";
75
75
  content: string;
76
76
  confidence?: number;
77
77
  date: string;
@@ -292,9 +292,9 @@ function readRelationshipNotes(since: Date): RelationshipNote[] {
292
292
  continue;
293
293
  }
294
294
 
295
- const behaviorMatch = noteContent.match(/^B:\s*(.+)$/);
295
+ const behaviorMatch = noteContent.match(/^Session:\s*(.+)$/);
296
296
  if (behaviorMatch) {
297
- notes.push({ type: "B", content: behaviorMatch[1], date: dateStr });
297
+ notes.push({ type: "Session", content: behaviorMatch[1], date: dateStr });
298
298
  }
299
299
  }
300
300
  }
@@ -376,7 +376,7 @@ function gatherData(days: number): SelfModelData {
376
376
  wisdomFrames,
377
377
  graduated,
378
378
  reflections,
379
- behaviorNotes: relNotes.filter((n) => n.type === "B").map((n) => n.content),
379
+ behaviorNotes: relNotes.filter((n) => n.type === "Session").map((n) => n.content),
380
380
  wisdomNotes: relNotes.filter((n) => n.type === "W").map((n) => n.content),
381
381
  selfObservations: reflections.map((r) => r.q1).filter(Boolean),
382
382
  algorithmObservations: reflections.map((r) => r.q2).filter(Boolean),
@@ -1,7 +0,0 @@
1
- # Projects
2
-
3
- <!-- Current projects, their status, and how they relate to each other. -->
4
-
5
- | Project | Status | Priority | Notes |
6
- |---------|--------|----------|-------|
7
- | | | | |