portable-agent-layer 0.88.1 → 0.89.1
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/readme-sync.ts +6 -2
- 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/export-manifest.ts +23 -0
- package/src/hooks/lib/export.ts +1 -24
- package/src/hooks/lib/hook-turn.ts +25 -2
- package/src/hooks/lib/import-merge.ts +1 -1
- 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/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/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
package/src/cli/doctor/agents.ts
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
2
|
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
3
3
|
import { isAbsolute, resolve } from "node:path";
|
|
4
|
-
import
|
|
4
|
+
import {
|
|
5
|
+
AGENT_REGISTRY,
|
|
6
|
+
type AgentName,
|
|
7
|
+
AGENT_NAMES as REGISTERED_AGENTS,
|
|
8
|
+
skillsDirOf,
|
|
9
|
+
} from "../../hooks/lib/agent-registry";
|
|
5
10
|
import { palPkg, platform } from "../../hooks/lib/paths";
|
|
6
11
|
import { nativeAgentsDir, staleShippedAgents } from "../../targets/lib";
|
|
7
12
|
import { NO_SESSION_AGENT_MESSAGE } from "../session-agent";
|
|
8
13
|
import { type Finding, type Fix, failing, optional, passed, warning } from "./finding";
|
|
9
14
|
|
|
10
|
-
export type AgentName
|
|
15
|
+
export type { AgentName };
|
|
11
16
|
|
|
12
|
-
const AGENT_NAMES: AgentName[] = [
|
|
17
|
+
const AGENT_NAMES: AgentName[] = [...REGISTERED_AGENTS].sort();
|
|
13
18
|
|
|
14
19
|
export interface ToolCheck {
|
|
15
20
|
name: string;
|
|
@@ -17,16 +22,11 @@ export interface ToolCheck {
|
|
|
17
22
|
version?: string;
|
|
18
23
|
}
|
|
19
24
|
|
|
20
|
-
export
|
|
25
|
+
export type DoctorResult = Record<AgentName, ToolCheck> & {
|
|
21
26
|
bun: ToolCheck;
|
|
22
|
-
claude: ToolCheck;
|
|
23
|
-
opencode: ToolCheck;
|
|
24
|
-
cursor: ToolCheck;
|
|
25
|
-
copilot: ToolCheck;
|
|
26
|
-
codex: ToolCheck;
|
|
27
27
|
rtk: ToolCheck;
|
|
28
28
|
hasAgent: boolean;
|
|
29
|
-
}
|
|
29
|
+
};
|
|
30
30
|
|
|
31
31
|
function checkTool(cmd: string, versionArgs: string[] = ["--version"]): ToolCheck {
|
|
32
32
|
try {
|
|
@@ -69,33 +69,39 @@ function checkCursor(): ToolCheck {
|
|
|
69
69
|
return checkTool("cursor");
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
const AGENT_PROBES: Record<AgentName, () => ToolCheck> = {
|
|
73
|
+
claude: () => checkTool("claude"),
|
|
74
|
+
opencode: () => checkTool("opencode"),
|
|
75
|
+
cursor: checkCursor,
|
|
76
|
+
copilot: checkCopilot,
|
|
77
|
+
codex: () => checkTool("codex"),
|
|
78
|
+
antigravity: () => checkTool("agy"),
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
function agentChecks(
|
|
82
|
+
probe: (agent: AgentName) => ToolCheck
|
|
83
|
+
): Record<AgentName, ToolCheck> {
|
|
84
|
+
return Object.fromEntries(
|
|
85
|
+
REGISTERED_AGENTS.map((agent) => [agent, probe(agent)])
|
|
86
|
+
) as Record<AgentName, ToolCheck>;
|
|
87
|
+
}
|
|
88
|
+
|
|
72
89
|
export function detectAgents(): DoctorResult {
|
|
90
|
+
const bun = { name: "bun", available: true, version: Bun.version };
|
|
73
91
|
if (process.env.PAL_SKIP_DOCTOR === "1") {
|
|
74
92
|
return {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
opencode: { name: "opencode", available: true },
|
|
78
|
-
cursor: { name: "cursor", available: true },
|
|
79
|
-
copilot: { name: "copilot", available: true },
|
|
80
|
-
codex: { name: "codex", available: true },
|
|
93
|
+
...agentChecks((agent) => ({ name: agent, available: true })),
|
|
94
|
+
bun,
|
|
81
95
|
rtk: { name: "rtk", available: true },
|
|
82
96
|
hasAgent: true,
|
|
83
97
|
};
|
|
84
98
|
}
|
|
85
|
-
const
|
|
86
|
-
const opencode = checkTool("opencode");
|
|
87
|
-
const cursor = checkCursor();
|
|
88
|
-
const copilot = checkCopilot();
|
|
89
|
-
const codex = checkTool("codex");
|
|
99
|
+
const agents = agentChecks((agent) => AGENT_PROBES[agent]());
|
|
90
100
|
return {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
opencode,
|
|
94
|
-
cursor,
|
|
95
|
-
copilot,
|
|
96
|
-
codex,
|
|
101
|
+
...agents,
|
|
102
|
+
bun,
|
|
97
103
|
rtk: checkTool("rtk"),
|
|
98
|
-
hasAgent:
|
|
104
|
+
hasAgent: Object.values(agents).some((tool) => tool.available),
|
|
99
105
|
};
|
|
100
106
|
}
|
|
101
107
|
|
|
@@ -103,46 +109,39 @@ export function installedAgents(result: DoctorResult): AgentName[] {
|
|
|
103
109
|
return AGENT_NAMES.filter((name) => result[name].available);
|
|
104
110
|
}
|
|
105
111
|
|
|
106
|
-
interface
|
|
107
|
-
label: string;
|
|
108
|
-
skillsDir: () => string;
|
|
112
|
+
interface AgentWiring {
|
|
109
113
|
hookFile?: () => string;
|
|
114
|
+
/** The hook whose absence means PAL's context never arrives; LoadContext unless set. */
|
|
115
|
+
contextHook?: string;
|
|
110
116
|
instructions?: { file: () => string; name: string };
|
|
111
117
|
}
|
|
112
118
|
|
|
113
|
-
const
|
|
119
|
+
const WIRING: Record<AgentName, AgentWiring> = {
|
|
114
120
|
claude: {
|
|
115
|
-
label: "Claude Code",
|
|
116
|
-
skillsDir: () => resolve(platform.claudeDir(), "skills"),
|
|
117
121
|
hookFile: () => resolve(platform.claudeDir(), "settings.json"),
|
|
118
122
|
instructions: {
|
|
119
123
|
file: () => resolve(platform.claudeDir(), "CLAUDE.md"),
|
|
120
124
|
name: "CLAUDE.md",
|
|
121
125
|
},
|
|
122
126
|
},
|
|
123
|
-
codex: {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
label: "Cursor",
|
|
135
|
-
skillsDir: () => resolve(platform.cursorDir(), "skills"),
|
|
136
|
-
hookFile: () => resolve(platform.cursorDir(), "hooks.json"),
|
|
137
|
-
},
|
|
138
|
-
opencode: {
|
|
139
|
-
label: "opencode",
|
|
140
|
-
skillsDir: () => resolve(platform.agentsDir(), "skills"),
|
|
127
|
+
codex: { hookFile: () => resolve(platform.codexDir(), "hooks.json") },
|
|
128
|
+
copilot: { hookFile: () => resolve(platform.copilotDir(), "hooks", "pal-hooks.json") },
|
|
129
|
+
cursor: { hookFile: () => resolve(platform.cursorDir(), "hooks.json") },
|
|
130
|
+
opencode: {},
|
|
131
|
+
antigravity: {
|
|
132
|
+
hookFile: () => resolve(platform.antigravityPluginDir(), "hooks.json"),
|
|
133
|
+
contextHook: "InvocationContext",
|
|
134
|
+
instructions: {
|
|
135
|
+
file: () => resolve(platform.antigravityPluginDir(), "rules", "pal.md"),
|
|
136
|
+
name: "PAL plugin rule",
|
|
137
|
+
},
|
|
141
138
|
},
|
|
142
139
|
};
|
|
143
140
|
|
|
141
|
+
const labelOf = (agent: AgentName) => AGENT_REGISTRY[agent].label;
|
|
142
|
+
|
|
144
143
|
const reinstall = (agent: AgentName): Fix => ({
|
|
145
|
-
say: `Reinstall PAL for ${
|
|
144
|
+
say: `Reinstall PAL for ${labelOf(agent)}`,
|
|
146
145
|
command: `pal cli install --${agent}`,
|
|
147
146
|
external: false,
|
|
148
147
|
});
|
|
@@ -207,8 +206,8 @@ function readHookCommands(file: string): string[] | "missing" | "unreadable" {
|
|
|
207
206
|
}
|
|
208
207
|
}
|
|
209
208
|
|
|
210
|
-
function hookFindings(agent: AgentName, file: string): Finding[] {
|
|
211
|
-
const label =
|
|
209
|
+
function hookFindings(agent: AgentName, file: string, contextHook: string): Finding[] {
|
|
210
|
+
const label = labelOf(agent);
|
|
212
211
|
const commands = readHookCommands(file);
|
|
213
212
|
if (commands === "unreadable")
|
|
214
213
|
return [
|
|
@@ -223,7 +222,7 @@ function hookFindings(agent: AgentName, file: string): Finding[] {
|
|
|
223
222
|
),
|
|
224
223
|
];
|
|
225
224
|
const pal = commands === "missing" ? [] : commands.filter((c) => isPalHook(c, agent));
|
|
226
|
-
if (!pal.some((c) => c.includes(
|
|
225
|
+
if (!pal.some((c) => c.includes(contextHook)))
|
|
227
226
|
return [
|
|
228
227
|
failing(
|
|
229
228
|
`${agent}.hooks.missing`,
|
|
@@ -276,8 +275,8 @@ function opencodePluginFindings(): Finding[] {
|
|
|
276
275
|
return [passed("opencode.hooks", "opencode plugin installed and current")];
|
|
277
276
|
}
|
|
278
277
|
|
|
279
|
-
function subagentFinding(agent:
|
|
280
|
-
const label =
|
|
278
|
+
function subagentFinding(agent: AgentName): Finding {
|
|
279
|
+
const label = labelOf(agent);
|
|
281
280
|
const stale = staleShippedAgents(nativeAgentsDir(agent), agent);
|
|
282
281
|
if (stale.length === 0)
|
|
283
282
|
return passed(`${agent}.subagents`, `${label}: subagents match this PAL version`);
|
|
@@ -294,16 +293,17 @@ function countSkills(dir: string): number {
|
|
|
294
293
|
}
|
|
295
294
|
|
|
296
295
|
function oneAgentFindings(agent: AgentName): Finding[] {
|
|
297
|
-
const layout =
|
|
298
|
-
const
|
|
296
|
+
const layout = WIRING[agent];
|
|
297
|
+
const label = labelOf(agent);
|
|
298
|
+
const skills = countSkills(skillsDirOf(agent));
|
|
299
299
|
const findings = [
|
|
300
300
|
skills > 0
|
|
301
|
-
? passed(`${agent}.skills`, `${
|
|
302
|
-
: warning(`${agent}.skills`, `${
|
|
301
|
+
? passed(`${agent}.skills`, `${label}: ${skills} skills`)
|
|
302
|
+
: warning(`${agent}.skills`, `${label} has no PAL skills`, reinstall(agent)),
|
|
303
303
|
];
|
|
304
304
|
findings.push(
|
|
305
305
|
...(layout.hookFile
|
|
306
|
-
? hookFindings(agent, layout.hookFile())
|
|
306
|
+
? hookFindings(agent, layout.hookFile(), layout.contextHook ?? "LoadContext")
|
|
307
307
|
: opencodePluginFindings()),
|
|
308
308
|
subagentFinding(agent)
|
|
309
309
|
);
|
|
@@ -345,7 +345,7 @@ export function rosterFindings(agents: AgentName[]): Finding[] {
|
|
|
345
345
|
return [
|
|
346
346
|
optional(
|
|
347
347
|
"agents.others",
|
|
348
|
-
`Other agents PAL supports — ${others.map(
|
|
348
|
+
`Other agents PAL supports — ${others.map(labelOf).join(", ")}`,
|
|
349
349
|
{
|
|
350
350
|
say: `install it, then run pal cli install --${others.length === 1 ? others[0] : "<agent>"}`,
|
|
351
351
|
}
|
package/src/cli/identity.ts
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* pal cli actor / pal cli machine — read and rename the two identities PAL keeps.
|
|
3
3
|
*
|
|
4
|
-
* pal cli actor Show this actor's label and id
|
|
5
|
-
* pal cli actor label <name> Rename the actor — who caused a record
|
|
6
|
-
* pal cli machine Show this install's label and id
|
|
7
|
-
* pal cli machine label <name> Rename the machine — where a record was written
|
|
8
|
-
*
|
|
9
4
|
* Renaming touches no stored record: both subjects resolve a label on read, so
|
|
10
5
|
* an id already written into a thread or a reflection reads under the new name
|
|
11
6
|
* immediately. The registry entry is refreshed here so the change also travels
|
|
@@ -26,6 +21,7 @@ import {
|
|
|
26
21
|
setLabel,
|
|
27
22
|
} from "../hooks/lib/machine";
|
|
28
23
|
import { log } from "../targets/lib";
|
|
24
|
+
import { type Group, group, leaf, runCommand, UsageError } from "../tools/lib/command";
|
|
29
25
|
|
|
30
26
|
export type IdentitySubject = "actor" | "machine";
|
|
31
27
|
|
|
@@ -84,21 +80,31 @@ function rename(subject: IdentitySubject, name: string): number {
|
|
|
84
80
|
return 0;
|
|
85
81
|
}
|
|
86
82
|
|
|
87
|
-
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
83
|
+
function renameTo(subject: IdentitySubject, words: string[]): number {
|
|
84
|
+
const name = words.join(" ").trim();
|
|
85
|
+
if (!name) throw new UsageError("the name is empty");
|
|
86
|
+
return rename(subject, name);
|
|
87
|
+
}
|
|
91
88
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
89
|
+
export function identityCommand(subject: IdentitySubject): Group {
|
|
90
|
+
const { noun } = SUBJECTS[subject];
|
|
91
|
+
return group({
|
|
92
|
+
summary: `Show or rename this ${subject} — ${noun}`,
|
|
93
|
+
fallback: "show",
|
|
94
|
+
commands: {
|
|
95
|
+
show: leaf({
|
|
96
|
+
summary: `Show this ${subject}'s label and id`,
|
|
97
|
+
run: () => show(subject),
|
|
98
|
+
}),
|
|
99
|
+
label: leaf({
|
|
100
|
+
summary: `Rename the ${subject}; stored records read under the new name at once`,
|
|
101
|
+
args: "<name...>",
|
|
102
|
+
run: ({ positionals }) => renameTo(subject, positionals),
|
|
103
|
+
}),
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
}
|
|
100
107
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
return 1;
|
|
108
|
+
export function runIdentity(subject: IdentitySubject, args: string[]): Promise<number> {
|
|
109
|
+
return runCommand(identityCommand(subject), args, ["pal", "cli", subject]);
|
|
104
110
|
}
|