portable-agent-layer 0.78.2 → 0.79.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 +3 -2
- package/assets/schema/pal-settings.schema.json +0 -1
- package/assets/skills/pal-reflect/SKILL.md +2 -2
- package/assets/templates/PAL/SYSTEM_ARCHITECTURE.md +4 -4
- package/assets/templates/pal-settings.json +0 -1
- package/package.json +2 -2
- package/src/cli/builtin-tools.ts +1 -0
- package/src/cli/index.ts +3 -48
- package/src/cli/setup-auto-update.ts +7 -7
- package/src/hooks/AutoUpdate.ts +1 -1
- package/src/hooks/LoadContext.ts +13 -1
- package/src/hooks/PreCompactPersist.ts +2 -2
- package/src/hooks/handlers/persist-last-exchange.ts +128 -33
- package/src/hooks/handlers/session-intelligence.ts +53 -14
- package/src/hooks/lib/algorithm-review.ts +12 -7
- package/src/hooks/lib/auto-update.ts +16 -6
- package/src/hooks/lib/context.ts +18 -56
- package/src/hooks/lib/graduation.ts +2 -2
- package/src/hooks/lib/handoff-context.ts +112 -0
- package/src/hooks/lib/inference.ts +12 -45
- package/src/hooks/lib/log.ts +44 -3
- package/src/hooks/lib/paths.ts +7 -2
- package/src/hooks/lib/projects.ts +16 -4
- package/src/hooks/lib/relationship.ts +2 -2
- package/src/hooks/lib/retrieval-index.ts +13 -6
- package/src/hooks/lib/security.ts +29 -3
- package/src/hooks/lib/semi-static.ts +10 -3
- package/src/hooks/lib/session-context.ts +22 -0
- package/src/hooks/lib/session-dir.ts +9 -0
- package/src/hooks/lib/settings.ts +11 -12
- package/src/hooks/lib/work-tracking.ts +9 -1
- package/src/tools/{relationship-reflect.ts → agent/relationship-reflect.ts} +13 -12
- package/src/tools/control-room/ui/dist/assets/{index-DyhnNmdi.js → index-D_o9Usd_.js} +1 -1
- package/src/tools/control-room/ui/dist/index.html +1 -1
- package/src/tools/control-room/ui/screens/settings.tsx +2 -2
- package/src/tools/self-model.ts +1 -0
|
@@ -7,10 +7,11 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { existsSync, readFileSync } from "node:fs";
|
|
10
|
-
import { resolve } from "node:path";
|
|
10
|
+
import { basename, resolve } from "node:path";
|
|
11
11
|
import { type FailureEntry, readFailures } from "./learning-store";
|
|
12
12
|
import { loadOpinionContext } from "./opinions";
|
|
13
13
|
import { palHome, paths } from "./paths";
|
|
14
|
+
import { type ProjectProgress, readAllProjects, resolveProjectFromCwd } from "./projects";
|
|
14
15
|
import { readFramePrinciples } from "./wisdom";
|
|
15
16
|
|
|
16
17
|
/** A single semi-static context source — built at session stop, loaded natively at session start. */
|
|
@@ -67,6 +68,12 @@ export function rankFailures(
|
|
|
67
68
|
.slice(0, limit);
|
|
68
69
|
}
|
|
69
70
|
|
|
71
|
+
function projectTag(cwd: string, projects: ProjectProgress[]): string {
|
|
72
|
+
if (!cwd) return "";
|
|
73
|
+
const name = resolveProjectFromCwd(cwd, projects)?.name ?? basename(cwd);
|
|
74
|
+
return `[${name}]`;
|
|
75
|
+
}
|
|
76
|
+
|
|
70
77
|
/** Build the failure avoid-list, prioritized by relevance to the current project. */
|
|
71
78
|
export function loadFailurePatterns(): string {
|
|
72
79
|
try {
|
|
@@ -74,11 +81,11 @@ export function loadFailurePatterns(): string {
|
|
|
74
81
|
const all = readFailures(paths.failures());
|
|
75
82
|
if (all.length === 0) return "";
|
|
76
83
|
|
|
84
|
+
const projects = readAllProjects();
|
|
77
85
|
const lines = rankFailures(all, cwd).map((e) => {
|
|
78
86
|
const label = e.rating ? `[${e.rating}/10]` : "";
|
|
79
|
-
const tag = e.cwd === cwd ? "[project]" : "[other]";
|
|
80
87
|
const text = e.principle || e.context;
|
|
81
|
-
return
|
|
88
|
+
return ["-", label, projectTag(e.cwd, projects), text].filter(Boolean).join(" ");
|
|
82
89
|
});
|
|
83
90
|
|
|
84
91
|
return ["## Lessons from Recent Failures — Apply These Now", ...lines].join("\n");
|
|
@@ -24,6 +24,28 @@ export function isSubagentSession(env: NodeJS.ProcessEnv): boolean {
|
|
|
24
24
|
return env.CLAUDE_PROJECT_DIR?.includes("/.claude/Agents/") ?? false;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
export type SessionStartContext = "full" | "without-handoff" | "none";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Claude Code and Codex replay the context injected at startup when a session
|
|
31
|
+
* is resumed. Copilot does not document it, and has shipped a release that
|
|
32
|
+
* dropped startup context, so it keeps getting the full context on resume.
|
|
33
|
+
*/
|
|
34
|
+
const RESUME_KEEPS_CONTEXT: ReadonlySet<string> = new Set(["claude", "codex"]);
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* After a compaction, CompactRecover restores the last exchange, so the
|
|
38
|
+
* handoff is redundant. Agents that name no source get everything.
|
|
39
|
+
*/
|
|
40
|
+
export function contextForSource(
|
|
41
|
+
agent: string,
|
|
42
|
+
source: string | undefined
|
|
43
|
+
): SessionStartContext {
|
|
44
|
+
if (source === "resume" && RESUME_KEEPS_CONTEXT.has(agent)) return "none";
|
|
45
|
+
if (source === "compact") return "without-handoff";
|
|
46
|
+
return "full";
|
|
47
|
+
}
|
|
48
|
+
|
|
27
49
|
/**
|
|
28
50
|
* Copilot and Cursor read AGENTS.md natively from nothing, so it is prepended
|
|
29
51
|
* here; Codex reaches it through a symlink and Claude Code loads it itself.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The folder a session was started in. A hook's own cwd follows every `cd`
|
|
3
|
+
* the agent makes, so keying by it files a session under whatever subfolder
|
|
4
|
+
* it happened to end in. Claude Code exports the start folder as
|
|
5
|
+
* CLAUDE_PROJECT_DIR; agents that do not fall back to the cwd.
|
|
6
|
+
*/
|
|
7
|
+
export function sessionDir(env: NodeJS.ProcessEnv = process.env): string {
|
|
8
|
+
return env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
9
|
+
}
|
|
@@ -54,28 +54,27 @@ const IDENTITY_DEFAULTS: Identity = {
|
|
|
54
54
|
|
|
55
55
|
// ── Singleton ──
|
|
56
56
|
|
|
57
|
-
let cached: PalSettingsData | null = null;
|
|
57
|
+
let cached: { path: string; data: PalSettingsData } | null = null;
|
|
58
58
|
|
|
59
59
|
function settingsPath(): string {
|
|
60
60
|
return resolve(paths.memory(), "pal-settings.json");
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
function
|
|
64
|
-
if (
|
|
65
|
-
const p = settingsPath();
|
|
66
|
-
if (!existsSync(p)) {
|
|
67
|
-
cached = {};
|
|
68
|
-
return cached;
|
|
69
|
-
}
|
|
63
|
+
function readSettingsFile(p: string): PalSettingsData {
|
|
64
|
+
if (!existsSync(p)) return {};
|
|
70
65
|
try {
|
|
71
|
-
|
|
72
|
-
return cached;
|
|
66
|
+
return JSON.parse(readFileSync(p, "utf-8")) as PalSettingsData;
|
|
73
67
|
} catch {
|
|
74
|
-
|
|
75
|
-
return cached;
|
|
68
|
+
return {};
|
|
76
69
|
}
|
|
77
70
|
}
|
|
78
71
|
|
|
72
|
+
function load(): PalSettingsData {
|
|
73
|
+
const p = settingsPath();
|
|
74
|
+
if (cached?.path !== p) cached = { path: p, data: readSettingsFile(p) };
|
|
75
|
+
return cached.data;
|
|
76
|
+
}
|
|
77
|
+
|
|
79
78
|
/** Force re-read from disk (useful after writes) */
|
|
80
79
|
export function reload(): PalSettingsData {
|
|
81
80
|
cached = null;
|
|
@@ -169,7 +169,15 @@ export function appendProjectHistory(cwd: string, entry: ProjectHistoryEntry): v
|
|
|
169
169
|
|
|
170
170
|
/** Read the session history for a given cwd */
|
|
171
171
|
export function readProjectHistory(cwd: string, limit = 15): ProjectHistoryEntry[] {
|
|
172
|
-
|
|
172
|
+
return readHistoryFile(historyFileFor(cwd), limit);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export function lastSessionTitle(project: string): string | undefined {
|
|
176
|
+
const historyPath = resolve(paths.projectHistory(), project, "history.jsonl");
|
|
177
|
+
return readHistoryFile(historyPath, 1)[0]?.title;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function readHistoryFile(historyPath: string, limit: number): ProjectHistoryEntry[] {
|
|
173
181
|
if (!existsSync(historyPath)) return [];
|
|
174
182
|
try {
|
|
175
183
|
const lines = readFileSync(historyPath, "utf-8").trim().split("\n").filter(Boolean);
|
|
@@ -8,17 +8,17 @@
|
|
|
8
8
|
* - Generate a summary report
|
|
9
9
|
*
|
|
10
10
|
* Usage:
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* pal cli relationship-reflect # Reflect on last 7 days
|
|
12
|
+
* pal cli relationship-reflect --month # Reflect on last 30 days
|
|
13
|
+
* pal cli relationship-reflect --dry-run # Preview without writing
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
17
17
|
import { resolve } from "node:path";
|
|
18
18
|
import { parseArgs } from "node:util";
|
|
19
|
-
import { readOpinions, saveOpinion, setLastReflectDate } from "
|
|
20
|
-
import { palHome } from "
|
|
21
|
-
import { emit } from "
|
|
19
|
+
import { readOpinions, saveOpinion, setLastReflectDate } from "../../hooks/lib/opinions";
|
|
20
|
+
import { palHome } from "../../hooks/lib/paths";
|
|
21
|
+
import { emit } from "../lib/emit";
|
|
22
22
|
import {
|
|
23
23
|
consoleLines,
|
|
24
24
|
formatReport,
|
|
@@ -27,7 +27,8 @@ import {
|
|
|
27
27
|
loadRatings,
|
|
28
28
|
planPromotions,
|
|
29
29
|
reportPath,
|
|
30
|
-
} from "
|
|
30
|
+
} from "../lib/relationship-reflect";
|
|
31
|
+
import { scriptArgs } from "../lib/script-args";
|
|
31
32
|
|
|
32
33
|
const HELP = `
|
|
33
34
|
RelationshipReflect — Periodic reflection + opinion promotion
|
|
@@ -36,9 +37,9 @@ Reads recent relationship notes and ratings. Promotes recurring
|
|
|
36
37
|
observations (O type) into tracked opinions with confidence scoring.
|
|
37
38
|
|
|
38
39
|
Usage:
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
|
42
43
|
|
|
43
44
|
Output:
|
|
44
45
|
- Updates memory/relationship/opinions.json (confidence tracking)
|
|
@@ -56,9 +57,9 @@ function saveReport(report: string, period: string): string {
|
|
|
56
57
|
return filepath;
|
|
57
58
|
}
|
|
58
59
|
|
|
59
|
-
function run() {
|
|
60
|
+
export function run(argv: string[] = scriptArgs()) {
|
|
60
61
|
const { values } = parseArgs({
|
|
61
|
-
args:
|
|
62
|
+
args: argv,
|
|
62
63
|
options: {
|
|
63
64
|
month: { type: "boolean" },
|
|
64
65
|
"dry-run": { type: "boolean" },
|