@mindfoldhq/trellis 0.5.0-beta.9 → 0.5.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/README.md +60 -95
  2. package/dist/cli/index.js +7 -0
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/commands/init.d.ts +3 -0
  5. package/dist/commands/init.d.ts.map +1 -1
  6. package/dist/commands/init.js +117 -117
  7. package/dist/commands/init.js.map +1 -1
  8. package/dist/commands/update.d.ts.map +1 -1
  9. package/dist/commands/update.js +289 -33
  10. package/dist/commands/update.js.map +1 -1
  11. package/dist/configurators/antigravity.d.ts.map +1 -1
  12. package/dist/configurators/antigravity.js +2 -8
  13. package/dist/configurators/antigravity.js.map +1 -1
  14. package/dist/configurators/claude.d.ts.map +1 -1
  15. package/dist/configurators/claude.js +4 -10
  16. package/dist/configurators/claude.js.map +1 -1
  17. package/dist/configurators/codebuddy.d.ts.map +1 -1
  18. package/dist/configurators/codebuddy.js +3 -3
  19. package/dist/configurators/codebuddy.js.map +1 -1
  20. package/dist/configurators/codex.d.ts.map +1 -1
  21. package/dist/configurators/codex.js +5 -13
  22. package/dist/configurators/codex.js.map +1 -1
  23. package/dist/configurators/copilot.d.ts.map +1 -1
  24. package/dist/configurators/copilot.js +5 -19
  25. package/dist/configurators/copilot.js.map +1 -1
  26. package/dist/configurators/cursor.d.ts.map +1 -1
  27. package/dist/configurators/cursor.js +3 -3
  28. package/dist/configurators/cursor.js.map +1 -1
  29. package/dist/configurators/droid.d.ts.map +1 -1
  30. package/dist/configurators/droid.js +3 -3
  31. package/dist/configurators/droid.js.map +1 -1
  32. package/dist/configurators/gemini.d.ts.map +1 -1
  33. package/dist/configurators/gemini.js +3 -5
  34. package/dist/configurators/gemini.js.map +1 -1
  35. package/dist/configurators/index.d.ts.map +1 -1
  36. package/dist/configurators/index.js +37 -49
  37. package/dist/configurators/index.js.map +1 -1
  38. package/dist/configurators/kilo.d.ts.map +1 -1
  39. package/dist/configurators/kilo.js +2 -8
  40. package/dist/configurators/kilo.js.map +1 -1
  41. package/dist/configurators/kiro.d.ts.map +1 -1
  42. package/dist/configurators/kiro.js +3 -3
  43. package/dist/configurators/kiro.js.map +1 -1
  44. package/dist/configurators/opencode.d.ts.map +1 -1
  45. package/dist/configurators/opencode.js +7 -4
  46. package/dist/configurators/opencode.js.map +1 -1
  47. package/dist/configurators/pi.d.ts +3 -0
  48. package/dist/configurators/pi.d.ts.map +1 -0
  49. package/dist/configurators/pi.js +44 -0
  50. package/dist/configurators/pi.js.map +1 -0
  51. package/dist/configurators/qoder.d.ts.map +1 -1
  52. package/dist/configurators/qoder.js +3 -5
  53. package/dist/configurators/qoder.js.map +1 -1
  54. package/dist/configurators/shared.d.ts +28 -6
  55. package/dist/configurators/shared.d.ts.map +1 -1
  56. package/dist/configurators/shared.js +47 -15
  57. package/dist/configurators/shared.js.map +1 -1
  58. package/dist/configurators/windsurf.d.ts.map +1 -1
  59. package/dist/configurators/windsurf.js +2 -8
  60. package/dist/configurators/windsurf.js.map +1 -1
  61. package/dist/constants/paths.d.ts +2 -0
  62. package/dist/constants/paths.d.ts.map +1 -1
  63. package/dist/constants/paths.js +2 -0
  64. package/dist/constants/paths.js.map +1 -1
  65. package/dist/migrations/manifests/0.5.0-beta.0.json +2 -0
  66. package/dist/migrations/manifests/0.5.0-beta.10.json +9 -0
  67. package/dist/migrations/manifests/0.5.0-beta.11.json +9 -0
  68. package/dist/migrations/manifests/0.5.0-beta.12.json +9 -0
  69. package/dist/migrations/manifests/0.5.0-beta.13.json +9 -0
  70. package/dist/migrations/manifests/0.5.0-beta.14.json +9 -0
  71. package/dist/migrations/manifests/0.5.0-beta.15.json +116 -0
  72. package/dist/migrations/manifests/0.5.0-beta.16.json +9 -0
  73. package/dist/migrations/manifests/0.5.0-beta.17.json +9 -0
  74. package/dist/migrations/manifests/0.5.0-beta.18.json +9 -0
  75. package/dist/migrations/manifests/0.5.0-beta.19.json +9 -0
  76. package/dist/migrations/manifests/0.5.0-beta.5.json +2 -0
  77. package/dist/migrations/manifests/0.5.0-rc.0.json +9 -0
  78. package/dist/templates/claude/agents/trellis-research.md +1 -1
  79. package/dist/templates/claude/settings.json +0 -4
  80. package/dist/templates/codebuddy/agents/trellis-research.md +1 -1
  81. package/dist/templates/codex/agents/trellis-research.toml +3 -2
  82. package/dist/templates/codex/hooks/session-start.py +126 -26
  83. package/dist/templates/codex/skills/finish-work/SKILL.md +41 -109
  84. package/dist/templates/codex/skills/start/SKILL.md +12 -9
  85. package/dist/templates/common/bundled-skills/trellis-meta/SKILL.md +73 -0
  86. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/add-project-local-conventions.md +83 -0
  87. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-agents.md +54 -0
  88. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-context-loading.md +81 -0
  89. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-hooks.md +57 -0
  90. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-skills-or-commands.md +78 -0
  91. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-spec-structure.md +83 -0
  92. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-task-lifecycle.md +90 -0
  93. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-workflow.md +64 -0
  94. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/overview.md +55 -0
  95. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/context-injection.md +68 -0
  96. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/generated-files.md +80 -0
  97. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/overview.md +51 -0
  98. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/spec-system.md +102 -0
  99. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/task-system.md +101 -0
  100. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/workflow.md +75 -0
  101. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/workspace-memory.md +71 -0
  102. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/agents.md +79 -0
  103. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/hooks-and-settings.md +69 -0
  104. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/overview.md +59 -0
  105. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/platform-map.md +74 -0
  106. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/skills-and-commands.md +83 -0
  107. package/dist/templates/common/commands/continue.md +9 -5
  108. package/dist/templates/common/commands/finish-work.md +34 -10
  109. package/dist/templates/common/index.d.ts +22 -2
  110. package/dist/templates/common/index.d.ts.map +1 -1
  111. package/dist/templates/common/index.js +53 -4
  112. package/dist/templates/common/index.js.map +1 -1
  113. package/dist/templates/common/skills/brainstorm.md +3 -0
  114. package/dist/templates/copilot/hooks/session-start.py +127 -30
  115. package/dist/templates/copilot/prompts/finish-work.prompt.md +44 -112
  116. package/dist/templates/copilot/prompts/start.prompt.md +12 -9
  117. package/dist/templates/cursor/agents/trellis-check.md +1 -1
  118. package/dist/templates/cursor/agents/trellis-implement.md +1 -1
  119. package/dist/templates/cursor/agents/trellis-research.md +2 -2
  120. package/dist/templates/cursor/hooks.json +7 -1
  121. package/dist/templates/droid/droids/trellis-research.md +1 -1
  122. package/dist/templates/extract.d.ts +6 -0
  123. package/dist/templates/extract.d.ts.map +1 -1
  124. package/dist/templates/extract.js +14 -0
  125. package/dist/templates/extract.js.map +1 -1
  126. package/dist/templates/gemini/agents/trellis-research.md +1 -1
  127. package/dist/templates/kiro/agents/trellis-research.json +1 -1
  128. package/dist/templates/markdown/agents.md +19 -12
  129. package/dist/templates/markdown/gitignore.txt +3 -0
  130. package/dist/templates/markdown/spec/guides/cross-platform-thinking-guide.md.txt +24 -0
  131. package/dist/templates/opencode/agents/trellis-check.md +1 -1
  132. package/dist/templates/opencode/agents/trellis-implement.md +7 -4
  133. package/dist/templates/opencode/agents/trellis-research.md +2 -2
  134. package/dist/templates/opencode/lib/trellis-context.js +100 -13
  135. package/dist/templates/opencode/plugins/inject-subagent-context.js +70 -5
  136. package/dist/templates/opencode/plugins/inject-workflow-state.js +38 -58
  137. package/dist/templates/opencode/plugins/session-start.js +76 -31
  138. package/dist/templates/pi/agents/trellis-check.md +28 -0
  139. package/dist/templates/pi/agents/trellis-implement.md +33 -0
  140. package/dist/templates/pi/agents/trellis-research.md +25 -0
  141. package/dist/templates/pi/extensions/trellis/index.ts.txt +997 -0
  142. package/dist/templates/pi/index.d.ts +5 -0
  143. package/dist/templates/pi/index.d.ts.map +1 -0
  144. package/dist/templates/pi/index.js +12 -0
  145. package/dist/templates/pi/index.js.map +1 -0
  146. package/dist/templates/pi/settings.json +12 -0
  147. package/dist/templates/qoder/agents/trellis-research.md +1 -1
  148. package/dist/templates/shared-hooks/index.d.ts +31 -0
  149. package/dist/templates/shared-hooks/index.d.ts.map +1 -1
  150. package/dist/templates/shared-hooks/index.js +59 -0
  151. package/dist/templates/shared-hooks/index.js.map +1 -1
  152. package/dist/templates/shared-hooks/inject-shell-session-context.py +180 -0
  153. package/dist/templates/shared-hooks/inject-subagent-context.py +156 -27
  154. package/dist/templates/shared-hooks/inject-workflow-state.py +85 -105
  155. package/dist/templates/shared-hooks/session-start.py +222 -36
  156. package/dist/templates/trellis/gitignore.txt +3 -0
  157. package/dist/templates/trellis/index.d.ts +1 -0
  158. package/dist/templates/trellis/index.d.ts.map +1 -1
  159. package/dist/templates/trellis/index.js +2 -0
  160. package/dist/templates/trellis/index.js.map +1 -1
  161. package/dist/templates/trellis/scripts/common/__init__.py +8 -0
  162. package/dist/templates/trellis/scripts/common/active_task.py +593 -0
  163. package/dist/templates/trellis/scripts/common/cli_adapter.py +72 -14
  164. package/dist/templates/trellis/scripts/common/paths.py +61 -58
  165. package/dist/templates/trellis/scripts/common/session_context.py +12 -0
  166. package/dist/templates/trellis/scripts/common/task_context.py +27 -194
  167. package/dist/templates/trellis/scripts/common/task_store.py +102 -26
  168. package/dist/templates/trellis/scripts/common/tasks.py +4 -1
  169. package/dist/templates/trellis/scripts/common/workflow_phase.py +15 -3
  170. package/dist/templates/trellis/scripts/task.py +99 -34
  171. package/dist/templates/trellis/workflow.md +332 -69
  172. package/dist/types/ai-tools.d.ts +12 -3
  173. package/dist/types/ai-tools.d.ts.map +1 -1
  174. package/dist/types/ai-tools.js +29 -0
  175. package/dist/types/ai-tools.js.map +1 -1
  176. package/dist/utils/file-writer.d.ts.map +1 -1
  177. package/dist/utils/file-writer.js +7 -2
  178. package/dist/utils/file-writer.js.map +1 -1
  179. package/dist/utils/posix.d.ts +13 -0
  180. package/dist/utils/posix.d.ts.map +1 -0
  181. package/dist/utils/posix.js +15 -0
  182. package/dist/utils/posix.js.map +1 -0
  183. package/dist/utils/template-fetcher.d.ts +22 -6
  184. package/dist/utils/template-fetcher.d.ts.map +1 -1
  185. package/dist/utils/template-fetcher.js +405 -27
  186. package/dist/utils/template-fetcher.js.map +1 -1
  187. package/dist/utils/template-hash.d.ts +22 -3
  188. package/dist/utils/template-hash.d.ts.map +1 -1
  189. package/dist/utils/template-hash.js +99 -19
  190. package/dist/utils/template-hash.js.map +1 -1
  191. package/package.json +7 -7
  192. package/dist/templates/shared-hooks/statusline.py +0 -218
@@ -3,18 +3,37 @@
3
3
  *
4
4
  * Stores SHA256 hashes of template files at install time.
5
5
  * Used to determine if users have modified templates.
6
+ *
7
+ * Cross-platform contract:
8
+ * - All hash dictionary keys are POSIX style (`/`), never `\`.
9
+ * - Hashes are computed against LF-normalized content, so CRLF and LF
10
+ * versions of the same logical content produce the same hash.
11
+ * - Persisted JSON uses schema `{ __version: 2, hashes: { ... } }`. Old
12
+ * flat-format files (no `__version`) are silently discarded; the hash
13
+ * set is regenerated on next init/update.
6
14
  */
7
15
  import type { TemplateHashes } from "../types/migration.js";
8
16
  /**
9
- * Compute SHA256 hash of content
17
+ * Compute SHA256 hash of content.
18
+ *
19
+ * Normalizes line endings (CRLF -> LF) before hashing so that the same
20
+ * logical content yields the same hash across platforms.
10
21
  */
11
22
  export declare function computeHash(content: string): string;
12
23
  /**
13
- * Load stored template hashes
24
+ * Load stored template hashes.
25
+ *
26
+ * Returns `{}` for: missing file, invalid JSON, or legacy flat-format
27
+ * files (no `__version`). Legacy files are silently dropped; the hash
28
+ * set is regenerated by subsequent init/update logic. This handles two
29
+ * Windows compatibility issues at once: backslash keys and CRLF-based
30
+ * hashes both differ from the v2 contract.
14
31
  */
15
32
  export declare function loadHashes(cwd: string): TemplateHashes;
16
33
  /**
17
- * Save template hashes
34
+ * Save template hashes.
35
+ *
36
+ * Always writes the v2 schema with POSIX-normalized keys.
18
37
  */
19
38
  export declare function saveHashes(cwd: string, hashes: TemplateHashes): void;
20
39
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"template-hash.d.ts","sourceRoot":"","sources":["../../src/utils/template-hash.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAK5D;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEnD;AASD;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAYtD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,IAAI,CAGpE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAQ1E;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAU1E;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAIlE;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,IAAI,CAON;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,cAAc,GACrB,OAAO,CAmBT;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,MAAM,EACpB,eAAe,EAAE,MAAM,GACtB,OAAO,CAST;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,MAAM,EACX,aAAa,EAAE,MAAM,EAAE,EACvB,MAAM,EAAE,cAAc,GACrB,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAQtB;AAmED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAoBpD"}
1
+ {"version":3,"file":"template-hash.d.ts","sourceRoot":"","sources":["../../src/utils/template-hash.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAQH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAe5D;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGnD;AAoBD;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CA6BtD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,IAAI,CAOpE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAQ1E;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAU1E;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAKlE;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,IAAI,CASN;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,cAAc,GACrB,OAAO,CAsBT;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,MAAM,EACpB,eAAe,EAAE,MAAM,GACtB,OAAO,CAST;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,MAAM,EACX,aAAa,EAAE,MAAM,EAAE,EACvB,MAAM,EAAE,cAAc,GACrB,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAQtB;AA0ED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAwCpD"}
@@ -3,19 +3,34 @@
3
3
  *
4
4
  * Stores SHA256 hashes of template files at install time.
5
5
  * Used to determine if users have modified templates.
6
+ *
7
+ * Cross-platform contract:
8
+ * - All hash dictionary keys are POSIX style (`/`), never `\`.
9
+ * - Hashes are computed against LF-normalized content, so CRLF and LF
10
+ * versions of the same logical content produce the same hash.
11
+ * - Persisted JSON uses schema `{ __version: 2, hashes: { ... } }`. Old
12
+ * flat-format files (no `__version`) are silently discarded; the hash
13
+ * set is regenerated on next init/update.
6
14
  */
7
15
  import { createHash } from "node:crypto";
8
16
  import fs from "node:fs";
9
17
  import path from "node:path";
10
- import { DIR_NAMES } from "../constants/paths.js";
18
+ import { DIR_NAMES, FILE_NAMES } from "../constants/paths.js";
11
19
  import { ALL_MANAGED_DIRS } from "../configurators/index.js";
20
+ import { toPosix } from "./posix.js";
12
21
  /** File name for storing template hashes */
13
22
  const HASHES_FILE = ".template-hashes.json";
23
+ /** Current schema version for `.template-hashes.json` */
24
+ const HASHES_SCHEMA_VERSION = 2;
14
25
  /**
15
- * Compute SHA256 hash of content
26
+ * Compute SHA256 hash of content.
27
+ *
28
+ * Normalizes line endings (CRLF -> LF) before hashing so that the same
29
+ * logical content yields the same hash across platforms.
16
30
  */
17
31
  export function computeHash(content) {
18
- return createHash("sha256").update(content, "utf-8").digest("hex");
32
+ const normalized = content.replace(/\r\n/g, "\n");
33
+ return createHash("sha256").update(normalized, "utf-8").digest("hex");
19
34
  }
20
35
  /**
21
36
  * Get path to the hashes file
@@ -24,7 +39,23 @@ function getHashesPath(cwd) {
24
39
  return path.join(cwd, DIR_NAMES.WORKFLOW, HASHES_FILE);
25
40
  }
26
41
  /**
27
- * Load stored template hashes
42
+ * Normalize all keys of a hashes record to POSIX form.
43
+ */
44
+ function normalizeHashKeys(hashes) {
45
+ const out = {};
46
+ for (const [key, value] of Object.entries(hashes)) {
47
+ out[toPosix(key)] = value;
48
+ }
49
+ return out;
50
+ }
51
+ /**
52
+ * Load stored template hashes.
53
+ *
54
+ * Returns `{}` for: missing file, invalid JSON, or legacy flat-format
55
+ * files (no `__version`). Legacy files are silently dropped; the hash
56
+ * set is regenerated by subsequent init/update logic. This handles two
57
+ * Windows compatibility issues at once: backslash keys and CRLF-based
58
+ * hashes both differ from the v2 contract.
28
59
  */
29
60
  export function loadHashes(cwd) {
30
61
  const hashesPath = getHashesPath(cwd);
@@ -33,18 +64,37 @@ export function loadHashes(cwd) {
33
64
  }
34
65
  try {
35
66
  const content = fs.readFileSync(hashesPath, "utf-8");
36
- return JSON.parse(content);
67
+ const parsed = JSON.parse(content);
68
+ if (parsed !== null &&
69
+ typeof parsed === "object" &&
70
+ "__version" in parsed &&
71
+ parsed.__version === HASHES_SCHEMA_VERSION &&
72
+ "hashes" in parsed &&
73
+ typeof parsed.hashes === "object" &&
74
+ parsed.hashes !== null) {
75
+ const stored = parsed;
76
+ // Defensive: enforce POSIX keys even if a writer slipped through.
77
+ return normalizeHashKeys(stored.hashes);
78
+ }
79
+ // Legacy flat format (no __version) or unknown shape: discard.
80
+ return {};
37
81
  }
38
82
  catch {
39
83
  return {};
40
84
  }
41
85
  }
42
86
  /**
43
- * Save template hashes
87
+ * Save template hashes.
88
+ *
89
+ * Always writes the v2 schema with POSIX-normalized keys.
44
90
  */
45
91
  export function saveHashes(cwd, hashes) {
46
92
  const hashesPath = getHashesPath(cwd);
47
- fs.writeFileSync(hashesPath, JSON.stringify(hashes, null, 2));
93
+ const payload = {
94
+ __version: HASHES_SCHEMA_VERSION,
95
+ hashes: normalizeHashKeys(hashes),
96
+ };
97
+ fs.writeFileSync(hashesPath, JSON.stringify(payload, null, 2));
48
98
  }
49
99
  /**
50
100
  * Update hashes for specific files
@@ -55,7 +105,7 @@ export function saveHashes(cwd, hashes) {
55
105
  export function updateHashes(cwd, files) {
56
106
  const hashes = loadHashes(cwd);
57
107
  for (const [relativePath, content] of files) {
58
- hashes[relativePath] = computeHash(content);
108
+ hashes[toPosix(relativePath)] = computeHash(content);
59
109
  }
60
110
  saveHashes(cwd, hashes);
61
111
  }
@@ -69,7 +119,7 @@ export function updateHashFromFile(cwd, relativePath) {
69
119
  }
70
120
  const content = fs.readFileSync(fullPath, "utf-8");
71
121
  const hashes = loadHashes(cwd);
72
- hashes[relativePath] = computeHash(content);
122
+ hashes[toPosix(relativePath)] = computeHash(content);
73
123
  saveHashes(cwd, hashes);
74
124
  }
75
125
  /**
@@ -77,7 +127,8 @@ export function updateHashFromFile(cwd, relativePath) {
77
127
  */
78
128
  export function removeHash(cwd, relativePath) {
79
129
  const hashes = loadHashes(cwd);
80
- const { [relativePath]: _, ...rest } = hashes;
130
+ const key = toPosix(relativePath);
131
+ const { [key]: _, ...rest } = hashes;
81
132
  saveHashes(cwd, rest);
82
133
  }
83
134
  /**
@@ -85,9 +136,11 @@ export function removeHash(cwd, relativePath) {
85
136
  */
86
137
  export function renameHash(cwd, oldPath, newPath) {
87
138
  const hashes = loadHashes(cwd);
88
- if (hashes[oldPath]) {
89
- const { [oldPath]: oldValue, ...rest } = hashes;
90
- rest[newPath] = oldValue;
139
+ const oldKey = toPosix(oldPath);
140
+ const newKey = toPosix(newPath);
141
+ if (hashes[oldKey]) {
142
+ const { [oldKey]: oldValue, ...rest } = hashes;
143
+ rest[newKey] = oldValue;
91
144
  saveHashes(cwd, rest);
92
145
  }
93
146
  }
@@ -105,8 +158,11 @@ export function isTemplateModified(cwd, relativePath, hashes) {
105
158
  if (!fs.existsSync(fullPath)) {
106
159
  return false;
107
160
  }
108
- // If we don't have a stored hash, assume it's modified (conservative)
109
- const storedHash = hashes[relativePath];
161
+ // If we don't have a stored hash, assume it's modified (conservative).
162
+ // Lookup by POSIX key — hashes loaded via loadHashes are already
163
+ // normalized, but the caller may have built `hashes` themselves.
164
+ const posixKey = toPosix(relativePath);
165
+ const storedHash = hashes[posixKey] ?? hashes[relativePath];
110
166
  if (!storedHash) {
111
167
  return true;
112
168
  }
@@ -151,6 +207,8 @@ export function getModificationStatus(cwd, relativePaths, hashes) {
151
207
  * Directories to scan for template files during init (derived from platform registry)
152
208
  */
153
209
  const TEMPLATE_DIRS = ALL_MANAGED_DIRS;
210
+ /** Root-level template files written by init and managed by update. */
211
+ const TEMPLATE_FILES = [FILE_NAMES.AGENTS];
154
212
  /**
155
213
  * Patterns to exclude from hash tracking
156
214
  */
@@ -162,22 +220,26 @@ const EXCLUDE_FROM_HASH = [
162
220
  "workspace/", // Workspace files (user data)
163
221
  "tasks/", // Task files (user data)
164
222
  ".current-task", // Current task marker (file, not directory)
165
- "spec/", // User-customized spec files
223
+ ".trellis/spec/", // User-customized spec files
166
224
  ".backup-", // Backup directories
167
225
  ];
168
226
  /**
169
227
  * Check if a path should be excluded from hash tracking
170
228
  */
171
229
  function shouldExcludeFromHash(relativePath) {
230
+ const normalizedPath = toPosix(relativePath);
172
231
  for (const pattern of EXCLUDE_FROM_HASH) {
173
- if (relativePath.includes(pattern)) {
232
+ if (normalizedPath.includes(pattern)) {
174
233
  return true;
175
234
  }
176
235
  }
177
236
  return false;
178
237
  }
179
238
  /**
180
- * Recursively collect all files in a directory
239
+ * Recursively collect all files in a directory.
240
+ *
241
+ * Returned paths are POSIX-normalized so they can be used directly as
242
+ * hash dictionary keys regardless of host OS.
181
243
  */
182
244
  function collectFiles(cwd, dir, relativeTo = "") {
183
245
  const fullDir = path.join(cwd, dir);
@@ -195,7 +257,7 @@ function collectFiles(cwd, dir, relativeTo = "") {
195
257
  files.push(...collectFiles(cwd, relativePath, relativeTo));
196
258
  }
197
259
  else if (entry.isFile()) {
198
- files.push(relativePath);
260
+ files.push(toPosix(relativePath));
199
261
  }
200
262
  }
201
263
  return files;
@@ -212,10 +274,28 @@ function collectFiles(cwd, dir, relativeTo = "") {
212
274
  */
213
275
  export function initializeHashes(cwd) {
214
276
  const hashes = {};
277
+ for (const relativePath of TEMPLATE_FILES) {
278
+ if (shouldExcludeFromHash(relativePath)) {
279
+ continue;
280
+ }
281
+ const fullPath = path.join(cwd, relativePath);
282
+ if (!fs.existsSync(fullPath)) {
283
+ continue;
284
+ }
285
+ try {
286
+ const content = fs.readFileSync(fullPath, "utf-8");
287
+ hashes[relativePath] = computeHash(content);
288
+ }
289
+ catch {
290
+ // Skip files that can't be read (binary, etc.)
291
+ }
292
+ }
215
293
  // Collect all template files
216
294
  for (const dir of TEMPLATE_DIRS) {
217
295
  const files = collectFiles(cwd, dir);
218
296
  for (const relativePath of files) {
297
+ // `relativePath` is POSIX (collectFiles normalizes); reconstruct an
298
+ // OS-native path for the actual fs read.
219
299
  const fullPath = path.join(cwd, relativePath);
220
300
  try {
221
301
  const content = fs.readFileSync(fullPath, "utf-8");
@@ -1 +1 @@
1
- {"version":3,"file":"template-hash.js","sourceRoot":"","sources":["../../src/utils/template-hash.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"template-hash.js","sourceRoot":"","sources":["../../src/utils/template-hash.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAE7D,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC,4CAA4C;AAC5C,MAAM,WAAW,GAAG,uBAAuB,CAAC;AAE5C,yDAAyD;AACzD,MAAM,qBAAqB,GAAG,CAAC,CAAC;AAQhC;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAClD,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACxE,CAAC;AAED;;GAEG;AACH,SAAS,aAAa,CAAC,GAAW;IAChC,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;AACzD,CAAC;AAED;;GAEG;AACH,SAAS,iBAAiB,CAAC,MAAsB;IAC/C,MAAM,GAAG,GAAmB,EAAE,CAAC;IAC/B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;IAC5B,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,MAAM,UAAU,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IACtC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACrD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAY,CAAC;QAE9C,IACE,MAAM,KAAK,IAAI;YACf,OAAO,MAAM,KAAK,QAAQ;YAC1B,WAAW,IAAI,MAAM;YACpB,MAAiC,CAAC,SAAS,KAAK,qBAAqB;YACtE,QAAQ,IAAI,MAAM;YAClB,OAAQ,MAA8B,CAAC,MAAM,KAAK,QAAQ;YACzD,MAA8B,CAAC,MAAM,KAAK,IAAI,EAC/C,CAAC;YACD,MAAM,MAAM,GAAG,MAAwB,CAAC;YACxC,kEAAkE;YAClE,OAAO,iBAAiB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC1C,CAAC;QAED,+DAA+D;QAC/D,OAAO,EAAE,CAAC;IACZ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,GAAW,EAAE,MAAsB;IAC5D,MAAM,UAAU,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IACtC,MAAM,OAAO,GAAmB;QAC9B,SAAS,EAAE,qBAAqB;QAChC,MAAM,EAAE,iBAAiB,CAAC,MAAM,CAAC;KAClC,CAAC;IACF,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AACjE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,KAA0B;IAClE,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAE/B,KAAK,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,IAAI,KAAK,EAAE,CAAC;QAC5C,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IACvD,CAAC;IAED,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW,EAAE,YAAoB;IAClE,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAC9C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACnD,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IACrD,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,GAAW,EAAE,YAAoB;IAC1D,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,GAAG,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAClC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,MAAM,CAAC;IACrC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AACxB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CACxB,GAAW,EACX,OAAe,EACf,OAAe;IAEf,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAChC,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAChC,IAAI,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QACnB,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,MAAM,CAAC;QAC/C,IAAI,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC;QACxB,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACxB,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAChC,GAAW,EACX,YAAoB,EACpB,MAAsB;IAEtB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAE9C,2CAA2C;IAC3C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,uEAAuE;IACvE,iEAAiE;IACjE,iEAAiE;IACjE,MAAM,QAAQ,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACvC,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,YAAY,CAAC,CAAC;IAC5D,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,gDAAgD;IAChD,MAAM,cAAc,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC1D,MAAM,WAAW,GAAG,WAAW,CAAC,cAAc,CAAC,CAAC;IAEhD,OAAO,WAAW,KAAK,UAAU,CAAC;AACpC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,uBAAuB,CACrC,GAAW,EACX,YAAoB,EACpB,eAAuB;IAEvB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAE9C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,cAAc,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC1D,OAAO,cAAc,KAAK,eAAe,CAAC;AAC5C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CACnC,GAAW,EACX,aAAuB,EACvB,MAAsB;IAEtB,MAAM,MAAM,GAAG,IAAI,GAAG,EAAmB,CAAC;IAE1C,KAAK,MAAM,YAAY,IAAI,aAAa,EAAE,CAAC;QACzC,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE,kBAAkB,CAAC,GAAG,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1E,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,aAAa,GAAG,gBAAgB,CAAC;AAEvC,uEAAuE;AACvE,MAAM,cAAc,GAAG,CAAC,UAAU,CAAC,MAAM,CAAU,CAAC;AAEpD;;GAEG;AACH,MAAM,iBAAiB,GAAG;IACxB,uBAAuB,EAAE,mBAAmB;IAC5C,UAAU,EAAE,eAAe;IAC3B,YAAY,EAAE,mBAAmB;IACjC,YAAY,EAAE,0BAA0B;IACxC,YAAY,EAAE,8BAA8B;IAC5C,QAAQ,EAAE,yBAAyB;IACnC,eAAe,EAAE,4CAA4C;IAC7D,gBAAgB,EAAE,6BAA6B;IAC/C,UAAU,EAAE,qBAAqB;CAClC,CAAC;AAEF;;GAEG;AACH,SAAS,qBAAqB,CAAC,YAAoB;IACjD,MAAM,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAC7C,KAAK,MAAM,OAAO,IAAI,iBAAiB,EAAE,CAAC;QACxC,IAAI,cAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YACrC,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH,SAAS,YAAY,CACnB,GAAW,EACX,GAAW,EACX,aAAqB,EAAE;IAEvB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACpC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAEjE,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAEhD,IAAI,qBAAqB,CAAC,YAAY,CAAC,EAAE,CAAC;YACxC,SAAS;QACX,CAAC;QAED,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,KAAK,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,GAAG,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC,CAAC;QAC7D,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YAC1B,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,MAAM,MAAM,GAAmB,EAAE,CAAC;IAElC,KAAK,MAAM,YAAY,IAAI,cAAc,EAAE,CAAC;QAC1C,IAAI,qBAAqB,CAAC,YAAY,CAAC,EAAE,CAAC;YACxC,SAAS;QACX,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;QAC9C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,SAAS;QACX,CAAC;QAED,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACnD,MAAM,CAAC,YAAY,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;QAC9C,CAAC;QAAC,MAAM,CAAC;YACP,+CAA+C;QACjD,CAAC;IACH,CAAC;IAED,6BAA6B;IAC7B,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAErC,KAAK,MAAM,YAAY,IAAI,KAAK,EAAE,CAAC;YACjC,oEAAoE;YACpE,yCAAyC;YACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;YAC9C,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;gBACnD,MAAM,CAAC,YAAY,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;YAC9C,CAAC;YAAC,MAAM,CAAC;gBACP,+CAA+C;YACjD,CAAC;QACH,CAAC;IACH,CAAC;IAED,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACxB,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC;AACpC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindfoldhq/trellis",
3
- "version": "0.5.0-beta.9",
3
+ "version": "0.5.0-rc.0",
4
4
  "description": "AI capabilities grow like ivy — Trellis provides the structure to guide them along a disciplined path",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -76,12 +76,12 @@
76
76
  "typecheck": "tsc --noEmit",
77
77
  "lint:py": "basedpyright",
78
78
  "lint:all": "pnpm lint && pnpm lint:py",
79
- "release": "pnpm test && git add -A -- ':!docs-site' && (git diff-index --quiet HEAD || git commit -m 'chore: pre-release updates') && pnpm version --no-git-tag-version patch && V=$(node -p \"require('./package.json').version\") && git add package.json && git commit -m \"$V\" && git tag \"v$V\" && git push origin main --tags",
80
- "release:minor": "pnpm test && git add -A -- ':!docs-site' && (git diff-index --quiet HEAD || git commit -m 'chore: pre-release updates') && pnpm version --no-git-tag-version minor && V=$(node -p \"require('./package.json').version\") && git add package.json && git commit -m \"$V\" && git tag \"v$V\" && git push origin main --tags",
81
- "release:major": "pnpm test && git add -A -- ':!docs-site' && (git diff-index --quiet HEAD || git commit -m 'chore: pre-release updates') && pnpm version --no-git-tag-version major && V=$(node -p \"require('./package.json').version\") && git add package.json && git commit -m \"$V\" && git tag \"v$V\" && git push origin main --tags",
82
- "release:beta": "pnpm test && git add -A -- ':!docs-site' && (git diff-index --quiet HEAD || git commit -m 'chore: pre-release updates') && pnpm version --no-git-tag-version prerelease --preid beta && V=$(node -p \"require('./package.json').version\") && git add package.json && git commit -m \"$V\" && git tag \"v$V\" && git push origin HEAD --tags",
83
- "release:rc": "pnpm test && git add -A -- ':!docs-site' && (git diff-index --quiet HEAD || git commit -m 'chore: pre-release updates') && pnpm version --no-git-tag-version prerelease --preid rc && V=$(node -p \"require('./package.json').version\") && git add package.json && git commit -m \"$V\" && git tag \"v$V\" && git push origin HEAD --tags",
84
- "release:promote": "pnpm test && git add -A -- ':!docs-site' && (git diff-index --quiet HEAD || git commit -m 'chore: pre-release updates') && pnpm version --no-git-tag-version \"$(node -p \"require('./package.json').version.replace(/-.*/, '')\")\" && V=$(node -p \"require('./package.json').version\") && git add package.json && git commit -m \"$V\" && git tag \"v$V\" && git push origin main --tags",
79
+ "release": "node scripts/check-manifest-continuity.js && pnpm test && git add -A -- ':!docs-site' && (git diff-index --quiet HEAD || git commit -m 'chore: pre-release updates') && pnpm version --no-git-tag-version patch && V=$(node -p \"require('./package.json').version\") && git add package.json && git commit -m \"$V\" && git tag \"v$V\" && git push origin main --tags",
80
+ "release:minor": "node scripts/check-manifest-continuity.js && pnpm test && git add -A -- ':!docs-site' && (git diff-index --quiet HEAD || git commit -m 'chore: pre-release updates') && pnpm version --no-git-tag-version minor && V=$(node -p \"require('./package.json').version\") && git add package.json && git commit -m \"$V\" && git tag \"v$V\" && git push origin main --tags",
81
+ "release:major": "node scripts/check-manifest-continuity.js && pnpm test && git add -A -- ':!docs-site' && (git diff-index --quiet HEAD || git commit -m 'chore: pre-release updates') && pnpm version --no-git-tag-version major && V=$(node -p \"require('./package.json').version\") && git add package.json && git commit -m \"$V\" && git tag \"v$V\" && git push origin main --tags",
82
+ "release:beta": "node scripts/check-manifest-continuity.js && node scripts/check-docs-changelog.js --type beta && pnpm test && git add -A -- ':!docs-site' && (git diff-index --quiet HEAD || git commit -m 'chore: pre-release updates') && pnpm version --no-git-tag-version prerelease --preid beta && V=$(node -p \"require('./package.json').version\") && git add package.json && git commit -m \"$V\" && git tag \"v$V\" && git push origin HEAD --tags",
83
+ "release:rc": "node scripts/check-manifest-continuity.js && node scripts/check-docs-changelog.js --type rc && pnpm test && git add -A -- ':!docs-site' && (git diff-index --quiet HEAD || git commit -m 'chore: pre-release updates') && pnpm version --no-git-tag-version prerelease --preid rc && V=$(node -p \"require('./package.json').version\") && git add package.json && git commit -m \"$V\" && git tag \"v$V\" && git push origin HEAD --tags",
84
+ "release:promote": "node scripts/check-manifest-continuity.js && node scripts/check-docs-changelog.js --type promote && pnpm test && git add -A -- ':!docs-site' && (git diff-index --quiet HEAD || git commit -m 'chore: pre-release updates') && pnpm version --no-git-tag-version \"$(node -p \"require('./package.json').version.replace(/-.*/, '')\")\" && V=$(node -p \"require('./package.json').version\") && git add package.json && git commit -m \"$V\" && git tag \"v$V\" && git push origin main --tags",
85
85
  "manifest": "node scripts/create-manifest.js"
86
86
  }
87
87
  }
@@ -1,218 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- """
4
- Trellis StatusLine — project-level status display for Claude Code.
5
-
6
- Reads Claude Code session JSON from stdin + Trellis task data from filesystem.
7
- Outputs 1-2 lines:
8
- With active task: [P1] Task title (status) + info line
9
- Without task: info line only
10
- Info line: model · ctx% · branch · duration · developer · tasks · rate limits
11
- """
12
- from __future__ import annotations
13
-
14
- import io
15
- import json
16
- import re
17
- import subprocess
18
- import sys
19
- from pathlib import Path
20
-
21
- # Fix: Windows Python defaults to GBK encoding, which corrupts UTF-8
22
- # characters like the middle dot (·). Wrap stdout/stderr with UTF-8.
23
- if sys.platform == "win32":
24
- sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding="utf-8")
25
- sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding="utf-8")
26
-
27
-
28
- def _read_text(path: Path) -> str:
29
- try:
30
- return path.read_text(encoding="utf-8").strip()
31
- except (FileNotFoundError, PermissionError, OSError):
32
- return ""
33
-
34
-
35
- def _read_json(path: Path) -> dict:
36
- text = _read_text(path)
37
- if not text:
38
- return {}
39
- try:
40
- return json.loads(text)
41
- except (json.JSONDecodeError, ValueError):
42
- return {}
43
-
44
-
45
- def _normalize_task_ref(task_ref: str) -> str:
46
- normalized = task_ref.strip()
47
- if not normalized:
48
- return ""
49
-
50
- path_obj = Path(normalized)
51
- if path_obj.is_absolute():
52
- return str(path_obj)
53
-
54
- normalized = normalized.replace("\\", "/")
55
- while normalized.startswith("./"):
56
- normalized = normalized[2:]
57
-
58
- if normalized.startswith("tasks/"):
59
- return f".trellis/{normalized}"
60
-
61
- return normalized
62
-
63
-
64
- def _resolve_task_dir(trellis_dir: Path, task_ref: str) -> Path:
65
- normalized = _normalize_task_ref(task_ref)
66
- path_obj = Path(normalized)
67
- if path_obj.is_absolute():
68
- return path_obj
69
- if normalized.startswith(".trellis/"):
70
- return trellis_dir.parent / path_obj
71
- return trellis_dir / "tasks" / path_obj
72
-
73
-
74
- def _find_trellis_dir() -> Path | None:
75
- """Walk up from cwd to find .trellis/ directory."""
76
- current = Path.cwd()
77
- for parent in [current, *current.parents]:
78
- candidate = parent / ".trellis"
79
- if candidate.is_dir():
80
- return candidate
81
- return None
82
-
83
-
84
- def _get_current_task(trellis_dir: Path) -> dict | None:
85
- """Load current task info. Returns dict with title/status/priority or None."""
86
- task_ref = _normalize_task_ref(_read_text(trellis_dir / ".current-task"))
87
- if not task_ref:
88
- return None
89
-
90
- # Resolve task directory
91
- task_path = _resolve_task_dir(trellis_dir, task_ref)
92
- task_data = _read_json(task_path / "task.json")
93
- if not task_data:
94
- return None
95
-
96
- return {
97
- "title": task_data.get("title") or task_data.get("name") or "unknown",
98
- "status": task_data.get("status", "unknown"),
99
- "priority": task_data.get("priority", "P2"),
100
- }
101
-
102
-
103
- def _count_active_tasks(trellis_dir: Path) -> int:
104
- """Count non-archived task directories with valid task.json."""
105
- tasks_dir = trellis_dir / "tasks"
106
- if not tasks_dir.is_dir():
107
- return 0
108
- count = 0
109
- for d in tasks_dir.iterdir():
110
- if d.is_dir() and d.name != "archive" and (d / "task.json").is_file():
111
- count += 1
112
- return count
113
-
114
-
115
- def _get_developer(trellis_dir: Path) -> str:
116
- content = _read_text(trellis_dir / ".developer")
117
- if not content:
118
- return "unknown"
119
- for line in content.splitlines():
120
- if line.startswith("name="):
121
- return line[5:].strip()
122
- return content.splitlines()[0].strip() or "unknown"
123
-
124
-
125
- def _get_git_branch() -> str:
126
- try:
127
- result = subprocess.run(
128
- ["git", "branch", "--show-current"],
129
- capture_output=True, text=True, timeout=3,
130
- )
131
- return result.stdout.strip() if result.returncode == 0 else ""
132
- except (FileNotFoundError, subprocess.TimeoutExpired):
133
- return ""
134
-
135
-
136
- def _format_ctx_size(size: int) -> str:
137
- if size >= 1_000_000:
138
- return f"{size // 1_000_000}M"
139
- if size >= 1_000:
140
- return f"{size // 1_000}K"
141
- return str(size)
142
-
143
-
144
- def _format_duration(ms: int) -> str:
145
- secs = ms // 1000
146
- hours, remainder = divmod(secs, 3600)
147
- mins = remainder // 60
148
- if hours > 0:
149
- return f"{hours}h{mins}m"
150
- return f"{mins}m"
151
-
152
-
153
- def main() -> None:
154
- # Read Claude Code session JSON from stdin
155
- try:
156
- cc_data = json.loads(sys.stdin.read())
157
- except (json.JSONDecodeError, ValueError):
158
- cc_data = {}
159
-
160
- trellis_dir = _find_trellis_dir()
161
- SEP = " \033[90m·\033[0m "
162
-
163
- # --- Trellis data ---
164
- task = _get_current_task(trellis_dir) if trellis_dir else None
165
- dev = _get_developer(trellis_dir) if trellis_dir else ""
166
- task_count = _count_active_tasks(trellis_dir) if trellis_dir else 0
167
-
168
- # --- CC session data ---
169
- model = cc_data.get("model", {}).get("display_name", "?")
170
- ctx_pct = int(cc_data.get("context_window", {}).get("used_percentage") or 0)
171
- ctx_size = _format_ctx_size(cc_data.get("context_window", {}).get("context_window_size") or 0)
172
- duration = _format_duration(cc_data.get("cost", {}).get("total_duration_ms") or 0)
173
- branch = _get_git_branch()
174
-
175
- # Avoid "Opus 4.6 (1M context) (1M)"
176
- if re.search(r"\d+[KMG]\b", model, re.IGNORECASE):
177
- model_label = model
178
- else:
179
- model_label = f"{model} ({ctx_size})"
180
-
181
- # Context % with color
182
- if ctx_pct >= 90:
183
- ctx_color = "\033[31m"
184
- elif ctx_pct >= 70:
185
- ctx_color = "\033[33m"
186
- else:
187
- ctx_color = "\033[32m"
188
-
189
- # Build info line: model · ctx · branch · duration · dev · tasks [· rate limits]
190
- parts = [
191
- model_label,
192
- f"ctx {ctx_color}{ctx_pct}%\033[0m",
193
- ]
194
- if branch:
195
- parts.append(f"\033[35m{branch}\033[0m")
196
- parts.append(duration)
197
- if dev:
198
- parts.append(f"\033[32m{dev}\033[0m")
199
- if task_count:
200
- parts.append(f"{task_count} task(s)")
201
-
202
- five_hr = cc_data.get("rate_limits", {}).get("five_hour", {}).get("used_percentage")
203
- if five_hr is not None:
204
- parts.append(f"5h {int(five_hr)}%")
205
- seven_day = cc_data.get("rate_limits", {}).get("seven_day", {}).get("used_percentage")
206
- if seven_day is not None:
207
- parts.append(f"7d {int(seven_day)}%")
208
-
209
- info_line = SEP.join(parts)
210
-
211
- # Output: task line (only if active) + info line
212
- if task:
213
- print(f"\033[36m[{task['priority']}]\033[0m {task['title']} \033[33m({task['status']})\033[0m")
214
- print(info_line)
215
-
216
-
217
- if __name__ == "__main__":
218
- main()