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
package/src/cli/index.ts
CHANGED
|
@@ -1,32 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
/**
|
|
3
|
-
* PAL CLI — Portable Agent Layer
|
|
4
|
-
*
|
|
5
|
-
* Usage:
|
|
6
|
-
* pal [agent-args...] Start the first installed agent: claude, codex, cursor-agent, copilot, opencode
|
|
7
|
-
* pal cli <command> [options] Admin commands
|
|
8
|
-
*
|
|
9
|
-
* Admin commands (pal cli ...):
|
|
10
|
-
* init Scaffold PAL home, install hooks for all targets
|
|
11
|
-
* install [--claude] [--opencode] [--cursor] [--codex] Register hooks/skills for targets
|
|
12
|
-
* uninstall [--claude] [--opencode] [--cursor] [--codex] Remove hooks/skills for targets
|
|
13
|
-
* update Update PAL (git pull or npm update)
|
|
14
|
-
* export [path] [--dry-run] Export user state to zip
|
|
15
|
-
* import [path] [--dry-run] [--overwrite] Merge user state from zip
|
|
16
|
-
* status Show current PAL configuration
|
|
17
|
-
* doctor Check prerequisites and system health
|
|
18
|
-
* usage Summarize token usage and cost
|
|
19
|
-
* ledger <sub> [filters] Query the action ledger (log · show · stats)
|
|
20
|
-
* rule list|approve|deny [id] Review rules drafted from your corrections
|
|
21
|
-
* server start|stop|restart|status The control room, a local page over ~/.pal
|
|
22
|
-
* <tool> [args] Run a built-in agent tool (project, thread, analyze, …)
|
|
23
|
-
* skill run <skill> <tool> [-- args] Run a skill's own tool by name, not by path
|
|
24
|
-
* skill link <name> Link a personal ~/.pal/skills/<name>/ into installed agents
|
|
25
|
-
* skill doctor <name|--all> Evaluate one skill, or every installed skill, against the authoring best practices
|
|
26
|
-
* subagent link <name> Install a personal ~/.pal/agents/<name>.md into installed agents
|
|
27
|
-
* subagent doctor <name> Evaluate a subagent against the authoring best practices
|
|
28
|
-
* debug [on|off] Enable / disable verbose hook debug logging
|
|
29
|
-
* version | -v Print the installed PAL version
|
|
3
|
+
* PAL CLI — Portable Agent Layer. `pal [agent-args...]` starts the first
|
|
4
|
+
* installed agent; `pal cli <command>` runs the command tree in ./tree.ts.
|
|
30
5
|
*/
|
|
31
6
|
|
|
32
7
|
import { spawnSync } from "node:child_process";
|
|
@@ -41,6 +16,12 @@ import {
|
|
|
41
16
|
} from "node:fs";
|
|
42
17
|
import { homedir } from "node:os";
|
|
43
18
|
import { resolve } from "node:path";
|
|
19
|
+
import {
|
|
20
|
+
AGENT_NAMES,
|
|
21
|
+
AGENT_REGISTRY,
|
|
22
|
+
type AgentName,
|
|
23
|
+
INFERENCE_PRIORITY,
|
|
24
|
+
} from "../hooks/lib/agent-registry";
|
|
44
25
|
import {
|
|
45
26
|
appendImportLog,
|
|
46
27
|
mergeArchive,
|
|
@@ -52,19 +33,35 @@ import { logDebug } from "../hooks/lib/log";
|
|
|
52
33
|
import { ensureRegistered, writeRegistryEntry } from "../hooks/lib/machine";
|
|
53
34
|
import { palHome, palPkg, paths, platform, toPath } from "../hooks/lib/paths";
|
|
54
35
|
import { log, narrateSteps } from "../targets/lib";
|
|
55
|
-
import {
|
|
36
|
+
import { helpText, runCommand } from "../tools/lib/command";
|
|
56
37
|
import { type DoctorResult, detectAgents } from "./doctor/agents";
|
|
57
38
|
import { installChromium } from "./doctor/environment";
|
|
58
39
|
import { runDoctor } from "./doctor/run";
|
|
59
40
|
import { findSessionAgent, NO_SESSION_AGENT_MESSAGE } from "./session-agent";
|
|
41
|
+
import { cliTree, type DebugState } from "./tree";
|
|
60
42
|
|
|
61
43
|
const allArgs = process.argv.slice(2);
|
|
44
|
+
const CLI_PATH = ["pal", "cli"];
|
|
45
|
+
const tree = cliTree({
|
|
46
|
+
init: ({ argv }) => init(argv),
|
|
47
|
+
install: async ({ argv }) => {
|
|
48
|
+
banner();
|
|
49
|
+
process.exit(await install(resolveTargets(argv), argv));
|
|
50
|
+
},
|
|
51
|
+
uninstall: ({ argv }) => uninstall(argv),
|
|
52
|
+
update: () => update(),
|
|
53
|
+
export: ({ argv }) => exportState(argv),
|
|
54
|
+
import: ({ argv }) => importState(argv),
|
|
55
|
+
status: () => status(),
|
|
56
|
+
doctor: ({ argv }) => doctor(argv),
|
|
57
|
+
debug: (state) => cliDebug(state),
|
|
58
|
+
version: () => showVersion(),
|
|
59
|
+
});
|
|
62
60
|
|
|
63
61
|
// ── Route: pal cli <command> or pal [claude-args] ──
|
|
64
62
|
|
|
65
63
|
if (allArgs[0] === "cli") {
|
|
66
|
-
|
|
67
|
-
await runCli(command, args);
|
|
64
|
+
process.exitCode = await runCommand(tree, allArgs.slice(1), CLI_PATH);
|
|
68
65
|
} else if (allArgs[0] === "--help" || allArgs[0] === "-h" || allArgs[0] === "help") {
|
|
69
66
|
showHelp();
|
|
70
67
|
} else {
|
|
@@ -146,124 +143,12 @@ async function session(sessionArgs: string[]) {
|
|
|
146
143
|
process.exit(exitCode);
|
|
147
144
|
}
|
|
148
145
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
switch (command) {
|
|
154
|
-
case "init":
|
|
155
|
-
await init(args);
|
|
156
|
-
break;
|
|
157
|
-
case "install":
|
|
158
|
-
banner();
|
|
159
|
-
process.exit(await install(resolveTargets(args), args));
|
|
160
|
-
break;
|
|
161
|
-
case "uninstall":
|
|
162
|
-
await uninstall(args);
|
|
163
|
-
break;
|
|
164
|
-
case "export":
|
|
165
|
-
await exportState(args);
|
|
166
|
-
break;
|
|
167
|
-
case "import":
|
|
168
|
-
await importState(args);
|
|
169
|
-
break;
|
|
170
|
-
case "update":
|
|
171
|
-
await update();
|
|
172
|
-
break;
|
|
173
|
-
case "status":
|
|
174
|
-
await status();
|
|
175
|
-
break;
|
|
176
|
-
case "doctor": {
|
|
177
|
-
const exitCode = runDoctor(args);
|
|
178
|
-
if (args.includes("--probe-inference") || args.includes("--probe")) {
|
|
179
|
-
await probeInference();
|
|
180
|
-
}
|
|
181
|
-
process.exit(exitCode);
|
|
182
|
-
break;
|
|
183
|
-
}
|
|
184
|
-
case "migrate": {
|
|
185
|
-
const { runMigrate } = await import("./migrate");
|
|
186
|
-
runMigrate(args);
|
|
187
|
-
break;
|
|
188
|
-
}
|
|
189
|
-
case "usage": {
|
|
190
|
-
const { usage } = await import("../tools/token-cost");
|
|
191
|
-
usage();
|
|
192
|
-
break;
|
|
193
|
-
}
|
|
194
|
-
case "knowledge": {
|
|
195
|
-
const { runKnowledge } = await import("./knowledge");
|
|
196
|
-
const code = await runKnowledge(args);
|
|
197
|
-
if (code !== 0) process.exit(code);
|
|
198
|
-
break;
|
|
199
|
-
}
|
|
200
|
-
case "ledger": {
|
|
201
|
-
const { runLedger } = await import("./ledger");
|
|
202
|
-
const code = await runLedger(args);
|
|
203
|
-
if (code !== 0) process.exit(code);
|
|
204
|
-
break;
|
|
205
|
-
}
|
|
206
|
-
case "rule": {
|
|
207
|
-
const { runRule } = await import("./rule");
|
|
208
|
-
const code = await runRule(args);
|
|
209
|
-
if (code !== 0) process.exit(code);
|
|
210
|
-
break;
|
|
211
|
-
}
|
|
212
|
-
case "server": {
|
|
213
|
-
const { runServer } = await import("./server");
|
|
214
|
-
const code = await runServer(args);
|
|
215
|
-
if (code !== 0) process.exit(code);
|
|
216
|
-
break;
|
|
217
|
-
}
|
|
218
|
-
case "subagent": {
|
|
219
|
-
const { runSubagent } = await import("./subagent");
|
|
220
|
-
const code = await runSubagent(args);
|
|
221
|
-
if (code !== 0) process.exit(code);
|
|
222
|
-
break;
|
|
223
|
-
}
|
|
224
|
-
case "skill": {
|
|
225
|
-
const { runSkill } = await import("./skill");
|
|
226
|
-
const code = await runSkill(args);
|
|
227
|
-
if (code !== 0) process.exit(code);
|
|
228
|
-
break;
|
|
229
|
-
}
|
|
230
|
-
case "actor":
|
|
231
|
-
case "machine": {
|
|
232
|
-
const { runIdentity } = await import("./identity");
|
|
233
|
-
const code = runIdentity(command, args);
|
|
234
|
-
if (code !== 0) process.exit(code);
|
|
235
|
-
break;
|
|
236
|
-
}
|
|
237
|
-
case "telos": {
|
|
238
|
-
const { runTelos } = await import("./personal-context");
|
|
239
|
-
const code = runTelos(args);
|
|
240
|
-
if (code !== 0) process.exit(code);
|
|
241
|
-
break;
|
|
242
|
-
}
|
|
243
|
-
case "timezone": {
|
|
244
|
-
const { runTimezone } = await import("./personal-context");
|
|
245
|
-
const code = runTimezone(args);
|
|
246
|
-
if (code !== 0) process.exit(code);
|
|
247
|
-
break;
|
|
248
|
-
}
|
|
249
|
-
case "debug":
|
|
250
|
-
cliDebug(args);
|
|
251
|
-
break;
|
|
252
|
-
case "version":
|
|
253
|
-
case "-v":
|
|
254
|
-
case "--version":
|
|
255
|
-
showVersion();
|
|
256
|
-
break;
|
|
257
|
-
case "--help":
|
|
258
|
-
case "-h":
|
|
259
|
-
case "help":
|
|
260
|
-
showHelp();
|
|
261
|
-
break;
|
|
262
|
-
default:
|
|
263
|
-
if (command) log.error(`Unknown command: ${command}`);
|
|
264
|
-
showHelp();
|
|
265
|
-
process.exit(command ? 1 : 0);
|
|
146
|
+
async function doctor(args: string[]): Promise<never> {
|
|
147
|
+
const exitCode = runDoctor(args);
|
|
148
|
+
if (args.includes("--probe-inference") || args.includes("--probe")) {
|
|
149
|
+
await probeInference();
|
|
266
150
|
}
|
|
151
|
+
process.exit(exitCode);
|
|
267
152
|
}
|
|
268
153
|
|
|
269
154
|
// ── Helpers ──
|
|
@@ -277,145 +162,52 @@ function banner() {
|
|
|
277
162
|
}
|
|
278
163
|
|
|
279
164
|
function showHelp() {
|
|
280
|
-
console.log(
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
pal cli <command> [options] Admin commands
|
|
284
|
-
|
|
285
|
-
Admin commands:
|
|
286
|
-
pal cli init [--claude] [--opencode] [--cursor] [--codex] Scaffold and install (default: all), then run the doctor
|
|
287
|
-
pal cli install [--claude] [--opencode] [--cursor] [--codex] Register hooks for targets, then run the doctor
|
|
288
|
-
Add --verbose to either for the step-by-step log
|
|
289
|
-
pal cli uninstall [--claude] [--opencode] [--cursor] [--codex] Remove hooks for targets
|
|
290
|
-
pal cli update Update PAL (git pull or npm update)
|
|
291
|
-
pal cli export [path] [--dry-run] Export state to zip
|
|
292
|
-
pal cli import [path] [--dry-run] Merge state from zip (--overwrite to replace)
|
|
293
|
-
pal cli status Show PAL configuration
|
|
294
|
-
pal cli doctor [--verbose] [--json] Find what is wrong and how to fix it; exits 1 on any failure
|
|
295
|
-
[--probe-inference] Also fire real inference per route
|
|
296
|
-
pal cli migrate [--list] [--dry-run] Run pending data migrations
|
|
297
|
-
pal cli <tool> [args] Run a built-in agent tool ('<tool> --help' for its flags):
|
|
298
|
-
${builtinToolVerbs.join(" · ")}
|
|
299
|
-
pal cli usage Summarize token usage and cost
|
|
300
|
-
pal cli actor [label <name>] Show or rename this actor (who caused a record)
|
|
301
|
-
pal cli machine [label <name>] Show or rename this install (where it was written)
|
|
302
|
-
pal cli telos Which TELOS topics are answered, in interview order
|
|
303
|
-
pal cli timezone [<zone>] Show or set your timezone (IANA name)
|
|
304
|
-
pal cli knowledge <sub> [args] Query & manage the knowledge store
|
|
305
|
-
(search · graph · stats · hubs · find · show · add · ls)
|
|
306
|
-
pal cli ledger <sub> [filters] Query the action ledger (log · show · stats)
|
|
307
|
-
e.g. ledger log --project X --since 7d
|
|
308
|
-
pal cli rule list|approve|deny [id] Review rules drafted from your corrections
|
|
309
|
-
pal cli server start|stop|restart|status The control room: a local page to open before a terminal
|
|
310
|
-
pal cli skill run <skill> <tool> [-- args] Run ~/.pal/skills/<skill>/tools/<tool> by name
|
|
311
|
-
pal cli skill link <name> Link a personal ~/.pal/skills/<name>/ into installed agents
|
|
312
|
-
pal cli skill doctor <name|--all> Evaluate one skill, or every installed skill
|
|
313
|
-
pal cli skill author-model Print the flagship model that authors skills for the active agent
|
|
314
|
-
pal cli subagent link <name> Install a personal ~/.pal/agents/<name>.md into installed agents
|
|
315
|
-
pal cli subagent doctor <name> Evaluate a subagent against the authoring best practices
|
|
316
|
-
pal cli subagent list List the user-authored subagents in ~/.pal/agents/
|
|
317
|
-
pal cli subagent author-model Print the flagship model that authors subagents for the active agent
|
|
318
|
-
pal cli debug [on|off] Enable/disable verbose hook debug logging (persisted)
|
|
319
|
-
pal cli version | -v Print the installed PAL version
|
|
320
|
-
|
|
321
|
-
Environment:
|
|
322
|
-
PAL_HOME Override user state directory (default: ~/.pal or repo root)
|
|
323
|
-
PAL_PKG Override package root
|
|
324
|
-
PAL_CLAUDE_DIR Override Claude config dir (default: ~/.claude)
|
|
325
|
-
PAL_OPENCODE_DIR Override opencode config dir (default: ~/.config/opencode)
|
|
326
|
-
PAL_CURSOR_DIR Override Cursor config dir (default: ~/.cursor)
|
|
327
|
-
PAL_COPILOT_DIR Override Copilot config dir (default: ~/.copilot)
|
|
328
|
-
PAL_CODEX_DIR Override Codex config dir (default: ~/.codex)
|
|
329
|
-
PAL_AGENTS_DIR Override agents dir (default: ~/.agents)
|
|
330
|
-
`);
|
|
165
|
+
console.log(
|
|
166
|
+
`Usage: pal [agent-args...]\n\n Start the first installed agent, passing the arguments on\n\n${helpText(tree, CLI_PATH)}`
|
|
167
|
+
);
|
|
331
168
|
}
|
|
332
169
|
|
|
333
|
-
type Targets =
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
}
|
|
170
|
+
type Targets = Record<AgentName, boolean>;
|
|
171
|
+
|
|
172
|
+
function targetsWhere(selected: (agent: AgentName) => boolean): Targets {
|
|
173
|
+
return Object.fromEntries(
|
|
174
|
+
AGENT_NAMES.map((agent) => [agent, selected(agent)])
|
|
175
|
+
) as Targets;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function namedTargets(args: string[]): AgentName[] {
|
|
179
|
+
if (args.includes("--all")) return AGENT_NAMES;
|
|
180
|
+
return AGENT_NAMES.filter((agent) => args.includes(`--${agent}`));
|
|
181
|
+
}
|
|
340
182
|
|
|
341
183
|
function parseTargets(args: string[]): Targets {
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
let codex = false;
|
|
347
|
-
for (const arg of args) {
|
|
348
|
-
if (arg === "--claude") claude = true;
|
|
349
|
-
else if (arg === "--opencode") opencode = true;
|
|
350
|
-
else if (arg === "--cursor") cursor = true;
|
|
351
|
-
else if (arg === "--copilot") copilot = true;
|
|
352
|
-
else if (arg === "--codex") codex = true;
|
|
353
|
-
else if (arg === "--all") {
|
|
354
|
-
claude = true;
|
|
355
|
-
opencode = true;
|
|
356
|
-
cursor = true;
|
|
357
|
-
copilot = true;
|
|
358
|
-
codex = true;
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
if (!claude && !opencode && !cursor && !copilot && !codex)
|
|
362
|
-
return { claude: true, opencode: true, cursor: true, copilot: true, codex: true };
|
|
363
|
-
return { claude, opencode, cursor, copilot, codex };
|
|
184
|
+
const named = namedTargets(args);
|
|
185
|
+
return named.length === 0
|
|
186
|
+
? targetsWhere(() => true)
|
|
187
|
+
: targetsWhere((a) => named.includes(a));
|
|
364
188
|
}
|
|
365
189
|
|
|
366
190
|
/** Resolve targets against available agents. Errors if explicitly requested but missing. */
|
|
367
191
|
function resolveTargets(args: string[], health?: DoctorResult): Targets {
|
|
368
192
|
const requested = parseTargets(args);
|
|
369
193
|
const h = health || detectAgents();
|
|
370
|
-
const explicit = args.some(
|
|
371
|
-
(a) =>
|
|
372
|
-
a === "--claude" ||
|
|
373
|
-
a === "--opencode" ||
|
|
374
|
-
a === "--cursor" ||
|
|
375
|
-
a === "--copilot" ||
|
|
376
|
-
a === "--codex" ||
|
|
377
|
-
a === "--all"
|
|
378
|
-
);
|
|
379
194
|
|
|
380
|
-
if (
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
log.error("opencode is not installed. Run 'pal cli doctor' for details.");
|
|
387
|
-
process.exit(1);
|
|
388
|
-
}
|
|
389
|
-
if (requested.cursor && !h.cursor.available) {
|
|
390
|
-
log.error("Cursor is not installed. Run 'pal cli doctor' for details.");
|
|
391
|
-
process.exit(1);
|
|
392
|
-
}
|
|
393
|
-
if (requested.copilot && !h.copilot.available) {
|
|
394
|
-
log.error("Copilot is not installed. Run 'pal cli doctor' for details.");
|
|
395
|
-
process.exit(1);
|
|
396
|
-
}
|
|
397
|
-
if (requested.codex && !h.codex.available) {
|
|
398
|
-
log.error("Codex is not installed. Run 'pal cli doctor' for details.");
|
|
195
|
+
if (namedTargets(args).length > 0) {
|
|
196
|
+
const missing = AGENT_NAMES.find((agent) => requested[agent] && !h[agent].available);
|
|
197
|
+
if (missing) {
|
|
198
|
+
log.error(
|
|
199
|
+
`${AGENT_REGISTRY[missing].label} is not installed. Run 'pal cli doctor' for details.`
|
|
200
|
+
);
|
|
399
201
|
process.exit(1);
|
|
400
202
|
}
|
|
401
203
|
return requested;
|
|
402
204
|
}
|
|
403
205
|
|
|
404
|
-
|
|
405
|
-
const
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
copilot: h.copilot.available,
|
|
410
|
-
codex: h.codex.available,
|
|
411
|
-
};
|
|
412
|
-
|
|
413
|
-
if (!targets.claude) log.info("Skipping Claude Code (not installed)");
|
|
414
|
-
if (!targets.opencode) log.info("Skipping opencode (not installed)");
|
|
415
|
-
if (!targets.cursor) log.info("Skipping Cursor (not installed)");
|
|
416
|
-
if (!targets.copilot) log.info("Skipping Copilot (not installed)");
|
|
417
|
-
if (!targets.codex) log.info("Skipping Codex (not installed)");
|
|
418
|
-
|
|
206
|
+
const targets = targetsWhere((agent) => h[agent].available);
|
|
207
|
+
for (const agent of AGENT_NAMES) {
|
|
208
|
+
if (!targets[agent])
|
|
209
|
+
log.info(`Skipping ${AGENT_REGISTRY[agent].label} (not installed)`);
|
|
210
|
+
}
|
|
419
211
|
return targets;
|
|
420
212
|
}
|
|
421
213
|
|
|
@@ -435,10 +227,9 @@ async function probeInference(): Promise<void> {
|
|
|
435
227
|
const yellow = "\x1b[33m";
|
|
436
228
|
const dim = "\x1b[90m";
|
|
437
229
|
const reset = "\x1b[0m";
|
|
438
|
-
const agents = ["claude", "codex", "opencode", "copilot", "cursor"] as const;
|
|
439
230
|
const savedAgent = process.env.PAL_AGENT;
|
|
440
231
|
try {
|
|
441
|
-
for (const agent of
|
|
232
|
+
for (const agent of INFERENCE_PRIORITY) {
|
|
442
233
|
process.env.PAL_AGENT = agent;
|
|
443
234
|
const preview = previewInferenceRoute();
|
|
444
235
|
const tag = `${agent.padEnd(10)} → ${preview.route.padEnd(15)}`;
|
|
@@ -515,14 +306,44 @@ function runQuietly(cmd: string, args: string[], cwd: string): number | null {
|
|
|
515
306
|
return r.status;
|
|
516
307
|
}
|
|
517
308
|
|
|
518
|
-
function
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
309
|
+
function targetScripts(): Record<
|
|
310
|
+
AgentName,
|
|
311
|
+
{ install: () => Promise<unknown>; uninstall: () => Promise<unknown> }
|
|
312
|
+
> {
|
|
313
|
+
return {
|
|
314
|
+
claude: {
|
|
315
|
+
install: () => import("../targets/claude/install"),
|
|
316
|
+
uninstall: () => import("../targets/claude/uninstall"),
|
|
317
|
+
},
|
|
318
|
+
opencode: {
|
|
319
|
+
install: () => import("../targets/opencode/install"),
|
|
320
|
+
uninstall: () => import("../targets/opencode/uninstall"),
|
|
321
|
+
},
|
|
322
|
+
cursor: {
|
|
323
|
+
install: () => import("../targets/cursor/install"),
|
|
324
|
+
uninstall: () => import("../targets/cursor/uninstall"),
|
|
325
|
+
},
|
|
326
|
+
copilot: {
|
|
327
|
+
install: () => import("../targets/copilot/install"),
|
|
328
|
+
uninstall: () => import("../targets/copilot/uninstall"),
|
|
329
|
+
},
|
|
330
|
+
codex: {
|
|
331
|
+
install: () => import("../targets/codex/install"),
|
|
332
|
+
uninstall: () => import("../targets/codex/uninstall"),
|
|
333
|
+
},
|
|
334
|
+
antigravity: {
|
|
335
|
+
install: () => import("../targets/antigravity/install"),
|
|
336
|
+
uninstall: () => import("../targets/antigravity/uninstall"),
|
|
337
|
+
},
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function targetInstallers(): [AgentName, string, () => Promise<unknown>][] {
|
|
342
|
+
return AGENT_NAMES.map((agent) => [
|
|
343
|
+
agent,
|
|
344
|
+
AGENT_REGISTRY[agent].label,
|
|
345
|
+
targetScripts()[agent].install,
|
|
346
|
+
]);
|
|
526
347
|
}
|
|
527
348
|
|
|
528
349
|
async function install(targets: Targets, args: string[]): Promise<number> {
|
|
@@ -572,7 +393,8 @@ async function install(targets: Targets, args: string[]): Promise<number> {
|
|
|
572
393
|
|
|
573
394
|
// The rest of the shared work reads what the installers just wrote: the index
|
|
574
395
|
// walks ~/.pal/skills, and the digests land in ~/.cursor/rules and
|
|
575
|
-
// ~/.copilot/instructions
|
|
396
|
+
// ~/.copilot/instructions and the Antigravity plugin's rules/, which are skipped
|
|
397
|
+
// when the agent's home is absent.
|
|
576
398
|
const { writeContextDigests } = await import("../hooks/handlers/context-digests");
|
|
577
399
|
const indexedSkills = generateSkillIndex();
|
|
578
400
|
writeContextDigests();
|
|
@@ -606,33 +428,9 @@ async function refreshControlRoom(): Promise<void> {
|
|
|
606
428
|
async function uninstall(args: string[]) {
|
|
607
429
|
const targets = parseTargets(args);
|
|
608
430
|
|
|
609
|
-
|
|
610
|
-
console.log(
|
|
611
|
-
await
|
|
612
|
-
console.log("");
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
if (targets.opencode) {
|
|
616
|
-
console.log("━━━ opencode ━━━");
|
|
617
|
-
await import("../targets/opencode/uninstall");
|
|
618
|
-
console.log("");
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
if (targets.cursor) {
|
|
622
|
-
console.log("━━━ Cursor ━━━");
|
|
623
|
-
await import("../targets/cursor/uninstall");
|
|
624
|
-
console.log("");
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
if (targets.copilot) {
|
|
628
|
-
console.log("━━━ Copilot ━━━");
|
|
629
|
-
await import("../targets/copilot/uninstall");
|
|
630
|
-
console.log("");
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
if (targets.codex) {
|
|
634
|
-
console.log("━━━ Codex ━━━");
|
|
635
|
-
await import("../targets/codex/uninstall");
|
|
431
|
+
for (const agent of AGENT_NAMES.filter((a) => targets[a])) {
|
|
432
|
+
console.log(`━━━ ${AGENT_REGISTRY[agent].label} ━━━`);
|
|
433
|
+
await targetScripts()[agent].uninstall();
|
|
636
434
|
console.log("");
|
|
637
435
|
}
|
|
638
436
|
|
|
@@ -891,18 +689,17 @@ async function update() {
|
|
|
891
689
|
process.exit(reinstallInFreshProcess());
|
|
892
690
|
}
|
|
893
691
|
|
|
894
|
-
function cliDebug(
|
|
692
|
+
function cliDebug(state: DebugState) {
|
|
895
693
|
const stateDir = resolve(palHome(), "memory", "state");
|
|
896
694
|
const flagFile = resolve(stateDir, "debug-enabled");
|
|
897
695
|
// Must match log.ts's logFile() — reporting a different path sends anyone
|
|
898
696
|
// debugging a hook to an empty file.
|
|
899
697
|
const logFile = resolve(paths.debug(), "debug.log");
|
|
900
|
-
|
|
901
|
-
if (sub === "on") {
|
|
698
|
+
if (state === "on") {
|
|
902
699
|
mkdirSync(stateDir, { recursive: true });
|
|
903
700
|
writeFileSync(flagFile, "");
|
|
904
701
|
log.success(`Debug logging enabled → ${logFile}`);
|
|
905
|
-
} else if (
|
|
702
|
+
} else if (state === "off") {
|
|
906
703
|
rmSync(flagFile, { force: true });
|
|
907
704
|
log.success("Debug logging disabled");
|
|
908
705
|
} else {
|