agent-trellis 0.8.0 → 0.8.2
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 +43 -207
- package/dist/adapters/zcode.d.ts +21 -0
- package/dist/adapters/zcode.js +234 -0
- package/dist/cli.js +25 -9
- package/dist/commands/doctor.js +2 -0
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.js +4 -1
- package/dist/commands/mcp.d.ts +56 -14
- package/dist/commands/mcp.js +105 -28
- package/dist/commands/mcpGateway.js +2 -1
- package/dist/commands/mcpImport.d.ts +21 -2
- package/dist/commands/mcpImport.js +30 -7
- package/dist/commands/memory.d.ts +13 -1
- package/dist/commands/memory.js +15 -0
- package/dist/commands/migrate.js +4 -1
- package/dist/commands/onboard.js +15 -4
- package/dist/commands/rollback.js +24 -1
- package/dist/commands/secretsAudit.js +4 -1
- package/dist/commands/skill.d.ts +35 -6
- package/dist/commands/skill.js +67 -13
- package/dist/commands/sync.js +3 -1
- package/dist/core/adapter.d.ts +11 -1
- package/dist/core/types.d.ts +1 -1
- package/dist/core/types.js +1 -0
- package/dist/lib/agentBridge.d.ts +169 -0
- package/dist/lib/agentBridge.js +367 -0
- package/dist/lib/agentBridgeProvider.d.ts +14 -0
- package/dist/lib/agentBridgeProvider.js +95 -0
- package/dist/lib/backup.d.ts +30 -0
- package/dist/lib/backup.js +16 -1
- package/dist/lib/chatAgents.d.ts +42 -0
- package/dist/lib/chatAgents.js +59 -0
- package/dist/lib/envVarNames.d.ts +3 -0
- package/dist/lib/envVarNames.js +19 -0
- package/dist/lib/installAgent.d.ts +1 -1
- package/dist/lib/installAgent.js +1 -1
- package/dist/lib/mcpMigrateRead.d.ts +1 -0
- package/dist/lib/mcpMigrateRead.js +19 -1
- package/dist/lib/realHomeSnapshot.js +5 -0
- package/dist/lib/runtimeControlProvider.js +2 -0
- package/dist/lib/taskStore.js +1 -1
- package/dist/lib/terminalPicker.js +33 -6
- package/dist/lib/zcodeOwnership.d.ts +17 -0
- package/dist/lib/zcodeOwnership.js +37 -0
- package/dist/pi-bridge/bundle.js +2 -1
- package/dist/probes/codex.d.ts +7 -0
- package/dist/probes/codex.js +37 -5
- package/dist/probes/zcode.d.ts +32 -0
- package/dist/probes/zcode.js +140 -0
- package/docs/architecture.md +9 -5
- package/docs/assets/brand-v3/trellis-mark-v3-a.png +0 -0
- package/docs/assets/brand-v3/trellis-mark-v3-a.svg +10 -0
- package/docs/assets/poster-series-v3/README.md +60 -0
- package/docs/assets/poster-series-v3/agent-trellis-poster-v3-horizontal-en.png +0 -0
- package/docs/assets/poster-series-v3/agent-trellis-poster-v3-horizontal-en.svg +51 -0
- package/docs/assets/poster-series-v3/agent-trellis-poster-v3-horizontal-zh.png +0 -0
- package/docs/assets/poster-series-v3/agent-trellis-poster-v3-horizontal-zh.svg +51 -0
- package/docs/assets/poster-series-v3/agent-trellis-poster-v3-memory-en.png +0 -0
- package/docs/assets/poster-series-v3/agent-trellis-poster-v3-memory-en.svg +48 -0
- package/docs/assets/poster-series-v3/agent-trellis-poster-v3-memory-zh.png +0 -0
- package/docs/assets/poster-series-v3/agent-trellis-poster-v3-memory-zh.svg +48 -0
- package/docs/assets/poster-series-v3/agent-trellis-poster-v3-migrate-en.png +0 -0
- package/docs/assets/poster-series-v3/agent-trellis-poster-v3-migrate-en.svg +56 -0
- package/docs/assets/poster-series-v3/agent-trellis-poster-v3-migrate-zh.png +0 -0
- package/docs/assets/poster-series-v3/agent-trellis-poster-v3-migrate-zh.svg +56 -0
- package/docs/assets/poster-series-v3/agent-trellis-poster-v3-switch-en.png +0 -0
- package/docs/assets/poster-series-v3/agent-trellis-poster-v3-switch-en.svg +47 -0
- package/docs/assets/poster-series-v3/agent-trellis-poster-v3-switch-zh.png +0 -0
- package/docs/assets/poster-series-v3/agent-trellis-poster-v3-switch-zh.svg +47 -0
- package/docs/assets/poster-series-v3/agent-trellis-poster-v3-unified-en.png +0 -0
- package/docs/assets/poster-series-v3/agent-trellis-poster-v3-unified-en.svg +51 -0
- package/docs/assets/poster-series-v3/agent-trellis-poster-v3-unified-zh.png +0 -0
- package/docs/assets/poster-series-v3/agent-trellis-poster-v3-unified-zh.svg +51 -0
- package/docs/getting-started.md +173 -12
- package/docs/overview.md +6 -3
- package/docs/overview.zh-CN.md +5 -3
- package/docs/roadmap.md +2 -1
- package/docs/video/README.md +76 -0
- package/docs/video/build/audio/01-opening.aiff +0 -0
- package/docs/video/build/audio/01-opening.mp3 +0 -0
- package/docs/video/build/audio/02-pain.aiff +0 -0
- package/docs/video/build/audio/02-pain.mp3 +0 -0
- package/docs/video/build/audio/03-solution.aiff +0 -0
- package/docs/video/build/audio/03-solution.mp3 +0 -0
- package/docs/video/build/audio/04-install.aiff +0 -0
- package/docs/video/build/audio/04-install.mp3 +0 -0
- package/docs/video/build/audio/04-setup.mp3 +0 -0
- package/docs/video/build/audio/05-dryrun.mp3 +0 -0
- package/docs/video/build/audio/05-init.aiff +0 -0
- package/docs/video/build/audio/05-init.mp3 +0 -0
- package/docs/video/build/audio/05-interactive.mp3 +0 -0
- package/docs/video/build/audio/06-dryrun.aiff +0 -0
- package/docs/video/build/audio/06-dryrun.mp3 +0 -0
- package/docs/video/build/audio/06-onboard.mp3 +0 -0
- package/docs/video/build/audio/06-run.mp3 +0 -0
- package/docs/video/build/audio/07-onboard.aiff +0 -0
- package/docs/video/build/audio/07-onboard.mp3 +0 -0
- package/docs/video/build/audio/07-verify.mp3 +0 -0
- package/docs/video/build/audio/08-closing.mp3 +0 -0
- package/docs/video/build/audio/08-doctor.aiff +0 -0
- package/docs/video/build/audio/08-doctor.mp3 +0 -0
- package/docs/video/build/audio/09-rollback.aiff +0 -0
- package/docs/video/build/audio/09-rollback.mp3 +0 -0
- package/docs/video/build/audio/10-principles.aiff +0 -0
- package/docs/video/build/audio/10-principles.mp3 +0 -0
- package/docs/video/build/audio/11-closing.aiff +0 -0
- package/docs/video/build/audio/11-closing.mp3 +0 -0
- package/docs/video/build/frames/01-opening-0.png +0 -0
- package/docs/video/build/frames/02-pain-1.png +0 -0
- package/docs/video/build/frames/02-pain-2.png +0 -0
- package/docs/video/build/frames/03-solution-3.png +0 -0
- package/docs/video/build/frames/04-install-4.png +0 -0
- package/docs/video/build/frames/04-setup-4.png +0 -0
- package/docs/video/build/frames/04-setup-5.png +0 -0
- package/docs/video/build/frames/05-dryrun-6.png +0 -0
- package/docs/video/build/frames/05-init-5.png +0 -0
- package/docs/video/build/frames/05-interactive-5.png +0 -0
- package/docs/video/build/frames/05-interactive-6.png +0 -0
- package/docs/video/build/frames/06-dryrun-6.png +0 -0
- package/docs/video/build/frames/06-dryrun-7.png +0 -0
- package/docs/video/build/frames/06-onboard-7.png +0 -0
- package/docs/video/build/frames/06-onboard-8.png +0 -0
- package/docs/video/build/frames/06-run-7.png +0 -0
- package/docs/video/build/frames/06-run-8.png +0 -0
- package/docs/video/build/frames/07-onboard-10.png +0 -0
- package/docs/video/build/frames/07-onboard-7.png +0 -0
- package/docs/video/build/frames/07-onboard-8.png +0 -0
- package/docs/video/build/frames/07-onboard-9.png +0 -0
- package/docs/video/build/frames/07-verify-10.png +0 -0
- package/docs/video/build/frames/07-verify-8.png +0 -0
- package/docs/video/build/frames/07-verify-9.png +0 -0
- package/docs/video/build/frames/08-closing-10.png +0 -0
- package/docs/video/build/frames/08-closing-11.png +0 -0
- package/docs/video/build/frames/08-doctor-11.png +0 -0
- package/docs/video/build/frames/08-doctor-9.png +0 -0
- package/docs/video/build/frames/09-rollback-10.png +0 -0
- package/docs/video/build/frames/09-rollback-12.png +0 -0
- package/docs/video/build/frames/10-principles-11.png +0 -0
- package/docs/video/build/frames/10-principles-13.png +0 -0
- package/docs/video/build/frames/11-closing-12.png +0 -0
- package/docs/video/build/frames/11-closing-14.png +0 -0
- package/docs/video/build/segments/01-opening.mp4 +0 -0
- package/docs/video/build/segments/01-opening.txt +3 -0
- package/docs/video/build/segments/02-pain.mp4 +0 -0
- package/docs/video/build/segments/02-pain.txt +5 -0
- package/docs/video/build/segments/03-solution.mp4 +0 -0
- package/docs/video/build/segments/03-solution.txt +3 -0
- package/docs/video/build/segments/04-install.mp4 +0 -0
- package/docs/video/build/segments/04-install.txt +3 -0
- package/docs/video/build/segments/04-setup.mp4 +0 -0
- package/docs/video/build/segments/04-setup.txt +3 -0
- package/docs/video/build/segments/05-dryrun.mp4 +0 -0
- package/docs/video/build/segments/05-dryrun.txt +3 -0
- package/docs/video/build/segments/05-init.mp4 +0 -0
- package/docs/video/build/segments/05-init.txt +3 -0
- package/docs/video/build/segments/05-interactive.mp4 +0 -0
- package/docs/video/build/segments/05-interactive.txt +5 -0
- package/docs/video/build/segments/06-dryrun.mp4 +0 -0
- package/docs/video/build/segments/06-dryrun.txt +3 -0
- package/docs/video/build/segments/06-onboard.mp4 +0 -0
- package/docs/video/build/segments/06-onboard.txt +5 -0
- package/docs/video/build/segments/06-run.mp4 +0 -0
- package/docs/video/build/segments/06-run.txt +3 -0
- package/docs/video/build/segments/07-onboard.mp4 +0 -0
- package/docs/video/build/segments/07-onboard.txt +5 -0
- package/docs/video/build/segments/07-verify.mp4 +0 -0
- package/docs/video/build/segments/07-verify.txt +5 -0
- package/docs/video/build/segments/08-closing.mp4 +0 -0
- package/docs/video/build/segments/08-closing.txt +3 -0
- package/docs/video/build/segments/08-doctor.mp4 +0 -0
- package/docs/video/build/segments/08-doctor.txt +3 -0
- package/docs/video/build/segments/09-rollback.mp4 +0 -0
- package/docs/video/build/segments/09-rollback.txt +3 -0
- package/docs/video/build/segments/10-principles.mp4 +0 -0
- package/docs/video/build/segments/10-principles.txt +3 -0
- package/docs/video/build/segments/11-closing.mp4 +0 -0
- package/docs/video/build/segments/11-closing.txt +3 -0
- package/docs/video/build/segments/final.txt +8 -0
- package/docs/video/build-ai/audio/01-hook.mp3 +0 -0
- package/docs/video/build-ai/audio/02-pain.mp3 +0 -0
- package/docs/video/build-ai/audio/03-solution.mp3 +0 -0
- package/docs/video/build-ai/audio/04-how.mp3 +0 -0
- package/docs/video/build-ai/audio/05-safe.mp3 +0 -0
- package/docs/video/build-ai/audio/06-closing.mp3 +0 -0
- package/docs/video/build-ai/clips/01-hook.mp4 +0 -0
- package/docs/video/build-ai/clips/02-pain.mp4 +0 -0
- package/docs/video/build-ai/clips/03-solution.mp4 +0 -0
- package/docs/video/build-ai/clips/04-how.mp4 +0 -0
- package/docs/video/build-ai/clips/05-safe.mp4 +0 -0
- package/docs/video/build-ai/clips/06-closing.mp4 +0 -0
- package/docs/video/build-ai/first-frame-02-pain.png +0 -0
- package/docs/video/build-ai/first-frame-03-solution.png +0 -0
- package/docs/video/build-ai/first-frame-04-how.png +0 -0
- package/docs/video/build-ai/first-frame-05-safe.png +0 -0
- package/docs/video/build-ai/segments/01-hook.caption.txt +2 -0
- package/docs/video/build-ai/segments/01-hook.mp4 +0 -0
- package/docs/video/build-ai/segments/02-pain.mp4 +0 -0
- package/docs/video/build-ai/segments/03-solution.mp4 +0 -0
- package/docs/video/build-ai/segments/04-how.mp4 +0 -0
- package/docs/video/build-ai/segments/05-safe.mp4 +0 -0
- package/docs/video/build-ai/segments/06-closing.mp4 +0 -0
- package/docs/video/build-ai/segments/cap-01-hook.png +0 -0
- package/docs/video/build-ai/segments/cap-02-pain.png +0 -0
- package/docs/video/build-ai/segments/cap-03-solution.png +0 -0
- package/docs/video/build-ai/segments/cap-04-how.png +0 -0
- package/docs/video/build-ai/segments/cap-05-safe.png +0 -0
- package/docs/video/build-ai/segments/cap-06-closing.png +0 -0
- package/docs/video/build-ai/segments/final.txt +6 -0
- package/docs/video/build-posters/audio/01-hook.mp3 +0 -0
- package/docs/video/build-posters/audio/02-pain.mp3 +0 -0
- package/docs/video/build-posters/audio/03-solution.mp3 +0 -0
- package/docs/video/build-posters/audio/04-how.mp3 +0 -0
- package/docs/video/build-posters/audio/05-safe.mp3 +0 -0
- package/docs/video/build-posters/audio/06-closing.mp3 +0 -0
- package/docs/video/build-posters/cap-01-hook.png +0 -0
- package/docs/video/build-posters/cap-02-pain.png +0 -0
- package/docs/video/build-posters/cap-03-solution.png +0 -0
- package/docs/video/build-posters/cap-04-how.png +0 -0
- package/docs/video/build-posters/cap-05-safe.png +0 -0
- package/docs/video/build-posters/cap-06-closing.png +0 -0
- package/docs/video/build-posters/card-01-hook.png +0 -0
- package/docs/video/build-posters/card-06-closing.png +0 -0
- package/docs/video/build-posters/segments/01-hook.mp4 +0 -0
- package/docs/video/build-posters/segments/02-pain.mp4 +0 -0
- package/docs/video/build-posters/segments/03-solution.mp4 +0 -0
- package/docs/video/build-posters/segments/04-how.mp4 +0 -0
- package/docs/video/build-posters/segments/05-safe.mp4 +0 -0
- package/docs/video/build-posters/segments/06-closing.mp4 +0 -0
- package/docs/video/build-posters/segments/final.txt +6 -0
- package/docs/video/generate-video-ai.mjs +334 -0
- package/docs/video/generate-video-posters.mjs +204 -0
- package/docs/video/generate-video.mjs +426 -0
- package/docs/video/outline.zh-CN.md +102 -0
- package/docs/video/trellis-demo-video-ai.mp4 +0 -0
- package/docs/video/trellis-demo-video.mp4 +0 -0
- package/docs/video/voiceover.zh-CN.md +49 -0
- package/package.json +5 -2
- package/schema/servers.example.yaml +1 -1
- package/docs/assets/agent-trellis-architecture-horizontal.svg +0 -80
- package/docs/assets/agent-trellis-architecture-vertical.svg +0 -82
- package/docs/assets/trellis-mark.svg +0 -12
|
@@ -26,7 +26,9 @@ import { loadCanonicalSource } from "../core/canonical.js";
|
|
|
26
26
|
import { ClaudeCodeAdapter } from "../adapters/claude-code.js";
|
|
27
27
|
import { CodexAdapter } from "../adapters/codex.js";
|
|
28
28
|
import { KiroAdapter } from "../adapters/kiro.js";
|
|
29
|
-
import {
|
|
29
|
+
import { ZcodeAdapter } from "../adapters/zcode.js";
|
|
30
|
+
import { declaredEnvNames, extractJsonEnvVarNames, extractTomlEnvVarNames, extractZcodeEnvVarNames } from "../lib/envVarNames.js";
|
|
31
|
+
import { resolveZcodeProfile } from "../probes/zcode.js";
|
|
30
32
|
import { resolveSecretEnv } from "../lib/secretEnv.js";
|
|
31
33
|
/** Only agents in `managedAgents` — a present-but-unmanaged agent's config
|
|
32
34
|
* file is never even read (trellis-managed-agents), same restriction as
|
|
@@ -38,6 +40,7 @@ function auditedAgents(homeDir, managedAgents) {
|
|
|
38
40
|
{ id: "claude-code", probe: () => new ClaudeCodeAdapter(homeDir).probe(), configPath: (h) => join(h, ".claude.json"), extractNames: extractJsonEnvVarNames },
|
|
39
41
|
{ id: "codex", probe: () => new CodexAdapter(homeDir).probe(), configPath: (h) => join(h, ".codex", "config.toml"), extractNames: extractTomlEnvVarNames },
|
|
40
42
|
{ id: "kiro", probe: () => new KiroAdapter(homeDir).probe(), configPath: (h) => join(h, ".kiro", "settings", "mcp.json"), extractNames: extractJsonEnvVarNames },
|
|
43
|
+
{ id: "zcode", probe: () => new ZcodeAdapter(homeDir).probe(), configPath: (h) => resolveZcodeProfile(h)?.configPath ?? join(h, ".zcode", "cli", "config.json"), extractNames: extractZcodeEnvVarNames },
|
|
41
44
|
];
|
|
42
45
|
return all.filter((a) => managedAgents.includes(a.id));
|
|
43
46
|
}
|
package/dist/commands/skill.d.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import type { AgentId } from "../core/types.js";
|
|
11
11
|
import { type BackupSession } from "../lib/backup.js";
|
|
12
|
+
import type { SyncReport } from "./sync.js";
|
|
12
13
|
export type BuiltinSkillUpdateAction = "create" | "update" | "already-current";
|
|
13
14
|
export interface BuiltinSkillUpdatePlan {
|
|
14
15
|
name: "trellis-runtime";
|
|
@@ -44,25 +45,53 @@ export interface SkillAddPlan {
|
|
|
44
45
|
sourceDir?: string;
|
|
45
46
|
}
|
|
46
47
|
export declare function collectSkillAddPlan(name: string, fromPath: string, homeDir?: string): SkillAddPlan;
|
|
47
|
-
export declare function applySkillAddPlan(plan: SkillAddPlan, homeDir?: string): void;
|
|
48
|
+
export declare function applySkillAddPlan(plan: SkillAddPlan, homeDir?: string, backup?: BackupSession): void;
|
|
49
|
+
export interface SkillAddOutcome {
|
|
50
|
+
plan: SkillAddPlan;
|
|
51
|
+
sync?: SyncReport;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* See `applyMcpAddWithSync`'s doc comment (mcp.ts) — same split, same
|
|
55
|
+
* reason: a non-CLI caller needs the structured result a JSON-mode CLI
|
|
56
|
+
* run prints, without scraping stdout. Also opens its own backup session
|
|
57
|
+
* around the canonical copy-in, for the same reason `applyMcpAddWithSync`
|
|
58
|
+
* does (trellis-gui tasks.md 3.5): this direct write used to be the one
|
|
59
|
+
* path in this file with no backup/rollback trace at all.
|
|
60
|
+
*/
|
|
61
|
+
export declare function applySkillAddWithSync(plan: SkillAddPlan, opts?: {
|
|
62
|
+
homeDir?: string;
|
|
63
|
+
dryRun?: boolean;
|
|
64
|
+
backupSession?: BackupSession;
|
|
65
|
+
}): Promise<SkillAddOutcome>;
|
|
48
66
|
export declare function runSkillAdd(name: string, fromPath: string, opts?: {
|
|
49
67
|
homeDir?: string;
|
|
50
68
|
json?: boolean;
|
|
51
69
|
dryRun?: boolean;
|
|
52
|
-
}): {
|
|
70
|
+
}): Promise<{
|
|
53
71
|
exitCode: number;
|
|
54
|
-
}
|
|
72
|
+
}>;
|
|
55
73
|
export type SkillRemoveAction = "removed" | "not-found";
|
|
56
74
|
export interface SkillRemovePlan {
|
|
57
75
|
name: string;
|
|
58
76
|
action: SkillRemoveAction;
|
|
59
77
|
}
|
|
60
78
|
export declare function collectSkillRemovePlan(name: string, homeDir?: string): SkillRemovePlan;
|
|
61
|
-
export declare function applySkillRemovePlan(plan: SkillRemovePlan, homeDir?: string): void;
|
|
79
|
+
export declare function applySkillRemovePlan(plan: SkillRemovePlan, homeDir?: string, backup?: BackupSession): void;
|
|
80
|
+
export interface SkillRemoveOutcome {
|
|
81
|
+
plan: SkillRemovePlan;
|
|
82
|
+
sync?: SyncReport;
|
|
83
|
+
}
|
|
84
|
+
/** See `applySkillAddWithSync`'s doc comment — same split, same reason,
|
|
85
|
+
* same own-backup-session fix. */
|
|
86
|
+
export declare function applySkillRemoveWithSync(plan: SkillRemovePlan, opts?: {
|
|
87
|
+
homeDir?: string;
|
|
88
|
+
dryRun?: boolean;
|
|
89
|
+
backupSession?: BackupSession;
|
|
90
|
+
}): Promise<SkillRemoveOutcome>;
|
|
62
91
|
export declare function runSkillRemove(name: string, opts?: {
|
|
63
92
|
homeDir?: string;
|
|
64
93
|
json?: boolean;
|
|
65
94
|
dryRun?: boolean;
|
|
66
|
-
}): {
|
|
95
|
+
}): Promise<{
|
|
67
96
|
exitCode: number;
|
|
68
|
-
}
|
|
97
|
+
}>;
|
package/dist/commands/skill.js
CHANGED
|
@@ -18,6 +18,7 @@ import { loadCanonicalSource } from "../core/canonical.js";
|
|
|
18
18
|
import { resolveScope } from "../core/types.js";
|
|
19
19
|
import { isBuiltinSkillName } from "../lib/builtinSkills.js";
|
|
20
20
|
import { openBackupSession } from "../lib/backup.js";
|
|
21
|
+
import { collectSyncReport, printReport as printSyncReport } from "./sync.js";
|
|
21
22
|
function builtinSkillTemplate() {
|
|
22
23
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
23
24
|
return readFileSync(join(here, "..", "..", "schema", "builtin-skills", "trellis-runtime", "SKILL.md"), "utf8");
|
|
@@ -97,27 +98,56 @@ export function collectSkillAddPlan(name, fromPath, homeDir = homedir()) {
|
|
|
97
98
|
return { name, action: "conflict", detail: `canonical skills/${name}/ already exists with different content — resolve by hand` };
|
|
98
99
|
}
|
|
99
100
|
}
|
|
100
|
-
export function applySkillAddPlan(plan, homeDir = homedir()) {
|
|
101
|
+
export function applySkillAddPlan(plan, homeDir = homedir(), backup) {
|
|
101
102
|
if (plan.action !== "create" || !plan.sourceDir)
|
|
102
103
|
return;
|
|
103
104
|
const dest = join(homeDir, ".trellis", "skills", plan.name);
|
|
105
|
+
if (backup) {
|
|
106
|
+
backup.createDirFromSource(dest, plan.sourceDir);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
104
109
|
mkdirSync(dest, { recursive: true });
|
|
105
110
|
cpSync(plan.sourceDir, dest, { recursive: true });
|
|
106
111
|
}
|
|
107
|
-
|
|
112
|
+
/**
|
|
113
|
+
* See `applyMcpAddWithSync`'s doc comment (mcp.ts) — same split, same
|
|
114
|
+
* reason: a non-CLI caller needs the structured result a JSON-mode CLI
|
|
115
|
+
* run prints, without scraping stdout. Also opens its own backup session
|
|
116
|
+
* around the canonical copy-in, for the same reason `applyMcpAddWithSync`
|
|
117
|
+
* does (trellis-gui tasks.md 3.5): this direct write used to be the one
|
|
118
|
+
* path in this file with no backup/rollback trace at all.
|
|
119
|
+
*/
|
|
120
|
+
export async function applySkillAddWithSync(plan, opts = {}) {
|
|
108
121
|
const homeDir = opts.homeDir ?? homedir();
|
|
109
|
-
const
|
|
122
|
+
const ownSession = !opts.dryRun && !opts.backupSession && plan.action === "create" ? openBackupSession(homeDir, "skill-add") : undefined;
|
|
123
|
+
const session = opts.backupSession ?? ownSession;
|
|
110
124
|
if (!opts.dryRun && plan.action === "create") {
|
|
111
|
-
applySkillAddPlan(plan, homeDir);
|
|
125
|
+
applySkillAddPlan(plan, homeDir, session);
|
|
112
126
|
}
|
|
127
|
+
ownSession?.finalize();
|
|
128
|
+
const failed = plan.action === "conflict" || plan.action === "invalid-source";
|
|
129
|
+
let syncReport;
|
|
130
|
+
if (!failed && plan.action === "create" && existsSync(join(homeDir, ".trellis"))) {
|
|
131
|
+
syncReport = await collectSyncReport({ target: "skills", homeDir, dryRun: opts.dryRun });
|
|
132
|
+
}
|
|
133
|
+
return { plan, ...(syncReport ? { sync: syncReport } : {}) };
|
|
134
|
+
}
|
|
135
|
+
export async function runSkillAdd(name, fromPath, opts = {}) {
|
|
136
|
+
const homeDir = opts.homeDir ?? homedir();
|
|
137
|
+
const plan = collectSkillAddPlan(name, fromPath, homeDir);
|
|
138
|
+
const { sync: syncReport } = await applySkillAddWithSync(plan, { homeDir, dryRun: opts.dryRun });
|
|
139
|
+
const failed = plan.action === "conflict" || plan.action === "invalid-source";
|
|
113
140
|
if (opts.json) {
|
|
114
|
-
console.log(JSON.stringify(plan, null, 2));
|
|
141
|
+
console.log(JSON.stringify(syncReport ? { ...plan, sync: syncReport } : plan, null, 2));
|
|
115
142
|
}
|
|
116
143
|
else {
|
|
117
144
|
console.log(`${opts.dryRun ? "[dry run] " : ""}skill add ${name}`);
|
|
118
145
|
console.log(` [${plan.action}] ${plan.detail}`);
|
|
146
|
+
if (syncReport)
|
|
147
|
+
printSyncReport(syncReport, opts.dryRun ?? false);
|
|
119
148
|
}
|
|
120
|
-
|
|
149
|
+
const syncConflict = syncReport?.reports.some((r) => r.items.some((i) => i.action === "conflict")) ?? false;
|
|
150
|
+
return { exitCode: failed || syncConflict ? 1 : 0 };
|
|
121
151
|
}
|
|
122
152
|
export function collectSkillRemovePlan(name, homeDir = homedir()) {
|
|
123
153
|
if (isBuiltinSkillName(name))
|
|
@@ -125,25 +155,49 @@ export function collectSkillRemovePlan(name, homeDir = homedir()) {
|
|
|
125
155
|
const dir = join(homeDir, ".trellis", "skills", name);
|
|
126
156
|
return { name, action: existsSync(dir) ? "removed" : "not-found" };
|
|
127
157
|
}
|
|
128
|
-
export function applySkillRemovePlan(plan, homeDir = homedir()) {
|
|
158
|
+
export function applySkillRemovePlan(plan, homeDir = homedir(), backup) {
|
|
129
159
|
if (plan.action !== "removed")
|
|
130
160
|
return;
|
|
131
|
-
|
|
161
|
+
const dir = join(homeDir, ".trellis", "skills", plan.name);
|
|
162
|
+
if (backup) {
|
|
163
|
+
backup.removeDir(dir);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
rmSync(dir, { recursive: true, force: true });
|
|
132
167
|
}
|
|
133
|
-
|
|
168
|
+
/** See `applySkillAddWithSync`'s doc comment — same split, same reason,
|
|
169
|
+
* same own-backup-session fix. */
|
|
170
|
+
export async function applySkillRemoveWithSync(plan, opts = {}) {
|
|
134
171
|
const homeDir = opts.homeDir ?? homedir();
|
|
135
|
-
const
|
|
172
|
+
const ownSession = !opts.dryRun && !opts.backupSession && plan.action === "removed" ? openBackupSession(homeDir, "skill-remove") : undefined;
|
|
173
|
+
const session = opts.backupSession ?? ownSession;
|
|
136
174
|
if (!opts.dryRun) {
|
|
137
|
-
applySkillRemovePlan(plan, homeDir);
|
|
175
|
+
applySkillRemovePlan(plan, homeDir, session);
|
|
176
|
+
}
|
|
177
|
+
ownSession?.finalize();
|
|
178
|
+
const failed = plan.action === "not-found";
|
|
179
|
+
let syncReport;
|
|
180
|
+
if (!failed && existsSync(join(homeDir, ".trellis"))) {
|
|
181
|
+
syncReport = await collectSyncReport({ target: "skills", homeDir, dryRun: opts.dryRun });
|
|
138
182
|
}
|
|
183
|
+
return { plan, ...(syncReport ? { sync: syncReport } : {}) };
|
|
184
|
+
}
|
|
185
|
+
export async function runSkillRemove(name, opts = {}) {
|
|
186
|
+
const homeDir = opts.homeDir ?? homedir();
|
|
187
|
+
const plan = collectSkillRemovePlan(name, homeDir);
|
|
188
|
+
const { sync: syncReport } = await applySkillRemoveWithSync(plan, { homeDir, dryRun: opts.dryRun });
|
|
189
|
+
const failed = plan.action === "not-found";
|
|
139
190
|
if (opts.json) {
|
|
140
|
-
console.log(JSON.stringify(plan, null, 2));
|
|
191
|
+
console.log(JSON.stringify(syncReport ? { ...plan, sync: syncReport } : plan, null, 2));
|
|
141
192
|
}
|
|
142
193
|
else if (plan.action === "not-found") {
|
|
143
194
|
console.error(`"${name}" is not a canonical skill — nothing to remove.`);
|
|
144
195
|
}
|
|
145
196
|
else {
|
|
146
197
|
console.log(`${opts.dryRun ? "[dry run] " : ""}removed skill "${name}" from canonical source.`);
|
|
198
|
+
if (syncReport)
|
|
199
|
+
printSyncReport(syncReport, opts.dryRun ?? false);
|
|
147
200
|
}
|
|
148
|
-
|
|
201
|
+
const syncConflict = syncReport?.reports.some((r) => r.items.some((i) => i.action === "conflict")) ?? false;
|
|
202
|
+
return { exitCode: failed || syncConflict ? 1 : 0 };
|
|
149
203
|
}
|
package/dist/commands/sync.js
CHANGED
|
@@ -12,6 +12,7 @@ import { CodexAdapter } from "../adapters/codex.js";
|
|
|
12
12
|
import { KiroAdapter } from "../adapters/kiro.js";
|
|
13
13
|
import { PiAdapter } from "../adapters/pi.js";
|
|
14
14
|
import { KimiCodeAdapter } from "../adapters/kimi-code.js";
|
|
15
|
+
import { ZcodeAdapter } from "../adapters/zcode.js";
|
|
15
16
|
import { openBackupSession } from "../lib/backup.js";
|
|
16
17
|
const ADAPTER_FACTORY = {
|
|
17
18
|
"claude-code": (homeDir) => new ClaudeCodeAdapter(homeDir),
|
|
@@ -19,6 +20,7 @@ const ADAPTER_FACTORY = {
|
|
|
19
20
|
kiro: (homeDir) => new KiroAdapter(homeDir),
|
|
20
21
|
pi: (homeDir) => new PiAdapter(homeDir),
|
|
21
22
|
"kimi-code": (homeDir) => new KimiCodeAdapter(homeDir),
|
|
23
|
+
zcode: (homeDir) => new ZcodeAdapter(homeDir),
|
|
22
24
|
};
|
|
23
25
|
/** Only agents in `canonical.managedAgents` — an agent present on this
|
|
24
26
|
* machine but not managed gets no adapter at all, not a zero-item plan
|
|
@@ -60,7 +62,7 @@ export async function collectSyncReport(opts = {}) {
|
|
|
60
62
|
// out (found via the sandbox: every agent reported "already in
|
|
61
63
|
// sync" even with real create items pending).
|
|
62
64
|
const kind = opts.target === "skills" ? "skill" : "instructions";
|
|
63
|
-
items = items.filter((item) => item.kind === kind);
|
|
65
|
+
items = items.filter((item) => item.kind === kind || (kind === "skill" && item.kind === "zcode-skill-control"));
|
|
64
66
|
}
|
|
65
67
|
if (!opts.dryRun) {
|
|
66
68
|
await adapter.apply(items, backup);
|
package/dist/core/adapter.d.ts
CHANGED
|
@@ -46,7 +46,7 @@ export interface AdapterPlanItem {
|
|
|
46
46
|
* a completely different target file and merge mechanism (see
|
|
47
47
|
* `approvedEnvVars` below) from `"mcp"`, not something the other
|
|
48
48
|
* three agents have an equivalent of. */
|
|
49
|
-
kind: "skill" | "instructions" | "mcp" | "extension" | "kiro-approved-env-vars";
|
|
49
|
+
kind: "skill" | "instructions" | "mcp" | "extension" | "kiro-approved-env-vars" | "zcode-skill-control";
|
|
50
50
|
/** Human-readable description of one change this adapter would make
|
|
51
51
|
* ("create" / "remove") or why it refused to ("conflict"). */
|
|
52
52
|
description: string;
|
|
@@ -88,6 +88,16 @@ export interface AdapterPlanItem {
|
|
|
88
88
|
* for Kiro, never a subtraction (trellis-kiro-approved-env-vars
|
|
89
89
|
* design.md D3/D4). */
|
|
90
90
|
approvedEnvVars?: string[];
|
|
91
|
+
/** ZCode Runtime-only isolation. `null` means the previous profile did
|
|
92
|
+
* not declare the value and restoration must remove the property. */
|
|
93
|
+
zcodeSkillControls?: {
|
|
94
|
+
featuresSkill: boolean | null;
|
|
95
|
+
skillsEnabled: boolean | null;
|
|
96
|
+
previous?: {
|
|
97
|
+
featuresSkill: boolean | null;
|
|
98
|
+
skillsEnabled: boolean | null;
|
|
99
|
+
};
|
|
100
|
+
};
|
|
91
101
|
}
|
|
92
102
|
export interface AdapterVerifyResult {
|
|
93
103
|
ok: boolean;
|
package/dist/core/types.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export type Transport = "stdio" | "http" | "sse";
|
|
8
8
|
export type McpAuthMode = "oauth";
|
|
9
|
-
export type AgentId = "claude-code" | "codex" | "kiro" | "pi" | "kimi-code";
|
|
9
|
+
export type AgentId = "claude-code" | "codex" | "kiro" | "pi" | "kimi-code" | "zcode";
|
|
10
10
|
export declare const ALL_AGENTS: readonly AgentId[];
|
|
11
11
|
/**
|
|
12
12
|
* Every scopable item (skill, subagent, memory entry, MCP server) defaults
|
package/dist/core/types.js
CHANGED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-Agent delegation (trellis-agent-bridge): lets a managed Agent call
|
|
3
|
+
* another managed Agent's own verified non-interactive/headless mode as a
|
|
4
|
+
* one-shot subprocess call, so each Agent's strengths can be used without a
|
|
5
|
+
* central orchestrator or any cross-machine protocol.
|
|
6
|
+
*
|
|
7
|
+
* Configuration lives at `~/.trellis/mcp/agent-bridge.yaml`, sibling to
|
|
8
|
+
* `servers.yaml`, and is fully optional — its absence means zero behavior
|
|
9
|
+
* change (design.md Migration Plan).
|
|
10
|
+
*/
|
|
11
|
+
import { type AgentId } from "../core/types.js";
|
|
12
|
+
export type AgentBridgeOutputFormat = "text" | "json" | "stream-json";
|
|
13
|
+
export type StreamProtocol = "claude" | "zcode";
|
|
14
|
+
export interface AgentBridgeTargetConfig {
|
|
15
|
+
/** Binary to spawn, e.g. "codex", "claude", "pi", "kimi". */
|
|
16
|
+
command: string;
|
|
17
|
+
/** Argv template for a fresh call. One element may be the literal
|
|
18
|
+
* placeholder `"{prompt}"`, substituted with the caller's prompt (and
|
|
19
|
+
* persona, if the target has no dedicated persona flag — see
|
|
20
|
+
* `PERSONA_PLACEHOLDER`) at call time — covers a trailing positional
|
|
21
|
+
* prompt (Codex, Claude Code, pi) and a flag-value prompt (Kimi Code's
|
|
22
|
+
* `-p, --prompt <prompt>`) with the same shape. */
|
|
23
|
+
args: string[];
|
|
24
|
+
/** Argv template used instead of `args` when the caller supplies a
|
|
25
|
+
* `sessionId` to resume — must reference `"{sessionId}"`. Omitting this
|
|
26
|
+
* means the target does not support resuming a prior session; a call
|
|
27
|
+
* that supplies `sessionId` against such a target fails with a clear
|
|
28
|
+
* error rather than silently starting a fresh session. */
|
|
29
|
+
resumeArgs?: string[];
|
|
30
|
+
/** How to interpret stdout. Omit for plain text. */
|
|
31
|
+
outputFormat?: AgentBridgeOutputFormat;
|
|
32
|
+
/** Selects a verified event envelope for stream-json output. Omit for
|
|
33
|
+
* Claude-compatible streams, which remains the existing default. */
|
|
34
|
+
streamProtocol?: StreamProtocol;
|
|
35
|
+
timeoutMs?: number;
|
|
36
|
+
/** Free-text, informational only — surfaced in the exposed tool's
|
|
37
|
+
* description so a caller can judge fit; never validated against a
|
|
38
|
+
* taxonomy. */
|
|
39
|
+
tags?: string[];
|
|
40
|
+
/** Default persona/role text applied to every call to this target
|
|
41
|
+
* unless a call overrides it. Substituted into `"{persona}"` when the
|
|
42
|
+
* chosen argv template has that placeholder; otherwise prepended to the
|
|
43
|
+
* prompt as a framing line, so every target gets persona support even
|
|
44
|
+
* without a native system-prompt flag. */
|
|
45
|
+
persona?: string;
|
|
46
|
+
}
|
|
47
|
+
export interface AgentBridgeConfig {
|
|
48
|
+
targets: Partial<Record<AgentId, AgentBridgeTargetConfig>>;
|
|
49
|
+
/** Maximum delegation chain depth before a call is refused, to bound
|
|
50
|
+
* A→B→A (or longer) cycles. Defaults to `DEFAULT_MAX_DELEGATION_DEPTH`. */
|
|
51
|
+
maxDepth?: number;
|
|
52
|
+
}
|
|
53
|
+
export declare const DEFAULT_DELEGATION_TIMEOUT_MS = 120000;
|
|
54
|
+
export declare const DEFAULT_MAX_DELEGATION_DEPTH = 2;
|
|
55
|
+
/** Carries the current delegation depth down the real process tree — the
|
|
56
|
+
* gateway that receives a delegated call inherits this from its spawning
|
|
57
|
+
* shell, so depth travels with the chain itself without a live shared
|
|
58
|
+
* registry (design.md Decision 3). */
|
|
59
|
+
export declare const DELEGATION_DEPTH_ENV = "TRELLIS_DELEGATION_DEPTH";
|
|
60
|
+
export declare function agentBridgePath(homeDir: string): string;
|
|
61
|
+
/** Reads the current chain depth from an environment map (defaults to
|
|
62
|
+
* `process.env`, injectable for tests). Anything absent or malformed
|
|
63
|
+
* reads as depth 0 — the safe "not part of a chain yet" default. */
|
|
64
|
+
export declare function readDelegationDepth(env?: NodeJS.ProcessEnv): number;
|
|
65
|
+
export declare function loadAgentBridgeConfig(homeDir: string): AgentBridgeConfig;
|
|
66
|
+
export interface DelegatedCallResult {
|
|
67
|
+
status: "completed" | "failed" | "timeout";
|
|
68
|
+
output: string;
|
|
69
|
+
durationMs: number;
|
|
70
|
+
targetAgent: AgentId;
|
|
71
|
+
/** Present when the target reported one (best-effort extraction from
|
|
72
|
+
* `json`/`stream-json` output). Pass back as `sessionId` in a later
|
|
73
|
+
* call to continue this exact conversation, if the target has
|
|
74
|
+
* `resumeArgs` configured. */
|
|
75
|
+
sessionId?: string;
|
|
76
|
+
}
|
|
77
|
+
export interface RunDelegatedCallOptions {
|
|
78
|
+
cwd?: string;
|
|
79
|
+
timeoutMs?: number;
|
|
80
|
+
/** Overrides the target's default `persona` for this call only. */
|
|
81
|
+
persona?: string;
|
|
82
|
+
/** Resume a prior conversation instead of starting a fresh one.
|
|
83
|
+
* Requires the target to have `resumeArgs` configured. */
|
|
84
|
+
sessionId?: string;
|
|
85
|
+
/** The chain depth *before* this call (0 for a call that isn't itself
|
|
86
|
+
* part of a delegation chain). The spawned child sees `depth + 1`. */
|
|
87
|
+
depth?: number;
|
|
88
|
+
}
|
|
89
|
+
/** Spawns the target's verified non-interactive invocation, enforces
|
|
90
|
+
* `timeoutMs` with SIGTERM-then-SIGKILL escalation, and normalizes the
|
|
91
|
+
* result into one envelope regardless of which CLI is underneath. Does
|
|
92
|
+
* NOT itself enforce a depth ceiling — refusing at the limit is the
|
|
93
|
+
* caller's job (AgentBridgeProvider), since only it knows the configured
|
|
94
|
+
* `maxDepth`; this function only propagates whatever depth it's given. */
|
|
95
|
+
export declare function runDelegatedCall(targetAgent: AgentId, target: AgentBridgeTargetConfig, prompt: string, opts?: RunDelegatedCallOptions): Promise<DelegatedCallResult>;
|
|
96
|
+
/** Best-effort structured interpretation of one line of a `stream-json`
|
|
97
|
+
* target's stdout, covering the four shapes documented by the community
|
|
98
|
+
* for Claude Code's non-interactive stream-json output (there is no
|
|
99
|
+
* official Anthropic schema — see upstream issue #24612): a `system/init`
|
|
100
|
+
* line, an `assistant` message carrying text or a `tool_use` block, a
|
|
101
|
+
* `user` message carrying a `tool_result` block, and the final `result`
|
|
102
|
+
* line. Anything that doesn't parse as JSON, or parses but doesn't match
|
|
103
|
+
* one of these shapes, returns `undefined` — the caller falls back to
|
|
104
|
+
* displaying the raw line rather than guessing. */
|
|
105
|
+
export type ParsedStreamEvent = {
|
|
106
|
+
kind: "init";
|
|
107
|
+
sessionId?: string;
|
|
108
|
+
} | {
|
|
109
|
+
kind: "text-delta";
|
|
110
|
+
text: string;
|
|
111
|
+
} | {
|
|
112
|
+
kind: "tool-call";
|
|
113
|
+
toolCallId: string;
|
|
114
|
+
name: string;
|
|
115
|
+
input: unknown;
|
|
116
|
+
} | {
|
|
117
|
+
kind: "tool-result";
|
|
118
|
+
toolCallId: string;
|
|
119
|
+
output: unknown;
|
|
120
|
+
} | {
|
|
121
|
+
kind: "final";
|
|
122
|
+
output: string;
|
|
123
|
+
sessionId?: string;
|
|
124
|
+
protocol?: "zcode";
|
|
125
|
+
};
|
|
126
|
+
export declare function tryParseClaudeStreamJsonLine(line: string): ParsedStreamEvent | undefined;
|
|
127
|
+
/** ZCode's documented headless result envelope is deliberately distinct from
|
|
128
|
+
* Claude-compatible streams: `{ type: "result", response, sessionId }`.
|
|
129
|
+
* Intermediate ZCode protocol events evolve with the runtime, so unknown
|
|
130
|
+
* records remain raw chunks rather than being guessed into false tool/text
|
|
131
|
+
* events. */
|
|
132
|
+
export declare function tryParseZcodeStreamJsonLine(line: string): ParsedStreamEvent | undefined;
|
|
133
|
+
export interface StreamChunk {
|
|
134
|
+
/** Raw text as received from the child, one line (no trailing newline). */
|
|
135
|
+
raw: string;
|
|
136
|
+
/** Present only when `outputFormat: "stream-json"` and the line matched
|
|
137
|
+
* a recognized Claude Code shape — see `tryParseClaudeStreamJsonLine`. */
|
|
138
|
+
parsed?: ParsedStreamEvent;
|
|
139
|
+
}
|
|
140
|
+
export interface DelegatedStreamResult {
|
|
141
|
+
status: "completed" | "failed" | "timeout" | "cancelled";
|
|
142
|
+
output: string;
|
|
143
|
+
durationMs: number;
|
|
144
|
+
/** Chat targets are identified by an arbitrary string id (`chat-agents.yaml`
|
|
145
|
+
* has no `AgentId` constraint — see `chatAgents.ts`), unlike
|
|
146
|
+
* `DelegatedCallResult.targetAgent` which is always a real managed Agent. */
|
|
147
|
+
targetAgent: string;
|
|
148
|
+
sessionId?: string;
|
|
149
|
+
}
|
|
150
|
+
export interface RunDelegatedCallStreamingOptions extends Omit<RunDelegatedCallOptions, "depth"> {
|
|
151
|
+
/** Called once per line of stdout, as it arrives — not batched until the
|
|
152
|
+
* process exits, unlike `runDelegatedCall`. */
|
|
153
|
+
onChunk: (chunk: StreamChunk) => void;
|
|
154
|
+
/** The chain depth before this call, same meaning as
|
|
155
|
+
* `RunDelegatedCallOptions.depth`. */
|
|
156
|
+
depth?: number;
|
|
157
|
+
/** Aborting triggers the same SIGTERM→SIGKILL escalation as a timeout;
|
|
158
|
+
* the returned result has `status: "cancelled"` instead of `"timeout"`. */
|
|
159
|
+
signal?: AbortSignal;
|
|
160
|
+
}
|
|
161
|
+
/** Streaming counterpart to `runDelegatedCall`: same argv-building,
|
|
162
|
+
* timeout escalation, and persona/session handling, but emits `onChunk`
|
|
163
|
+
* for every line of stdout as it arrives instead of buffering until the
|
|
164
|
+
* process exits, and supports cooperative cancellation via `signal`. Takes
|
|
165
|
+
* a plain `string` target id (not `AgentId`) so it can serve both a future
|
|
166
|
+
* streaming MCP delegation tool and today's GUI chat feature, whose
|
|
167
|
+
* targets come from `chat-agents.yaml` and are not required to be one of
|
|
168
|
+
* the fully-managed Agents in `ALL_AGENTS`. */
|
|
169
|
+
export declare function runDelegatedCallStreaming(targetAgent: string, target: AgentBridgeTargetConfig, prompt: string, opts: RunDelegatedCallStreamingOptions): Promise<DelegatedStreamResult>;
|