@ai-substrate/engineering-harness 0.2.0-canary.45

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 (229) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +119 -0
  3. package/harness/cli/bin/harness.js +12 -0
  4. package/harness/cli/dist/acts/docs.d.ts +17 -0
  5. package/harness/cli/dist/acts/docs.js +73 -0
  6. package/harness/cli/dist/acts/docs.js.map +1 -0
  7. package/harness/cli/dist/acts/doctor.d.ts +14 -0
  8. package/harness/cli/dist/acts/doctor.js +43 -0
  9. package/harness/cli/dist/acts/doctor.js.map +1 -0
  10. package/harness/cli/dist/acts/help.d.ts +14 -0
  11. package/harness/cli/dist/acts/help.js +29 -0
  12. package/harness/cli/dist/acts/help.js.map +1 -0
  13. package/harness/cli/dist/acts/init.d.ts +22 -0
  14. package/harness/cli/dist/acts/init.js +61 -0
  15. package/harness/cli/dist/acts/init.js.map +1 -0
  16. package/harness/cli/dist/acts/instructions.d.ts +21 -0
  17. package/harness/cli/dist/acts/instructions.js +75 -0
  18. package/harness/cli/dist/acts/instructions.js.map +1 -0
  19. package/harness/cli/dist/acts/new.d.ts +19 -0
  20. package/harness/cli/dist/acts/new.js +66 -0
  21. package/harness/cli/dist/acts/new.js.map +1 -0
  22. package/harness/cli/dist/acts/observe.d.ts +23 -0
  23. package/harness/cli/dist/acts/observe.js +129 -0
  24. package/harness/cli/dist/acts/observe.js.map +1 -0
  25. package/harness/cli/dist/acts/record.d.ts +24 -0
  26. package/harness/cli/dist/acts/record.js +93 -0
  27. package/harness/cli/dist/acts/record.js.map +1 -0
  28. package/harness/cli/dist/acts/skills.d.ts +32 -0
  29. package/harness/cli/dist/acts/skills.js +256 -0
  30. package/harness/cli/dist/acts/skills.js.map +1 -0
  31. package/harness/cli/dist/acts/update.d.ts +23 -0
  32. package/harness/cli/dist/acts/update.js +297 -0
  33. package/harness/cli/dist/acts/update.js.map +1 -0
  34. package/harness/cli/dist/acts/verb.d.ts +27 -0
  35. package/harness/cli/dist/acts/verb.js +56 -0
  36. package/harness/cli/dist/acts/verb.js.map +1 -0
  37. package/harness/cli/dist/adapters/clock/clock-port.d.ts +10 -0
  38. package/harness/cli/dist/adapters/clock/clock-port.js +2 -0
  39. package/harness/cli/dist/adapters/clock/clock-port.js.map +1 -0
  40. package/harness/cli/dist/adapters/clock/fake-clock.d.ts +15 -0
  41. package/harness/cli/dist/adapters/clock/fake-clock.js +25 -0
  42. package/harness/cli/dist/adapters/clock/fake-clock.js.map +1 -0
  43. package/harness/cli/dist/adapters/clock/system-clock.d.ts +5 -0
  44. package/harness/cli/dist/adapters/clock/system-clock.js +7 -0
  45. package/harness/cli/dist/adapters/clock/system-clock.js.map +1 -0
  46. package/harness/cli/dist/adapters/env/env-port.d.ts +17 -0
  47. package/harness/cli/dist/adapters/env/env-port.js +2 -0
  48. package/harness/cli/dist/adapters/env/env-port.js.map +1 -0
  49. package/harness/cli/dist/adapters/env/fake-env.d.ts +15 -0
  50. package/harness/cli/dist/adapters/env/fake-env.js +24 -0
  51. package/harness/cli/dist/adapters/env/fake-env.js.map +1 -0
  52. package/harness/cli/dist/adapters/env/node-env.d.ts +6 -0
  53. package/harness/cli/dist/adapters/env/node-env.js +16 -0
  54. package/harness/cli/dist/adapters/env/node-env.js.map +1 -0
  55. package/harness/cli/dist/adapters/exec/exec-port.d.ts +22 -0
  56. package/harness/cli/dist/adapters/exec/exec-port.js +2 -0
  57. package/harness/cli/dist/adapters/exec/exec-port.js.map +1 -0
  58. package/harness/cli/dist/adapters/exec/fake-exec.d.ts +25 -0
  59. package/harness/cli/dist/adapters/exec/fake-exec.js +25 -0
  60. package/harness/cli/dist/adapters/exec/fake-exec.js.map +1 -0
  61. package/harness/cli/dist/adapters/exec/node-exec.d.ts +14 -0
  62. package/harness/cli/dist/adapters/exec/node-exec.js +38 -0
  63. package/harness/cli/dist/adapters/exec/node-exec.js.map +1 -0
  64. package/harness/cli/dist/adapters/fs/fake-fs.d.ts +22 -0
  65. package/harness/cli/dist/adapters/fs/fake-fs.js +63 -0
  66. package/harness/cli/dist/adapters/fs/fake-fs.js.map +1 -0
  67. package/harness/cli/dist/adapters/fs/fs-port.d.ts +20 -0
  68. package/harness/cli/dist/adapters/fs/fs-port.js +2 -0
  69. package/harness/cli/dist/adapters/fs/fs-port.js.map +1 -0
  70. package/harness/cli/dist/adapters/fs/node-fs.d.ts +9 -0
  71. package/harness/cli/dist/adapters/fs/node-fs.js +30 -0
  72. package/harness/cli/dist/adapters/fs/node-fs.js.map +1 -0
  73. package/harness/cli/dist/adapters/git/exec-git.d.ts +6 -0
  74. package/harness/cli/dist/adapters/git/exec-git.js +21 -0
  75. package/harness/cli/dist/adapters/git/exec-git.js.map +1 -0
  76. package/harness/cli/dist/adapters/git/fake-git.d.ts +15 -0
  77. package/harness/cli/dist/adapters/git/fake-git.js +20 -0
  78. package/harness/cli/dist/adapters/git/fake-git.js.map +1 -0
  79. package/harness/cli/dist/adapters/git/git-port.d.ts +12 -0
  80. package/harness/cli/dist/adapters/git/git-port.js +2 -0
  81. package/harness/cli/dist/adapters/git/git-port.js.map +1 -0
  82. package/harness/cli/dist/adapters/loader/fake-loader.d.ts +13 -0
  83. package/harness/cli/dist/adapters/loader/fake-loader.js +25 -0
  84. package/harness/cli/dist/adapters/loader/fake-loader.js.map +1 -0
  85. package/harness/cli/dist/adapters/loader/jiti-loader.d.ts +15 -0
  86. package/harness/cli/dist/adapters/loader/jiti-loader.js +29 -0
  87. package/harness/cli/dist/adapters/loader/jiti-loader.js.map +1 -0
  88. package/harness/cli/dist/adapters/loader/module-loader-port.d.ts +12 -0
  89. package/harness/cli/dist/adapters/loader/module-loader-port.js +2 -0
  90. package/harness/cli/dist/adapters/loader/module-loader-port.js.map +1 -0
  91. package/harness/cli/dist/adapters/process/fake-process.d.ts +13 -0
  92. package/harness/cli/dist/adapters/process/fake-process.js +21 -0
  93. package/harness/cli/dist/adapters/process/fake-process.js.map +1 -0
  94. package/harness/cli/dist/adapters/process/node-process.d.ts +6 -0
  95. package/harness/cli/dist/adapters/process/node-process.js +17 -0
  96. package/harness/cli/dist/adapters/process/node-process.js.map +1 -0
  97. package/harness/cli/dist/adapters/process/process-port.d.ts +13 -0
  98. package/harness/cli/dist/adapters/process/process-port.js +2 -0
  99. package/harness/cli/dist/adapters/process/process-port.js.map +1 -0
  100. package/harness/cli/dist/adapters/version-lookup/fake-version-lookup.d.ts +13 -0
  101. package/harness/cli/dist/adapters/version-lookup/fake-version-lookup.js +21 -0
  102. package/harness/cli/dist/adapters/version-lookup/fake-version-lookup.js.map +1 -0
  103. package/harness/cli/dist/adapters/version-lookup/node-version-lookup.d.ts +18 -0
  104. package/harness/cli/dist/adapters/version-lookup/node-version-lookup.js +51 -0
  105. package/harness/cli/dist/adapters/version-lookup/node-version-lookup.js.map +1 -0
  106. package/harness/cli/dist/adapters/version-lookup/version-lookup-port.d.ts +19 -0
  107. package/harness/cli/dist/adapters/version-lookup/version-lookup-port.js +2 -0
  108. package/harness/cli/dist/adapters/version-lookup/version-lookup-port.js.map +1 -0
  109. package/harness/cli/dist/app.d.ts +70 -0
  110. package/harness/cli/dist/app.js +221 -0
  111. package/harness/cli/dist/app.js.map +1 -0
  112. package/harness/cli/dist/index.d.ts +2 -0
  113. package/harness/cli/dist/index.js +26 -0
  114. package/harness/cli/dist/index.js.map +1 -0
  115. package/harness/cli/dist/output/envelope.d.ts +68 -0
  116. package/harness/cli/dist/output/envelope.js +56 -0
  117. package/harness/cli/dist/output/envelope.js.map +1 -0
  118. package/harness/cli/dist/output/error-codes.d.ts +57 -0
  119. package/harness/cli/dist/output/error-codes.js +57 -0
  120. package/harness/cli/dist/output/error-codes.js.map +1 -0
  121. package/harness/cli/dist/output/exit.d.ts +29 -0
  122. package/harness/cli/dist/output/exit.js +36 -0
  123. package/harness/cli/dist/output/exit.js.map +1 -0
  124. package/harness/cli/dist/output/output-port.d.ts +54 -0
  125. package/harness/cli/dist/output/output-port.js +55 -0
  126. package/harness/cli/dist/output/output-port.js.map +1 -0
  127. package/harness/cli/dist/output/style.d.ts +33 -0
  128. package/harness/cli/dist/output/style.js +68 -0
  129. package/harness/cli/dist/output/style.js.map +1 -0
  130. package/harness/cli/dist/services/config/load-config.d.ts +27 -0
  131. package/harness/cli/dist/services/config/load-config.js +114 -0
  132. package/harness/cli/dist/services/config/load-config.js.map +1 -0
  133. package/harness/cli/dist/services/docs/contract.d.ts +41 -0
  134. package/harness/cli/dist/services/docs/contract.js +14 -0
  135. package/harness/cli/dist/services/docs/contract.js.map +1 -0
  136. package/harness/cli/dist/services/docs/docs-content.d.ts +37 -0
  137. package/harness/cli/dist/services/docs/docs-content.js +48 -0
  138. package/harness/cli/dist/services/docs/docs-content.js.map +1 -0
  139. package/harness/cli/dist/services/docs/docs-service.d.ts +26 -0
  140. package/harness/cli/dist/services/docs/docs-service.js +25 -0
  141. package/harness/cli/dist/services/docs/docs-service.js.map +1 -0
  142. package/harness/cli/dist/services/doctor/doctor-service.d.ts +69 -0
  143. package/harness/cli/dist/services/doctor/doctor-service.js +237 -0
  144. package/harness/cli/dist/services/doctor/doctor-service.js.map +1 -0
  145. package/harness/cli/dist/services/extensions/contract.d.ts +138 -0
  146. package/harness/cli/dist/services/extensions/contract.js +17 -0
  147. package/harness/cli/dist/services/extensions/contract.js.map +1 -0
  148. package/harness/cli/dist/services/extensions/discovery.d.ts +53 -0
  149. package/harness/cli/dist/services/extensions/discovery.js +116 -0
  150. package/harness/cli/dist/services/extensions/discovery.js.map +1 -0
  151. package/harness/cli/dist/services/extensions/registry.d.ts +63 -0
  152. package/harness/cli/dist/services/extensions/registry.js +165 -0
  153. package/harness/cli/dist/services/extensions/registry.js.map +1 -0
  154. package/harness/cli/dist/services/extensions/verb-context.d.ts +44 -0
  155. package/harness/cli/dist/services/extensions/verb-context.js +97 -0
  156. package/harness/cli/dist/services/extensions/verb-context.js.map +1 -0
  157. package/harness/cli/dist/services/help/help-service.d.ts +42 -0
  158. package/harness/cli/dist/services/help/help-service.js +108 -0
  159. package/harness/cli/dist/services/help/help-service.js.map +1 -0
  160. package/harness/cli/dist/services/init/governance-template.d.ts +27 -0
  161. package/harness/cli/dist/services/init/governance-template.js +72 -0
  162. package/harness/cli/dist/services/init/governance-template.js.map +1 -0
  163. package/harness/cli/dist/services/init/init-service.d.ts +38 -0
  164. package/harness/cli/dist/services/init/init-service.js +44 -0
  165. package/harness/cli/dist/services/init/init-service.js.map +1 -0
  166. package/harness/cli/dist/services/instructions/core-instructions.d.ts +11 -0
  167. package/harness/cli/dist/services/instructions/core-instructions.js +80 -0
  168. package/harness/cli/dist/services/instructions/core-instructions.js.map +1 -0
  169. package/harness/cli/dist/services/instructions/instructions-service.d.ts +52 -0
  170. package/harness/cli/dist/services/instructions/instructions-service.js +53 -0
  171. package/harness/cli/dist/services/instructions/instructions-service.js.map +1 -0
  172. package/harness/cli/dist/services/observe/buffer-codec.d.ts +51 -0
  173. package/harness/cli/dist/services/observe/buffer-codec.js +139 -0
  174. package/harness/cli/dist/services/observe/buffer-codec.js.map +1 -0
  175. package/harness/cli/dist/services/observe/observe-service.d.ts +87 -0
  176. package/harness/cli/dist/services/observe/observe-service.js +221 -0
  177. package/harness/cli/dist/services/observe/observe-service.js.map +1 -0
  178. package/harness/cli/dist/services/record/contract.d.ts +32 -0
  179. package/harness/cli/dist/services/record/contract.js +17 -0
  180. package/harness/cli/dist/services/record/contract.js.map +1 -0
  181. package/harness/cli/dist/services/record/core-types/retro.d.ts +20 -0
  182. package/harness/cli/dist/services/record/core-types/retro.js +55 -0
  183. package/harness/cli/dist/services/record/core-types/retro.js.map +1 -0
  184. package/harness/cli/dist/services/record/record-service.d.ts +38 -0
  185. package/harness/cli/dist/services/record/record-service.js +144 -0
  186. package/harness/cli/dist/services/record/record-service.js.map +1 -0
  187. package/harness/cli/dist/services/record/registry.d.ts +46 -0
  188. package/harness/cli/dist/services/record/registry.js +71 -0
  189. package/harness/cli/dist/services/record/registry.js.map +1 -0
  190. package/harness/cli/dist/services/scaffold/scaffold-service.d.ts +29 -0
  191. package/harness/cli/dist/services/scaffold/scaffold-service.js +88 -0
  192. package/harness/cli/dist/services/scaffold/scaffold-service.js.map +1 -0
  193. package/harness/cli/dist/services/scaffold/templates.d.ts +42 -0
  194. package/harness/cli/dist/services/scaffold/templates.js +178 -0
  195. package/harness/cli/dist/services/scaffold/templates.js.map +1 -0
  196. package/harness/cli/dist/services/shared/posix-path.d.ts +54 -0
  197. package/harness/cli/dist/services/shared/posix-path.js +94 -0
  198. package/harness/cli/dist/services/shared/posix-path.js.map +1 -0
  199. package/harness/cli/dist/services/shared/temp.d.ts +24 -0
  200. package/harness/cli/dist/services/shared/temp.js +29 -0
  201. package/harness/cli/dist/services/shared/temp.js.map +1 -0
  202. package/harness/cli/dist/services/skills/contract.d.ts +52 -0
  203. package/harness/cli/dist/services/skills/contract.js +55 -0
  204. package/harness/cli/dist/services/skills/contract.js.map +1 -0
  205. package/harness/cli/dist/services/skills/skills-service.d.ts +73 -0
  206. package/harness/cli/dist/services/skills/skills-service.js +132 -0
  207. package/harness/cli/dist/services/skills/skills-service.js.map +1 -0
  208. package/harness/cli/dist/services/update/banner.d.ts +26 -0
  209. package/harness/cli/dist/services/update/banner.js +28 -0
  210. package/harness/cli/dist/services/update/banner.js.map +1 -0
  211. package/harness/cli/dist/services/update/cache.d.ts +21 -0
  212. package/harness/cli/dist/services/update/cache.js +61 -0
  213. package/harness/cli/dist/services/update/cache.js.map +1 -0
  214. package/harness/cli/dist/services/update/constants.d.ts +9 -0
  215. package/harness/cli/dist/services/update/constants.js +10 -0
  216. package/harness/cli/dist/services/update/constants.js.map +1 -0
  217. package/harness/cli/dist/services/update/install.d.ts +26 -0
  218. package/harness/cli/dist/services/update/install.js +78 -0
  219. package/harness/cli/dist/services/update/install.js.map +1 -0
  220. package/harness/cli/dist/services/update/semver.d.ts +16 -0
  221. package/harness/cli/dist/services/update/semver.js +108 -0
  222. package/harness/cli/dist/services/update/semver.js.map +1 -0
  223. package/harness/cli/dist/services/update/update-service.d.ts +46 -0
  224. package/harness/cli/dist/services/update/update-service.js +91 -0
  225. package/harness/cli/dist/services/update/update-service.js.map +1 -0
  226. package/harness/cli/dist/version.d.ts +8 -0
  227. package/harness/cli/dist/version.js +15 -0
  228. package/harness/cli/dist/version.js.map +1 -0
  229. package/package.json +56 -0
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Deterministic git for tests. Seeded with repo/branch state; records each
3
+ * method called on `calls` (fakes over mocks).
4
+ */
5
+ export class FakeGit {
6
+ state;
7
+ calls = [];
8
+ constructor(state = {}) {
9
+ this.state = state;
10
+ }
11
+ isRepo() {
12
+ this.calls.push('isRepo');
13
+ return this.state.isRepo ?? false;
14
+ }
15
+ currentBranch() {
16
+ this.calls.push('currentBranch');
17
+ return this.state.branch ?? null;
18
+ }
19
+ }
20
+ //# sourceMappingURL=fake-git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake-git.js","sourceRoot":"","sources":["../../../src/adapters/git/fake-git.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,OAAO,OAAO;IAGW;IAFpB,KAAK,GAAa,EAAE,CAAC;IAE9B,YAA6B,QAAsD,EAAE;QAAxD,UAAK,GAAL,KAAK,CAAmD;IAAG,CAAC;IAEzF,MAAM;QACJ,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC1B,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC;IACpC,CAAC;IAED,aAAa;QACX,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACjC,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC;IACnC,CAAC;CACF"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Git port — informational repository facts behind an interface.
3
+ *
4
+ * Used by `doctor` for context (are we in a repo? which branch?). Injected so
5
+ * doctor stays unit-testable with `FakeGit` and never shells out to `git`.
6
+ */
7
+ export interface GitPort {
8
+ /** True if the cwd is inside a git work tree. */
9
+ isRepo(): boolean;
10
+ /** Current branch name, or null if not a repo / detached HEAD. */
11
+ currentBranch(): string | null;
12
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=git-port.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-port.js","sourceRoot":"","sources":["../../../src/adapters/git/git-port.ts"],"names":[],"mappings":""}
@@ -0,0 +1,13 @@
1
+ import type { ModuleLoaderPort } from './module-loader-port.js';
2
+ /**
3
+ * Deterministic module loader for tests. Seeded with `{ absPath: defaultExport }`;
4
+ * records every requested path on `loads` (fakes over mocks). To simulate a load
5
+ * failure, script an `Error` for the path — `load` rejects with it. An unscripted
6
+ * path also rejects (the registry treats a load rejection as `failed`/E140).
7
+ */
8
+ export declare class FakeModuleLoader implements ModuleLoaderPort {
9
+ private readonly scripts;
10
+ readonly loads: string[];
11
+ constructor(scripts?: Record<string, unknown>);
12
+ load(absPath: string): Promise<unknown>;
13
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Deterministic module loader for tests. Seeded with `{ absPath: defaultExport }`;
3
+ * records every requested path on `loads` (fakes over mocks). To simulate a load
4
+ * failure, script an `Error` for the path — `load` rejects with it. An unscripted
5
+ * path also rejects (the registry treats a load rejection as `failed`/E140).
6
+ */
7
+ export class FakeModuleLoader {
8
+ scripts;
9
+ loads = [];
10
+ constructor(scripts = {}) {
11
+ this.scripts = scripts;
12
+ }
13
+ load(absPath) {
14
+ this.loads.push(absPath);
15
+ if (!(absPath in this.scripts)) {
16
+ return Promise.reject(new Error(`No module scripted for ${absPath}`));
17
+ }
18
+ const entry = this.scripts[absPath];
19
+ if (entry instanceof Error) {
20
+ return Promise.reject(entry);
21
+ }
22
+ return Promise.resolve(entry);
23
+ }
24
+ }
25
+ //# sourceMappingURL=fake-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake-loader.js","sourceRoot":"","sources":["../../../src/adapters/loader/fake-loader.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,OAAO,gBAAgB;IAGE;IAFpB,KAAK,GAAa,EAAE,CAAC;IAE9B,YAA6B,UAAmC,EAAE;QAArC,YAAO,GAAP,OAAO,CAA8B;IAAG,CAAC;IAEtE,IAAI,CAAC,OAAe;QAClB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzB,IAAI,CAAC,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/B,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,0BAA0B,OAAO,EAAE,CAAC,CAAC,CAAC;QACxE,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACpC,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC/B,CAAC;QACD,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;CACF"}
@@ -0,0 +1,15 @@
1
+ import type { ModuleLoaderPort } from './module-loader-port.js';
2
+ /**
3
+ * Real module loader — the ONLY place `jiti` is imported.
4
+ *
5
+ * `.ts`/`.tsx` load through jiti with `moduleCache: false` (pi-parity): full TS
6
+ * transpile (enums, etc.) and each extension resolves its own `node_modules`.
7
+ * `.js`/`.mjs`/`.cjs` skip jiti entirely via native dynamic `import()`. Both
8
+ * return the module's **default** export (a module with no default → `undefined`,
9
+ * which the registry then rejects as a malformed export — never the namespace).
10
+ */
11
+ export declare class JitiLoader implements ModuleLoaderPort {
12
+ private jiti;
13
+ private getJiti;
14
+ load(absPath: string): Promise<unknown>;
15
+ }
@@ -0,0 +1,29 @@
1
+ import { pathToFileURL } from 'node:url';
2
+ import { createJiti } from 'jiti';
3
+ const TS_FILE = /\.(ts|tsx)$/;
4
+ /**
5
+ * Real module loader — the ONLY place `jiti` is imported.
6
+ *
7
+ * `.ts`/`.tsx` load through jiti with `moduleCache: false` (pi-parity): full TS
8
+ * transpile (enums, etc.) and each extension resolves its own `node_modules`.
9
+ * `.js`/`.mjs`/`.cjs` skip jiti entirely via native dynamic `import()`. Both
10
+ * return the module's **default** export (a module with no default → `undefined`,
11
+ * which the registry then rejects as a malformed export — never the namespace).
12
+ */
13
+ export class JitiLoader {
14
+ jiti;
15
+ getJiti() {
16
+ if (!this.jiti) {
17
+ this.jiti = createJiti(import.meta.url, { moduleCache: false });
18
+ }
19
+ return this.jiti;
20
+ }
21
+ async load(absPath) {
22
+ if (TS_FILE.test(absPath)) {
23
+ return this.getJiti().import(absPath, { default: true });
24
+ }
25
+ const mod = (await import(pathToFileURL(absPath).href));
26
+ return mod.default;
27
+ }
28
+ }
29
+ //# sourceMappingURL=jiti-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jiti-loader.js","sourceRoot":"","sources":["../../../src/adapters/loader/jiti-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAGlC,MAAM,OAAO,GAAG,aAAa,CAAC;AAE9B;;;;;;;;GAQG;AACH,MAAM,OAAO,UAAU;IACb,IAAI,CAA4C;IAEhD,OAAO;QACb,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YACf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;QAClE,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,OAAe;QACxB,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAC1B,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3D,CAAC;QACD,MAAM,GAAG,GAAG,CAAC,MAAM,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAA0B,CAAC;QACjF,OAAO,GAAG,CAAC,OAAO,CAAC;IACrB,CAAC;CACF"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Module-loader port — turns an extension file on disk into its default export.
3
+ *
4
+ * `.ts`/`.tsx` go through jiti (full transpile, like pi's loader); `.js`/`.mjs`/
5
+ * `.cjs` use a plain dynamic `import()` (no transpile — the fast path). Injected
6
+ * so the registry/discovery logic is unit-testable with `FakeModuleLoader` and
7
+ * never touches jiti or the real module system (WS-A Decision 1/4).
8
+ */
9
+ export interface ModuleLoaderPort {
10
+ /** Import by absolute path and return the module's default export. */
11
+ load(absPath: string): Promise<unknown>;
12
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=module-loader-port.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module-loader-port.js","sourceRoot":"","sources":["../../../src/adapters/loader/module-loader-port.ts"],"names":[],"mappings":""}
@@ -0,0 +1,13 @@
1
+ import type { ProcessPort } from './process-port.js';
2
+ /**
3
+ * Deterministic process access for tests. Seeded with a `{command: path}` map;
4
+ * records every looked-up command on `lookups` (fakes over mocks).
5
+ */
6
+ export declare class FakeProcess implements ProcessPort {
7
+ private readonly paths;
8
+ private readonly cwdPath;
9
+ readonly lookups: string[];
10
+ constructor(paths?: Record<string, string>, cwdPath?: string);
11
+ which(command: string): string | null;
12
+ cwd(): string;
13
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Deterministic process access for tests. Seeded with a `{command: path}` map;
3
+ * records every looked-up command on `lookups` (fakes over mocks).
4
+ */
5
+ export class FakeProcess {
6
+ paths;
7
+ cwdPath;
8
+ lookups = [];
9
+ constructor(paths = {}, cwdPath = '/repo') {
10
+ this.paths = paths;
11
+ this.cwdPath = cwdPath;
12
+ }
13
+ which(command) {
14
+ this.lookups.push(command);
15
+ return this.paths[command] ?? null;
16
+ }
17
+ cwd() {
18
+ return this.cwdPath;
19
+ }
20
+ }
21
+ //# sourceMappingURL=fake-process.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake-process.js","sourceRoot":"","sources":["../../../src/adapters/process/fake-process.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,OAAO,WAAW;IAIH;IACA;IAJV,OAAO,GAAa,EAAE,CAAC;IAEhC,YACmB,QAAgC,EAAE,EAClC,UAAU,OAAO;QADjB,UAAK,GAAL,KAAK,CAA6B;QAClC,YAAO,GAAP,OAAO,CAAU;IACjC,CAAC;IAEJ,KAAK,CAAC,OAAe;QACnB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3B,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;IACrC,CAAC;IAED,GAAG;QACD,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;CACF"}
@@ -0,0 +1,6 @@
1
+ import type { ProcessPort } from './process-port.js';
2
+ /** Real process access — the only place a child process is spawned. */
3
+ export declare class NodeProcess implements ProcessPort {
4
+ which(command: string): string | null;
5
+ cwd(): string;
6
+ }
@@ -0,0 +1,17 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ /** Real process access — the only place a child process is spawned. */
3
+ export class NodeProcess {
4
+ which(command) {
5
+ const locator = process.platform === 'win32' ? 'where' : 'which';
6
+ const result = spawnSync(locator, [command], { encoding: 'utf8' });
7
+ if (result.status === 0 && result.stdout) {
8
+ const first = result.stdout.split('\n')[0]?.trim();
9
+ return first ? first : null;
10
+ }
11
+ return null;
12
+ }
13
+ cwd() {
14
+ return process.cwd();
15
+ }
16
+ }
17
+ //# sourceMappingURL=node-process.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-process.js","sourceRoot":"","sources":["../../../src/adapters/process/node-process.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAG/C,uEAAuE;AACvE,MAAM,OAAO,WAAW;IACtB,KAAK,CAAC,OAAe;QACnB,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;QACjE,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;QACnE,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YACzC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;YACnD,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;QAC9B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,GAAG;QACD,OAAO,OAAO,CAAC,GAAG,EAAE,CAAC;IACvB,CAAC;CACF"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Process port — toolchain probing behind an interface (read-only this slice).
3
+ *
4
+ * `which` answers "is this tool on PATH, and where?" for `doctor`'s toolchain
5
+ * layer. Injected so the doctor service stays unit-testable with `FakeProcess`
6
+ * and never spawns a real process.
7
+ */
8
+ export interface ProcessPort {
9
+ /** Absolute path to `command` if found on PATH, else null. */
10
+ which(command: string): string | null;
11
+ /** The current working directory — the root discovery resolves `.harness/extensions/` against. */
12
+ cwd(): string;
13
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=process-port.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-port.js","sourceRoot":"","sources":["../../../src/adapters/process/process-port.ts"],"names":[],"mappings":""}
@@ -0,0 +1,13 @@
1
+ import type { VersionLookupPort } from './version-lookup-port.js';
2
+ /**
3
+ * Deterministic version lookup for tests. Returns a scripted latest version
4
+ * (or null), or rejects with a scripted error to exercise the caller's failure
5
+ * handling; records how many times it was called (fakes over mocks).
6
+ */
7
+ export declare class FakeVersionLookup implements VersionLookupPort {
8
+ private readonly result;
9
+ private readonly error?;
10
+ calls: number;
11
+ constructor(result?: string | null, error?: Error | undefined);
12
+ latest(): Promise<string | null>;
13
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Deterministic version lookup for tests. Returns a scripted latest version
3
+ * (or null), or rejects with a scripted error to exercise the caller's failure
4
+ * handling; records how many times it was called (fakes over mocks).
5
+ */
6
+ export class FakeVersionLookup {
7
+ result;
8
+ error;
9
+ calls = 0;
10
+ constructor(result = null, error) {
11
+ this.result = result;
12
+ this.error = error;
13
+ }
14
+ latest() {
15
+ this.calls++;
16
+ if (this.error)
17
+ return Promise.reject(this.error);
18
+ return Promise.resolve(this.result);
19
+ }
20
+ }
21
+ //# sourceMappingURL=fake-version-lookup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake-version-lookup.js","sourceRoot":"","sources":["../../../src/adapters/version-lookup/fake-version-lookup.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,OAAO,iBAAiB;IAIT;IACA;IAJnB,KAAK,GAAG,CAAC,CAAC;IAEV,YACmB,SAAwB,IAAI,EAC5B,KAAa;QADb,WAAM,GAAN,MAAM,CAAsB;QAC5B,UAAK,GAAL,KAAK,CAAQ;IAC7B,CAAC;IAEJ,MAAM;QACJ,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClD,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;CACF"}
@@ -0,0 +1,18 @@
1
+ import type { ExecPort } from '../exec/exec-port.js';
2
+ import type { VersionLookupPort } from './version-lookup-port.js';
3
+ /**
4
+ * Real version lookup — shells `npm view <pkg> version --json` via the injected
5
+ * `ExecPort` (so the only child spawn stays in `NodeExec`). Reads the PUBLIC npm
6
+ * registry — no auth needed for a public package (FX001); cwd only lets npm pick
7
+ * up a project `.npmrc` if one is present.
8
+ *
9
+ * Never throws: a non-zero exit (not-found, registry unreachable) or unparseable
10
+ * output maps to null so the update check degrades silently (AC9).
11
+ */
12
+ export declare class NodeVersionLookup implements VersionLookupPort {
13
+ private readonly exec;
14
+ private readonly pkg;
15
+ private readonly cwd;
16
+ constructor(exec: ExecPort, pkg: string, cwd: string);
17
+ latest(): Promise<string | null>;
18
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Real version lookup — shells `npm view <pkg> version --json` via the injected
3
+ * `ExecPort` (so the only child spawn stays in `NodeExec`). Reads the PUBLIC npm
4
+ * registry — no auth needed for a public package (FX001); cwd only lets npm pick
5
+ * up a project `.npmrc` if one is present.
6
+ *
7
+ * Never throws: a non-zero exit (not-found, registry unreachable) or unparseable
8
+ * output maps to null so the update check degrades silently (AC9).
9
+ */
10
+ export class NodeVersionLookup {
11
+ exec;
12
+ pkg;
13
+ cwd;
14
+ constructor(exec, pkg, cwd) {
15
+ this.exec = exec;
16
+ this.pkg = pkg;
17
+ this.cwd = cwd;
18
+ }
19
+ async latest() {
20
+ const result = await this.exec.run('npm', ['view', this.pkg, 'version', '--json'], {
21
+ cwd: this.cwd,
22
+ });
23
+ if (!result.ok)
24
+ return null;
25
+ return parseNpmVersion(result.stdout);
26
+ }
27
+ }
28
+ /**
29
+ * `npm view pkg version --json` emits a JSON-encoded string for a single match
30
+ * ("0.2.0") or a JSON array when several versions resolve — take the last.
31
+ * Anything else (empty, non-JSON) ⇒ null (unknown, not an error).
32
+ */
33
+ function parseNpmVersion(stdout) {
34
+ const text = stdout.trim();
35
+ if (!text)
36
+ return null;
37
+ try {
38
+ const parsed = JSON.parse(text);
39
+ if (typeof parsed === 'string')
40
+ return parsed;
41
+ if (Array.isArray(parsed) && parsed.length > 0) {
42
+ const last = parsed[parsed.length - 1];
43
+ return typeof last === 'string' ? last : null;
44
+ }
45
+ return null;
46
+ }
47
+ catch {
48
+ return null;
49
+ }
50
+ }
51
+ //# sourceMappingURL=node-version-lookup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-version-lookup.js","sourceRoot":"","sources":["../../../src/adapters/version-lookup/node-version-lookup.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,MAAM,OAAO,iBAAiB;IAET;IACA;IACA;IAHnB,YACmB,IAAc,EACd,GAAW,EACX,GAAW;QAFX,SAAI,GAAJ,IAAI,CAAU;QACd,QAAG,GAAH,GAAG,CAAQ;QACX,QAAG,GAAH,GAAG,CAAQ;IAC3B,CAAC;IAEJ,KAAK,CAAC,MAAM;QACV,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE;YACjF,GAAG,EAAE,IAAI,CAAC,GAAG;SACd,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QAC5B,OAAO,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACxC,CAAC;CACF;AAED;;;;GAIG;AACH,SAAS,eAAe,CAAC,MAAc;IACrC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,IAAI,CAAC;QACH,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACzC,IAAI,OAAO,MAAM,KAAK,QAAQ;YAAE,OAAO,MAAM,CAAC;QAC9C,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACvC,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QAChD,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Version-lookup port — the latest published version of the harness package on
3
+ * its registry (the public npm registry).
4
+ *
5
+ * Injected so the update service stays unit-testable with `FakeVersionLookup`
6
+ * and never shells a child or touches the network directly. The Node adapter
7
+ * shells `npm view` (architecture §2.1 defers a real HTTP adapter), composing
8
+ * `ExecPort` rather than spawning itself.
9
+ */
10
+ export interface VersionLookupPort {
11
+ /**
12
+ * Latest published version string (e.g. "0.3.0"), or null when it cannot be
13
+ * determined — package not found, empty registry, or an auth/transport
14
+ * failure. Implementations SHOULD map failures to null so the caller can
15
+ * degrade silently (AC9); tests may also reject to exercise the caller's
16
+ * defensive catch.
17
+ */
18
+ latest(): Promise<string | null>;
19
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=version-lookup-port.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version-lookup-port.js","sourceRoot":"","sources":["../../../src/adapters/version-lookup/version-lookup-port.ts"],"names":[],"mappings":""}
@@ -0,0 +1,70 @@
1
+ import { Command } from 'commander';
2
+ import { type VerbActDeps } from './acts/verb.js';
3
+ import type { Clock } from './adapters/clock/clock-port.js';
4
+ import type { ModuleLoaderPort } from './adapters/loader/module-loader-port.js';
5
+ import { type Envelope } from './output/envelope.js';
6
+ import { type CliIo, type Writers } from './output/output-port.js';
7
+ import { type ExtensionRegistry, type VerbRegistry } from './services/extensions/registry.js';
8
+ import { type ExtensionRecordType } from './services/record/registry.js';
9
+ /**
10
+ * Tri-state read of the output flag from argv. The entrypoint resolves this
11
+ * ONCE — commander collapses `--json`/`--no-json` to a single boolean and loses
12
+ * the "absent" state that lets env/TTY decide, so acts must never re-derive it.
13
+ */
14
+ export declare function jsonFlag(argv: string[]): boolean | undefined;
15
+ /**
16
+ * Safe mode: skip extension discovery entirely (core commands only). Detected
17
+ * from raw argv (`--no-extensions`) or env (`HARNESS_NO_EXTENSIONS=1`) BEFORE
18
+ * parse, since the registry must be known before commander is built.
19
+ *
20
+ * NOTE (v1): the argv scan is a simple `includes`, so a `--no-extensions` placed
21
+ * after a verb name (as a verb's own option) would also trigger safe mode. The
22
+ * env var is the unambiguous path; revisit if a verb ever needs that flag.
23
+ */
24
+ export declare function isExtensionsDisabled(argv: string[], env: NodeJS.ProcessEnv): boolean;
25
+ /**
26
+ * Map a thrown commander error (raised because `exitOverride` is set) to an
27
+ * actionable envelope. Returns `null` for help/version display (commander
28
+ * already printed; the caller exits 0). Unknown command/option/missing-arg →
29
+ * `E108`; anything else (an unexpected bug) → `E100` — so no raw stack trace
30
+ * ever escapes.
31
+ */
32
+ export declare function commanderErrorEnvelope(err: {
33
+ code?: string;
34
+ message?: string;
35
+ }, clock: Clock): Envelope | null;
36
+ /**
37
+ * Discover + load the repo's extensions into the extension registry (verbs +
38
+ * record types + provenance) in one pass, unless safe mode is on (then the
39
+ * registry is empty — core commands + core record types only). Core record-type
40
+ * names are reserved so an extension can never shadow them. Runs BEFORE parse so
41
+ * each verb is a registered command (WS-A Decision 6).
42
+ */
43
+ export declare function loadRegistry(argv: string[], env: NodeJS.ProcessEnv, deps: VerbActDeps, loader: ModuleLoaderPort): Promise<ExtensionRegistry>;
44
+ /**
45
+ * Build the composition root: global flags + core commands (incl. `record`, built
46
+ * from the merged record registry = core ∪ extension) + one subcommand per
47
+ * discovered verb, each registered with the pre-resolved `io` + injected ports. No
48
+ * business logic, no fs/process/git here.
49
+ */
50
+ export declare function buildProgram(version: string, io: CliIo, deps: VerbActDeps, registry: VerbRegistry & {
51
+ recordTypes?: ExtensionRecordType[];
52
+ }): Command;
53
+ /** Injectable seams so the composition root is testable without real adapters/streams. */
54
+ export interface MainOverrides {
55
+ deps: VerbActDeps;
56
+ loader: ModuleLoaderPort;
57
+ env: NodeJS.ProcessEnv;
58
+ isTty: boolean;
59
+ writers: Writers;
60
+ version: string;
61
+ }
62
+ /**
63
+ * The async composition root (WS-A Decision 6): resolve output mode, discover +
64
+ * load extensions, validate the assembled registry, then `await parseAsync`.
65
+ * Three distinct error boundaries keep the kernel the sole exit point:
66
+ * 1. an unexpected discovery/load error → `E100` (routed through the kernel);
67
+ * 2. a malformed registry → the `E120` validation envelope;
68
+ * 3. a commander parse error → `commanderErrorEnvelope` (help/version → exit 0).
69
+ */
70
+ export declare function main(argv?: string[], overrides?: Partial<MainOverrides>): Promise<void>;