@ai-substrate/engineering-harness 0.2.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 (229) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +141 -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,66 @@
1
+ import { formatError, formatOk } from '../output/envelope.js';
2
+ import { exitWithEnvelope } from '../output/exit.js';
3
+ import { createOutputPort } from '../output/output-port.js';
4
+ import { scaffoldExtension } from '../services/scaffold/scaffold-service.js';
5
+ /**
6
+ * Variant-aware "what next". A `--wrap` scaffold already has a working `run()`,
7
+ * so telling the author to "implement run()" is misleading (MH-003) — point them
8
+ * at running/reviewing it instead. A minimal stub genuinely needs implementing.
9
+ */
10
+ function nextActionFor(variant, path, verb) {
11
+ if (variant === 'record-ts') {
12
+ return `Edit the template body in ${path}, then run \`harness record ${verb}\`. \`harness doctor\` confirms it loaded.`;
13
+ }
14
+ const isWrap = variant.startsWith('wrap');
15
+ return isWrap
16
+ ? `Run \`harness ${verb}\` to try it (run() already wraps your command); edit ${path} to tweak. \`harness doctor\` confirms it loaded.`
17
+ : `Edit ${path} to implement run(), then run \`harness ${verb}\`. \`harness doctor\` confirms it loaded.`;
18
+ }
19
+ /**
20
+ * Register the `new` command — scaffolds a fresh, loadable extension into the
21
+ * repo's `.harness/extensions/`. A CORE command (reserved, like `help`/`doctor`,
22
+ * runs even in `--no-extensions` mode); it owns no business logic — the
23
+ * `scaffold-service` validates + writes, and this act maps the outcome onto the
24
+ * Envelope + exit code (ok → 0, error → 1).
25
+ */
26
+ export function registerNewAct(program, io, deps) {
27
+ program
28
+ .command('new')
29
+ .description('Scaffold a new extension package into .harness/extensions/<name>/ (entry + instructions.md)')
30
+ .argument('<name>', 'verb name (lowercase, hyphenated — becomes `harness <name>`)')
31
+ .option('--wrap <command>', 'wrap a real repo command, e.g. --wrap "npm test"')
32
+ .option('--js', 'emit a plain .js starter (JSDoc contract, no TypeScript)')
33
+ .option('--record', 'scaffold a record-type extension (`harness record <name>`) instead of a verb')
34
+ .option('--force', 'overwrite an existing extension file')
35
+ .action((name, opts) => {
36
+ const outcome = scaffoldExtension({ name, wrap: opts.wrap, js: opts.js, record: opts.record, force: opts.force }, { fs: deps.fs, proc: deps.proc });
37
+ const envelope = outcome.ok
38
+ ? formatOk('new', {
39
+ path: outcome.path,
40
+ instructionsPath: outcome.instructionsPath,
41
+ verb: outcome.verb,
42
+ variant: outcome.variant,
43
+ }, deps.clock, { next_action: nextActionFor(outcome.variant, outcome.path, outcome.verb) })
44
+ : formatError('new', outcome.code, outcome.message, deps.clock, {
45
+ next_action: outcome.next_action,
46
+ });
47
+ const port = io.mode === 'json'
48
+ ? createOutputPort('json', io.writers)
49
+ : {
50
+ emit: (e) => {
51
+ if (e.status === 'ok' && outcome.ok) {
52
+ io.writers.out(`Created ${outcome.path}\n`);
53
+ io.writers.out(`Created ${outcome.instructionsPath} (author the agent briefing)\n`);
54
+ }
55
+ else {
56
+ io.writers.err(`harness new: ${e.error?.message ?? 'failed'}\n`);
57
+ if (e.next_action)
58
+ io.writers.err(` → ${e.next_action}\n`);
59
+ }
60
+ io.writers.out(`new: ${e.status}\n`);
61
+ },
62
+ };
63
+ exitWithEnvelope(envelope, port);
64
+ });
65
+ }
66
+ //# sourceMappingURL=new.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"new.js","sourceRoot":"","sources":["../../src/acts/new.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { Command } from 'commander';
2
+ import type { Clock } from '../adapters/clock/clock-port.js';
3
+ import type { EnvPort } from '../adapters/env/env-port.js';
4
+ import type { FsPort } from '../adapters/fs/fs-port.js';
5
+ import type { ProcessPort } from '../adapters/process/process-port.js';
6
+ import { type CliIo } from '../output/output-port.js';
7
+ /** The ports the `observe` act injects into the observe service (a subset of VerbActDeps). */
8
+ export interface ObserveActDeps {
9
+ fs: FsPort;
10
+ proc: ProcessPort;
11
+ clock: Clock;
12
+ env: EnvPort;
13
+ }
14
+ /**
15
+ * Register the `observe` command — CLI-owned in-flight friction capture into the
16
+ * gitignored transient buffer (`.harness/temp/<bucket>/session-buffer.md`), plus
17
+ * the `--list`/`--clear` drain surface that sweeps ALL buckets by default
18
+ * (plan 015 D-12). A CORE command (reserved, like `record`/`instructions`). It
19
+ * owns no business logic — `observe-service` resolves identity, validates,
20
+ * assigns IDs, and appends; this act maps outcomes onto the Envelope + exit code
21
+ * (ok → 0, unconfigured → 2, error → 1).
22
+ */
23
+ export declare function registerObserveAct(program: Command, io: CliIo, deps: ObserveActDeps): void;
@@ -0,0 +1,129 @@
1
+ import { formatError, formatOk, formatUnconfigured } from '../output/envelope.js';
2
+ import { ErrorCodes } from '../output/error-codes.js';
3
+ import { exitWithEnvelope } from '../output/exit.js';
4
+ import { createOutputPort } from '../output/output-port.js';
5
+ import { OBSERVATION_KINDS, OBSERVATION_SEVERITIES } from '../services/observe/buffer-codec.js';
6
+ import { captureObservation, clearObservations, listObservations, } from '../services/observe/observe-service.js';
7
+ /**
8
+ * Register the `observe` command — CLI-owned in-flight friction capture into the
9
+ * gitignored transient buffer (`.harness/temp/<bucket>/session-buffer.md`), plus
10
+ * the `--list`/`--clear` drain surface that sweeps ALL buckets by default
11
+ * (plan 015 D-12). A CORE command (reserved, like `record`/`instructions`). It
12
+ * owns no business logic — `observe-service` resolves identity, validates,
13
+ * assigns IDs, and appends; this act maps outcomes onto the Envelope + exit code
14
+ * (ok → 0, unconfigured → 2, error → 1).
15
+ */
16
+ export function registerObserveAct(program, io, deps) {
17
+ const kinds = Object.keys(OBSERVATION_KINDS).join(' | ');
18
+ program
19
+ .command('observe')
20
+ .description('Capture one friction observation to the gitignored transient buffer (.harness/temp/)')
21
+ .argument('[description]', 'what you noticed (>=10 chars); omit with --list/--clear')
22
+ .option('--kind <kind>', `entry kind: ${kinds}`)
23
+ .option('--target <target>', 'free-form target, e.g. tooling | project-sensor | skill')
24
+ .option('--severity <severity>', `severity: ${OBSERVATION_SEVERITIES.join(' | ')}`)
25
+ .option('--workaround <text>', 'what you did to get past it')
26
+ .option('--suggested-encoding <text>', 'a hint for the retro drain encoding flow')
27
+ .option('--agent <slug>', 'bucket override (else HARNESS_AGENT env, else "agent")')
28
+ .option('--list', 'list pending observations (all buckets by default)')
29
+ .option('--clear', 'truncate pending observations (all buckets by default; files kept)')
30
+ .action((description, opts) => {
31
+ const serviceDeps = deps;
32
+ if (opts.list) {
33
+ const outcome = listObservations({ agent: opts.agent }, serviceDeps);
34
+ if (!outcome.ok) {
35
+ exitWithEnvelope(failureEnvelope(outcome, deps.clock), portFor(io, 'list'));
36
+ return;
37
+ }
38
+ const envelope = formatOk('observe', {
39
+ observations: outcome.observations,
40
+ buckets_scanned: outcome.buckets_scanned,
41
+ malformed_skipped: outcome.malformed_skipped,
42
+ }, deps.clock, {
43
+ next_action: 'Drain: save what matters via `harness record retro`, then `harness observe --clear`.',
44
+ });
45
+ const port = io.mode === 'json'
46
+ ? createOutputPort('json', io.writers)
47
+ : {
48
+ emit: () => {
49
+ for (const o of outcome.observations) {
50
+ io.writers.out(`[${o.kind}${o.target ? `/${o.target}` : ''}] ${o.bucket}:${o.id} ${o.description}\n`);
51
+ }
52
+ io.writers.out(`observe: ${outcome.observations.length} pending across ${outcome.buckets_scanned.length} bucket(s)` +
53
+ `${outcome.malformed_skipped > 0 ? `, ${outcome.malformed_skipped} malformed skipped` : ''}\n`);
54
+ },
55
+ };
56
+ exitWithEnvelope(envelope, port);
57
+ return;
58
+ }
59
+ if (opts.clear) {
60
+ const outcome = clearObservations({ agent: opts.agent }, serviceDeps);
61
+ if (!outcome.ok) {
62
+ exitWithEnvelope(failureEnvelope(outcome, deps.clock), portFor(io, 'clear'));
63
+ return;
64
+ }
65
+ const envelope = formatOk('observe', {
66
+ cleared: outcome.cleared,
67
+ buckets_scanned: outcome.buckets_scanned,
68
+ malformed_skipped: outcome.malformed_skipped,
69
+ }, deps.clock);
70
+ const port = io.mode === 'json'
71
+ ? createOutputPort('json', io.writers)
72
+ : {
73
+ emit: () => {
74
+ io.writers.out(`observe: cleared ${outcome.cleared} entr(y/ies)\n`);
75
+ },
76
+ };
77
+ exitWithEnvelope(envelope, port);
78
+ return;
79
+ }
80
+ const outcome = captureObservation({
81
+ description,
82
+ kind: opts.kind,
83
+ target: opts.target,
84
+ severity: opts.severity,
85
+ workaround: opts.workaround,
86
+ suggestedEncoding: opts.suggestedEncoding,
87
+ agent: opts.agent,
88
+ }, serviceDeps);
89
+ if (!outcome.ok) {
90
+ exitWithEnvelope(failureEnvelope(outcome, deps.clock), portFor(io, 'capture'));
91
+ return;
92
+ }
93
+ const envelope = formatOk('observe', { bucket: outcome.bucket, id: outcome.id, kind: outcome.kind, path: outcome.path }, deps.clock, {
94
+ evidence: [{ label: 'observation buffer', path: outcome.path }],
95
+ next_action: 'Keep working — drain at session end with `harness observe --list` then `harness record retro`.',
96
+ });
97
+ const port = io.mode === 'json'
98
+ ? createOutputPort('json', io.writers)
99
+ : {
100
+ emit: () => {
101
+ io.writers.out(`Captured ${outcome.id} → ${outcome.path}\n`);
102
+ io.writers.out('observe: ok\n');
103
+ },
104
+ };
105
+ exitWithEnvelope(envelope, port);
106
+ });
107
+ }
108
+ /** Map a service failure onto the canonical envelope (unconfigured → 2, error → 1). */
109
+ function failureEnvelope(outcome, clock) {
110
+ return outcome.status === 'unconfigured'
111
+ ? formatUnconfigured('observe', outcome.next_action, clock)
112
+ : formatError('observe', outcome.code ?? ErrorCodes.UNKNOWN, outcome.message, clock, {
113
+ next_action: outcome.next_action,
114
+ });
115
+ }
116
+ /** Human-mode failure port (JSON mode uses the standard port). */
117
+ function portFor(io, what) {
118
+ return io.mode === 'json'
119
+ ? createOutputPort('json', io.writers)
120
+ : {
121
+ emit: (e) => {
122
+ io.writers.err(`harness observe: ${e.error?.message ?? e.next_action ?? 'failed'}\n`);
123
+ if (e.next_action)
124
+ io.writers.err(` → ${e.next_action}\n`);
125
+ io.writers.out(`observe (${what}): ${e.status}\n`);
126
+ },
127
+ };
128
+ }
129
+ //# sourceMappingURL=observe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observe.js","sourceRoot":"","sources":["../../src/acts/observe.ts"],"names":[],"mappings":"AAKA,OAAO,EAAiB,WAAW,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AACjG,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAc,gBAAgB,EAAmB,MAAM,0BAA0B,CAAC;AACzF,OAAO,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAChG,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,GAGjB,MAAM,wCAAwC,CAAC;AAqBhD;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAgB,EAAE,EAAS,EAAE,IAAoB;IAClF,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzD,OAAO;SACJ,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CACV,sFAAsF,CACvF;SACA,QAAQ,CAAC,eAAe,EAAE,yDAAyD,CAAC;SACpF,MAAM,CAAC,eAAe,EAAE,eAAe,KAAK,EAAE,CAAC;SAC/C,MAAM,CAAC,mBAAmB,EAAE,yDAAyD,CAAC;SACtF,MAAM,CAAC,uBAAuB,EAAE,aAAa,sBAAsB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;SAClF,MAAM,CAAC,qBAAqB,EAAE,6BAA6B,CAAC;SAC5D,MAAM,CAAC,6BAA6B,EAAE,0CAA0C,CAAC;SACjF,MAAM,CAAC,gBAAgB,EAAE,wDAAwD,CAAC;SAClF,MAAM,CAAC,QAAQ,EAAE,oDAAoD,CAAC;SACtE,MAAM,CAAC,SAAS,EAAE,oEAAoE,CAAC;SACvF,MAAM,CAAC,CAAC,WAA+B,EAAE,IAAiB,EAAE,EAAE;QAC7D,MAAM,WAAW,GAAgB,IAAI,CAAC;QAEtC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,MAAM,OAAO,GAAG,gBAAgB,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,WAAW,CAAC,CAAC;YACrE,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;gBAChB,gBAAgB,CAAC,eAAe,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;gBAC5E,OAAO;YACT,CAAC;YACD,MAAM,QAAQ,GAAG,QAAQ,CACvB,SAAS,EACT;gBACE,YAAY,EAAE,OAAO,CAAC,YAAY;gBAClC,eAAe,EAAE,OAAO,CAAC,eAAe;gBACxC,iBAAiB,EAAE,OAAO,CAAC,iBAAiB;aAC7C,EACD,IAAI,CAAC,KAAK,EACV;gBACE,WAAW,EACT,sFAAsF;aACzF,CACF,CAAC;YACF,MAAM,IAAI,GACR,EAAE,CAAC,IAAI,KAAK,MAAM;gBAChB,CAAC,CAAC,gBAAgB,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC;gBACtC,CAAC,CAAC;oBACE,IAAI,EAAE,GAAG,EAAE;wBACT,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;4BACrC,EAAE,CAAC,OAAO,CAAC,GAAG,CACZ,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,WAAW,IAAI,CACtF,CAAC;wBACJ,CAAC;wBACD,EAAE,CAAC,OAAO,CAAC,GAAG,CACZ,YAAY,OAAO,CAAC,YAAY,CAAC,MAAM,mBAAmB,OAAO,CAAC,eAAe,CAAC,MAAM,YAAY;4BAClG,GAAG,OAAO,CAAC,iBAAiB,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,iBAAiB,oBAAoB,CAAC,CAAC,CAAC,EAAE,IAAI,CACjG,CAAC;oBACJ,CAAC;iBACF,CAAC;YACR,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YACjC,OAAO;QACT,CAAC;QAED,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,iBAAiB,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,WAAW,CAAC,CAAC;YACtE,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;gBAChB,gBAAgB,CAAC,eAAe,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;gBAC7E,OAAO;YACT,CAAC;YACD,MAAM,QAAQ,GAAG,QAAQ,CACvB,SAAS,EACT;gBACE,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,eAAe,EAAE,OAAO,CAAC,eAAe;gBACxC,iBAAiB,EAAE,OAAO,CAAC,iBAAiB;aAC7C,EACD,IAAI,CAAC,KAAK,CACX,CAAC;YACF,MAAM,IAAI,GACR,EAAE,CAAC,IAAI,KAAK,MAAM;gBAChB,CAAC,CAAC,gBAAgB,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC;gBACtC,CAAC,CAAC;oBACE,IAAI,EAAE,GAAG,EAAE;wBACT,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,OAAO,CAAC,OAAO,gBAAgB,CAAC,CAAC;oBACtE,CAAC;iBACF,CAAC;YACR,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YACjC,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,kBAAkB,CAChC;YACE,WAAW;YACX,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;YACzC,KAAK,EAAE,IAAI,CAAC,KAAK;SAClB,EACD,WAAW,CACZ,CAAC;QACF,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;YAChB,gBAAgB,CAAC,eAAe,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC;YAC/E,OAAO;QACT,CAAC;QACD,MAAM,QAAQ,GAAG,QAAQ,CACvB,SAAS,EACT,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,EAClF,IAAI,CAAC,KAAK,EACV;YACE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;YAC/D,WAAW,EACT,gGAAgG;SACnG,CACF,CAAC;QACF,MAAM,IAAI,GACR,EAAE,CAAC,IAAI,KAAK,MAAM;YAChB,CAAC,CAAC,gBAAgB,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC;YACtC,CAAC,CAAC;gBACE,IAAI,EAAE,GAAG,EAAE;oBACT,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC;oBAC7D,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;gBAClC,CAAC;aACF,CAAC;QACR,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;AACP,CAAC;AAED,uFAAuF;AACvF,SAAS,eAAe,CAAC,OAAuB,EAAE,KAAY;IAC5D,OAAO,OAAO,CAAC,MAAM,KAAK,cAAc;QACtC,CAAC,CAAC,kBAAkB,CAAC,SAAS,EAAE,OAAO,CAAC,WAAW,EAAE,KAAK,CAAC;QAC3D,CAAC,CAAC,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,IAAI,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,KAAK,EAAE;YACjF,WAAW,EAAE,OAAO,CAAC,WAAW;SACjC,CAAC,CAAC;AACT,CAAC;AAED,kEAAkE;AAClE,SAAS,OAAO,CAAC,EAAS,EAAE,IAAY;IACtC,OAAO,EAAE,CAAC,IAAI,KAAK,MAAM;QACvB,CAAC,CAAC,gBAAgB,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC;QACtC,CAAC,CAAC;YACE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE;gBACV,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,KAAK,EAAE,OAAO,IAAI,CAAC,CAAC,WAAW,IAAI,QAAQ,IAAI,CAAC,CAAC;gBACtF,IAAI,CAAC,CAAC,WAAW;oBAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC;gBAC5D,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,MAAM,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC;YACrD,CAAC;SACF,CAAC;AACR,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { Command } from 'commander';
2
+ import type { Clock } from '../adapters/clock/clock-port.js';
3
+ import type { FsPort } from '../adapters/fs/fs-port.js';
4
+ import type { ProcessPort } from '../adapters/process/process-port.js';
5
+ import { type CliIo } from '../output/output-port.js';
6
+ import type { RecordRegistry } from '../services/record/registry.js';
7
+ /** The ports the `record` act injects into the record service (a subset of VerbActDeps). */
8
+ export interface RecordActDeps {
9
+ fs: FsPort;
10
+ proc: ProcessPort;
11
+ clock: Clock;
12
+ }
13
+ /**
14
+ * Register the `record` command — scaffolds a record file from a record type's
15
+ * template into `.harness/records/<type>/` and returns its path for the calling
16
+ * agent to fill. A CORE command (reserved, like `help`/`doctor`/`new`/`docs`/
17
+ * `skills`; runs even in `--no-extensions` mode). It owns no business logic — the
18
+ * `record-service` resolves the type + path + writes, and this act maps the
19
+ * outcome onto the Envelope + exit code (ok → 0, error → 1, unconfigured → 2).
20
+ *
21
+ * `harness record` (bare) and `harness record --list` both emit the orientation
22
+ * listing of available types (core ∪ extension), non-blocking, exit 0.
23
+ */
24
+ export declare function registerRecordAct(program: Command, io: CliIo, deps: RecordActDeps, registry: RecordRegistry): void;
@@ -0,0 +1,93 @@
1
+ import { formatError, formatOk, formatUnconfigured } from '../output/envelope.js';
2
+ import { ErrorCodes } from '../output/error-codes.js';
3
+ import { exitWithEnvelope } from '../output/exit.js';
4
+ import { createOutputPort } from '../output/output-port.js';
5
+ import { createRecord } from '../services/record/record-service.js';
6
+ /**
7
+ * Register the `record` command — scaffolds a record file from a record type's
8
+ * template into `.harness/records/<type>/` and returns its path for the calling
9
+ * agent to fill. A CORE command (reserved, like `help`/`doctor`/`new`/`docs`/
10
+ * `skills`; runs even in `--no-extensions` mode). It owns no business logic — the
11
+ * `record-service` resolves the type + path + writes, and this act maps the
12
+ * outcome onto the Envelope + exit code (ok → 0, error → 1, unconfigured → 2).
13
+ *
14
+ * `harness record` (bare) and `harness record --list` both emit the orientation
15
+ * listing of available types (core ∪ extension), non-blocking, exit 0.
16
+ */
17
+ export function registerRecordAct(program, io, deps, registry) {
18
+ program
19
+ .command('record')
20
+ .description('Scaffold a record file from a record type into .harness/records/<type>/ (returns its path)')
21
+ .argument('[type]', 'record type to create; omit (or use --list) to list available types')
22
+ .option('--slug <slug>', 'optional filename slug (lowercased to [a-z0-9-])')
23
+ .option('--list', 'list available record types (core ∪ extension)')
24
+ .action((type, opts) => {
25
+ if (opts.list || type === undefined) {
26
+ emitList(io, deps.clock, registry);
27
+ return;
28
+ }
29
+ const outcome = createRecord({ type, slug: opts.slug }, registry, deps);
30
+ if (outcome.ok) {
31
+ const envelope = formatOk('record', { type: outcome.type, path: outcome.path, source: outcome.source }, deps.clock, {
32
+ evidence: [{ label: `${outcome.type} record`, path: outcome.path }],
33
+ next_action: `Open and fill ${outcome.path}, then save.`,
34
+ });
35
+ const port = io.mode === 'json'
36
+ ? createOutputPort('json', io.writers)
37
+ : {
38
+ emit: () => {
39
+ io.writers.out(`Created ${outcome.path}\n`);
40
+ io.writers.out('record: ok\n');
41
+ },
42
+ };
43
+ exitWithEnvelope(envelope, port);
44
+ return;
45
+ }
46
+ const envelope = outcome.status === 'unconfigured'
47
+ ? formatUnconfigured('record', outcome.next_action, deps.clock)
48
+ : formatError('record', outcome.code ?? ErrorCodes.UNKNOWN, outcome.message, deps.clock, {
49
+ next_action: outcome.next_action,
50
+ });
51
+ const port = io.mode === 'json'
52
+ ? createOutputPort('json', io.writers)
53
+ : {
54
+ emit: (e) => {
55
+ io.writers.err(`harness record: ${e.error?.message ?? e.next_action ?? 'failed'}\n`);
56
+ if (e.next_action)
57
+ io.writers.err(` → ${e.next_action}\n`);
58
+ io.writers.out(`record: ${e.status}\n`);
59
+ },
60
+ };
61
+ exitWithEnvelope(envelope, port);
62
+ });
63
+ }
64
+ /** Emit the orientation listing of available record types (core ∪ extension). */
65
+ function emitList(io, clock, registry) {
66
+ const types = registry.types.map((t) => ({
67
+ type: t.type,
68
+ description: t.description,
69
+ source: t.source,
70
+ ...(t.entryPath && { entryPath: t.entryPath }),
71
+ }));
72
+ const envelope = formatOk('record', { types }, clock, {
73
+ next_action: 'Create one with `harness record <type> --slug "<name>"`.',
74
+ });
75
+ const port = io.mode === 'json'
76
+ ? createOutputPort('json', io.writers)
77
+ : { emit: () => io.writers.out(renderListText(registry)) };
78
+ exitWithEnvelope(envelope, port);
79
+ }
80
+ /** Human-readable listing of record types. */
81
+ function renderListText(registry) {
82
+ const lines = ['harness record — available types:'];
83
+ if (registry.types.length === 0) {
84
+ lines.push(' (none)');
85
+ }
86
+ for (const t of registry.types) {
87
+ const provenance = t.source === 'extension' ? `[extension] ${t.entryPath ?? ''}`.trim() : '[core]';
88
+ lines.push(` • ${t.type}\t${t.description}\t${provenance}`);
89
+ }
90
+ lines.push('', ' harness record <type> [--slug "<name>"]');
91
+ return `${lines.join('\n')}\n`;
92
+ }
93
+ //# sourceMappingURL=record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record.js","sourceRoot":"","sources":["../../src/acts/record.ts"],"names":[],"mappings":"AAIA,OAAO,EAAiB,WAAW,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AACjG,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAc,gBAAgB,EAAmB,MAAM,0BAA0B,CAAC;AACzF,OAAO,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAepE;;;;;;;;;;GAUG;AACH,MAAM,UAAU,iBAAiB,CAC/B,OAAgB,EAChB,EAAS,EACT,IAAmB,EACnB,QAAwB;IAExB,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CACV,4FAA4F,CAC7F;SACA,QAAQ,CAAC,QAAQ,EAAE,qEAAqE,CAAC;SACzF,MAAM,CAAC,eAAe,EAAE,kDAAkD,CAAC;SAC3E,MAAM,CAAC,QAAQ,EAAE,gDAAgD,CAAC;SAClE,MAAM,CAAC,CAAC,IAAwB,EAAE,IAAgB,EAAE,EAAE;QACrD,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACpC,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YACnC,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,YAAY,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;QAExE,IAAI,OAAO,CAAC,EAAE,EAAE,CAAC;YACf,MAAM,QAAQ,GAAG,QAAQ,CACvB,QAAQ,EACR,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,EAClE,IAAI,CAAC,KAAK,EACV;gBACE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC,IAAI,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;gBACnE,WAAW,EAAE,iBAAiB,OAAO,CAAC,IAAI,cAAc;aACzD,CACF,CAAC;YACF,MAAM,IAAI,GACR,EAAE,CAAC,IAAI,KAAK,MAAM;gBAChB,CAAC,CAAC,gBAAgB,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC;gBACtC,CAAC,CAAC;oBACE,IAAI,EAAE,GAAG,EAAE;wBACT,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC;wBAC5C,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;oBACjC,CAAC;iBACF,CAAC;YACR,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YACjC,OAAO;QACT,CAAC;QAED,MAAM,QAAQ,GACZ,OAAO,CAAC,MAAM,KAAK,cAAc;YAC/B,CAAC,CAAC,kBAAkB,CAAC,QAAQ,EAAE,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC;YAC/D,CAAC,CAAC,WAAW,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,IAAI,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,EAAE;gBACrF,WAAW,EAAE,OAAO,CAAC,WAAW;aACjC,CAAC,CAAC;QACT,MAAM,IAAI,GACR,EAAE,CAAC,IAAI,KAAK,MAAM;YAChB,CAAC,CAAC,gBAAgB,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC;YACtC,CAAC,CAAC;gBACE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE;oBACV,EAAE,CAAC,OAAO,CAAC,GAAG,CACZ,mBAAmB,CAAC,CAAC,KAAK,EAAE,OAAO,IAAI,CAAC,CAAC,WAAW,IAAI,QAAQ,IAAI,CACrE,CAAC;oBACF,IAAI,CAAC,CAAC,WAAW;wBAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC;oBAC5D,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC;gBAC1C,CAAC;aACF,CAAC;QACR,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;AACP,CAAC;AAED,iFAAiF;AACjF,SAAS,QAAQ,CAAC,EAAS,EAAE,KAAY,EAAE,QAAwB;IACjE,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACvC,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,GAAG,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC;KAC/C,CAAC,CAAC,CAAC;IACJ,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE;QACpD,WAAW,EAAE,0DAA0D;KACxE,CAAC,CAAC;IACH,MAAM,IAAI,GACR,EAAE,CAAC,IAAI,KAAK,MAAM;QAChB,CAAC,CAAC,gBAAgB,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC;QACtC,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;IAC/D,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;AACnC,CAAC;AAED,8CAA8C;AAC9C,SAAS,cAAc,CAAC,QAAwB;IAC9C,MAAM,KAAK,GAAa,CAAC,mCAAmC,CAAC,CAAC;IAC9D,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACzB,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;QAC/B,MAAM,UAAU,GACd,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,SAAS,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;QAClF,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,WAAW,KAAK,UAAU,EAAE,CAAC,CAAC;IAC/D,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,2CAA2C,CAAC,CAAC;IAC5D,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AACjC,CAAC"}
@@ -0,0 +1,32 @@
1
+ import type { Command } from 'commander';
2
+ import type { Clock } from '../adapters/clock/clock-port.js';
3
+ import type { ExecPort } from '../adapters/exec/exec-port.js';
4
+ import type { ProcessPort } from '../adapters/process/process-port.js';
5
+ import { type CliIo } from '../output/output-port.js';
6
+ /** The ports the `skills` act injects — a subset of VerbActDeps (no fs/git/env needed). */
7
+ export interface SkillsActDeps {
8
+ exec: ExecPort;
9
+ proc: ProcessPort;
10
+ clock: Clock;
11
+ }
12
+ /**
13
+ * Register the `skills` command + its `install` subcommand — a first-class CORE
14
+ * capability (reserved, like `help`/`doctor`/`new`/`docs`; it ships with the
15
+ * published CLI so the harness can install its own skills in any repo). It owns
16
+ * no install logic: it is a transparent PASS-THROUGH to Vercel's `npx skills add`
17
+ * (Principle 8, wrap-don't-rebuild — that tool already owns the CLI-target × scope
18
+ * matrix). The act:
19
+ * - builds the exact argv with the pure `buildInstallArgv` (always `-y`, so the
20
+ * blocking interactive picker never appears);
21
+ * - **announces the exact `npx …` command before running it** — to stderr in
22
+ * human mode, and inside the envelope (`data.command` + `next_action`) in JSON
23
+ * mode, so the `--json` stdout stays a single parseable envelope (Principle 4);
24
+ * - shells out ONLY through the injected `ExecPort` (no direct child/shell);
25
+ * - maps the result onto an Envelope + exit code (ok → 0, `E170` → 1).
26
+ *
27
+ * Targets are flags, not a blocking prompt: the harness CLI is agent-first and
28
+ * non-blocking, so a missing `--target` returns `E108` with a `next_action` that
29
+ * enumerates the valid targets. The *skill* (`eng-harness-0-adopt`) is what asks
30
+ * the user, then runs this with flags.
31
+ */
32
+ export declare function registerSkillsAct(program: Command, io: CliIo, deps: SkillsActDeps): void;