@mindfoldhq/trellis 0.6.4 → 0.6.6

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 (116) hide show
  1. package/README.md +1 -1
  2. package/dist/cli/index.js +2 -0
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/commands/channel/messages.js +1 -1
  5. package/dist/commands/channel/supervisor/stdout.d.ts +7 -5
  6. package/dist/commands/channel/supervisor/stdout.d.ts.map +1 -1
  7. package/dist/commands/channel/supervisor/stdout.js +65 -18
  8. package/dist/commands/channel/supervisor/stdout.js.map +1 -1
  9. package/dist/commands/channel/supervisor.d.ts +13 -0
  10. package/dist/commands/channel/supervisor.d.ts.map +1 -1
  11. package/dist/commands/channel/supervisor.js +54 -2
  12. package/dist/commands/channel/supervisor.js.map +1 -1
  13. package/dist/commands/init.d.ts +2 -0
  14. package/dist/commands/init.d.ts.map +1 -1
  15. package/dist/commands/init.js.map +1 -1
  16. package/dist/commands/uninstall.d.ts.map +1 -1
  17. package/dist/commands/uninstall.js +8 -1
  18. package/dist/commands/uninstall.js.map +1 -1
  19. package/dist/commands/update.d.ts.map +1 -1
  20. package/dist/commands/update.js +83 -42
  21. package/dist/commands/update.js.map +1 -1
  22. package/dist/configurators/copilot.d.ts +1 -0
  23. package/dist/configurators/copilot.d.ts.map +1 -1
  24. package/dist/configurators/copilot.js +4 -1
  25. package/dist/configurators/copilot.js.map +1 -1
  26. package/dist/configurators/index.d.ts.map +1 -1
  27. package/dist/configurators/index.js +27 -1
  28. package/dist/configurators/index.js.map +1 -1
  29. package/dist/configurators/omp.d.ts +11 -0
  30. package/dist/configurators/omp.d.ts.map +1 -0
  31. package/dist/configurators/omp.js +51 -0
  32. package/dist/configurators/omp.js.map +1 -0
  33. package/dist/configurators/pi.d.ts.map +1 -1
  34. package/dist/configurators/pi.js +14 -4
  35. package/dist/configurators/pi.js.map +1 -1
  36. package/dist/configurators/shared.d.ts +7 -0
  37. package/dist/configurators/shared.d.ts.map +1 -1
  38. package/dist/configurators/shared.js +27 -0
  39. package/dist/configurators/shared.js.map +1 -1
  40. package/dist/configurators/trae.d.ts +17 -0
  41. package/dist/configurators/trae.d.ts.map +1 -0
  42. package/dist/configurators/trae.js +42 -0
  43. package/dist/configurators/trae.js.map +1 -0
  44. package/dist/configurators/zcode.d.ts +3 -3
  45. package/dist/configurators/zcode.js +12 -12
  46. package/dist/configurators/zcode.js.map +1 -1
  47. package/dist/migrations/manifests/0.6.5.json +9 -0
  48. package/dist/migrations/manifests/0.6.6.json +17 -0
  49. package/dist/templates/codex/hooks/session-start.py +6 -6
  50. package/dist/templates/codex/skills/brainstorm/SKILL.md +19 -1
  51. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-agents.md +1 -1
  52. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-hooks.md +1 -1
  53. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-skills-or-commands.md +1 -1
  54. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/bundled-skills.md +2 -1
  55. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/generated-files.md +3 -3
  56. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/agents.md +1 -1
  57. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/hooks-and-settings.md +1 -0
  58. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/overview.md +5 -5
  59. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/platform-map.md +21 -2
  60. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/skills-and-commands.md +1 -1
  61. package/dist/templates/common/skills/brainstorm.md +19 -1
  62. package/dist/templates/copilot/copilot-instructions.md +11 -0
  63. package/dist/templates/copilot/hooks/session-start.py +6 -6
  64. package/dist/templates/copilot/index.d.ts +6 -1
  65. package/dist/templates/copilot/index.d.ts.map +1 -1
  66. package/dist/templates/copilot/index.js +8 -1
  67. package/dist/templates/copilot/index.js.map +1 -1
  68. package/dist/templates/copilot/prompts/brainstorm.prompt.md +19 -1
  69. package/dist/templates/omp/agents/trellis-check.md +41 -0
  70. package/dist/templates/omp/agents/trellis-implement.md +45 -0
  71. package/dist/templates/omp/agents/trellis-research.md +30 -0
  72. package/dist/templates/omp/extensions/trellis/index.ts.txt +462 -0
  73. package/dist/templates/omp/index.d.ts +4 -0
  74. package/dist/templates/omp/index.d.ts.map +1 -0
  75. package/dist/templates/omp/index.js +9 -0
  76. package/dist/templates/omp/index.js.map +1 -0
  77. package/dist/templates/pi/agents/trellis-check.md +1 -1
  78. package/dist/templates/pi/agents/trellis-implement.md +1 -1
  79. package/dist/templates/pi/agents/trellis-research.md +1 -1
  80. package/dist/templates/pi/extensions/trellis/index.ts.txt +111 -9
  81. package/dist/templates/shared-hooks/index.d.ts +1 -1
  82. package/dist/templates/shared-hooks/index.d.ts.map +1 -1
  83. package/dist/templates/shared-hooks/index.js +1 -0
  84. package/dist/templates/shared-hooks/index.js.map +1 -1
  85. package/dist/templates/shared-hooks/inject-workflow-state.py +41 -6
  86. package/dist/templates/shared-hooks/session-start.py +12 -7
  87. package/dist/templates/trae/agents/trellis-check.md +108 -0
  88. package/dist/templates/trae/agents/trellis-implement.md +103 -0
  89. package/dist/templates/trae/agents/trellis-research.md +137 -0
  90. package/dist/templates/trae/hooks.json +27 -0
  91. package/dist/templates/trae/index.d.ts +15 -0
  92. package/dist/templates/trae/index.d.ts.map +1 -0
  93. package/dist/templates/trae/index.js +15 -0
  94. package/dist/templates/trae/index.js.map +1 -0
  95. package/dist/templates/trellis/scripts/add_session.py +65 -17
  96. package/dist/templates/trellis/scripts/common/active_task.py +2 -0
  97. package/dist/templates/trellis/scripts/common/cli_adapter.py +72 -11
  98. package/dist/templates/trellis/scripts/common/config.py +29 -0
  99. package/dist/templates/trellis/scripts/common/session_context.py +1 -1
  100. package/dist/templates/trellis/scripts/common/task_store.py +79 -19
  101. package/dist/templates/trellis/scripts/task.py +8 -2
  102. package/dist/templates/trellis/workflow.md +22 -20
  103. package/dist/templates/zcode/agents/trellis-research.md +133 -0
  104. package/dist/templates/zcode/index.d.ts +6 -5
  105. package/dist/templates/zcode/index.d.ts.map +1 -1
  106. package/dist/templates/zcode/index.js +6 -5
  107. package/dist/templates/zcode/index.js.map +1 -1
  108. package/dist/types/ai-tools.d.ts +4 -4
  109. package/dist/types/ai-tools.d.ts.map +1 -1
  110. package/dist/types/ai-tools.js +45 -2
  111. package/dist/types/ai-tools.js.map +1 -1
  112. package/dist/utils/uninstall-scrubbers.d.ts +1 -0
  113. package/dist/utils/uninstall-scrubbers.d.ts.map +1 -1
  114. package/dist/utils/uninstall-scrubbers.js +19 -0
  115. package/dist/utils/uninstall-scrubbers.js.map +1 -1
  116. package/package.json +2 -2
@@ -31,11 +31,13 @@ interface SubagentInput {
31
31
  interface AgentConfig {
32
32
  model?: string;
33
33
  thinking?: string;
34
+ tools?: string[];
34
35
  fallbackModels: string[];
35
36
  }
36
37
  interface PiRunConfig {
37
38
  model?: string;
38
39
  thinking?: string;
40
+ tools?: string[];
39
41
  }
40
42
 
41
43
  // ── Lazy-load pi-tui (avoid failing top-level imports) ─────────────────
@@ -81,6 +83,10 @@ const MAX_PARALLEL_PROMPTS = 6;
81
83
  const ABORT_KILL_GRACE_MS = 1500;
82
84
  const SESSION_OVERVIEW_TIMEOUT_MS = 1500;
83
85
  const THROTTLE_MS = 500;
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.
89
+ </first-reply-notice>`;
84
90
 
85
91
  // ── State types ───────────────────────────────────────────────────────
86
92
  type RunStatus = "pending" | "running" | "succeeded" | "failed" | "cancelled";
@@ -654,8 +660,8 @@ function resolveRunCfg(
654
660
  agentSuffixThinking ??
655
661
  normalize(inheritedThinking);
656
662
  if (baseModel && thinking && thinking !== "off")
657
- return { model: `${baseModel}:${thinking}`, thinking };
658
- return { model: baseModel || rawModel, thinking };
663
+ return { model: `${baseModel}:${thinking}`, thinking, tools: agentCfg.tools };
664
+ return { model: baseModel || rawModel, thinking, tools: agentCfg.tools };
659
665
  }
660
666
 
661
667
  function buildPiArgs(cfg: PiRunConfig): string[] {
@@ -669,6 +675,8 @@ function buildPiArgs(cfg: PiRunConfig): string[] {
669
675
  );
670
676
  else if (cfg.thinking && cfg.thinking !== "off")
671
677
  args.push("--thinking", cfg.thinking);
678
+ if (cfg.tools && cfg.tools.length > 0)
679
+ args.push("--tools", cfg.tools.join(","));
672
680
  return args;
673
681
  }
674
682
 
@@ -762,6 +770,16 @@ function parseAgentFM(c: string): AgentConfig {
762
770
  }
763
771
  i--;
764
772
  }
773
+ } else if (k === "tools") {
774
+ // Pi tool names are lowercase (read, bash, edit, write, grep, find, ls).
775
+ // Normalize to lowercase so mixed-case frontmatter still matches.
776
+ if (v.trim()) {
777
+ cfg.tools = v
778
+ .trim()
779
+ .split(",")
780
+ .map((s) => s.trim().replace(/^["']|["']$/g, "").toLowerCase())
781
+ .filter(Boolean);
782
+ }
765
783
  }
766
784
  }
767
785
  return cfg;
@@ -862,12 +880,12 @@ function workflowBreadcrumb(root: string, key: string | null): string {
862
880
  }
863
881
 
864
882
  // ── Session Overview ───────────────────────────────────────────────────
865
- function sessionOverview(root: string, key: string | null): string {
883
+ function runContextScript(root: string, key: string | null, args: string[]): string {
866
884
  const script = join(root, ".trellis", "scripts", "get_context.py");
867
885
  if (!exists(script)) return "";
868
886
  try {
869
887
  const py = process.platform === "win32" ? "python" : "python3";
870
- const result = spawnSync(py, [script], {
888
+ const result = spawnSync(py, [script, ...args], {
871
889
  cwd: root,
872
890
  env: key ? { ...process.env, TRELLIS_CONTEXT_ID: key } : process.env,
873
891
  encoding: "utf-8",
@@ -876,12 +894,44 @@ function sessionOverview(root: string, key: string | null): string {
876
894
  });
877
895
  if (result.status !== 0) return "";
878
896
  const stdout = (result.stdout ?? "").trim();
879
- return stdout ? `<session-overview>\n${stdout}\n</session-overview>` : "";
897
+ return stdout;
880
898
  } catch {
881
899
  return "";
882
900
  }
883
901
  }
884
902
 
903
+ function sessionOverview(root: string, key: string | null): string {
904
+ const stdout = runContextScript(root, key, []);
905
+ return stdout ? `<session-overview>\n${stdout}\n</session-overview>` : "";
906
+ }
907
+
908
+ function workflowOverview(root: string, key: string | null): string {
909
+ const stdout = runContextScript(root, key, [
910
+ "--mode",
911
+ "phase",
912
+ "--platform",
913
+ "pi",
914
+ ]);
915
+ return stdout ? `<trellis-workflow>\n${stdout}\n</trellis-workflow>` : "";
916
+ }
917
+
918
+ function buildStartupContext(
919
+ root: string,
920
+ key: string | null,
921
+ overview: string,
922
+ ): string {
923
+ const workflow = workflowOverview(root, key);
924
+ return [
925
+ "<session-context>\nTrellis compact SessionStart context. Use it to orient the session; load details on demand.\n</session-context>",
926
+ FIRST_REPLY_NOTICE,
927
+ overview,
928
+ workflow,
929
+ "<ready>\nUse the current workflow state to decide whether to create, continue, or skip a Trellis task.\n</ready>",
930
+ ]
931
+ .filter(Boolean)
932
+ .join("\n\n");
933
+ }
934
+
885
935
  function buildContext(root: string, agent: string, key: string | null): string {
886
936
  const dir = readTaskDir(root, key);
887
937
  if (!dir)
@@ -1372,6 +1422,26 @@ export default function trellisExtension(pi: {
1372
1422
  };
1373
1423
  return turnCache;
1374
1424
  };
1425
+ // Provider prefix caches invalidate from byte 0 whenever the system prompt
1426
+ // changes, so everything injected into systemPrompt is memoized per context
1427
+ // key and stays byte-identical for the life of the process. Volatile state
1428
+ // travels through persisted custom messages instead (append-only history).
1429
+ const startupCtxCache = new Map<string, string>();
1430
+ const getStartupCtx = (
1431
+ k: string | null,
1432
+ turn: { ov: string },
1433
+ ): string => {
1434
+ const key = k ?? "default";
1435
+ let startup = startupCtxCache.get(key);
1436
+ if (startup === undefined) {
1437
+ startup = buildStartupContext(root, k, turn.ov);
1438
+ startupCtxCache.set(key, startup);
1439
+ }
1440
+ return startup;
1441
+ };
1442
+ const taskCtxSnapshot = new Map<string, string>();
1443
+ const lastSentTaskCtx = new Map<string, string>();
1444
+ const lastSentRuntimeCtx = new Map<string, string>();
1375
1445
 
1376
1446
  // Toggle only the latest subagent native card; do not use Pi global tool expansion.
1377
1447
  const toggleDetail = (ctx: PiExtensionContext) => {
@@ -1550,7 +1620,7 @@ export default function trellisExtension(pi: {
1550
1620
  pi.on?.("session_start", (event, ctx) => {
1551
1621
  getKey(event, ctx);
1552
1622
  ctx?.ui?.notify?.(
1553
- "Trellis project context is available. Use /trellis-continue to resume the current task.",
1623
+ "Trellis project context is available. Use /trellis-start to bootstrap or /trellis-continue to resume.",
1554
1624
  "info",
1555
1625
  );
1556
1626
  });
@@ -1587,11 +1657,43 @@ export default function trellisExtension(pi: {
1587
1657
  });
1588
1658
  pi.on?.("before_agent_start", (event, ctx) => {
1589
1659
  const k = getKey(event, ctx);
1660
+ const key = k ?? "default";
1590
1661
  const cur = (event as { systemPrompt?: string }).systemPrompt ?? "";
1591
- const ctxText = buildContext(root, "trellis-implement", k);
1592
- const { wf, ov } = getTurnCtx(k);
1662
+ const turn = getTurnCtx(k);
1663
+ const startup = getStartupCtx(k, turn);
1664
+ // Task context is snapshotted into systemPrompt once; later on-disk
1665
+ // changes are delivered as persisted messages so the prefix stays stable.
1666
+ const freshTaskCtx = buildContext(root, "trellis-implement", k);
1667
+ let taskCtx = taskCtxSnapshot.get(key);
1668
+ if (taskCtx === undefined) {
1669
+ taskCtx = freshTaskCtx;
1670
+ taskCtxSnapshot.set(key, taskCtx);
1671
+ lastSentTaskCtx.set(key, freshTaskCtx);
1672
+ }
1673
+ const updates: string[] = [];
1674
+ const runtimeContext = [turn.wf, turn.ov].filter(Boolean).join("\n\n");
1675
+ if (runtimeContext && runtimeContext !== lastSentRuntimeCtx.get(key)) {
1676
+ lastSentRuntimeCtx.set(key, runtimeContext);
1677
+ updates.push(runtimeContext);
1678
+ }
1679
+ if (freshTaskCtx !== lastSentTaskCtx.get(key)) {
1680
+ lastSentTaskCtx.set(key, freshTaskCtx);
1681
+ updates.push(
1682
+ "<trellis-task-context-update>\nTask context changed on disk. This supersedes the Trellis Task Context in the system prompt.\n\n" +
1683
+ freshTaskCtx +
1684
+ "\n</trellis-task-context-update>",
1685
+ );
1686
+ }
1687
+ const content = updates.join("\n\n");
1593
1688
  return {
1594
- systemPrompt: [cur, ctxText, wf, ov].filter(Boolean).join("\n\n"),
1689
+ message: content
1690
+ ? {
1691
+ customType: "trellis-runtime-context",
1692
+ content,
1693
+ display: false,
1694
+ }
1695
+ : undefined,
1696
+ systemPrompt: [cur, startup, taskCtx].filter(Boolean).join("\n\n"),
1595
1697
  };
1596
1698
  });
1597
1699
  pi.on?.("context", (event, ctx) => {
@@ -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";
15
+ export type SharedHookPlatform = "claude" | "cursor" | "codex" | "gemini" | "qoder" | "copilot" | "codebuddy" | "droid" | "kiro" | "trae";
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)
@@ -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,CAAC;AAEX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,wBAAwB,EAAE,MAAM,CAC3C,kBAAkB,EAClB,SAAS,cAAc,EAAE,CA+B1B,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,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"}
@@ -73,6 +73,7 @@ export const SHARED_HOOKS_BY_PLATFORM = {
73
73
  "inject-workflow-state.py",
74
74
  "inject-subagent-context.py",
75
75
  ],
76
+ trae: ["session-start.py", "inject-workflow-state.py"],
76
77
  };
77
78
  /**
78
79
  * 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;AA0BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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;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"}
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"}
@@ -34,6 +34,8 @@ import json
34
34
  import os
35
35
  import re
36
36
  import sys
37
+ import queue
38
+ import threading
37
39
  from pathlib import Path
38
40
 
39
41
  # Force UTF-8 on stdin/stdout/stderr on Windows. Default codepage there is
@@ -51,12 +53,12 @@ if sys.platform.startswith("win"):
51
53
  try:
52
54
  _stream.reconfigure(encoding="utf-8", errors="replace") # type: ignore[union-attr]
53
55
  except Exception:
54
- pass
56
+ pass # Optional Windows stream setup; keep hook startup non-fatal.
55
57
  elif hasattr(_stream, "detach"):
56
58
  try:
57
59
  setattr(sys, _stream_name, _io.TextIOWrapper(_stream.detach(), encoding="utf-8", errors="replace"))
58
60
  except Exception:
59
- pass
61
+ pass # Optional Windows stream setup; keep hook startup non-fatal.
60
62
  from typing import Optional
61
63
 
62
64
 
@@ -102,6 +104,7 @@ def _detect_platform(input_data: dict) -> str | None:
102
104
  "QODER_PROJECT_DIR": "qoder",
103
105
  "KIRO_PROJECT_DIR": "kiro",
104
106
  "COPILOT_PROJECT_DIR": "copilot",
107
+ "TRAE_PROJECT_DIR": "trae",
105
108
  }
106
109
  for env_name, platform in env_map.items():
107
110
  if os.environ.get(env_name):
@@ -123,6 +126,8 @@ def _detect_platform(input_data: dict) -> str | None:
123
126
  return "droid"
124
127
  if ".kiro" in script_parts:
125
128
  return "kiro"
129
+ if ".trae" in script_parts:
130
+ return "trae"
126
131
  return None
127
132
 
128
133
 
@@ -302,14 +307,44 @@ def build_breadcrumb(
302
307
  # Entry
303
308
  # ---------------------------------------------------------------------------
304
309
 
310
+ def _load_hook_input() -> dict:
311
+ """Read hook JSON without trusting host runners to close stdin.
312
+
313
+ Kiro IDE `runCommand` and similar hook runners can leave stdin open while
314
+ sending no payload. A plain `json.load(sys.stdin)` then blocks forever.
315
+ Normal hook runners write the complete JSON payload and close stdin, so the
316
+ short daemon read preserves that path while failing closed to `{}` for
317
+ non-piping hosts.
318
+ """
319
+ result_queue: "queue.Queue[str | Exception]" = queue.Queue(maxsize=1)
320
+
321
+ def _read() -> None:
322
+ try:
323
+ result_queue.put(sys.stdin.read())
324
+ except Exception as exc:
325
+ result_queue.put(exc)
326
+
327
+ reader = threading.Thread(target=_read, daemon=True)
328
+ reader.start()
329
+ try:
330
+ raw = result_queue.get(timeout=0.2)
331
+ except queue.Empty:
332
+ return {}
333
+
334
+ if isinstance(raw, Exception):
335
+ return {}
336
+ try:
337
+ data = json.loads(raw) if raw.strip() else {}
338
+ except (json.JSONDecodeError, ValueError):
339
+ return {}
340
+ return data if isinstance(data, dict) else {}
341
+
342
+
305
343
  def main() -> int:
306
344
  if os.environ.get("TRELLIS_HOOKS") == "0" or os.environ.get("TRELLIS_DISABLE_HOOKS") == "1":
307
345
  return 0
308
346
 
309
- try:
310
- data = json.load(sys.stdin)
311
- except (json.JSONDecodeError, ValueError):
312
- data = {}
347
+ data = _load_hook_input()
313
348
 
314
349
  cwd_str = data.get("cwd") or os.getcwd()
315
350
  cwd = Path(cwd_str)
@@ -87,12 +87,12 @@ if sys.platform.startswith("win"):
87
87
  try:
88
88
  _stream.reconfigure(encoding="utf-8", errors="replace") # type: ignore[union-attr]
89
89
  except Exception:
90
- pass
90
+ pass # Optional Windows stream setup; keep hook startup non-fatal.
91
91
  elif hasattr(_stream, "detach"):
92
92
  try:
93
93
  setattr(sys, _stream_name, _io.TextIOWrapper(_stream.detach(), encoding="utf-8", errors="replace"))
94
94
  except Exception:
95
- pass
95
+ pass # Optional Windows stream setup; keep hook startup non-fatal.
96
96
 
97
97
 
98
98
 
@@ -137,6 +137,7 @@ def should_skip_injection() -> bool:
137
137
  "GEMINI_NON_INTERACTIVE",
138
138
  "KIRO_NON_INTERACTIVE",
139
139
  "COPILOT_NON_INTERACTIVE",
140
+ "TRAE_NON_INTERACTIVE",
140
141
  ]
141
142
  return any(os.environ.get(var) == "1" for var in non_interactive_vars)
142
143
 
@@ -195,6 +196,7 @@ def _detect_platform(input_data: dict) -> str | None:
195
196
  "QODER_PROJECT_DIR": "qoder",
196
197
  "KIRO_PROJECT_DIR": "kiro",
197
198
  "COPILOT_PROJECT_DIR": "copilot",
199
+ "TRAE_PROJECT_DIR": "trae",
198
200
  }
199
201
  for env_name, platform in env_map.items():
200
202
  if os.environ.get(env_name):
@@ -216,6 +218,8 @@ def _detect_platform(input_data: dict) -> str | None:
216
218
  return "droid"
217
219
  if ".kiro" in script_parts:
218
220
  return "kiro"
221
+ if ".trae" in script_parts:
222
+ return "trae"
219
223
  return None
220
224
 
221
225
 
@@ -245,7 +249,7 @@ def _persist_context_key_for_bash(context_key: str | None) -> None:
245
249
  with open(env_file, "a", encoding="utf-8") as handle:
246
250
  handle.write(f"export TRELLIS_CONTEXT_ID={shlex.quote(context_key)}\n")
247
251
  except OSError:
248
- pass
252
+ pass # Optional shell bridge; keep session-start non-fatal.
249
253
 
250
254
 
251
255
  def _resolve_active_task(trellis_dir: Path, input_data: dict):
@@ -347,7 +351,7 @@ def _get_task_status(trellis_dir: Path, input_data: dict) -> str:
347
351
  try:
348
352
  task_data = json.loads(task_json_path.read_text(encoding="utf-8"))
349
353
  except (json.JSONDecodeError, PermissionError):
350
- pass
354
+ pass # Optional task metadata; fall back to generic status.
351
355
 
352
356
  task_title = task_data.get("title", task_ref)
353
357
  task_status = task_data.get("status", "unknown")
@@ -449,7 +453,7 @@ def _load_trellis_config(trellis_dir: Path, input_data: dict) -> tuple:
449
453
  if isinstance(tp, str) and tp:
450
454
  task_pkg = tp
451
455
  except (json.JSONDecodeError, OSError):
452
- pass
456
+ pass # Optional package metadata; fall back to default scope.
453
457
 
454
458
  default_pkg = get_default_package(repo_root)
455
459
  return is_mono, packages, scope, task_pkg, default_pkg
@@ -626,7 +630,7 @@ def _build_compact_current_state(
626
630
  if isinstance(data, dict):
627
631
  status = str(data.get("status") or "unknown")
628
632
  except (json.JSONDecodeError, OSError):
629
- pass
633
+ pass # Optional task metadata; fall back to generic status.
630
634
  lines.append(f"Current task: {_repo_relative(repo_root, task_dir)}; status={status}.")
631
635
  else:
632
636
  lines.append("Current task: none.")
@@ -638,7 +642,7 @@ def _build_compact_current_state(
638
642
  f"Active tasks: {task_count} total. Use `python3 ./.trellis/scripts/task.py list --mine` only if needed."
639
643
  )
640
644
  except Exception:
641
- pass
645
+ pass # Optional task summary; keep compact state available.
642
646
 
643
647
  if get_active_journal_file and count_lines:
644
648
  journal = get_active_journal_file(repo_root)
@@ -739,6 +743,7 @@ def main():
739
743
  "GEMINI_PROJECT_DIR",
740
744
  "KIRO_PROJECT_DIR",
741
745
  "COPILOT_PROJECT_DIR",
746
+ "TRAE_PROJECT_DIR",
742
747
  ]
743
748
  project_dir = None
744
749
  for var in project_dir_env_vars:
@@ -0,0 +1,108 @@
1
+ ---
2
+ name: trellis-check
3
+ description: |
4
+ Code quality check expert. Reviews code changes against specs and self-fixes issues.
5
+ tools: Read, Write, Edit, Bash, Glob, Grep
6
+ ---
7
+ # Check Agent
8
+
9
+ You are the Check Agent in the Trellis workflow.
10
+
11
+ ## Recursion Guard
12
+
13
+ You are already the `trellis-check` sub-agent that the main session dispatched. Do the review and fixes directly.
14
+
15
+ - Do NOT spawn another `trellis-check` or `trellis-implement` sub-agent.
16
+ - If SessionStart context, workflow-state breadcrumbs, or workflow.md say to dispatch `trellis-implement` / `trellis-check`, treat that as a main-session instruction that is already satisfied by your current role.
17
+ - Only the main session may dispatch Trellis implement/check agents. If more implementation work is needed, report that recommendation instead of spawning.
18
+
19
+ ## Context
20
+
21
+ Before checking, read:
22
+ - `.trellis/spec/` - Development guidelines
23
+ - Task `prd.md` - Requirements document
24
+ - Task `design.md` - Technical design (if exists)
25
+ - Task `implement.md` - Execution plan (if exists)
26
+ - Pre-commit checklist for quality standards
27
+
28
+ ## Core Responsibilities
29
+
30
+ 1. **Get code changes** - Use git diff to get uncommitted code
31
+ 2. **Review task artifacts** - Check changes against prd.md, design.md if present, and implement.md if present
32
+ 3. **Check against specs** - Verify code follows guidelines
33
+ 4. **Self-fix** - Fix issues yourself, not just report them
34
+ 5. **Run verification** - typecheck and lint
35
+
36
+ ## Important
37
+
38
+ **Fix issues yourself**, don't just report them.
39
+
40
+ You have write and edit tools, you can modify code directly.
41
+
42
+ ---
43
+
44
+ ## Workflow
45
+
46
+ ### Step 1: Get Changes
47
+
48
+ ```bash
49
+ git diff --name-only # List changed files
50
+ git diff # View specific changes
51
+ ```
52
+
53
+ ### Step 2: Check Against Specs and Task Artifacts
54
+
55
+ Read the task's prd.md, design.md if present, and implement.md if present, then read relevant specs in `.trellis/spec/` to check code:
56
+
57
+ - Does it satisfy the task requirements
58
+ - Does it follow the technical design and implementation plan when present
59
+ - Does it follow directory structure conventions
60
+ - Does it follow naming conventions
61
+ - Does it follow code patterns
62
+ - Are there missing types
63
+ - Are there potential bugs
64
+
65
+ ### Step 3: Self-Fix
66
+
67
+ After finding issues:
68
+
69
+ 1. Fix the issue directly (use edit tool)
70
+ 2. Record what was fixed
71
+ 3. Continue checking other issues
72
+
73
+ ### Step 4: Run Verification
74
+
75
+ Run project's lint and typecheck commands to verify changes.
76
+
77
+ If failed, fix issues and re-run.
78
+
79
+ ---
80
+
81
+ ## Report Format
82
+
83
+ ```markdown
84
+ ## Self-Check Complete
85
+
86
+ ### Files Checked
87
+
88
+ - src/components/Feature.tsx
89
+ - src/hooks/useFeature.ts
90
+
91
+ ### Issues Found and Fixed
92
+
93
+ 1. `<file>:<line>` - <what was fixed>
94
+ 2. `<file>:<line>` - <what was fixed>
95
+
96
+ ### Issues Not Fixed
97
+
98
+ (If there are issues that cannot be self-fixed, list them here with reasons)
99
+
100
+ ### Verification Results
101
+
102
+ - TypeCheck: Passed
103
+ - Lint: Passed
104
+
105
+ ### Summary
106
+
107
+ Checked X files, found Y issues, all fixed.
108
+ ```
@@ -0,0 +1,103 @@
1
+ ---
2
+ name: trellis-implement
3
+ description: |
4
+ Code implementation expert. Understands specs and requirements, then implements features. No git commit allowed.
5
+ tools: Read, Write, Edit, Bash, Glob, Grep
6
+ ---
7
+ # Implement Agent
8
+
9
+ You are the Implement Agent in the Trellis workflow.
10
+
11
+ ## Recursion Guard
12
+
13
+ You are already the `trellis-implement` sub-agent that the main session dispatched. Do the implementation work directly.
14
+
15
+ - Do NOT spawn another `trellis-implement` or `trellis-check` sub-agent.
16
+ - If SessionStart context, workflow-state breadcrumbs, or workflow.md say to dispatch `trellis-implement` / `trellis-check`, treat that as a main-session instruction that is already satisfied by your current role.
17
+ - Only the main session may dispatch Trellis implement/check agents. If more parallel work is needed, report that recommendation instead of spawning.
18
+
19
+ ## Context
20
+
21
+ Before implementing, read:
22
+ - `.trellis/workflow.md` - Project workflow
23
+ - `.trellis/spec/` - Development guidelines
24
+ - Task `prd.md` - Requirements document
25
+ - Task `design.md` - Technical design (if exists)
26
+ - Task `implement.md` - Execution plan (if exists)
27
+
28
+ ## Core Responsibilities
29
+
30
+ 1. **Understand specs** - Read relevant spec files in `.trellis/spec/`
31
+ 2. **Understand task artifacts** - Read prd.md, design.md if present, and implement.md if present
32
+ 3. **Implement features** - Write code following specs and task artifacts
33
+ 4. **Self-check** - Ensure code quality
34
+ 5. **Report results** - Report completion status
35
+
36
+ ## Forbidden Operations
37
+
38
+ **Do NOT execute these git commands:**
39
+
40
+ - `git commit`
41
+ - `git push`
42
+ - `git merge`
43
+
44
+ ---
45
+
46
+ ## Workflow
47
+
48
+ ### 1. Understand Specs
49
+
50
+ Read relevant specs based on task type:
51
+
52
+ - Spec layers: `.trellis/spec/<package>/<layer>/`
53
+ - Shared guides: `.trellis/spec/guides/`
54
+
55
+ ### 2. Understand Requirements
56
+
57
+ Read the task's prd.md, design.md if present, and implement.md if present:
58
+
59
+ - What are the core requirements
60
+ - Key points of technical design
61
+ - Implementation order, validation commands, and rollback points
62
+
63
+ ### 3. Implement Features
64
+
65
+ - Write code following specs and task artifacts
66
+ - Follow existing code patterns
67
+ - Only do what's required, no over-engineering
68
+
69
+ ### 4. Verify
70
+
71
+ Run project's lint and typecheck commands to verify changes.
72
+
73
+ ---
74
+
75
+ ## Report Format
76
+
77
+ ```markdown
78
+ ## Implementation Complete
79
+
80
+ ### Files Modified
81
+
82
+ - `src/components/Feature.tsx` - New component
83
+ - `src/hooks/useFeature.ts` - New hook
84
+
85
+ ### Implementation Summary
86
+
87
+ 1. Created Feature component...
88
+ 2. Added useFeature hook...
89
+
90
+ ### Verification Results
91
+
92
+ - Lint: Passed
93
+ - TypeCheck: Passed
94
+ ```
95
+
96
+ ---
97
+
98
+ ## Code Standards
99
+
100
+ - Follow existing code patterns
101
+ - Don't add unnecessary abstractions
102
+ - Only do what's required, no over-engineering
103
+ - Keep code readable