opencode-plugin-flow 8.1.3 → 8.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  One short entry per release, written for users deciding whether to upgrade.
4
4
 
5
+ ## [8.2.0] - 2026-08-31
6
+
7
+ Reviewer selection is now native plugin configuration, and Flow reports enough
8
+ derived evidence for a bounded delivery handoff.
9
+
10
+ - OpenCode plugin tuple options can select the reviewer model and step budget.
11
+ Flow resolves the selection once per process and reports it in `/flow-status`.
12
+ Environment variables remain fallback configuration.
13
+ - Every accepted close returns a deterministic, versioned delivery summary with
14
+ feature attempts, outcomes, terminal findings, changed-artifact declarations,
15
+ and tiered assurance. The handoff grants no external action authority.
16
+ - A new quickstart and structured external pilot cover installation, reviewer
17
+ selection, first-run checks, recovery, and feedback without telemetry.
18
+ - Report-only evals now measure repository gate discovery and task-specific risk
19
+ questions. Eval host configuration uses the same reviewer tuple as production,
20
+ and release notes derive their provider evidence from retained artifacts.
21
+ - **Session v5 schema:** unchanged. Runtime tools, commands, guides, and agents
22
+ keep their existing names and inputs.
23
+
24
+ Install or update:
25
+
26
+ ```bash
27
+ opencode plugin opencode-plugin-flow@8.2.0 --global --force
28
+ ```
29
+
5
30
  ## [8.1.3] - 2026-08-28
6
31
 
7
32
  Release claims now come from retained evidence instead of trusted summaries.
package/README.md CHANGED
@@ -40,7 +40,7 @@ expensive, and it is overhead when it is not.
40
40
  Install the exact npm release through OpenCode:
41
41
 
42
42
  ```bash
43
- opencode plugin opencode-plugin-flow@8.1.3 --global --force
43
+ opencode plugin opencode-plugin-flow@8.2.0 --global --force
44
44
  ```
45
45
 
46
46
  Omit `--global` for project scope. Version pins are exact and never update on
@@ -51,10 +51,28 @@ The equivalent manual project configuration is:
51
51
  ```json
52
52
  {
53
53
  "$schema": "https://opencode.ai/config.json",
54
- "plugin": ["opencode-plugin-flow@8.1.3"]
54
+ "plugin": ["opencode-plugin-flow@8.2.0"]
55
55
  }
56
56
  ```
57
57
 
58
+ For an explicit reviewer model, use OpenCode's plugin tuple options:
59
+
60
+ ```json
61
+ {
62
+ "$schema": "https://opencode.ai/config.json",
63
+ "plugin": [
64
+ [
65
+ "opencode-plugin-flow@8.2.0",
66
+ { "reviewer": { "model": "provider/model", "steps": 80 } }
67
+ ]
68
+ ]
69
+ }
70
+ ```
71
+
72
+ The tuple values take precedence over `OPENCODE_FLOW_REVIEWER_MODEL` and
73
+ `OPENCODE_FLOW_REVIEWER_STEPS`. `/flow-status` reports the process-local
74
+ selection, but only a successful reviewer run confirms model availability.
75
+
58
76
  Restart OpenCode after changing configuration. OpenCode owns installation and
59
77
  configuration; see its
60
78
  [plugin documentation](https://opencode.ai/docs/plugins/). Flow has no installer
@@ -68,6 +86,9 @@ remain inert history, and there is no migration or rollback layer.
68
86
 
69
87
  ## Quick start
70
88
 
89
+ For a clean installation and reviewer-configuration check, follow the
90
+ [quickstart](docs/quickstart.md).
91
+
71
92
  ```text
72
93
  /flow-auto add rate limiting to the public API
73
94
  ```
@@ -127,9 +148,10 @@ you granted.
127
148
  6. A passing review advances the plan. A failed feature is never picked up again
128
149
  implicitly — Flow reports the blocker and waits for an explicit retry or an
129
150
  independent-feature choice. The last passing feature allows closure, and every
130
- accepted close returns a delivery summary derived from recorded state: each
131
- feature's attempts, latest outcome, terminal findings, and tiered assurance with
132
- explicit limitations.
151
+ accepted close returns a versioned delivery summary derived from recorded state:
152
+ each feature's attempts, latest outcome, terminal findings, and tiered assurance
153
+ with explicit limitations. Delivery grants no PR, merge, publish, or release
154
+ authority.
133
155
 
134
156
  Findings keep stable ids across retries, and a failed review must carry every
135
157
  still-live finding forward — the runtime rejects a submission that drops one. A
package/dist/index.js CHANGED
@@ -184,6 +184,14 @@ without rediscovering the goal.
184
184
  context. Do not dispatch \`flow-worker\` while planning; that role is only for
185
185
  authorized implementation slices after approval. Ask only for a missing
186
186
  product choice that materially changes the outcome.
187
+ - Discover evidence in order: repository instructions such as \`AGENTS.md\` and
188
+ \`CONTRIBUTING.md\`, maintained development docs, CI workflows, then build and
189
+ test manifests. Compare candidates with the requested behavior and current
190
+ platform. Prefer an explicit whole-repository command over a conveniently
191
+ named narrow script. Probe command fitness when it is observable without
192
+ mutation. Record the chosen source and rationale in \`decisions\` when the gate
193
+ is not obvious. Discovery never counts as passing evidence; only an armed
194
+ observation does.
187
195
 
188
196
  ## Plan contract
189
197
 
@@ -532,8 +540,15 @@ last relevant edit.
532
540
 
533
541
  After successful applicable validation, call \`flow_review_start\` with a fresh
534
542
  operation id, current revision, feature id, \`artifactsChanged\`, and a bounded
535
- packet. Dispatch only reserved \`flow-reviewer\`. Never review or submit its
536
- verdict in manager context.
543
+ packet. For persistence, schema, migration, replay, or recovery work, add only
544
+ the relevant full questions to \`riskLenses\`: can interruption leave partial
545
+ state; are retry and replay idempotent; can older state or readers fail visibly;
546
+ does rollback preserve data? For public API, config, command, package, or
547
+ documented-contract work, ask whether existing callers keep their defaults,
548
+ invalid inputs fail at the boundary, and the packed artifact exposes the
549
+ approved contract. Leave \`riskLenses\` empty for ordinary low-risk changes.
550
+ Dispatch only reserved \`flow-reviewer\`. Never review or submit its verdict in
551
+ manager context.
537
552
 
538
553
  After dispatch, read compact status. On top-level error, report exact
539
554
  summary/recovery and stop without further mutation. If status remains running,
@@ -666,31 +681,22 @@ var FLOW_WORKER_PROMPT = [
666
681
  var FLOW_STATUS_PROMPT = [
667
682
  'Call `flow_status { request: { view: "compact" } }` first.',
668
683
  "Do not mutate.",
684
+ "Report `workflowData.reviewerConfiguration.report` verbatim when present and label it process-local, not persisted state.",
685
+ "Report `workflowData.statusReport` verbatim when present; do not reconstruct lifecycle or recovery facts from the projection.",
669
686
  "If the top-level response status is `error`, report its exact summary and",
670
687
  "`workflowData.failure.recovery` when present; otherwise say no recovery guidance was supplied.",
671
- "When `workflowData.delivery` is present, also report its `report` lines verbatim.",
688
+ "When `workflowData.delivery` is present, report its `report` lines verbatim.",
672
689
  "For the terminal ID map use only `outcomeSummary` and `terminalFindings`: IDs are `verified`",
673
690
  "only when proven, otherwise `incomplete` or explicitly `deferred`; `fixed` needs later passing",
674
691
  "review plus current evidence, `recurring` current confirmation, `residual` a confirmed nonblocker,",
675
692
  "and `abandoned` remains the closure kind.",
676
693
  "Missing IDs are unavailable.",
677
- "State that `/flow-status` made no Git or release mutation, report any lifecycle state effect",
678
- "disclosed by the response, and stop.",
694
+ "State that `/flow-status` made no Git or release mutation, note any lifecycle effect, and stop.",
679
695
  "Do not interpret recovery guidance as a blocked review.",
680
696
  "If `projection.status` is `blocked` or `projection.nextAction` is `await-user-direction`,",
681
697
  'call `flow_status { request: { view: "detail" } }` exactly once and label the result overall incomplete.',
682
- "From that detail projection, report the goal and progress; any blocked feature, attempt,",
683
- "`failedReviewCount`, and findings; every retry-required feature whose latest relevant reviewed",
684
- "outcome remains failed; completed and untouched features; validations and `artifactsChanged`",
685
- "as Flow-reported artifact evidence; and the exact status and `nextAction`.",
686
- "For a blocked first failed review, explain that `flow_feature_reset` is the projected default.",
687
- "For blocked `await-user-direction`, explain that an authorized retry or independent choice",
688
- "uses atomic `flow_feature_reset` with `nextFeatureId`.",
689
- "For ready `await-user-direction`, explain that no blocked run remains, so an authorized retry",
690
- "uses `flow_run_start` with an explicit `featureId`, never reset or default selection.",
691
- "When `workflowData.autoTiming` is present, report `activeMs` as non-authoritative process-local",
692
- "wall time classified active, not CPU or pure work, and `waitingForUserMs` as only projected",
693
- "`flow_plan_approve` plus `await-user-direction` time for the latest `/flow-auto`.",
698
+ "Report the detail `workflowData.statusReport` verbatim when present; it owns retry, evidence, artifact, and recovery text.",
699
+ "When `workflowData.autoTiming` is present, report `activeMs` as non-authoritative process-local wall time, not CPU or pure work, and `waitingForUserMs` as only projected `flow_plan_approve` plus `await-user-direction` time for the latest `/flow-auto`.",
694
700
  "State that paused, inactive, errored, and unprojected waits are excluded.",
695
701
  "Otherwise report the compact projection and its exact `nextAction`, state that `/flow-status`",
696
702
  "made no lifecycle, Git, or release mutation, and stop."
@@ -854,13 +860,104 @@ function reviewerSteps(env, onWarning) {
854
860
  }
855
861
  return Number(raw);
856
862
  }
857
- var SHARED_REVIEWER_MODEL_NOTICE = "Flow: no OPENCODE_FLOW_REVIEWER_MODEL is set, so the independent reviewer runs on the same model as the manager. Independence is stronger with a different model family; set OPENCODE_FLOW_REVIEWER_MODEL to a provider/model this host can reach.";
858
- function createFlowCoreConfigEntries(options) {
863
+ function pluginReviewerOptions(options, onWarning) {
864
+ const reviewer = options?.reviewer;
865
+ if (reviewer === undefined)
866
+ return {};
867
+ if (typeof reviewer !== "object" || reviewer === null || Array.isArray(reviewer)) {
868
+ onWarning?.("Flow plugin option reviewer must be an object; ignoring it.");
869
+ return {};
870
+ }
871
+ return Object.fromEntries(Object.entries(reviewer));
872
+ }
873
+ function pluginReviewerModel(reviewer, onWarning) {
874
+ if (!Object.hasOwn(reviewer, "model"))
875
+ return;
876
+ const value = reviewer.model;
877
+ if (typeof value !== "string") {
878
+ onWarning?.("Flow plugin option reviewer.model must be a non-empty string; ignoring it.");
879
+ return;
880
+ }
881
+ const model = value.trim();
882
+ if (!model) {
883
+ onWarning?.("Flow plugin option reviewer.model must be a non-empty string; ignoring it.");
884
+ return;
885
+ }
886
+ return model;
887
+ }
888
+ function pluginReviewerSteps(reviewer, onWarning) {
889
+ if (!Object.hasOwn(reviewer, "steps"))
890
+ return;
891
+ const value = reviewer.steps;
892
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1 || value > 1000) {
893
+ onWarning?.("Flow plugin option reviewer.steps must be an integer from 1 through 1000; ignoring it.");
894
+ return;
895
+ }
896
+ return value;
897
+ }
898
+ function resolveFlowReviewerConfiguration(options) {
859
899
  const env = options?.env ?? process.env;
860
- const model = envValue(env, "OPENCODE_FLOW_REVIEWER_MODEL");
900
+ const reviewer = pluginReviewerOptions(options?.pluginOptions, options?.onWarning);
901
+ const configuredModel = pluginReviewerModel(reviewer, options?.onWarning);
902
+ const configuredSteps = pluginReviewerSteps(reviewer, options?.onWarning);
903
+ const environmentModel = configuredModel ? undefined : envValue(env, "OPENCODE_FLOW_REVIEWER_MODEL");
904
+ const environmentSteps = configuredSteps === undefined ? reviewerSteps(env, options?.onWarning) : undefined;
905
+ return {
906
+ model: configuredModel ? { kind: "explicit", source: "plugin-option", value: configuredModel } : environmentModel ? {
907
+ kind: "explicit",
908
+ source: "environment",
909
+ value: environmentModel
910
+ } : { kind: "shared-with-manager" },
911
+ steps: configuredSteps !== undefined ? {
912
+ kind: "explicit",
913
+ source: "plugin-option",
914
+ value: configuredSteps
915
+ } : environmentSteps !== undefined ? {
916
+ kind: "explicit",
917
+ source: "environment",
918
+ value: environmentSteps
919
+ } : { kind: "host-default" }
920
+ };
921
+ }
922
+ function flowReviewerStatus(reviewer) {
923
+ const model = reviewer.model.kind === "explicit" ? {
924
+ kind: "explicit",
925
+ source: reviewer.model.source,
926
+ requested: reviewer.model.value
927
+ } : {
928
+ kind: "shared-manager-model",
929
+ source: "host-default",
930
+ requested: null
931
+ };
932
+ const steps = reviewer.steps.kind === "explicit" ? {
933
+ kind: "explicit",
934
+ source: reviewer.steps.source,
935
+ requested: reviewer.steps.value
936
+ } : {
937
+ kind: "host-default",
938
+ source: "host-default",
939
+ requested: null
940
+ };
941
+ return {
942
+ scope: "current-plugin-process",
943
+ model,
944
+ steps,
945
+ availability: "unverified",
946
+ report: [
947
+ reviewer.model.kind === "explicit" ? "Reviewer selection: explicit." : "Reviewer selection: shared manager model.",
948
+ model.kind === "explicit" ? `Requested reviewer model: ${model.requested} (from ${model.source}).` : "Requested reviewer model: none; the reviewer inherits the manager model.",
949
+ reviewer.steps.kind === "host-default" ? "Requested reviewer step budget: host default." : `Requested reviewer step budget: ${reviewer.steps.value} (from ${reviewer.steps.source}).`,
950
+ "Reviewer model availability: unverified; configuration proves only what Flow requested from OpenCode."
951
+ ]
952
+ };
953
+ }
954
+ var SHARED_REVIEWER_MODEL_NOTICE = "Flow: no reviewer model is set, so the independent reviewer runs on the same model as the manager. Independence is stronger with a different model family; use the plugin reviewer.model option or OPENCODE_FLOW_REVIEWER_MODEL.";
955
+ function createFlowCoreConfigEntries(options) {
956
+ const reviewer = options?.reviewerConfiguration ?? resolveFlowReviewerConfiguration(options);
957
+ const model = reviewer.model.kind === "explicit" ? reviewer.model.value : undefined;
861
958
  if (!model)
862
959
  options?.onNotice?.(SHARED_REVIEWER_MODEL_NOTICE);
863
- const steps = reviewerSteps(env, options?.onWarning);
960
+ const steps = reviewer.steps.kind === "explicit" ? reviewer.steps.value : undefined;
864
961
  return {
865
962
  agent: {
866
963
  "flow-reviewer": {
@@ -883,7 +980,9 @@ function createFlowCoreConfigEntries(options) {
883
980
  function applyFlowConfig(config, options) {
884
981
  const entries = createFlowCoreConfigEntries({
885
982
  ...options?.onWarning ? { onWarning: options.onWarning } : {},
886
- ...options?.onNotice ? { onNotice: options.onNotice } : {}
983
+ ...options?.onNotice ? { onNotice: options.onNotice } : {},
984
+ ...options?.pluginOptions ? { pluginOptions: options.pluginOptions } : {},
985
+ ...options?.reviewerConfiguration ? { reviewerConfiguration: options.reviewerConfiguration } : {}
887
986
  });
888
987
  for (const name of Object.keys(entries.agent)) {
889
988
  if (config.agent && name in config.agent)
@@ -2551,6 +2650,8 @@ function formatReport(delivery) {
2551
2650
  ]
2552
2651
  ]);
2553
2652
  return [
2653
+ `Handoff format: ${delivery.handoff.formatVersion}`,
2654
+ `External action authority: ${delivery.handoff.externalActionAuthority}`,
2554
2655
  `Goal: ${delivery.goal}`,
2555
2656
  `Closure: ${delivery.closure.kind}${delivery.closure.summary ? ` — ${delivery.closure.summary}` : ""}`,
2556
2657
  `Progress: ${delivery.progress.completed} of ${delivery.progress.total} features complete`,
@@ -2580,6 +2681,7 @@ function deliveryProjection(session) {
2580
2681
  const allArtifacts = new Set(session.runs.flatMap((run) => run.artifactsChanged.map((item) => item.path)));
2581
2682
  const digest2 = findingsDigest(session);
2582
2683
  const delivery = {
2684
+ handoff: { formatVersion: 1, externalActionAuthority: "not-granted" },
2583
2685
  goal: session.goal,
2584
2686
  closure: { kind: session.closure.kind, summary: session.closure.summary },
2585
2687
  progress: {
@@ -2608,6 +2710,124 @@ function deliveryProjection(session) {
2608
2710
  }
2609
2711
 
2610
2712
  // src/application/session-projection.ts
2713
+ function actionGuidance(projection) {
2714
+ const action = projection.nextAction;
2715
+ switch (action) {
2716
+ case "flow_plan_save":
2717
+ return "Action guidance: inspect the repository and save one draft plan with flow_plan_save.";
2718
+ case "flow_plan_approve":
2719
+ return "Action guidance: review the draft and approve it only with explicit or prior implementation authority.";
2720
+ case "flow_run_start":
2721
+ return projection.status === "ready" ? "Action guidance: start one exact dependency-ready feature with flow_run_start." : "Action guidance: refresh status before starting another feature.";
2722
+ case "flow_feature_reset":
2723
+ return projection.status === "blocked" ? "Action guidance: reset the failed feature and select the exact authorized retry or independent feature with flow_feature_reset." : "Action guidance: reset the source-stale active feature; do not redispatch its reviewer.";
2724
+ case "await-user-direction":
2725
+ if (projection.status === "ready")
2726
+ return "Action guidance: choose the exact failed feature to retry with flow_run_start; do not use default selection.";
2727
+ if (projection.status === "blocked")
2728
+ return "Action guidance: choose an exact retry or dependency-independent feature through flow_feature_reset with nextFeatureId.";
2729
+ return "Action guidance: supply the missing declared evidence or explicitly choose deferred or abandoned closure.";
2730
+ case "flow_session_close":
2731
+ return "archiveRetry" in projection && projection.archiveRetry ? "Action guidance: replay the projected flow_session_close request byte-for-byte before any other recovery action." : "Action guidance: close the completed session with flow_session_close.";
2732
+ case "flow_status":
2733
+ return "Action guidance: refresh Flow status before another lifecycle action.";
2734
+ case "dispatch-flow-reviewer":
2735
+ return "Action guidance: dispatch the existing pending assignment to flow-reviewer.";
2736
+ case "flow_validation_start":
2737
+ return "Action guidance: arm the exact next validation command with flow_validation_start.";
2738
+ case "flow_review_start":
2739
+ return "Action guidance: create one independent review assignment with flow_review_start.";
2740
+ default: {
2741
+ const exhaustive = action;
2742
+ return exhaustive;
2743
+ }
2744
+ }
2745
+ }
2746
+ function compactReport(projection) {
2747
+ return [
2748
+ `View: ${projection.view}`,
2749
+ `Session: ${projection.sessionId}`,
2750
+ `Status: ${projection.status}`,
2751
+ `Approval: ${projection.approval}`,
2752
+ `Revision: ${projection.revision}`,
2753
+ `Goal: ${projection.goal}`,
2754
+ `Progress: ${projection.progress.completed} of ${projection.progress.total} features complete; ${projection.progress.remaining} remaining`,
2755
+ `Active feature: ${projection.activeFeatureId ?? "none"}`,
2756
+ `Active run: ${projection.activeRunId ?? "none"}`,
2757
+ ...projection.blockedFeature ? [
2758
+ `Blocked feature: ${projection.blockedFeature.featureId}`,
2759
+ `Blocked attempt: ${projection.blockedFeature.attempt}`,
2760
+ `Failed review count: ${projection.blockedFeature.failedReviewCount}`,
2761
+ `Scope blocker: ${projection.blockedFeature.scopeBlocker ? "yes" : "no"}`
2762
+ ] : [],
2763
+ `Next action: ${projection.nextAction}`,
2764
+ `Archive retry: ${projection.archiveRetry ? "yes" : "no"}`,
2765
+ actionGuidance(projection),
2766
+ ...digestReportLines(projection.findingsDigest)
2767
+ ];
2768
+ }
2769
+ function retryRequiredFeatureIds(projection) {
2770
+ return (projection.plan?.features ?? []).flatMap((feature) => {
2771
+ const run = projection.runs.findLast((candidate) => candidate.featureId === feature.id);
2772
+ const reviewed = run?.reviews.findLast((review) => review.result !== null);
2773
+ return reviewed?.result?.verdict === "failed" ? [feature.id] : [];
2774
+ });
2775
+ }
2776
+ function statusReport(projection) {
2777
+ if (!("sessionId" in projection)) {
2778
+ return [
2779
+ `View: ${projection.view}`,
2780
+ "Status: idle",
2781
+ "Revision: 0",
2782
+ "Next action: flow_plan_save",
2783
+ "No active Flow session.",
2784
+ actionGuidance(projection),
2785
+ ...digestReportLines(projection.findingsDigest)
2786
+ ];
2787
+ }
2788
+ if (projection.view === "reviewer") {
2789
+ return [
2790
+ "View: reviewer",
2791
+ `Session: ${projection.sessionId}`,
2792
+ `Revision: ${projection.revision}`,
2793
+ `Goal: ${projection.goal}`,
2794
+ `Feature: ${projection.feature ? `${projection.feature.id} - ${projection.feature.title}` : "unavailable"}`,
2795
+ `Reviewer assignment: ${projection.assignment.id}`,
2796
+ `Assignment kind: ${projection.assignment.kind}`,
2797
+ `Review feature: ${projection.assignment.featureId}`,
2798
+ `Risk lenses: ${projection.assignment.packet.riskLenses.join(", ") || "none"}`,
2799
+ `Artifacts changed: ${projection.artifactsChanged.length}`,
2800
+ `Validations: ${projection.validations.length}`,
2801
+ `Completed features: ${projection.completedFeatureIds.length}`,
2802
+ `Prior findings: ${projection.priorFindings.length}`,
2803
+ `Next finding id prefix: ${projection.nextFindingIdPrefix}`
2804
+ ];
2805
+ }
2806
+ const common = compactReport(projection);
2807
+ if (projection.view === "execution") {
2808
+ return [
2809
+ ...common,
2810
+ `Feature: ${projection.feature ? `${projection.feature.id} - ${projection.feature.title}` : "none"}`,
2811
+ `Run: ${projection.run ? `${projection.run.id}; state ${projection.run.state}` : "none"}`
2812
+ ];
2813
+ }
2814
+ if (projection.view === "detail") {
2815
+ const retryRequired = retryRequiredFeatureIds(projection);
2816
+ const validations = projection.runs.reduce((total, run) => total + run.validations.length, 0);
2817
+ const artifacts = new Set(projection.runs.flatMap((run) => run.artifactsChanged.map((artifact) => artifact.path)));
2818
+ return [
2819
+ ...common,
2820
+ `Plan features: ${projection.plan?.features.length ?? 0}`,
2821
+ `Runs: ${projection.runs.length}`,
2822
+ `Retry-required features: ${retryRequired.join(", ") || "none"}`,
2823
+ `Validation observations: ${validations}`,
2824
+ `Flow-reported artifacts: ${[...artifacts].sort().join(", ") || "none"}`,
2825
+ `Closure: ${projection.closure ? `${projection.closure.kind} - ${projection.closure.summary || "none"}` : "none"}`,
2826
+ `Operations recorded: ${projection.operations.length}`
2827
+ ];
2828
+ }
2829
+ return common;
2830
+ }
2611
2831
  function featureProgress(session) {
2612
2832
  const total = session.plan?.features.length ?? 0;
2613
2833
  const completed = session.plan?.features.filter((feature) => isFeatureComplete(session, feature.id)).length ?? 0;
@@ -4605,6 +4825,7 @@ function createConfigHook(ctx, options) {
4605
4825
  return;
4606
4826
  }
4607
4827
  applyFlowConfig(config, {
4828
+ ...options?.reviewerConfiguration ? { reviewerConfiguration: options.reviewerConfiguration } : {},
4608
4829
  onWarning: (warning) => log("warn", warning),
4609
4830
  onNotice: (notice) => log("info", notice),
4610
4831
  onCollision: (kind, name) => log("warn", `Flow replaced a user-defined ${kind} named '${name}'; rename the local entry while Flow is enabled.`)
@@ -4839,6 +5060,13 @@ function bestEffort(read) {
4839
5060
  }
4840
5061
  function withAutoContext(response, options, view) {
4841
5062
  let workflowData = response.workflowData;
5063
+ const reviewer = options.reviewerConfiguration;
5064
+ if (reviewer) {
5065
+ workflowData = {
5066
+ ...workflowData,
5067
+ reviewerConfiguration: flowReviewerStatus(reviewer)
5068
+ };
5069
+ }
4842
5070
  if (options.runtimeIdentity)
4843
5071
  workflowData = {
4844
5072
  ...workflowData,
@@ -4890,7 +5118,17 @@ function createTools(_ctx, options) {
4890
5118
  flow_status: defineFlowTool({
4891
5119
  description: "Read compact, execution, detail, or reviewer Flow state.",
4892
5120
  schema: StatusInputSchema,
4893
- execute: (args, context) => execute(context, async (workspace) => withAutoContext(await workspace.status(args), options, args.request.view))
5121
+ execute: (args, context) => execute(context, async (workspace) => {
5122
+ const response = await workspace.status(args);
5123
+ const workflowData = "projection" in response.workflowData ? {
5124
+ ...response.workflowData,
5125
+ statusReport: statusReport(response.workflowData.projection)
5126
+ } : response.workflowData;
5127
+ return withAutoContext({
5128
+ ...response,
5129
+ workflowData
5130
+ }, options, args.request.view);
5131
+ })
4894
5132
  }),
4895
5133
  flow_plan_save: defineFlowTool({
4896
5134
  description: "Create or replace the active draft plan.",
@@ -5266,8 +5504,12 @@ function guardTools(tools, runtimeGuard, autoDrive) {
5266
5504
  }
5267
5505
  ]));
5268
5506
  }
5269
- var FlowPlugin = async (ctx) => {
5507
+ var FlowPlugin = async (ctx, pluginOptions) => {
5270
5508
  const log = createFlowLog(ctx);
5509
+ const reviewerConfiguration = resolveFlowReviewerConfiguration({
5510
+ pluginOptions,
5511
+ onWarning: (warning) => log("warn", warning)
5512
+ });
5271
5513
  const version = resolveFlowPluginVersion();
5272
5514
  const pluginEntrySha256 = `sha256:${createHash6("sha256").update(await readFile2(fileURLToPath(import.meta.url))).digest("hex")}`;
5273
5515
  const runtimeGuard = registerFlowPluginInstance(ctx.worktree ?? ctx.directory, {
@@ -5320,11 +5562,13 @@ var FlowPlugin = async (ctx) => {
5320
5562
  prepareValidation: prepareWorkspaceValidation,
5321
5563
  autoTimingSnapshot: () => autoDrive.timingSnapshot(),
5322
5564
  autoContinuationSupport: () => autoDrive.continuationSupport(),
5565
+ reviewerConfiguration,
5323
5566
  runtimeIdentity: { packageVersion: version, pluginEntrySha256 }
5324
5567
  });
5325
5568
  return {
5326
5569
  config: createConfigHook(ctx, {
5327
- assertOperational: (action) => runtimeGuard.assertOperational(action)
5570
+ assertOperational: (action) => runtimeGuard.assertOperational(action),
5571
+ reviewerConfiguration
5328
5572
  }),
5329
5573
  tool: guardTools(tools, runtimeGuard, autoDrive),
5330
5574
  "command.execute.before": createCommandHook((action) => runtimeGuard.assertOperational(action), autoDrive, workspace),
@@ -5387,4 +5631,4 @@ export {
5387
5631
  plugin_default as default
5388
5632
  };
5389
5633
 
5390
- //# debugId=B115FE46858F6B0164756E2164756E21
5634
+ //# debugId=29653CBC4F7B7BAE64756E2164756E21