@mindfoldhq/trellis 0.6.6 → 0.6.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/README.md +1 -1
  2. package/dist/cli/index.d.ts.map +1 -1
  3. package/dist/cli/index.js +37 -0
  4. package/dist/cli/index.js.map +1 -1
  5. package/dist/commands/channel/adapters/codex.d.ts +7 -1
  6. package/dist/commands/channel/adapters/codex.d.ts.map +1 -1
  7. package/dist/commands/channel/adapters/codex.js +19 -2
  8. package/dist/commands/channel/adapters/codex.js.map +1 -1
  9. package/dist/commands/channel/adapters/index.d.ts +3 -1
  10. package/dist/commands/channel/adapters/index.d.ts.map +1 -1
  11. package/dist/commands/channel/adapters/index.js +1 -1
  12. package/dist/commands/channel/adapters/index.js.map +1 -1
  13. package/dist/commands/channel/guard.d.ts.map +1 -1
  14. package/dist/commands/channel/guard.js +7 -2
  15. package/dist/commands/channel/guard.js.map +1 -1
  16. package/dist/commands/channel/index.d.ts.map +1 -1
  17. package/dist/commands/channel/index.js +4 -0
  18. package/dist/commands/channel/index.js.map +1 -1
  19. package/dist/commands/channel/spawn.d.ts +3 -0
  20. package/dist/commands/channel/spawn.d.ts.map +1 -1
  21. package/dist/commands/channel/spawn.js +1 -0
  22. package/dist/commands/channel/spawn.js.map +1 -1
  23. package/dist/commands/channel/store/paths.d.ts +14 -0
  24. package/dist/commands/channel/store/paths.d.ts.map +1 -1
  25. package/dist/commands/channel/store/paths.js +26 -0
  26. package/dist/commands/channel/store/paths.js.map +1 -1
  27. package/dist/commands/channel/supervisor.d.ts +3 -0
  28. package/dist/commands/channel/supervisor.d.ts.map +1 -1
  29. package/dist/commands/channel/supervisor.js +1 -0
  30. package/dist/commands/channel/supervisor.js.map +1 -1
  31. package/dist/commands/init.d.ts +2 -0
  32. package/dist/commands/init.d.ts.map +1 -1
  33. package/dist/commands/init.js.map +1 -1
  34. package/dist/commands/mem.d.ts.map +1 -1
  35. package/dist/commands/mem.js +30 -9
  36. package/dist/commands/mem.js.map +1 -1
  37. package/dist/commands/uninstall.d.ts +9 -0
  38. package/dist/commands/uninstall.d.ts.map +1 -1
  39. package/dist/commands/uninstall.js +67 -3
  40. package/dist/commands/uninstall.js.map +1 -1
  41. package/dist/commands/update.d.ts +40 -1
  42. package/dist/commands/update.d.ts.map +1 -1
  43. package/dist/commands/update.js +126 -34
  44. package/dist/commands/update.js.map +1 -1
  45. package/dist/configurators/codex.d.ts.map +1 -1
  46. package/dist/configurators/codex.js +11 -12
  47. package/dist/configurators/codex.js.map +1 -1
  48. package/dist/configurators/grok.d.ts +22 -0
  49. package/dist/configurators/grok.d.ts.map +1 -0
  50. package/dist/configurators/grok.js +58 -0
  51. package/dist/configurators/grok.js.map +1 -0
  52. package/dist/configurators/index.d.ts.map +1 -1
  53. package/dist/configurators/index.js +12 -2
  54. package/dist/configurators/index.js.map +1 -1
  55. package/dist/configurators/kimi.d.ts +29 -0
  56. package/dist/configurators/kimi.d.ts.map +1 -0
  57. package/dist/configurators/kimi.js +81 -0
  58. package/dist/configurators/kimi.js.map +1 -0
  59. package/dist/configurators/pi.js +9 -9
  60. package/dist/configurators/pi.js.map +1 -1
  61. package/dist/configurators/shared.d.ts.map +1 -1
  62. package/dist/configurators/shared.js +11 -4
  63. package/dist/configurators/shared.js.map +1 -1
  64. package/dist/configurators/zcode.d.ts +9 -4
  65. package/dist/configurators/zcode.d.ts.map +1 -1
  66. package/dist/configurators/zcode.js +41 -12
  67. package/dist/configurators/zcode.js.map +1 -1
  68. package/dist/migrations/manifests/0.5.0-beta.0.json +1 -1
  69. package/dist/migrations/manifests/0.6.7.json +9 -0
  70. package/dist/migrations/manifests/0.6.8.json +17 -0
  71. package/dist/templates/codex/agents/trellis-check.toml +5 -12
  72. package/dist/templates/codex/agents/trellis-implement.toml +5 -12
  73. package/dist/templates/codex/agents/trellis-research.toml +13 -15
  74. package/dist/templates/codex/config.toml +11 -0
  75. package/dist/templates/codex/hooks/session-start.py +9 -3
  76. package/dist/templates/codex/hooks.json +12 -0
  77. package/dist/templates/codex/skills/brainstorm/SKILL.md +40 -13
  78. package/dist/templates/common/bundled-skills/trellis-meta/SKILL.md +2 -2
  79. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-skills-or-commands.md +1 -1
  80. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/agents.md +1 -0
  81. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/hooks-and-settings.md +1 -1
  82. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/overview.md +1 -1
  83. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/platform-map.md +8 -4
  84. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/skills-and-commands.md +2 -1
  85. package/dist/templates/common/bundled-skills/trellis-session-insight/SKILL.md +1 -1
  86. package/dist/templates/common/skills/brainstorm.md +40 -13
  87. package/dist/templates/copilot/prompts/brainstorm.prompt.md +40 -13
  88. package/dist/templates/grok/agents/trellis-check.md +105 -0
  89. package/dist/templates/grok/agents/trellis-implement.md +116 -0
  90. package/dist/templates/grok/agents/trellis-research.md +146 -0
  91. package/dist/templates/grok/index.d.ts +16 -0
  92. package/dist/templates/grok/index.d.ts.map +1 -0
  93. package/dist/templates/grok/index.js +19 -0
  94. package/dist/templates/grok/index.js.map +1 -0
  95. package/dist/templates/kimi/agents/trellis-check.md +103 -0
  96. package/dist/templates/kimi/agents/trellis-implement.md +114 -0
  97. package/dist/templates/kimi/agents/trellis-research.md +140 -0
  98. package/dist/templates/kimi/index.d.ts +19 -0
  99. package/dist/templates/kimi/index.d.ts.map +1 -0
  100. package/dist/templates/kimi/index.js +22 -0
  101. package/dist/templates/kimi/index.js.map +1 -0
  102. package/dist/templates/omp/extensions/trellis/index.ts.txt +19 -5
  103. package/dist/templates/opencode/lib/session-utils.js +8 -2
  104. package/dist/templates/pi/extensions/trellis/index.ts.txt +8 -2
  105. package/dist/templates/pi/settings.json +0 -3
  106. package/dist/templates/shared-hooks/index.d.ts +11 -5
  107. package/dist/templates/shared-hooks/index.d.ts.map +1 -1
  108. package/dist/templates/shared-hooks/index.js +16 -5
  109. package/dist/templates/shared-hooks/index.js.map +1 -1
  110. package/dist/templates/shared-hooks/inject-subagent-context.py +151 -17
  111. package/dist/templates/shared-hooks/inject-workflow-state.py +50 -28
  112. package/dist/templates/shared-hooks/session-start.py +26 -6
  113. package/dist/templates/trellis/config.yaml +9 -7
  114. package/dist/templates/trellis/scripts/common/active_task.py +40 -13
  115. package/dist/templates/trellis/scripts/common/cli_adapter.py +69 -5
  116. package/dist/templates/trellis/scripts/common/config.py +16 -8
  117. package/dist/templates/trellis/scripts/common/git.py +36 -0
  118. package/dist/templates/trellis/scripts/common/io.py +28 -4
  119. package/dist/templates/trellis/scripts/common/task_context.py +19 -1
  120. package/dist/templates/trellis/scripts/common/task_store.py +98 -21
  121. package/dist/templates/trellis/scripts/common/task_utils.py +24 -0
  122. package/dist/templates/trellis/scripts/common/workflow_phase.py +19 -12
  123. package/dist/templates/trellis/scripts/task.py +85 -8
  124. package/dist/templates/trellis/workflow.md +20 -19
  125. package/dist/templates/zcode/agents/trellis-check.md +7 -0
  126. package/dist/templates/zcode/agents/trellis-implement.md +13 -4
  127. package/dist/templates/zcode/config.json +42 -0
  128. package/dist/templates/zcode/index.d.ts +10 -1
  129. package/dist/templates/zcode/index.d.ts.map +1 -1
  130. package/dist/templates/zcode/index.js +12 -2
  131. package/dist/templates/zcode/index.js.map +1 -1
  132. package/dist/types/ai-tools.d.ts +4 -4
  133. package/dist/types/ai-tools.d.ts.map +1 -1
  134. package/dist/types/ai-tools.js +76 -2
  135. package/dist/types/ai-tools.js.map +1 -1
  136. package/dist/utils/atomic-write.d.ts +12 -0
  137. package/dist/utils/atomic-write.d.ts.map +1 -0
  138. package/dist/utils/atomic-write.js +30 -0
  139. package/dist/utils/atomic-write.js.map +1 -0
  140. package/dist/utils/file-writer.d.ts.map +1 -1
  141. package/dist/utils/file-writer.js +6 -5
  142. package/dist/utils/file-writer.js.map +1 -1
  143. package/dist/utils/registry-config.d.ts.map +1 -1
  144. package/dist/utils/registry-config.js +3 -2
  145. package/dist/utils/registry-config.js.map +1 -1
  146. package/dist/utils/template-fetcher.d.ts.map +1 -1
  147. package/dist/utils/template-fetcher.js +35 -6
  148. package/dist/utils/template-fetcher.js.map +1 -1
  149. package/dist/utils/template-hash.d.ts.map +1 -1
  150. package/dist/utils/template-hash.js +2 -1
  151. package/dist/utils/template-hash.js.map +1 -1
  152. package/package.json +2 -2
@@ -0,0 +1,140 @@
1
+ ---
2
+ name: trellis-research
3
+ description: |
4
+ Code and tech search expert for Trellis. Finds files, patterns, and tech
5
+ solutions, and PERSISTS every finding to the current task's research/
6
+ directory. No code modifications outside that directory. On Kimi Code the
7
+ main session dispatches the built-in explore sub-agent with these
8
+ instructions.
9
+ ---
10
+ # Research Agent
11
+
12
+ You are the Research Agent in the Trellis workflow.
13
+
14
+ ## Core Principle
15
+
16
+ **You do one thing: find, explain, and PERSIST information.**
17
+
18
+ Conversations get compacted; files don't. Every research output MUST end up as a file under `{TASK_DIR}/research/`. Returning findings only through the chat reply is a failure - the caller cannot read them next session.
19
+
20
+ ## Dispatch note (main session)
21
+
22
+ Kimi Code has no project-level custom sub-agent definitions — only the built-in `coder` / `explore` / `plan` sub-agents. The main session dispatches the built-in `explore` sub-agent via the Agent tool with a prompt that starts with `Active task: <path from task.py current>` and includes this skill's instructions (`.kimi-code/skills/trellis-research/SKILL.md`).
23
+
24
+ ---
25
+
26
+ ## Core Responsibilities
27
+
28
+ 1. **Internal Search** - locate files/components, understand code logic, discover patterns
29
+ 2. **External Search** - library docs, API references, best practices
30
+ 3. **Persist** - write each research topic to `{TASK_DIR}/research/<topic>.md`
31
+ 4. **Report** - return file paths + one-line summaries to the main agent, not full content
32
+
33
+ ---
34
+
35
+ ## Workflow
36
+
37
+ ### Step 1: Resolve Current Task
38
+
39
+ Run `python3 ./.trellis/scripts/task.py current --source` to get the active task path. Prefer an `Active task: <path>` line in the dispatch prompt when present. If no active task is set, ask the user where to write output; do NOT guess.
40
+
41
+ Ensure `{TASK_DIR}/research/` exists before writing findings.
42
+
43
+ ### Step 2: Understand Search Request
44
+
45
+ Classify the request as internal, external, or mixed. Determine scope and expected output shape.
46
+
47
+ ### Step 3: Execute Search
48
+
49
+ Run independent searches in parallel where possible. Read relevant source files, specs, and documentation before forming conclusions.
50
+
51
+ ### Step 4: Persist Each Topic
52
+
53
+ For each distinct research topic, write a markdown file at `{TASK_DIR}/research/<topic-slug>.md` using the File Format below.
54
+
55
+ ### Step 5: Report to Main Agent
56
+
57
+ Reply with ONLY:
58
+
59
+ - List of files written, paths relative to repo root
60
+ - One-line summary per file
61
+ - Any critical caveats that the main agent needs to know right now
62
+
63
+ Do NOT paste full research content into the reply. The files are the contract.
64
+
65
+ ---
66
+
67
+ ## Scope Limits
68
+
69
+ ### Write Allowed
70
+
71
+ - `{TASK_DIR}/research/*.md` - your own output
72
+ - Creating `{TASK_DIR}/research/` if it doesn't exist
73
+
74
+ ### Write Forbidden
75
+
76
+ - Code files (`src/`, `lib/`, etc.)
77
+ - Spec files (`.trellis/spec/`) - main agent should use the update-spec skill instead
78
+ - `.trellis/scripts/`, `.trellis/workflow.md`, platform config (`.kimi-code/`, `.claude/`, `.cursor/`, etc.)
79
+ - Other task directories
80
+ - Any git operation
81
+
82
+ If the user asks you to edit code, decline and suggest spawning `trellis-implement` instead.
83
+
84
+ ---
85
+
86
+ ## File Format
87
+
88
+ Each `{TASK_DIR}/research/<topic>.md` should follow:
89
+
90
+ ```markdown
91
+ # Research: <topic>
92
+
93
+ - Query: <original query>
94
+ - Scope: internal / external / mixed
95
+ - Date: YYYY-MM-DD
96
+
97
+ ## Findings
98
+
99
+ ### Files Found
100
+
101
+ | File Path | Description |
102
+ |---|---|
103
+ | `src/services/xxx.ts` | Main implementation |
104
+ | `src/types/xxx.ts` | Type definitions |
105
+
106
+ ### Code Patterns
107
+
108
+ <describe patterns, cite file:line>
109
+
110
+ ### External References
111
+
112
+ - [Library X docs](url) - <why relevant, version constraints>
113
+
114
+ ### Related Specs
115
+
116
+ - `.trellis/spec/xxx.md` - <description>
117
+
118
+ ## Caveats / Not Found
119
+
120
+ <anything incomplete or uncertain>
121
+ ```
122
+
123
+ ---
124
+
125
+ ## Guidelines
126
+
127
+ ### Do
128
+
129
+ - Provide specific file paths and line numbers
130
+ - Quote actual code snippets only when they are relevant
131
+ - Persist every topic to its own file
132
+ - Return file paths in your reply, not the full content
133
+ - Mark "not found" explicitly when searches come up empty
134
+
135
+ ### Don't
136
+
137
+ - Don't write code or modify files outside `{TASK_DIR}/research/`
138
+ - Don't guess uncertain info
139
+ - Don't paste full research text into the reply
140
+ - Don't propose implementation changes unless the main agent explicitly asked for research options
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Kimi Code template module.
3
+ *
4
+ * Kimi Code is a class-2 pull-based platform:
5
+ * - Workflow/bundled skills go to the shared `.agents/skills/` root via the
6
+ * neutral resolver (byte-identical to Codex/Gemini/Pi writes).
7
+ * - User-invocable entry points (`trellis-start` / `trellis-continue` /
8
+ * `trellis-finish-work`, invoked as `/skill:trellis-<name>`) and the Trellis
9
+ * agent prompts live under `.kimi-code/skills/<name>/SKILL.md`.
10
+ *
11
+ * Kimi has no project-level hooks/settings file Trellis may write and no
12
+ * custom sub-agent definitions (built-in coder/explore/plan only), so the
13
+ * Trellis agent prompts ship as skills; trellis-implement / trellis-check get
14
+ * the pull-based prelude, trellis-research stays standalone.
15
+ */
16
+ import { type AgentTemplate } from "../template-utils.js";
17
+ /** Trellis agent prompts (trellis-implement, trellis-check, trellis-research), installed as Kimi skills. */
18
+ export declare function getAllAgents(): AgentTemplate[];
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/kimi/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAwB,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIhF,4GAA4G;AAC5G,wBAAgB,YAAY,IAAI,aAAa,EAAE,CAE9C"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Kimi Code template module.
3
+ *
4
+ * Kimi Code is a class-2 pull-based platform:
5
+ * - Workflow/bundled skills go to the shared `.agents/skills/` root via the
6
+ * neutral resolver (byte-identical to Codex/Gemini/Pi writes).
7
+ * - User-invocable entry points (`trellis-start` / `trellis-continue` /
8
+ * `trellis-finish-work`, invoked as `/skill:trellis-<name>`) and the Trellis
9
+ * agent prompts live under `.kimi-code/skills/<name>/SKILL.md`.
10
+ *
11
+ * Kimi has no project-level hooks/settings file Trellis may write and no
12
+ * custom sub-agent definitions (built-in coder/explore/plan only), so the
13
+ * Trellis agent prompts ship as skills; trellis-implement / trellis-check get
14
+ * the pull-based prelude, trellis-research stays standalone.
15
+ */
16
+ import { createTemplateReader } from "../template-utils.js";
17
+ const { listMdAgents } = createTemplateReader(import.meta.url);
18
+ /** Trellis agent prompts (trellis-implement, trellis-check, trellis-research), installed as Kimi skills. */
19
+ export function getAllAgents() {
20
+ return listMdAgents();
21
+ }
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/kimi/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,oBAAoB,EAAsB,MAAM,sBAAsB,CAAC;AAEhF,MAAM,EAAE,YAAY,EAAE,GAAG,oBAAoB,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAE/D,4GAA4G;AAC5G,MAAM,UAAU,YAAY;IAC1B,OAAO,YAAY,EAAE,CAAC;AACxB,CAAC"}
@@ -40,7 +40,7 @@ function buildContextKey(platformName: string, kind: string, value: string): str
40
40
  return safeValue ? `${platformName}_${safeValue}` : `${platformName}_${hashValue(value)}`;
41
41
  }
42
42
 
43
- function deriveContextKey(ctx?: { sessionManager?: { getSessionId?: () => string; getSessionFile?: () => string } }): string | null {
43
+ function deriveContextKey(ctx?: { sessionManager?: { getSessionId?: () => string | undefined; getSessionFile?: () => string | undefined } }): string | null {
44
44
  const sessionId = ctx?.sessionManager?.getSessionId?.();
45
45
  if (sessionId) {
46
46
  return buildContextKey("omp", "session", sessionId);
@@ -336,7 +336,7 @@ export default function(pi: ExtensionAPI): void {
336
336
  let lastCompactionTs = 0;
337
337
  let lastInjectionTs = 0;
338
338
 
339
- const rememberContextKey = (ctx?: { sessionManager?: { getSessionId?: () => string; getSessionFile?: () => string } }): string | null => {
339
+ const rememberContextKey = (ctx?: { sessionManager?: { getSessionId?: () => string | undefined; getSessionFile?: () => string | undefined } }): string | null => {
340
340
  const key = deriveContextKey(ctx);
341
341
  if (!key) return null;
342
342
  return key;
@@ -439,24 +439,38 @@ export default function(pi: ExtensionAPI): void {
439
439
  messages: [
440
440
  ...event.messages,
441
441
  {
442
- role: "custom",
442
+ role: "custom" as const,
443
443
  customType: "trellis-workflow-state",
444
444
  content: cached.workflowMsg,
445
+ display: false,
445
446
  timestamp: Date.now(),
446
447
  },
447
448
  ],
448
449
  };
449
450
  });
450
451
 
452
+ // OMP passes Bash event.input through to the tool execution parameters, so
453
+ // inject the session key through the shell-agnostic env field. An explicit
454
+ // per-call value wins over the derived key.
455
+ pi.on("tool_call", (event, ctx) => {
456
+ if (event.toolName !== "bash") return;
457
+ const contextKey = rememberContextKey(ctx);
458
+ if (!contextKey) return;
459
+ const input = event.input as { env?: Record<string, string> };
460
+ input.env = {
461
+ TRELLIS_CONTEXT_ID: contextKey,
462
+ ...input.env,
463
+ };
464
+ });
465
+
451
466
  pi.on("input", async (_event, ctx) => {
452
467
  if (!projectRoot) {
453
468
  projectRoot = findProjectRoot(ctx.cwd);
454
469
  }
455
470
  // Resolve projectRoot on first input if session_start missed it
456
- if (!projectRoot) return { action: "continue" };
471
+ if (!projectRoot) return;
457
472
  const contextKey = rememberContextKey(ctx);
458
473
  // Pre-warm the cache so before_agent_start and context can use it
459
474
  turnCache.get(projectRoot, contextKey);
460
- return { action: "continue" };
461
475
  });
462
476
  }
@@ -8,8 +8,14 @@ import { debugLog } from "./trellis-context.js"
8
8
  const PYTHON_CMD = platform() === "win32" ? "python" : "python3"
9
9
 
10
10
  const FIRST_REPLY_NOTICE = `<first-reply-notice>
11
- First visible reply: say once in Chinese that Trellis SessionStart context is loaded, then answer directly.
12
- This notice is one-shot: do not repeat it after the first assistant reply in the same session.
11
+ On the first visible assistant reply in this session, briefly acknowledge that Trellis SessionStart context loaded.
12
+ Choose the acknowledgment language in this order:
13
+ 1. Use the language of the user's current request (the user message that triggered this reply).
14
+ 2. If that request has no clear natural language, use an explicitly established project communication language.
15
+ 3. If neither provides a language, output the language-neutral fallback exactly: \`Trellis SessionStart ✓\`.
16
+ Continue directly with the user's request after the acknowledgment.
17
+ The acknowledgment must not alter the language used for the remainder of the response.
18
+ This notice is one-shot: do not repeat it after the first visible assistant reply in this session.
13
19
  </first-reply-notice>`
14
20
 
15
21
  function hasCuratedJsonlEntry(jsonlPath) {
@@ -84,8 +84,14 @@ const ABORT_KILL_GRACE_MS = 1500;
84
84
  const SESSION_OVERVIEW_TIMEOUT_MS = 1500;
85
85
  const THROTTLE_MS = 500;
86
86
  const FIRST_REPLY_NOTICE = `<first-reply-notice>
87
- First visible reply: say once in Chinese that Trellis SessionStart context is loaded, then answer directly.
88
- This notice is one-shot: do not repeat it after the first assistant reply in the same session.
87
+ On the first visible assistant reply in this session, briefly acknowledge that Trellis SessionStart context loaded.
88
+ Choose the acknowledgment language in this order:
89
+ 1. Use the language of the user's current request (the user message that triggered this reply).
90
+ 2. If that request has no clear natural language, use an explicitly established project communication language.
91
+ 3. If neither provides a language, output the language-neutral fallback exactly: \`Trellis SessionStart ✓\`.
92
+ Continue directly with the user's request after the acknowledgment.
93
+ The acknowledgment must not alter the language used for the remainder of the response.
94
+ This notice is one-shot: do not repeat it after the first visible assistant reply in this session.
89
95
  </first-reply-notice>`;
90
96
 
91
97
  // ── State types ───────────────────────────────────────────────────────
@@ -3,9 +3,6 @@
3
3
  "extensions": [
4
4
  "./extensions/trellis/index.ts"
5
5
  ],
6
- "skills": [
7
- "./skills"
8
- ],
9
6
  "prompts": [
10
7
  "./prompts"
11
8
  ]
@@ -12,7 +12,7 @@ export interface HookScript {
12
12
  content: string;
13
13
  }
14
14
  export type SharedHookName = "session-start.py" | "inject-shell-session-context.py" | "inject-workflow-state.py" | "inject-subagent-context.py";
15
- export type SharedHookPlatform = "claude" | "cursor" | "codex" | "gemini" | "qoder" | "copilot" | "codebuddy" | "droid" | "kiro" | "trae";
15
+ export type SharedHookPlatform = "claude" | "cursor" | "codex" | "gemini" | "qoder" | "copilot" | "codebuddy" | "droid" | "kiro" | "trae" | "zcode";
16
16
  /**
17
17
  * Which shared hooks each platform actually invokes. Single source of truth
18
18
  * for shared-hook distribution — both `writeSharedHooks` (runtime install)
@@ -25,10 +25,11 @@ export type SharedHookPlatform = "claude" | "cursor" | "codex" | "gemini" | "qod
25
25
  * - `inject-workflow-state.py` — every platform with a UserPromptSubmit
26
26
  * (or equivalent) event. Kiro + codex self-included; platforms without
27
27
  * per-turn main-session hooks are excluded.
28
- * - `inject-subagent-context.py` — class-1 (push-based) platforms only.
29
- * Class-2 (pull-based) platforms (codex, copilot, gemini, qoder) can't
30
- * have hooks mutate sub-agent prompts — their sub-agents load context
31
- * via a prelude instead.
28
+ * - `inject-subagent-context.py` — platforms with native sub-agent context
29
+ * delivery. Most use a PreToolUse prompt mutation; Codex uses its
30
+ * SubagentStart `additionalContext` event. Class-2 (pull-based) platforms
31
+ * such as copilot, gemini, qoder, and trae still load context from a
32
+ * self-loading agent profile.
32
33
  * - Kiro supports per-turn + spawn hooks on both surfaces (per the official
33
34
  * docs https://kiro.dev/docs/cli/hooks/): the CLI custom agent declares
34
35
  * `hooks.userPromptSubmit` + `hooks.agentSpawn`, and the IDE declares a
@@ -42,6 +43,11 @@ export type SharedHookPlatform = "claude" | "cursor" | "codex" | "gemini" | "qod
42
43
  * or opt in to the Trellis one via `trellis init --with-statusline`
43
44
  * (installed from `templates/claude/hooks/`, not from this table — no
44
45
  * other platform has a statusLine event).
46
+ * - ZCode (3.x) ships a workspace hook config at `.zcode/config.json` covering
47
+ * SessionStart + UserPromptSubmit in the main session, plus PreToolUse for
48
+ * `Agent|Task`. Live probing confirmed `hookSpecificOutput.updatedInput`
49
+ * reaches the sub-agent prompt, so ZCode is class-1 and ships
50
+ * `inject-subagent-context.py`.
45
51
  */
46
52
  export declare const SHARED_HOOKS_BY_PLATFORM: Record<SharedHookPlatform, readonly SharedHookName[]>;
47
53
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/shared-hooks/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAaH,MAAM,WAAW,UAAU;IACzB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,cAAc,GACtB,kBAAkB,GAClB,iCAAiC,GACjC,0BAA0B,GAC1B,4BAA4B,CAAC;AAEjC,MAAM,MAAM,kBAAkB,GAC1B,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,OAAO,GACP,SAAS,GACT,WAAW,GACX,OAAO,GACP,MAAM,GACN,MAAM,CAAC;AAEX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,wBAAwB,EAAE,MAAM,CAC3C,kBAAkB,EAClB,SAAS,cAAc,EAAE,CAgC1B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,UAAU,EAAE,CAWnD;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,kBAAkB,GAC3B,UAAU,EAAE,CAGd"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/shared-hooks/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAaH,MAAM,WAAW,UAAU;IACzB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,cAAc,GACtB,kBAAkB,GAClB,iCAAiC,GACjC,0BAA0B,GAC1B,4BAA4B,CAAC;AAEjC,MAAM,MAAM,kBAAkB,GAC1B,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,OAAO,GACP,SAAS,GACT,WAAW,GACX,OAAO,GACP,MAAM,GACN,MAAM,GACN,OAAO,CAAC;AAEZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,wBAAwB,EAAE,MAAM,CAC3C,kBAAkB,EAClB,SAAS,cAAc,EAAE,CAqC1B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,UAAU,EAAE,CAWnD;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,kBAAkB,GAC3B,UAAU,EAAE,CAGd"}
@@ -25,10 +25,11 @@ function readTemplate(relativePath) {
25
25
  * - `inject-workflow-state.py` — every platform with a UserPromptSubmit
26
26
  * (or equivalent) event. Kiro + codex self-included; platforms without
27
27
  * per-turn main-session hooks are excluded.
28
- * - `inject-subagent-context.py` — class-1 (push-based) platforms only.
29
- * Class-2 (pull-based) platforms (codex, copilot, gemini, qoder) can't
30
- * have hooks mutate sub-agent prompts — their sub-agents load context
31
- * via a prelude instead.
28
+ * - `inject-subagent-context.py` — platforms with native sub-agent context
29
+ * delivery. Most use a PreToolUse prompt mutation; Codex uses its
30
+ * SubagentStart `additionalContext` event. Class-2 (pull-based) platforms
31
+ * such as copilot, gemini, qoder, and trae still load context from a
32
+ * self-loading agent profile.
32
33
  * - Kiro supports per-turn + spawn hooks on both surfaces (per the official
33
34
  * docs https://kiro.dev/docs/cli/hooks/): the CLI custom agent declares
34
35
  * `hooks.userPromptSubmit` + `hooks.agentSpawn`, and the IDE declares a
@@ -42,6 +43,11 @@ function readTemplate(relativePath) {
42
43
  * or opt in to the Trellis one via `trellis init --with-statusline`
43
44
  * (installed from `templates/claude/hooks/`, not from this table — no
44
45
  * other platform has a statusLine event).
46
+ * - ZCode (3.x) ships a workspace hook config at `.zcode/config.json` covering
47
+ * SessionStart + UserPromptSubmit in the main session, plus PreToolUse for
48
+ * `Agent|Task`. Live probing confirmed `hookSpecificOutput.updatedInput`
49
+ * reaches the sub-agent prompt, so ZCode is class-1 and ships
50
+ * `inject-subagent-context.py`.
45
51
  */
46
52
  export const SHARED_HOOKS_BY_PLATFORM = {
47
53
  claude: [
@@ -54,7 +60,7 @@ export const SHARED_HOOKS_BY_PLATFORM = {
54
60
  "inject-shell-session-context.py",
55
61
  "inject-subagent-context.py",
56
62
  ],
57
- codex: ["inject-workflow-state.py"],
63
+ codex: ["inject-workflow-state.py", "inject-subagent-context.py"],
58
64
  gemini: ["session-start.py", "inject-workflow-state.py"],
59
65
  qoder: ["session-start.py", "inject-workflow-state.py"],
60
66
  copilot: ["inject-workflow-state.py"],
@@ -74,6 +80,11 @@ export const SHARED_HOOKS_BY_PLATFORM = {
74
80
  "inject-subagent-context.py",
75
81
  ],
76
82
  trae: ["session-start.py", "inject-workflow-state.py"],
83
+ zcode: [
84
+ "session-start.py",
85
+ "inject-workflow-state.py",
86
+ "inject-subagent-context.py",
87
+ ],
77
88
  };
78
89
  /**
79
90
  * Get all shared hook scripts. Content is platform-independent and can be
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/shared-hooks/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,SAAS,YAAY,CAAC,YAAoB;IACxC,OAAO,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,EAAE,OAAO,CAAC,CAAC;AAC9D,CAAC;AA2BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAGjC;IACF,MAAM,EAAE;QACN,kBAAkB;QAClB,0BAA0B;QAC1B,4BAA4B;KAC7B;IACD,MAAM,EAAE;QACN,kBAAkB;QAClB,iCAAiC;QACjC,4BAA4B;KAC7B;IACD,KAAK,EAAE,CAAC,0BAA0B,CAAC;IACnC,MAAM,EAAE,CAAC,kBAAkB,EAAE,0BAA0B,CAAC;IACxD,KAAK,EAAE,CAAC,kBAAkB,EAAE,0BAA0B,CAAC;IACvD,OAAO,EAAE,CAAC,0BAA0B,CAAC;IACrC,SAAS,EAAE;QACT,kBAAkB;QAClB,0BAA0B;QAC1B,4BAA4B;KAC7B;IACD,KAAK,EAAE;QACL,kBAAkB;QAClB,0BAA0B;QAC1B,4BAA4B;KAC7B;IACD,IAAI,EAAE;QACJ,kBAAkB;QAClB,0BAA0B;QAC1B,4BAA4B;KAC7B;IACD,IAAI,EAAE,CAAC,kBAAkB,EAAE,0BAA0B,CAAC;CACvD,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,oBAAoB;IAClC,MAAM,OAAO,GAAiB,EAAE,CAAC;IACjC,MAAM,KAAK,GAAG,WAAW,CAAC,SAAS,CAAC;SACjC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;SAChC,IAAI,EAAE,CAAC;IAEV,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,+BAA+B,CAC7C,QAA4B;IAE5B,MAAM,OAAO,GAAG,IAAI,GAAG,CAAS,wBAAwB,CAAC,QAAQ,CAAC,CAAC,CAAC;IACpE,OAAO,oBAAoB,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACnE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/shared-hooks/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,SAAS,YAAY,CAAC,YAAoB;IACxC,OAAO,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,EAAE,OAAO,CAAC,CAAC;AAC9D,CAAC;AA4BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAGjC;IACF,MAAM,EAAE;QACN,kBAAkB;QAClB,0BAA0B;QAC1B,4BAA4B;KAC7B;IACD,MAAM,EAAE;QACN,kBAAkB;QAClB,iCAAiC;QACjC,4BAA4B;KAC7B;IACD,KAAK,EAAE,CAAC,0BAA0B,EAAE,4BAA4B,CAAC;IACjE,MAAM,EAAE,CAAC,kBAAkB,EAAE,0BAA0B,CAAC;IACxD,KAAK,EAAE,CAAC,kBAAkB,EAAE,0BAA0B,CAAC;IACvD,OAAO,EAAE,CAAC,0BAA0B,CAAC;IACrC,SAAS,EAAE;QACT,kBAAkB;QAClB,0BAA0B;QAC1B,4BAA4B;KAC7B;IACD,KAAK,EAAE;QACL,kBAAkB;QAClB,0BAA0B;QAC1B,4BAA4B;KAC7B;IACD,IAAI,EAAE;QACJ,kBAAkB;QAClB,0BAA0B;QAC1B,4BAA4B;KAC7B;IACD,IAAI,EAAE,CAAC,kBAAkB,EAAE,0BAA0B,CAAC;IACtD,KAAK,EAAE;QACL,kBAAkB;QAClB,0BAA0B;QAC1B,4BAA4B;KAC7B;CACF,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,oBAAoB;IAClC,MAAM,OAAO,GAAiB,EAAE,CAAC;IACjC,MAAM,KAAK,GAAG,WAAW,CAAC,SAAS,CAAC;SACjC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;SAChC,IAAI,EAAE,CAAC;IAEV,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,+BAA+B,CAC7C,QAA4B;IAE5B,MAAM,OAAO,GAAG,IAAI,GAAG,CAAS,wBAAwB,CAAC,QAAQ,CAAC,CAAC,CAAC;IACpE,OAAO,oBAAoB,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACnE,CAAC"}
@@ -80,9 +80,12 @@ def find_repo_root(start_path: str) -> str | None:
80
80
 
81
81
 
82
82
  def _detect_platform(input_data: dict) -> str | None:
83
+ if _hook_event_name(input_data) == "SubagentStart":
84
+ return "codex"
83
85
  if isinstance(input_data.get("cursor_version"), str):
84
86
  return "cursor"
85
87
  env_map = {
88
+ "ZCODE_PROJECT_DIR": "zcode",
86
89
  "CLAUDE_PROJECT_DIR": "claude",
87
90
  "CURSOR_PROJECT_DIR": "cursor",
88
91
  "CODEBUDDY_PROJECT_DIR": "codebuddy",
@@ -110,10 +113,20 @@ def _detect_platform(input_data: dict) -> str | None:
110
113
  return "droid"
111
114
  if ".kiro" in script_parts:
112
115
  return "kiro"
116
+ if ".zcode" in script_parts:
117
+ return "zcode"
113
118
  return None
114
119
 
115
120
 
116
- def get_current_task(repo_root: str, input_data: dict) -> str | None:
121
+ def get_current_task(
122
+ repo_root: str,
123
+ input_data: dict,
124
+ *,
125
+ platform: str | None = None,
126
+ allow_single_session_fallback: bool = True,
127
+ allow_environment_context: bool = True,
128
+ require_existing: bool = False,
129
+ ) -> str | None:
117
130
  """Resolve current task directory through the unified active task resolver."""
118
131
  scripts_dir = Path(repo_root) / DIR_WORKFLOW / "scripts"
119
132
  if str(scripts_dir) not in sys.path:
@@ -126,8 +139,12 @@ def get_current_task(repo_root: str, input_data: dict) -> str | None:
126
139
  active = resolve_active_task(
127
140
  Path(repo_root),
128
141
  input_data,
129
- platform=_detect_platform(input_data),
142
+ platform=platform or _detect_platform(input_data),
143
+ allow_single_session_fallback=allow_single_session_fallback,
144
+ allow_environment_context=allow_environment_context,
130
145
  )
146
+ if require_existing and active.stale:
147
+ return None
131
148
  return active.task_path
132
149
 
133
150
 
@@ -574,6 +591,98 @@ def _string_value(value: Any) -> str:
574
591
  return ""
575
592
 
576
593
 
594
+ def _hook_event_name(input_data: dict) -> str:
595
+ """Return a hook event name from the documented snake/camel-case fields."""
596
+ return _string_value(
597
+ input_data.get("hook_event_name") or input_data.get("hookEventName")
598
+ )
599
+
600
+
601
+ def _codex_subagent_type(input_data: dict) -> str:
602
+ """Return a Trellis Codex agent type only for a native start event."""
603
+ if _hook_event_name(input_data) != "SubagentStart":
604
+ return ""
605
+ agent_type = _string_value(
606
+ input_data.get("agent_type") or input_data.get("agentType")
607
+ )
608
+ return agent_type if agent_type in AGENTS_ALL else ""
609
+
610
+
611
+ def build_codex_subagent_context(
612
+ subagent_type: str,
613
+ task_dir: str,
614
+ context: str,
615
+ ) -> str:
616
+ """Build developer context for a native, already-dispatched Codex role."""
617
+ role = subagent_type.removeprefix("trellis-")
618
+ return f"""<!-- trellis-hook-injected -->
619
+ # Trellis Native {role.title()} Subagent
620
+
621
+ You are the dispatched `{subagent_type}` role for this task. Perform that role
622
+ directly; do not follow main-session dispatch or wait instructions, and do not
623
+ spawn another Trellis subagent.
624
+
625
+ Active task: {task_dir}
626
+
627
+ ## Curated Context
628
+
629
+ {context}"""
630
+
631
+
632
+ def _handle_codex_subagent_start(input_data: dict) -> None:
633
+ """Emit Codex developer context for a recognised native Trellis subagent.
634
+
635
+ The event supplies the parent session id. Disabling the generic
636
+ single-session fallback is essential here: native starts must never borrow
637
+ a task from another Codex window when that parent id is absent or stale.
638
+ """
639
+ subagent_type = _codex_subagent_type(input_data)
640
+ parent_session_id = _string_value(input_data.get("session_id"))
641
+ if not subagent_type or not parent_session_id:
642
+ return
643
+
644
+ cwd = _string_value(input_data.get("cwd")) or os.getcwd()
645
+ repo_root = find_repo_root(cwd)
646
+ if not repo_root:
647
+ return
648
+
649
+ task_dir = get_current_task(
650
+ repo_root,
651
+ {"session_id": parent_session_id},
652
+ platform="codex",
653
+ allow_single_session_fallback=False,
654
+ allow_environment_context=False,
655
+ require_existing=True,
656
+ )
657
+ if not task_dir:
658
+ return
659
+
660
+ if subagent_type in AGENTS_REQUIRE_TASK:
661
+ task_dir_full = Path(repo_root) / task_dir
662
+ if not task_dir_full.is_dir():
663
+ return
664
+
665
+ if subagent_type == AGENT_IMPLEMENT:
666
+ context = get_implement_context(repo_root, task_dir)
667
+ elif subagent_type == AGENT_CHECK:
668
+ context = get_check_context(repo_root, task_dir)
669
+ else:
670
+ context = get_research_context(repo_root, task_dir)
671
+
672
+ if not context:
673
+ return
674
+
675
+ output = {
676
+ "hookSpecificOutput": {
677
+ "hookEventName": "SubagentStart",
678
+ "additionalContext": build_codex_subagent_context(
679
+ subagent_type, task_dir, context
680
+ ),
681
+ }
682
+ }
683
+ print(json.dumps(output, ensure_ascii=False))
684
+
685
+
577
686
  def _extract_subagent_name(value: Any) -> str:
578
687
  """Extract a sub-agent name from common platform encodings.
579
688
 
@@ -652,10 +761,15 @@ def _parse_hook_input(input_data: dict) -> tuple[str, str, dict]:
652
761
  - Claude Code / Qoder / CodeBuddy / Droid: tool_name=Task|Agent, tool_input.subagent_type
653
762
  - Cursor: tool_name=Task|Subagent, tool_input.subagent_type
654
763
  - Copilot CLI: toolName=task (camelCase key, lowercase value)
764
+ - ZCode: toolName=Agent, toolInput/tool_input.subagent_type
655
765
  - Gemini CLI: tool_name IS the agent name (BeforeTool matcher already filtered)
656
766
  - Kiro: agentSpawn hook, agent_name field at top level
657
767
  """
658
768
  tool_input = input_data.get("tool_input", {})
769
+ if not isinstance(tool_input, dict):
770
+ tool_input = input_data.get("toolInput", {})
771
+ if not isinstance(tool_input, dict):
772
+ tool_input = {}
659
773
 
660
774
  # Standard format: Task/Agent tool with subagent_type
661
775
  tool_name = input_data.get("tool_name", "") or input_data.get("toolName", "")
@@ -692,6 +806,17 @@ def main():
692
806
  input_data = json.load(sys.stdin)
693
807
  except json.JSONDecodeError:
694
808
  sys.exit(0)
809
+ if not isinstance(input_data, dict):
810
+ sys.exit(0)
811
+
812
+ if _hook_event_name(input_data) == "SubagentStart":
813
+ try:
814
+ _handle_codex_subagent_start(input_data)
815
+ except Exception:
816
+ # A native context hook must never prevent Codex from spawning the
817
+ # requested child when its runtime state is unavailable or stale.
818
+ pass
819
+ sys.exit(0)
695
820
 
696
821
  subagent_type, original_prompt, tool_input = _parse_hook_input(input_data)
697
822
  cwd = input_data.get("cwd", os.getcwd())
@@ -745,23 +870,32 @@ def main():
745
870
  if not context:
746
871
  sys.exit(0)
747
872
 
748
- # Return updated input use a multi-format output that covers all platforms.
749
- # Most platforms ignore unrecognized fields, so we include multiple formats.
750
- # The platform picks whichever fields it understands.
873
+ # Return updated input. Most platforms ignore unrecognized fields, so we
874
+ # include multiple formats. ZCode is stricter; live probing confirmed the
875
+ # nested Claude-compatible shape below reaches the sub-agent prompt.
751
876
  updated = {**tool_input, "prompt": new_prompt}
752
- output = {
753
- # Claude Code / Qoder / CodeBuddy / Droid format
754
- "hookSpecificOutput": {
755
- "hookEventName": "PreToolUse",
756
- "permissionDecision": "allow",
877
+ if _detect_platform(input_data) == "zcode":
878
+ output = {
879
+ "hookSpecificOutput": {
880
+ "hookEventName": "PreToolUse",
881
+ "permissionDecision": "allow",
882
+ "updatedInput": updated,
883
+ }
884
+ }
885
+ else:
886
+ output = {
887
+ # Claude Code / Qoder / CodeBuddy / Droid format
888
+ "hookSpecificOutput": {
889
+ "hookEventName": "PreToolUse",
890
+ "permissionDecision": "allow",
891
+ "updatedInput": updated,
892
+ },
893
+ # Cursor format
894
+ "permission": "allow",
895
+ "updated_input": updated,
896
+ # Gemini format
757
897
  "updatedInput": updated,
758
- },
759
- # Cursor format
760
- "permission": "allow",
761
- "updated_input": updated,
762
- # Gemini format
763
- "updatedInput": updated,
764
- }
898
+ }
765
899
 
766
900
  print(json.dumps(output, ensure_ascii=False))
767
901
  sys.exit(0)