orchestrator-workflow 0.27.0 → 0.28.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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.28.0] - 2026-09-04
11
+
12
+ ### Added
13
+
14
+ - The explorer, reviewer, and implementer prompts, and `SKILL.md`'s
15
+ Discover step, each gained one tool-agnostic sentence pointing the role
16
+ at a connected structural code-search, verify, or mutation-probe runner
17
+ when one is available in the session, in place of raw grep, hand-editing
18
+ probe files, or reading full logs. Anchored by a pandora-workspace
19
+ measurement of subagent tool-call patterns (see run
20
+ `.ai/runs/2026-09-03-agent-tools-kit`).
21
+
22
+ ### Changed
23
+
24
+ - `init`'s interactive harnesses prompt on a target whose own manifest
25
+ recorded a real `harnesses: []` (a deliberate `--harness none`
26
+ templates-only install) now starts with nothing pre-checked, matching
27
+ `apply`'s existing semantics, instead of pre-checking whatever
28
+ `detectHarnesses(targetDir)` found on disk. Decision D-002 (agent-dx
29
+ 7669907c): the weak-signal argument that motivated `apply`'s own fix
30
+ (agent-tasks fe834823, a stray harness config left on disk, e.g. a
31
+ `.claude/` directory, is not the recorded intent, the manifest is)
32
+ applies to `init` identically, and the earlier fix's concern (ask
33
+ instead of silently falling back to templates-only) is preserved
34
+ because the prompt still appears and still annotates detection with a
35
+ " (detected)" label; only the pre-check now follows recorded intent
36
+ instead of on-disk detection. `init` and `apply` now share one
37
+ resolution inside `resolveInitInputs` (`stickyPreChecked ?? []`,
38
+ `stickyAnnotateDetected ?? detected`) instead of `init`'s own call site
39
+ relying on a different default.
40
+
10
41
  ## [0.27.0] - 2026-09-01
11
42
 
12
43
  ### Added
package/README.md CHANGED
@@ -89,9 +89,10 @@ files on disk from something else; add a harness back with an explicit
89
89
  `--profile`/`--models`/`--tiers` use, applied to the no-harness case. An
90
90
  **interactive** re-run is different: it still prompts, with nothing forced
91
91
  pre-selected, instead of silently skipping straight back to templates-only
92
- without asking; deselect every checkbox to stay templates-only. `init`
93
- pre-checks whatever it detects on disk; `apply` pre-checks nothing at all
94
- (both still annotate what is detected with a " (detected)" label).
92
+ without asking; deselect every checkbox to stay templates-only. `init` and
93
+ `apply` both pre-check nothing at all on this prompt, and both still
94
+ annotate what is detected on disk with a " (detected)" label; select a
95
+ harness to install it.
95
96
 
96
97
  ```bash
97
98
  npx orchestrator-workflow init --harness none --yes
@@ -399,12 +400,9 @@ what `init` would have auto-detected) -- except a target whose own
399
400
  manifest recorded a real `harnesses: []` (a deliberate templates-only
400
401
  install, see "Templates-only mode" above), which stays templates-only on
401
402
  a flagless run regardless of the operator's defaults or what is on disk;
402
- an **interactive** re-run on such a target still prompts, but with
403
- nothing pre-checked at all -- neither whatever `apply`'s harness fallback
404
- (recorded harnesses, else operator defaults, else detection) would
405
- otherwise have picked, nor a harness config left on disk from something
406
- else, which is a weak signal next to the target's own recorded
407
- `harnesses: []`.
403
+ an **interactive** re-run on such a target still prompts, with the same
404
+ nothing-pre-checked behaviour described in "Templates-only mode" above
405
+ (it applies identically to `apply`).
408
406
  Pass `--sync` to invert that for
409
407
  profile, tiers, and models: the operator's defaults then win over whatever
410
408
  the target already had recorded. A target pinned to a kit version other
@@ -504,3 +502,11 @@ organizational guidance (when to use agents at all, review depth, risk tiers)
504
502
  live in the sibling package
505
503
  [agentic-coding-playbook](../agentic-coding-playbook), which the skill
506
504
  references.
505
+
506
+ ## okf-kit version pin
507
+
508
+ `test/docs-consistency.test.ts` pins the `okf-kit@<version>` this repo's own
509
+ `.github/workflows/` install against the sibling `packages/okf-kit`
510
+ package's version, so a release of `okf-kit` must bump those pins in the
511
+ same commit as the version cut; see `CONTRIBUTING.md`'s "Releasing okf-kit"
512
+ section (repo root) for the order.
@@ -16,10 +16,11 @@ Rules:
16
16
  repository; follow the question.
17
17
  - Before mapping terrain by hand, check whether the repo carries a curated
18
18
  knowledge bundle (for example a `docs/okf/` directory with an `index.md`):
19
- if one exists, read its index first and then the relevant docs it points
20
- to, treating their claims as leads to verify, not as ground truth. If a semantic
19
+ if one exists, read its index first and then the relevant docs it points to,
20
+ treating their claims as leads to verify, not as ground truth. If a semantic
21
21
  code-search tool is connected in the session, prefer it over raw grep for
22
- orientation questions.
22
+ orientation questions; when a structural code-search tool is available,
23
+ prefer it over text grep for symbol lookups (callers, definitions).
23
24
  - Report what you actually found, with `file:line` references. Distinguish
24
25
  verified facts from inference, and never present a guess as a fact.
25
26
  - Surface the constraints and conventions a plan must respect (existing
@@ -19,6 +19,10 @@ Rules:
19
19
  field when probes were named is treated as a misfire, not evidence. When
20
20
  the assignment names no mutation probes, return `mutation_probes: []`
21
21
  rather than omitting the field.
22
+ - When a verify runner is available, run it for the checks the acceptance
23
+ criteria name and report its summary under `tests.executed`; when a
24
+ mutation-probe runner is available, run the named probes through it and
25
+ copy its fields into `mutation_probes`.
22
26
  - Report the full sha of every commit you produced on the task branch, in
23
27
  order, in the `commits` field of your output; an output missing that field
24
28
  when the task assignment asked for a commit is treated as a misfire, not
@@ -64,6 +64,10 @@ Rules:
64
64
  implementer's log — and record the method, sample size, and result against
65
65
  the implementer's claim in the `reproduction` field. Deterministic checks
66
66
  (a single test run, `tsc`, lint) do not trigger this.
67
+ - When a mutation-probe runner is available in the session, run probes
68
+ through it instead of editing files by hand, and carry its result fields
69
+ into your findings and `reproduction`; when a verify runner is available,
70
+ read its summary before opening full logs.
67
71
 
68
72
  Return exactly this structure as your final output, nothing else:
69
73
 
@@ -140,9 +140,10 @@ directory and the subagents.
140
140
  check for a curated knowledge bundle (for example a `docs/okf/` directory
141
141
  with an index) before mapping terrain by hand, treating any claims found
142
142
  there as leads to verify, not as ground truth, and prefer a connected
143
- semantic code-search tool over raw grep for orientation questions. Fold its
144
- findings into a
145
- "Terrain" section of `01-plan.md`. Skip this step when the change is well
143
+ semantic code-search tool over raw grep for orientation questions; when a
144
+ structural code-search tool is available, prefer it over text grep for
145
+ symbol lookups (callers, definitions). Fold its findings into a "Terrain"
146
+ section of `01-plan.md`. Skip this step when the change is well
146
147
  understood. If the explorer surfaces a question only the operator can
147
148
  answer, ask the operator instead of guessing. Under a `minimal` profile
148
149
  there is no explorer subagent to send; run this step inline with the same
@@ -0,0 +1,20 @@
1
+ import type { Harness } from "./detect.js";
2
+ import type { Manifest } from "./init.js";
3
+ import type { InitResolutionOptions, ResolveInitInputsParams } from "./cli-inputs.js";
4
+ /**
5
+ * Builds `init`'s own `resolveInitInputs` params. Mirrors
6
+ * `buildApplyInitInputs` (`cli-apply.ts`): kept in its own side-effect-free
7
+ * module, rather than inline in `cli.ts`'s action, so a future edit to the
8
+ * call site cannot silently reintroduce a `stickyPreChecked` (or
9
+ * `stickyAnnotateDetected`) override without a targeted test catching it.
10
+ * `init`'s call site never overrides either field: the sticky branch must
11
+ * fall back to `resolveInitInputs`'s own `stickyPreChecked ?? []` and
12
+ * `stickyAnnotateDetected ?? detected` defaults (D-002, agent-dx 7669907c;
13
+ * see `ResolveInitInputsParams.stickyPreChecked`'s doc comment for why),
14
+ * exactly as `apply` does via its own hardcoded `[]`. Unlike
15
+ * `buildApplyInitInputs`, this builder does not set those two fields at
16
+ * all, since `init` has no analogue of `apply`'s already-resolved
17
+ * `chosenHarnesses` to guard against; omitting them is what lets
18
+ * `resolveInitInputs`'s defaults do the pinning.
19
+ */
20
+ export declare function buildInitInitInputs(detected: Harness[], previous: Manifest | undefined, interactive: boolean, opts: InitResolutionOptions): ResolveInitInputsParams;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Builds `init`'s own `resolveInitInputs` params. Mirrors
3
+ * `buildApplyInitInputs` (`cli-apply.ts`): kept in its own side-effect-free
4
+ * module, rather than inline in `cli.ts`'s action, so a future edit to the
5
+ * call site cannot silently reintroduce a `stickyPreChecked` (or
6
+ * `stickyAnnotateDetected`) override without a targeted test catching it.
7
+ * `init`'s call site never overrides either field: the sticky branch must
8
+ * fall back to `resolveInitInputs`'s own `stickyPreChecked ?? []` and
9
+ * `stickyAnnotateDetected ?? detected` defaults (D-002, agent-dx 7669907c;
10
+ * see `ResolveInitInputsParams.stickyPreChecked`'s doc comment for why),
11
+ * exactly as `apply` does via its own hardcoded `[]`. Unlike
12
+ * `buildApplyInitInputs`, this builder does not set those two fields at
13
+ * all, since `init` has no analogue of `apply`'s already-resolved
14
+ * `chosenHarnesses` to guard against; omitting them is what lets
15
+ * `resolveInitInputs`'s defaults do the pinning.
16
+ */
17
+ export function buildInitInitInputs(detected, previous, interactive, opts) {
18
+ return {
19
+ detected,
20
+ interactive,
21
+ previous,
22
+ opts,
23
+ // `previous` here is `readInstalledManifest(targetDir)` (undefined, or
24
+ // the target's own actually-recorded manifest), unlike `apply`'s
25
+ // synthetic operator-defaults "floor" object: an empty harnesses array
26
+ // is a real recorded `--harness none` install here.
27
+ previousIsRecordedManifest: true,
28
+ };
29
+ }
@@ -52,34 +52,36 @@ export interface ResolveInitInputsParams {
52
52
  * The entries pre-checked in the interactive prompt when the target
53
53
  * recorded `harnesses: []` (the harnesses-stickiness gate's branch,
54
54
  * gated on `previousIsRecordedManifest && previous.
55
- * harnessesRecordedEmpty`). Defaults to `detected` when omitted, which
56
- * is `init`'s own call site's behaviour (it does not pass this field at
57
- * all): a fresh interactive re-run on a templates-only `init` target
58
- * still pre-checks whatever `detectHarnesses(targetDir)` finds on disk,
59
- * unchanged from before this field existed. `apply`'s call site passes
60
- * `[]` instead: the operator's recorded `harnesses: []` is the intent
61
- * that matters, not a `.claude/`-style directory the harness itself
62
- * left on disk, which is a weak signal and must not re-widen a
63
- * deliberate `--harness none` install just because a bare Enter is
64
- * pressed (agent-tasks fe834823). Only the sticky branch reads this
65
- * field; the normal (non-recorded-empty) branch still prompts from
66
- * `detected` unchanged, matching `apply`'s existing pre-check behaviour
67
- * on a normal target.
55
+ * harnessesRecordedEmpty`). Defaults to `[]` when omitted: `init` and
56
+ * `apply` share this semantics (D-002, agent-dx 7669907c). A fresh
57
+ * interactive re-run on a templates-only target starts with nothing
58
+ * pre-checked, because the recorded `harnesses: []` is the intent that
59
+ * matters, not a `.claude/`-style directory the harness itself left on
60
+ * disk, which is a weak signal and must not re-widen a deliberate
61
+ * `--harness none` install just because a bare Enter is pressed
62
+ * (agent-tasks fe834823; the same argument applies identically to
63
+ * `init`). `apply`'s call site still passes `[]` explicitly, as defence
64
+ * in depth (see `buildApplyInitInputs`'s doc comment). Only the sticky
65
+ * branch reads this field; the normal (non-recorded-empty) branch still
66
+ * prompts from `detected` unchanged, matching `apply`'s existing
67
+ * pre-check behaviour on a normal target.
68
68
  */
69
69
  stickyPreChecked?: Harness[];
70
70
  /**
71
71
  * The sticky branch's own `promptHarnesses` " (detected)" label source,
72
72
  * independent of `stickyPreChecked` (which drives what is actually
73
- * pre-checked, not what is merely labelled). Defaults to
74
- * `stickyPreChecked ?? detected` when omitted, matching `promptHarnesses`'
75
- * own default and `init`'s call site (which omits both fields, so its
76
- * sticky prompt still labels from real on-disk detection, unchanged).
77
- * `apply`'s call site passes `[]` for `stickyPreChecked` (nothing is
78
- * pre-checked; see that field's doc comment) but still wants the
79
- * operator to see which harness is actually on disk, so it passes a
80
- * fresh `detectHarnesses(targetDir)` call here instead: labelling is a
81
- * hint, not an intent signal, so it is safe to annotate what the
82
- * pre-check itself must not read (agent-tasks fe834823, fix round 3).
73
+ * pre-checked, not what is merely labelled). Defaults to `detected`
74
+ * when omitted: even though nothing is pre-checked (see
75
+ * `stickyPreChecked`'s doc comment), the operator still sees which
76
+ * harness is actually on disk, because labelling is a hint, not an
77
+ * intent signal, so it is safe to annotate what the pre-check itself
78
+ * must not read (agent-tasks fe834823, fix round 3). `init`'s call site
79
+ * omits this field and gets its own `detectHarnesses(targetDir)` result
80
+ * via this default; `apply`'s call site passes a fresh
81
+ * `detectHarnesses(targetDir)` call explicitly, since its own
82
+ * `detected` parameter is `resolveApplyHarnesses`'s chosen-harnesses
83
+ * result, not real on-disk detection, and would mislabel the checkbox
84
+ * if relied on as the default here.
83
85
  */
84
86
  stickyAnnotateDetected?: Harness[];
85
87
  }
@@ -110,13 +112,12 @@ export interface ResolvedInitInputs {
110
112
  * omitted) keeps the previously installed value; a fresh install with no
111
113
  * prior manifest falls back to the shipped default.
112
114
  *
113
- * `params.detected` doubles as the fallback-chain input the non-sticky
114
- * "else" branch below prompts and falls back from, and (for `init`'s call
115
- * site only, since it omits `stickyPreChecked`) the harnesses-stickiness
116
- * branch's own pre-check. `apply`'s call site's `detected` is
117
- * `resolveApplyHarnesses`'s fallback-chain result (never empty), which is
118
- * not what the sticky branch should pre-check (see
119
- * `ResolveInitInputsParams.stickyPreChecked`'s doc comment), so it passes
120
- * that field separately (`[]`) for the sticky branch to read instead.
115
+ * `params.detected` is the fallback-chain input the non-sticky "else"
116
+ * branch below prompts and falls back from. It plays no role in the
117
+ * harnesses-stickiness branch's own pre-check any more: that branch
118
+ * always pre-checks `stickyPreChecked ?? []` (D-002, agent-dx 7669907c),
119
+ * never `detected`, so `init` and `apply` share one semantics there. It
120
+ * still feeds that branch's " (detected)" label by default (see
121
+ * `ResolveInitInputsParams.stickyAnnotateDetected`'s doc comment).
121
122
  */
122
123
  export declare function resolveInitInputs(params: ResolveInitInputsParams): Promise<ResolvedInitInputs>;
@@ -5,12 +5,13 @@ import { detectProvider, loadOpencodeCatalog, resolveAlias, resolveOpencodeModel
5
5
  export async function promptHarnesses(detected, installed, fallbackToClaude = true,
6
6
  // Drives only the checkbox's " (detected)" label suffix, independent of
7
7
  // `detected`'s own role in pre-checking a choice: defaults to `detected`
8
- // so every call site that omits this parameter keeps annotating exactly
9
- // what it pre-checks from, unchanged. `apply`'s sticky-branch call site
10
- // is the one caller that passes a different value here: it pre-checks
11
- // nothing (`stickyPreChecked ?? detected` is `[]`) but still wants the
12
- // operator to see which harness is actually on disk, so it annotates
13
- // from a fresh `detectHarnesses(targetDir)` call instead
8
+ // so a call site that omits this parameter keeps annotating exactly what
9
+ // it pre-checks from, unchanged. `resolveInitInputs`'s harnesses-
10
+ // stickiness branch (shared by `init` and `apply`, D-002, agent-dx
11
+ // 7669907c) always passes an explicit value here (`stickyAnnotateDetected
12
+ // ?? detected`) instead of relying on this default: that branch pre-checks
13
+ // nothing but still wants the operator to see which harness is actually
14
+ // on disk, so labelling and pre-checking are resolved separately
14
15
  // (agent-tasks fe834823, fix round 3).
15
16
  annotateDetected = detected) {
16
17
  const known = [...new Set([...detected, ...installed])];
@@ -18,22 +19,17 @@ annotateDetected = detected) {
18
19
  // case pre-checks `claude` as a sane default (`fallbackToClaude`'s default
19
20
  // `true`). The templates-only re-run branch below opts OUT of that
20
21
  // (`fallbackToClaude: false`): a repo the operator explicitly recorded as
21
- // `harnesses: []` has no harness files by construction, so `detected` is
22
- // always empty there too, and pre-checking `claude` on Enter would
23
- // silently re-widen an explicit `--harness none` install -- contradicting
24
- // README.md's and this function's own "nothing forced pre-selected" claim
25
- // (see CHANGELOG). That "`detected` is always empty there too" premise
26
- // holds for `init`'s own call site, where `detected` is
27
- // `detectHarnesses(targetDir)` on a target with no harness files by
28
- // construction. `apply`'s call site (`resolveInitInputs`'s interactive
29
- // branch just below) does not call this function with its own
30
- // `resolveApplyHarnesses` result at all for this branch: that result is
31
- // never empty (it falls back through the operator default, then
32
- // detection, then `["claude"]`), so it passes `stickyPreChecked: []`
33
- // here instead, regardless of what is actually on disk -- the operator's
34
- // recorded `harnesses: []` is the intent that matters, not a harness
35
- // config a harness itself left behind (agent-tasks fe834823; the
36
- // residual noted in docs/okf/log.md's 2026-08-31 entry is closed).
22
+ // `harnesses: []` has no harness files by construction, and pre-checking
23
+ // `claude` on Enter would silently re-widen an explicit `--harness none`
24
+ // install -- contradicting README.md's and this function's own "nothing
25
+ // forced pre-selected" claim (see CHANGELOG). `resolveInitInputs`'s
26
+ // harnesses-stickiness branch (shared by `init` and `apply`, D-002,
27
+ // agent-dx 7669907c) always calls this function with `stickyPreChecked ??
28
+ // []` regardless of what is actually on disk or previously chosen --
29
+ // the operator's recorded `harnesses: []` is the intent that matters,
30
+ // not a harness config a harness itself left behind (agent-tasks
31
+ // fe834823; the residual noted in docs/okf/log.md's 2026-08-31 entry is
32
+ // closed).
37
33
  const preselected = known.length > 0 ? known : fallbackToClaude ? ["claude"] : [];
38
34
  const { harnesses } = await inquirer.prompt([
39
35
  {
@@ -134,14 +130,13 @@ export async function promptModels(base, roles) {
134
130
  * omitted) keeps the previously installed value; a fresh install with no
135
131
  * prior manifest falls back to the shipped default.
136
132
  *
137
- * `params.detected` doubles as the fallback-chain input the non-sticky
138
- * "else" branch below prompts and falls back from, and (for `init`'s call
139
- * site only, since it omits `stickyPreChecked`) the harnesses-stickiness
140
- * branch's own pre-check. `apply`'s call site's `detected` is
141
- * `resolveApplyHarnesses`'s fallback-chain result (never empty), which is
142
- * not what the sticky branch should pre-check (see
143
- * `ResolveInitInputsParams.stickyPreChecked`'s doc comment), so it passes
144
- * that field separately (`[]`) for the sticky branch to read instead.
133
+ * `params.detected` is the fallback-chain input the non-sticky "else"
134
+ * branch below prompts and falls back from. It plays no role in the
135
+ * harnesses-stickiness branch's own pre-check any more: that branch
136
+ * always pre-checks `stickyPreChecked ?? []` (D-002, agent-dx 7669907c),
137
+ * never `detected`, so `init` and `apply` share one semantics there. It
138
+ * still feeds that branch's " (detected)" label by default (see
139
+ * `ResolveInitInputsParams.stickyAnnotateDetected`'s doc comment).
145
140
  */
146
141
  export async function resolveInitInputs(params) {
147
142
  const { detected, interactive, previous, opts, previousIsRecordedManifest, stickyPreChecked, stickyAnnotateDetected, } = params;
@@ -176,28 +171,31 @@ export async function resolveInitInputs(params) {
176
171
  // as `[]` (not the recorded `previous.harnesses`) so nothing is
177
172
  // pre-checked from the previous install, unlike the "else" branch
178
173
  // below's normal re-run prompt.
179
- // `stickyPreChecked ?? detected` is used here rather than plain
180
- // `detected`: `init` does not pass `stickyPreChecked` at all, so its
181
- // own call site keeps pre-checking whatever `detectHarnesses(targetDir)`
182
- // finds on disk, unchanged from before this field existed. `apply`
183
- // passes `stickyPreChecked: []`: the operator's recorded
184
- // `harnesses: []` is the intent that matters here, not a harness
185
- // config left on disk (a weak signal `apply`'s own `detected` --
186
- // `resolveApplyHarnesses`'s fallback-chain result, never empty --
187
- // cannot represent either), so the interactive prompt on a templates-
188
- // only `apply` target starts with nothing pre-checked at all
189
- // (agent-tasks fe834823). `fallbackToClaude: false` closes the same
190
- // gap for the case where nothing is pre-checked either: without it,
191
- // `promptHarnesses` would pre-check `claude` on its own "nothing
192
- // known" fallback, re-widening the install on a bare Enter.
193
- // `stickyAnnotateDetected` is passed through as the fourth argument so
194
- // the checkbox's " (detected)" label can still point at what is
195
- // actually on disk even though nothing is pre-checked from it; when
196
- // omitted (as `init`'s call site does), `promptHarnesses` defaults it
197
- // to its own first argument, i.e. `stickyPreChecked ?? detected`,
198
- // matching pre-round-3 labelling behaviour exactly.
174
+ // `stickyPreChecked ?? []` pre-checks nothing by default: `init` and
175
+ // `apply` share this semantics (D-002, agent-dx 7669907c; see
176
+ // CHANGELOG). Neither call site needs to pass `stickyPreChecked`
177
+ // itself for this default to apply (`apply` still does, as defence in
178
+ // depth; see `buildApplyInitInputs`'s doc comment); a bare Enter on a
179
+ // target recorded as `harnesses: []` must not re-widen a deliberate
180
+ // `--harness none` install just because a harness config happens to
181
+ // still be on disk, which is a weak signal, not the recorded intent
182
+ // (agent-tasks fe834823; the same argument applies identically to
183
+ // `init`). `fallbackToClaude: false` closes the same gap for the case
184
+ // where nothing is pre-checked either: without it, `promptHarnesses`
185
+ // would pre-check `claude` on its own "nothing known" fallback,
186
+ // re-widening the install on a bare Enter.
187
+ // `stickyAnnotateDetected ?? detected` is passed through as the fourth
188
+ // argument so the checkbox's " (detected)" label still points at what
189
+ // is actually on disk even though nothing is pre-checked from it: the
190
+ // label is a hint, not an intent signal, so `init`'s call site (which
191
+ // omits `stickyAnnotateDetected`) still labels from its own
192
+ // `detectHarnesses(targetDir)` result via this default, and `apply`'s
193
+ // call site still passes a fresh `detectHarnesses(targetDir)` call
194
+ // explicitly, since its own `detected` parameter is
195
+ // `resolveApplyHarnesses`'s chosen-harnesses result, not real on-disk
196
+ // detection.
199
197
  harnesses = interactive
200
- ? await promptHarnesses(stickyPreChecked ?? detected, [], false, stickyAnnotateDetected)
198
+ ? await promptHarnesses(stickyPreChecked ?? [], [], false, stickyAnnotateDetected ?? detected)
201
199
  : [];
202
200
  }
203
201
  else {
package/dist/cli.js CHANGED
@@ -5,6 +5,7 @@ import { Command } from "commander";
5
5
  import inquirer from "inquirer";
6
6
  import { PACKAGE_VERSION } from "./assets.js";
7
7
  import { buildApplyInitInputs } from "./cli-apply.js";
8
+ import { buildInitInitInputs } from "./cli-init.js";
8
9
  import { resolveInitInputs } from "./cli-inputs.js";
9
10
  import { HARNESSES, detectHarnesses } from "./detect.js";
10
11
  import { DEFAULT_MODELS, PROFILES } from "./models.js";
@@ -124,17 +125,13 @@ program
124
125
  : "none recorded";
125
126
  console.log(`Found existing install (${version.startsWith("unknown") ? version : `v${version}`}, harnesses: ${installedFor}, profile: ${previous.profile}, tiers: ${previous.tiers})`);
126
127
  }
127
- const { harnesses, profile, models, tiers, opencodeModels, opencodeClassModels, warnings, } = await resolveInitInputs({
128
- detected,
129
- interactive,
130
- previous,
131
- opts,
132
- // `previous` here is `readInstalledManifest(targetDir)` (undefined,
133
- // or the target's own actually-recorded manifest), unlike `apply`'s
134
- // synthetic operator-defaults "floor" object: an empty harnesses
135
- // array is a real recorded --harness none install here.
136
- previousIsRecordedManifest: true,
137
- });
128
+ const { harnesses, profile, models, tiers, opencodeModels, opencodeClassModels, warnings, } = await resolveInitInputs(
129
+ // The sticky-branch wiring itself (neither `stickyPreChecked` nor
130
+ // `stickyAnnotateDetected` overridden, so `resolveInitInputs`'s own
131
+ // `?? []` / `?? detected` defaults apply) is pinned inside
132
+ // `buildInitInitInputs` and covered by a dedicated test
133
+ // (`test/cli-init.test.ts`), not by this call site.
134
+ buildInitInitInputs(detected, previous, interactive, opts));
138
135
  for (const w of warnings) {
139
136
  process.stderr.write(`${w}\n`);
140
137
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orchestrator-workflow",
3
- "version": "0.27.0",
3
+ "version": "0.28.0",
4
4
  "description": "Installer for an orchestrator-led agent workflow: .ai/ run state, an AGENTS.md policy section, and per-harness subagent definitions for Claude Code, OpenAI Codex, and opencode",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",