@open-agent-toolkit/cli 0.2.72 → 0.2.74

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 (165) hide show
  1. package/assets/agents/oat-reviewer.md +4 -3
  2. package/assets/agents/recon-worker.md +42 -8
  3. package/assets/bundle-metadata.json +1 -1
  4. package/assets/docs/cli-utilities/configuration.md +3 -56
  5. package/assets/docs/cli-utilities/tool-packs.md +4 -4
  6. package/assets/docs/contributing/code.md +2 -2
  7. package/assets/docs/contributing/index.md +0 -1
  8. package/assets/docs/reference/cli-reference.md +1 -1
  9. package/assets/docs/reference/troubleshooting.md +17 -40
  10. package/assets/docs/workflows/projects/artifacts.md +16 -34
  11. package/assets/docs/workflows/projects/lifecycle.md +20 -19
  12. package/assets/docs/workflows/skills/explainer-kit.md +180 -440
  13. package/assets/docs/workflows/skills/index.md +1 -2
  14. package/assets/docs/workflows/skills/recon.md +114 -23
  15. package/assets/public-package-versions.json +4 -4
  16. package/assets/skills/explainer-kit/SKILL.md +96 -171
  17. package/assets/skills/explainer-kit/recipes/engineer-tour.json +1 -22
  18. package/assets/skills/explainer-kit/recipes/program-recap.json +1 -29
  19. package/assets/skills/explainer-kit/recipes/project-explainer.json +1 -22
  20. package/assets/skills/explainer-kit/recipes/project-recap.v2.json +1 -43
  21. package/assets/skills/explainer-kit/references/fact-base-contract.md +76 -101
  22. package/assets/skills/explainer-kit/references/recap-authoring.md +99 -0
  23. package/assets/skills/explainer-kit/schemas/manifest.schema.json +13 -135
  24. package/assets/skills/explainer-kit/scripts/bundle.mjs +712 -0
  25. package/assets/skills/explainer-kit/scripts/lib/claim-subject.mjs +40 -0
  26. package/assets/skills/explainer-kit/scripts/lib/contracts.mjs +113 -1504
  27. package/assets/skills/explainer-kit/scripts/lib/failure.mjs +13 -0
  28. package/assets/skills/explainer-kit/scripts/lib/package-coverage.mjs +57 -403
  29. package/assets/skills/explainer-kit/scripts/lib/qa-result.mjs +168 -0
  30. package/assets/skills/explainer-kit/scripts/lib/qa.mjs +90 -488
  31. package/assets/skills/explainer-kit/scripts/lib/recipes.mjs +28 -545
  32. package/assets/skills/explainer-kit/scripts/lib/run-package.mjs +120 -0
  33. package/assets/skills/explainer-kit/scripts/lib/sanitize.mjs +42 -0
  34. package/assets/skills/explainer-kit/scripts/record.mjs +335 -0
  35. package/assets/skills/explainer-kit/scripts/verify.mjs +648 -0
  36. package/assets/skills/oat-explainer-kit/SKILL.md +57 -117
  37. package/assets/skills/oat-explainer-kit/references/config-contract.md +20 -64
  38. package/assets/skills/oat-explainer-kit/references/lifecycle-contract.md +85 -237
  39. package/assets/skills/oat-explainer-kit/scripts/bind-project-sources.mjs +18 -10
  40. package/assets/skills/oat-explainer-kit/scripts/check-core.mjs +1 -0
  41. package/assets/skills/oat-explainer-kit/scripts/check-terminal-outcome.mjs +256 -21
  42. package/assets/skills/oat-explainer-kit/scripts/persist-intent.mjs +82 -3
  43. package/assets/skills/oat-explainer-kit/scripts/resolve-config.mjs +0 -162
  44. package/assets/skills/oat-explainer-kit/scripts/resolve-intent.mjs +57 -123
  45. package/assets/skills/oat-project-autonomous/SKILL.md +14 -13
  46. package/assets/skills/oat-project-autonomous/references/gate-inventory.md +165 -165
  47. package/assets/skills/oat-project-complete/SKILL.md +168 -349
  48. package/assets/skills/oat-project-complete/scripts/consume-persisted-recap-intent.mjs +125 -0
  49. package/assets/skills/oat-project-complete/scripts/execute-synced-archive-entry.mjs +0 -30
  50. package/assets/skills/oat-project-complete/scripts/parse-completion-retry-fields.mjs +4 -37
  51. package/assets/skills/oat-project-complete/scripts/parse-synced-archive-resume-fields.mjs +17 -16
  52. package/assets/skills/oat-project-complete/scripts/recover-completion-receipts.mjs +9 -174
  53. package/assets/skills/oat-project-complete/scripts/resolve-completion-retry.mjs +1 -2
  54. package/assets/skills/oat-project-document/SKILL.md +1 -1
  55. package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +165 -165
  56. package/assets/skills/oat-project-implement/SKILL.md +1 -1
  57. package/assets/skills/oat-project-implement/references/completion-and-closeout.md +44 -56
  58. package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +165 -165
  59. package/assets/skills/oat-project-lite/SKILL.md +1 -1
  60. package/assets/skills/oat-project-lite/references/docs/autonomy-contract.md +165 -165
  61. package/assets/skills/oat-project-plan/SKILL.md +5 -6
  62. package/assets/skills/oat-project-pr-final/SKILL.md +1 -1
  63. package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +165 -165
  64. package/assets/skills/oat-project-quick-start/SKILL.md +1 -1
  65. package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +165 -165
  66. package/assets/skills/oat-project-review-receive/SKILL.md +14 -1
  67. package/assets/skills/oat-project-summary/SKILL.md +35 -25
  68. package/assets/skills/oat-wave-execute/SKILL.md +11 -36
  69. package/assets/skills/oat-wave-program/SKILL.md +13 -37
  70. package/assets/skills/recon/SKILL.md +103 -40
  71. package/assets/skills/recon/references/packet-contract.md +150 -67
  72. package/assets/skills/recon/references/profiles.md +38 -16
  73. package/assets/skills/recon/references/worker-contract.md +39 -8
  74. package/assets/skills/recon/scripts/lib/contracts.mjs +703 -55
  75. package/assets/skills/recon/scripts/lib/routing.mjs +588 -0
  76. package/assets/skills/recon/scripts/lib/validated-run.mjs +2 -0
  77. package/assets/skills/recon/scripts/prepare-routing.mjs +88 -0
  78. package/assets/skills/recon/scripts/render-packet.mjs +69 -1
  79. package/assets/skills/recon/scripts/validate-packet.mjs +473 -56
  80. package/assets/skills/subagent-orchestration/SKILL.md +18 -9
  81. package/assets/skills/subagent-orchestration/references/model-selection-principles.md +17 -8
  82. package/dist/commands/config/index.d.ts.map +1 -1
  83. package/dist/commands/config/index.js +9 -113
  84. package/dist/commands/project/archive/archive-utils.d.ts.map +1 -1
  85. package/dist/commands/project/archive/archive-utils.js +32 -184
  86. package/dist/commands/project/archive/explainer-package-coverage.d.ts +3 -8
  87. package/dist/commands/project/archive/explainer-package-coverage.d.ts.map +1 -1
  88. package/dist/commands/project/archive/explainer-package-coverage.js +1 -1
  89. package/dist/config/oat-config.d.ts +0 -11
  90. package/dist/config/oat-config.d.ts.map +1 -1
  91. package/dist/config/oat-config.js +0 -34
  92. package/dist/config/resolve.d.ts.map +1 -1
  93. package/dist/config/resolve.js +0 -8
  94. package/dist/release/public-package-contract.d.ts.map +1 -1
  95. package/dist/release/public-package-contract.js +2 -10
  96. package/dist/validation/project-state.d.ts.map +1 -1
  97. package/dist/validation/project-state.js +42 -3
  98. package/package.json +2 -2
  99. package/assets/docs/contributing/explainer-kit-verification.md +0 -133
  100. package/assets/docs/workflows/skills/explainer-kit-providers.md +0 -155
  101. package/assets/skills/explainer-kit/briefs/deep-dive.md +0 -35
  102. package/assets/skills/explainer-kit/briefs/project-page.md +0 -38
  103. package/assets/skills/explainer-kit/briefs/supporting-diagram.md +0 -28
  104. package/assets/skills/explainer-kit/briefs/walkthrough-deck.md +0 -35
  105. package/assets/skills/explainer-kit/examples/project-explainer/content.md +0 -31
  106. package/assets/skills/explainer-kit/examples/project-explainer/fact-base.md +0 -22
  107. package/assets/skills/explainer-kit/examples/project-recap/content.md +0 -77
  108. package/assets/skills/explainer-kit/examples/project-recap/fact-base.json +0 -104
  109. package/assets/skills/explainer-kit/examples/project-recap/fact-base.md +0 -44
  110. package/assets/skills/explainer-kit/examples/theme-bundle.json +0 -87
  111. package/assets/skills/explainer-kit/recipes/project-recap.v1.json +0 -93
  112. package/assets/skills/explainer-kit/references/contracts.md +0 -324
  113. package/assets/skills/explainer-kit/references/destination-contract.md +0 -210
  114. package/assets/skills/explainer-kit/references/extension-contract.md +0 -80
  115. package/assets/skills/explainer-kit/references/golden-conformance.md +0 -80
  116. package/assets/skills/explainer-kit/references/visual-review.md +0 -71
  117. package/assets/skills/explainer-kit/schemas/author-request.v2.schema.json +0 -212
  118. package/assets/skills/explainer-kit/schemas/author-request.v3.schema.json +0 -241
  119. package/assets/skills/explainer-kit/schemas/author-result.v2.schema.json +0 -52
  120. package/assets/skills/explainer-kit/schemas/build-record.schema.json +0 -98
  121. package/assets/skills/explainer-kit/schemas/durability-evidence.schema.json +0 -53
  122. package/assets/skills/explainer-kit/schemas/publish-receipt.v1.schema.json +0 -97
  123. package/assets/skills/explainer-kit/schemas/publish-receipt.v2.schema.json +0 -215
  124. package/assets/skills/explainer-kit/schemas/publish-request.v1.schema.json +0 -32
  125. package/assets/skills/explainer-kit/schemas/publish-request.v2.schema.json +0 -34
  126. package/assets/skills/explainer-kit/schemas/run-request.schema.json +0 -147
  127. package/assets/skills/explainer-kit/schemas/set-plan.v1.schema.json +0 -149
  128. package/assets/skills/explainer-kit/schemas/terminal-evidence.v1.schema.json +0 -81
  129. package/assets/skills/explainer-kit/schemas/visual-review-evidence.v1.schema.json +0 -66
  130. package/assets/skills/explainer-kit/schemas/visual-review-request.v1.schema.json +0 -117
  131. package/assets/skills/explainer-kit/schemas/visual-review-result.v1.schema.json +0 -80
  132. package/assets/skills/explainer-kit/scripts/lib/catalog.mjs +0 -349
  133. package/assets/skills/explainer-kit/scripts/lib/content-approval.mjs +0 -418
  134. package/assets/skills/explainer-kit/scripts/lib/diagram.mjs +0 -514
  135. package/assets/skills/explainer-kit/scripts/lib/durability.mjs +0 -643
  136. package/assets/skills/explainer-kit/scripts/lib/fact-base.mjs +0 -664
  137. package/assets/skills/explainer-kit/scripts/lib/internal-references.mjs +0 -538
  138. package/assets/skills/explainer-kit/scripts/lib/markdown.mjs +0 -414
  139. package/assets/skills/explainer-kit/scripts/lib/publication-policy.mjs +0 -54
  140. package/assets/skills/explainer-kit/scripts/lib/records.mjs +0 -954
  141. package/assets/skills/explainer-kit/scripts/lib/render.mjs +0 -703
  142. package/assets/skills/explainer-kit/scripts/lib/s3-roots.mjs +0 -353
  143. package/assets/skills/explainer-kit/scripts/lib/s3-static.mjs +0 -759
  144. package/assets/skills/explainer-kit/scripts/lib/set-plan.mjs +0 -209
  145. package/assets/skills/explainer-kit/scripts/lib/source-backlinks.mjs +0 -218
  146. package/assets/skills/explainer-kit/scripts/lib/terminal-evidence.mjs +0 -157
  147. package/assets/skills/explainer-kit/scripts/lib/visual-review.mjs +0 -400
  148. package/assets/skills/explainer-kit/scripts/publish.mjs +0 -76
  149. package/assets/skills/explainer-kit/scripts/record-durability.mjs +0 -64
  150. package/assets/skills/explainer-kit/scripts/render-qa.mjs +0 -461
  151. package/assets/skills/explainer-kit/scripts/run.mjs +0 -3038
  152. package/assets/skills/explainer-kit/scripts/validate.mjs +0 -59
  153. package/assets/skills/oat-explainer-kit/references/author-callback.md +0 -53
  154. package/assets/skills/oat-explainer-kit/references/migration.md +0 -144
  155. package/assets/skills/oat-explainer-kit/references/visual-review-callback.md +0 -83
  156. package/assets/skills/oat-explainer-kit/scripts/derive-destination.mjs +0 -91
  157. package/assets/skills/oat-explainer-kit/scripts/finalize-tracked-run.mjs +0 -531
  158. package/assets/skills/oat-explainer-kit/scripts/probe-recap-seams.mjs +0 -371
  159. package/assets/skills/oat-explainer-kit/scripts/run.mjs +0 -905
  160. package/dist/commands/project/archive/explainer-source-backlinks.d.ts +0 -18
  161. package/dist/commands/project/archive/explainer-source-backlinks.d.ts.map +0 -1
  162. package/dist/commands/project/archive/explainer-source-backlinks.js +0 -27
  163. package/dist/commands/project/archive/explainer-terminal-evidence.d.ts +0 -29
  164. package/dist/commands/project/archive/explainer-terminal-evidence.d.ts.map +0 -1
  165. package/dist/commands/project/archive/explainer-terminal-evidence.js +0 -37
@@ -1,371 +0,0 @@
1
- /**
2
- * Pre-flight capability probe for the provider-neutral seams a lifecycle
3
- * `project-recap` run requires.
4
- *
5
- * The probe is pure: it inspects only the inputs a caller would hand to
6
- * `runOatExplainer`, applying the same resolution and exclusivity rules
7
- * `scripts/run.mjs` applies at runtime. It never imports a module, calls a
8
- * callback, validates a browser-session brand, or touches the filesystem.
9
- *
10
- * Three outcomes are kept distinct and are never conflated:
11
- *
12
- * - `missing` — no provider is supplied for a seam this mode requires. This is
13
- * the only outcome that may become a recordable `skip` / `capability_probe`
14
- * intent (`code: 'seams-unavailable'`).
15
- * - `invalid` — a seam is supplied but violates a resolution rule (both a
16
- * callback and a module path, a non-function callback, an empty module path,
17
- * or an unsupported `coreOptions` route). It fails closed with the same
18
- * message the runtime would raise (`code: 'seams-invalid'`) and is never a
19
- * skip.
20
- * - runtime failure — an unloadable module, a non-function export, an unbranded
21
- * browser session, or a failed generation. The probe never observes these
22
- * because it never loads or calls anything, so a failed run after a passing
23
- * probe stays `failed`.
24
- *
25
- * Each seam has its own classifier that mirrors its `run.mjs` resolver check by
26
- * check and in the same order, because the resolvers do not share one order:
27
- * `resolveLifecycleCritic` counts only function/truthy candidates before it
28
- * type-checks, while the author, visual critic, and set planner type-check the
29
- * callback before they reject a direct-plus-module conflict. Keep each
30
- * classifier aligned with the resolver named in its comment.
31
- */
32
-
33
- const MODES = new Set(['interactive', 'unattended']);
34
-
35
- const isSet = (value) => value !== undefined;
36
-
37
- const invalid = (reason, message) => ({ status: 'invalid', reason, message });
38
- const supplied = () => ({ status: 'supplied' });
39
- const absent = () => ({ status: 'absent' });
40
-
41
- function badModulePath(value) {
42
- return typeof value !== 'string' || value.trim().length === 0;
43
- }
44
-
45
- /** Mirrors `run.mjs#resolveLifecycleAuthor`. */
46
- function classifyAuthor({ author, authorModulePath }, coreOptions) {
47
- if (isSet(coreOptions.author)) {
48
- return invalid(
49
- 'unsupported-core-option',
50
- 'coreOptions.author is not supported at the OAT adapter boundary; supply author directly.',
51
- );
52
- }
53
- if (isSet(author) && typeof author !== 'function') {
54
- return invalid(
55
- 'callback-not-a-function',
56
- 'author must be a function when supplied.',
57
- );
58
- }
59
- if (isSet(author) && isSet(authorModulePath)) {
60
- return invalid(
61
- 'multiple-sources',
62
- 'Supply only one provider-neutral author callback or author module entry point.',
63
- );
64
- }
65
- if (!isSet(author) && !isSet(authorModulePath)) return absent();
66
- if (isSet(authorModulePath) && badModulePath(authorModulePath)) {
67
- return invalid(
68
- 'empty-module-path',
69
- 'authorModulePath must be a non-empty path.',
70
- );
71
- }
72
- return supplied();
73
- }
74
-
75
- /**
76
- * Mirrors `run.mjs#resolveLifecycleCritic`.
77
- *
78
- * `resolveLifecycleCritic` returns `null` rather than throwing when no critic is
79
- * supplied, so treating the critic as required looks stricter than the adapter
80
- * resolver in isolation. It is not, for the runs this probe serves: an
81
- * artifact-bound lifecycle closeout recap passes no `suppliedFactBasePath`, so
82
- * `bindProjectSources` binds it `factBase.mode: 'federated'`
83
- * (`bind-project-sources.mjs`), and the core throws for a federated fact base
84
- * with no critic (`explainer-kit/scripts/lib/fact-base.mjs`). Such a host cannot
85
- * produce a recap today; probing the critic turns that mid-run core failure into
86
- * a pre-flight capability skip. (A `supplied` fact base is a different
87
- * invocation path and does skip the core's critic check, but no lifecycle recap
88
- * caller uses it.) Do not "fix" this to match `resolveLifecycleCritic` — that
89
- * would reintroduce an unrunnable recap.
90
- */
91
- function classifyCritic({ critic, criticModulePath }, coreOptions) {
92
- // The runtime counts only candidates that already look usable, so a
93
- // non-function callback beside a module path is a type error rather than a
94
- // conflict.
95
- const candidates = [
96
- typeof critic === 'function' ? critic : null,
97
- typeof coreOptions.critic === 'function' ? coreOptions.critic : null,
98
- criticModulePath ? criticModulePath : null,
99
- ].filter(Boolean);
100
- if (candidates.length > 1) {
101
- return invalid(
102
- 'multiple-sources',
103
- 'Supply only one provider-neutral critic callback or critic module entry point.',
104
- );
105
- }
106
- if (isSet(critic) && typeof critic !== 'function') {
107
- return invalid(
108
- 'callback-not-a-function',
109
- 'critic must be a function when supplied.',
110
- );
111
- }
112
- if (isSet(coreOptions.critic) && typeof coreOptions.critic !== 'function') {
113
- return invalid(
114
- 'callback-not-a-function',
115
- 'coreOptions.critic must be a function when supplied.',
116
- );
117
- }
118
- if (isSet(criticModulePath)) {
119
- return badModulePath(criticModulePath)
120
- ? invalid(
121
- 'empty-module-path',
122
- 'criticModulePath must be a non-empty path.',
123
- )
124
- : supplied();
125
- }
126
- // `coreOptions.critic` is the documented compatibility route, so it satisfies
127
- // the seam rather than invalidating it.
128
- return (critic ?? coreOptions.critic) ? supplied() : absent();
129
- }
130
-
131
- /** Mirrors `run.mjs#resolveLifecycleBrowserSession`. */
132
- function classifyBrowserSession(
133
- {
134
- browserSession,
135
- browserSessionModulePath,
136
- browserProbe,
137
- browserProbeModulePath,
138
- },
139
- coreOptions,
140
- ) {
141
- if (isSet(coreOptions.browserProbe)) {
142
- return invalid(
143
- 'unsupported-core-option',
144
- 'coreOptions.browserProbe is not supported at the OAT adapter boundary; supply browserSession directly.',
145
- );
146
- }
147
- if (isSet(browserProbe) || isSet(browserProbeModulePath)) {
148
- return invalid(
149
- 'unsupported-input',
150
- 'Bare browserProbe callbacks are not supported at the OAT adapter boundary; supply a branded browserSession created by createBrowserProbeSession().',
151
- );
152
- }
153
- if (isSet(coreOptions.browserSession)) {
154
- return invalid(
155
- 'unsupported-core-option',
156
- 'coreOptions.browserSession is not supported at the OAT adapter boundary; supply browserSession directly.',
157
- );
158
- }
159
- if (isSet(browserSession) && isSet(browserSessionModulePath)) {
160
- return invalid(
161
- 'multiple-sources',
162
- 'Supply only one browser session descriptor or browser session module entry point.',
163
- );
164
- }
165
- if (isSet(browserSessionModulePath)) {
166
- return badModulePath(browserSessionModulePath)
167
- ? invalid(
168
- 'empty-module-path',
169
- 'browserSessionModulePath must be a non-empty path.',
170
- )
171
- : supplied();
172
- }
173
- // A browser session is a descriptor the runtime resolves by truthiness, so a
174
- // falsy one raises the same "requires exactly one" error as supplying none.
175
- // Classifying it invalid would fail the unattended completion this probe
176
- // exists to unblock.
177
- return browserSession ? supplied() : absent();
178
- }
179
-
180
- /** Mirrors `run.mjs#resolveLifecycleVisualCritic` and `resolveProviderCallback`. */
181
- function classifyVisualCritic(
182
- { visualCritic, visualCriticModulePath },
183
- coreOptions,
184
- ) {
185
- if (isSet(coreOptions.visualCritic)) {
186
- return invalid(
187
- 'unsupported-core-option',
188
- 'coreOptions.visualCritic is not supported at the OAT adapter boundary; supply visualCritic directly.',
189
- );
190
- }
191
- if (isSet(visualCritic) && typeof visualCritic !== 'function') {
192
- return invalid(
193
- 'callback-not-a-function',
194
- 'visualCritic must be a function when supplied.',
195
- );
196
- }
197
- if (isSet(visualCritic) && isSet(visualCriticModulePath)) {
198
- return invalid(
199
- 'multiple-sources',
200
- 'Supply only one provider-neutral visual critic callback or visual critic module entry point.',
201
- );
202
- }
203
- if (!isSet(visualCriticModulePath)) {
204
- return visualCritic ? supplied() : absent();
205
- }
206
- return badModulePath(visualCriticModulePath)
207
- ? invalid(
208
- 'empty-module-path',
209
- 'visualCriticModulePath must be a non-empty path.',
210
- )
211
- : supplied();
212
- }
213
-
214
- /** Mirrors `run.mjs#resolveLifecycleSetPlanner`. */
215
- function classifyPlanSet({ planSet, planSetModulePath }, coreOptions) {
216
- if (isSet(coreOptions.planSet)) {
217
- return invalid(
218
- 'unsupported-core-option',
219
- 'coreOptions.planSet is not supported at the OAT adapter boundary; supply planSet directly.',
220
- );
221
- }
222
- if (isSet(planSet) && typeof planSet !== 'function') {
223
- return invalid(
224
- 'callback-not-a-function',
225
- 'planSet must be a function when supplied.',
226
- );
227
- }
228
- if (isSet(planSet) && isSet(planSetModulePath)) {
229
- return invalid(
230
- 'multiple-sources',
231
- 'Supply only one provider-neutral set planner callback or set planner module entry point.',
232
- );
233
- }
234
- if (!isSet(planSet) && !isSet(planSetModulePath)) return absent();
235
- if (isSet(planSetModulePath) && badModulePath(planSetModulePath)) {
236
- return invalid(
237
- 'empty-module-path',
238
- 'planSetModulePath must be a non-empty path.',
239
- );
240
- }
241
- return supplied();
242
- }
243
-
244
- /**
245
- * The five seams an unattended `project-recap` requires, in report order.
246
- *
247
- * `requiredIn` mirrors the adapter contract: the author and the fact critic are
248
- * required by every federated adapter run, while the browser session, visual
249
- * critic, and set planner are required only for unattended project recaps.
250
- */
251
- const SEAMS = [
252
- {
253
- id: 'author',
254
- requiredIn: ['interactive', 'unattended'],
255
- classify: classifyAuthor,
256
- },
257
- {
258
- id: 'critic',
259
- requiredIn: ['interactive', 'unattended'],
260
- classify: classifyCritic,
261
- },
262
- {
263
- id: 'browserSession',
264
- requiredIn: ['unattended'],
265
- classify: classifyBrowserSession,
266
- },
267
- {
268
- id: 'visualCritic',
269
- requiredIn: ['unattended'],
270
- classify: classifyVisualCritic,
271
- },
272
- {
273
- id: 'planSet',
274
- requiredIn: ['unattended'],
275
- classify: classifyPlanSet,
276
- },
277
- ];
278
-
279
- export const RECAP_SEAM_IDS = Object.freeze(SEAMS.map((seam) => seam.id));
280
- export const RECAP_PROBE_CODES = Object.freeze([
281
- 'seams-ok',
282
- 'seams-unavailable',
283
- 'seams-invalid',
284
- ]);
285
-
286
- export function probeRecapSeams(inputs = {}) {
287
- if (!inputs || typeof inputs !== 'object' || Array.isArray(inputs)) {
288
- throw new TypeError('Seam probe inputs must be an object.');
289
- }
290
- const { mode = 'unattended', coreOptions = {} } = inputs;
291
- if (!MODES.has(mode)) {
292
- throw new Error(`Unsupported lifecycle mode: ${String(mode)}`);
293
- }
294
- if (!coreOptions || typeof coreOptions !== 'object') {
295
- throw new TypeError('coreOptions must be an object when supplied.');
296
- }
297
-
298
- const missing = [];
299
- const invalidSeams = [];
300
- const resolved = [];
301
-
302
- for (const seam of SEAMS) {
303
- const outcome = seam.classify(inputs, coreOptions);
304
- if (outcome.status === 'invalid') {
305
- invalidSeams.push({
306
- seam: seam.id,
307
- reason: outcome.reason,
308
- message: outcome.message,
309
- });
310
- } else if (outcome.status === 'supplied') {
311
- resolved.push(seam.id);
312
- } else if (seam.requiredIn.includes(mode)) {
313
- missing.push(seam.id);
314
- }
315
- }
316
-
317
- // Invalid outranks missing: a broken configuration must fail closed rather
318
- // than degrade into a capability skip.
319
- if (invalidSeams.length > 0) {
320
- return {
321
- ok: false,
322
- mode,
323
- code: 'seams-invalid',
324
- missing,
325
- invalid: invalidSeams,
326
- resolved,
327
- message: `Recap seam configuration is invalid: ${invalidSeams
328
- .map((entry) => entry.message)
329
- .join(' ')}`,
330
- guidance:
331
- 'Correct the reported seam configuration. A configured-but-invalid seam fails closed and is never a capability skip.',
332
- };
333
- }
334
-
335
- if (missing.length > 0) {
336
- return {
337
- ok: false,
338
- mode,
339
- code: 'seams-unavailable',
340
- missing,
341
- invalid: invalidSeams,
342
- resolved,
343
- message: `No provider is configured for ${formatList(missing)}, so ${article(mode)} ${mode} project recap cannot run on this host.`,
344
- guidance:
345
- mode === 'unattended'
346
- ? `Configure ${formatList(missing)} to generate an unattended project recap, or let autonomous resolution record the recap as skip / capability_probe.`
347
- : `Configure ${formatList(missing)} to generate an interactive project recap, or record an interactive skip decision.`,
348
- };
349
- }
350
-
351
- return {
352
- ok: true,
353
- mode,
354
- code: 'seams-ok',
355
- missing,
356
- invalid: invalidSeams,
357
- resolved,
358
- message: `Every ${mode} project recap seam resolves on this host.`,
359
- guidance: null,
360
- };
361
- }
362
-
363
- /** `unattended` and `interactive` both take "an"; keep the surface grammatical. */
364
- function article(mode) {
365
- return /^[aeiou]/i.test(mode) ? 'an' : 'a';
366
- }
367
-
368
- function formatList(values) {
369
- if (values.length === 1) return values[0];
370
- return `${values.slice(0, -1).join(', ')} and ${values.at(-1)}`;
371
- }