opencode-plugin-flow 4.3.9 → 5.0.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 (43) hide show
  1. package/CHANGELOG.md +84 -0
  2. package/README.md +59 -48
  3. package/dist/application/errors.d.ts +5 -0
  4. package/dist/{runtime/api.d.ts → application/flow-service.d.ts} +89 -57
  5. package/dist/application/ports/session-repository.d.ts +11 -0
  6. package/dist/{runtime → application}/schema.d.ts +291 -371
  7. package/dist/cli.js +283 -2773
  8. package/dist/cli.js.map +7 -6
  9. package/dist/config-shared.d.ts +30 -16
  10. package/dist/config.d.ts +1 -1
  11. package/dist/distribution/legacy-cleanup.d.ts +25 -0
  12. package/dist/domain/feature-id.d.ts +3 -0
  13. package/dist/domain/limits.d.ts +1 -0
  14. package/dist/domain/orchestration-policy.d.ts +27 -0
  15. package/dist/domain/session.d.ts +181 -0
  16. package/dist/domain/transitions.d.ts +80 -0
  17. package/dist/guidance/catalog.d.ts +18 -0
  18. package/dist/guidance/ids.d.ts +4 -0
  19. package/dist/index.d.ts +1 -1
  20. package/dist/index.js +2676 -1929
  21. package/dist/index.js.map +24 -16
  22. package/dist/infrastructure/fs/session-repository.d.ts +2 -0
  23. package/dist/infrastructure/fs/workspace-flow-service.d.ts +9 -0
  24. package/dist/{runtime → infrastructure/fs}/workspace.d.ts +10 -14
  25. package/dist/infrastructure/system/transition-environment.d.ts +2 -0
  26. package/dist/platform/opencode/config.d.ts +2 -0
  27. package/dist/{adapters → platform}/opencode/plugin.d.ts +1 -1
  28. package/dist/{adapters → platform}/opencode/sdk.d.ts +0 -1
  29. package/dist/platform/opencode/tools.d.ts +6 -0
  30. package/dist/prompt-baseline-fixtures.d.ts +19 -0
  31. package/dist/prompt-model-evaluation.d.ts +88 -0
  32. package/dist/prompt-quality.d.ts +73 -0
  33. package/dist/prompt-surfaces.d.ts +28 -0
  34. package/dist/version.d.ts +1 -0
  35. package/package.json +19 -12
  36. package/dist/adapters/opencode/config.d.ts +0 -3
  37. package/dist/adapters/opencode/tools.d.ts +0 -322
  38. package/dist/distribution/flow-skill-definitions.d.ts +0 -9
  39. package/dist/distribution/sync.d.ts +0 -69
  40. package/dist/runtime/time.d.ts +0 -2
  41. package/dist/runtime/transitions.d.ts +0 -230
  42. /package/dist/{runtime/json/strict-object.d.ts → infrastructure/fs/strict-json-object.d.ts} +0 -0
  43. /package/dist/{adapters → platform}/opencode/logging.d.ts +0 -0
@@ -0,0 +1,2 @@
1
+ import type { SessionRepository } from "../../application/ports/session-repository.js";
2
+ export declare function createFileSessionRepository(workspace: string): SessionRepository;
@@ -0,0 +1,9 @@
1
+ import { type FlowResponse, type FlowService } from "../../application/flow-service.js";
2
+ export declare function createWorkspaceFlowService(workspace: string): FlowService;
3
+ export declare function flowStatus(workspace: string): Promise<FlowResponse>;
4
+ export declare function flowPlanSave(workspace: string, input: unknown): Promise<FlowResponse>;
5
+ export declare function flowPlanApprove(workspace: string): Promise<FlowResponse>;
6
+ export declare function flowRunStart(workspace: string, input: unknown): Promise<FlowResponse>;
7
+ export declare function flowFeatureComplete(workspace: string, input: unknown): Promise<FlowResponse>;
8
+ export declare function flowFeatureReset(workspace: string, input: unknown): Promise<FlowResponse>;
9
+ export declare function flowSessionClose(workspace: string, input: unknown): Promise<FlowResponse>;
@@ -1,7 +1,15 @@
1
- import { type Session } from "./schema";
1
+ import type { Session } from "../../domain/session.js";
2
2
  export declare class InvalidFlowWorkspaceRootError extends Error {
3
3
  readonly code = "INVALID_FLOW_WORKSPACE_ROOT";
4
- constructor(message: string);
4
+ constructor(message: string, options?: ErrorOptions);
5
+ }
6
+ export declare class UnsafeFlowWorkspaceLayoutError extends Error {
7
+ readonly code = "UNSAFE_FLOW_WORKSPACE_LAYOUT";
8
+ constructor(message: string, options?: ErrorOptions);
9
+ }
10
+ export declare class ArchiveCollisionError extends Error {
11
+ readonly code = "FLOW_ARCHIVE_COLLISION";
12
+ constructor(message: string, options?: ErrorOptions);
5
13
  }
6
14
  export declare function normalizeWorkspaceRoot(rawPath: string | undefined): string | null;
7
15
  export declare function assertMutableWorkspaceRoot(rawPath: string): string;
@@ -11,25 +19,13 @@ export declare function resolveWorkspaceRoot(context: {
11
19
  }): string;
12
20
  export declare function flowDir(worktree: string): string;
13
21
  export declare function sessionPath(worktree: string): string;
14
- export declare function flowInstructionPath(worktree: string): string;
15
22
  export declare function historyDir(worktree: string): string;
16
23
  export declare function archivedSessionPath(worktree: string, sessionId: string): string;
17
24
  export type SessionLockOptions = {
18
25
  timeoutMs?: number;
19
- staleMs?: number;
20
26
  };
21
27
  export declare function withSessionLock<T>(worktree: string, task: () => Promise<T>, lockOptions?: SessionLockOptions): Promise<T>;
22
- export declare class UnreadableFlowSessionError extends Error {
23
- readonly reason: string;
24
- readonly code = "UNREADABLE_FLOW_SESSION";
25
- constructor(message: string, reason: string);
26
- }
27
28
  export declare function loadSession(worktree: string): Promise<Session | null>;
28
29
  export declare function quarantineUnreadableSession(worktree: string): Promise<string | null>;
29
- export declare function flowSessionProgress(session: Session): {
30
- completed: number;
31
- total: number;
32
- };
33
- export declare function refreshFlowInstructionFile(worktree: string): Promise<void>;
34
30
  export declare function saveSession(worktree: string, session: Session): Promise<Session>;
35
31
  export declare function archiveAndClearSession(worktree: string, session: Session): Promise<void>;
@@ -0,0 +1,2 @@
1
+ import type { TransitionEnvironment } from "../../domain/transitions.js";
2
+ export declare const systemTransitionEnvironment: TransitionEnvironment;
@@ -0,0 +1,2 @@
1
+ import { type MutableFlowConfig } from "../../config-shared.js";
2
+ export declare function createConfigHook(ctx: unknown): (config: MutableFlowConfig) => Promise<void>;
@@ -1,3 +1,3 @@
1
- import type { Plugin } from "./sdk";
1
+ import type { Plugin } from "./sdk.js";
2
2
  declare const FlowPlugin: Plugin;
3
3
  export default FlowPlugin;
@@ -1,3 +1,2 @@
1
1
  export type { Hooks, Plugin, ToolContext } from "@opencode-ai/plugin";
2
2
  export { tool } from "@opencode-ai/plugin";
3
- export type { Part } from "@opencode-ai/sdk";
@@ -0,0 +1,6 @@
1
+ import { type Hooks } from "@opencode-ai/plugin";
2
+ export type FlowHostInputOperation = "planSave" | "runStart" | "featureComplete" | "featureReset" | "sessionClose";
3
+ export declare function acceptsFlowHostInput(operation: FlowHostInputOperation, input: unknown): boolean;
4
+ type FlowTools = NonNullable<Hooks["tool"]>;
5
+ export declare function createTools(ctx: unknown): FlowTools;
6
+ export {};
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Frozen historical prompt assembly used only for comparative evaluation.
3
+ *
4
+ * These strings capture the pre-compiler public startup and hidden-worker
5
+ * prompts. They are not production prompt sources and must never be selected by
6
+ * the default compiled Flow surfaces. Keep the exception explicit so manual
7
+ * baseline text cannot be mistaken for a maintained projection of skill rules.
8
+ */
9
+ export declare const LEGACY_PROMPT_BASELINE: Readonly<{
10
+ publicCommandPreflight: string;
11
+ workerPrompts: Readonly<{
12
+ "flow-evidence-worker": "Use Flow evidence mode. Inspect only the assigned slice, do not edit files, do not call state-changing Flow tools, and return coverage, evidence inspected, confidence-tagged findings or facts, gaps, and manager follow-ups. Return only the assigned Flow handoff. Cite or drop every claim, label single-source, inferred, and unsettled claims, and report blocked if the assigned scope, expected coverage, or handoff shape is missing. Empty or unstructured output is a failed handoff; return blocked with the missing elements instead.";
13
+ "flow-validation-worker": "Use Flow validation mode. Run only manager-specified commands or propose focused checks, do not edit files, do not call state-changing Flow tools, and report exact command, status, raw outcome summary, coverage, confidence, gaps, and manager follow-ups. Return only the assigned Flow handoff. Cite or drop every claim, label single-source, inferred, and unsettled claims, and report blocked if the assigned scope, expected coverage, or handoff shape is missing. Empty or unstructured output is a failed handoff; return blocked with the missing elements instead.";
14
+ "flow-audit-worker": "Use Flow audit mode. Inspect only the assigned slice, actively refute candidate findings before reporting them, do not edit files, do not call state-changing Flow tools, and return coverage, evidence, guards checked, confidence, gaps, and manager follow-ups. Return only the assigned Flow handoff. Cite or drop every claim, label single-source, inferred, and unsettled claims, and report blocked if the assigned scope, expected coverage, or handoff shape is missing. Empty or unstructured output is a failed handoff; return blocked with the missing elements instead.";
15
+ "flow-candidate-worker": "Use Flow candidate-implementation mode only when the manager assigned an isolated worktree or exact non-overlapping path ownership. Do not edit .flow/**, do not call state-changing Flow tools, do not complete Flow state, and return changed or proposed patch, verification run, coverage, confidence, merge risks, and manager follow-ups. Return only the assigned Flow handoff. Cite or drop every claim, label single-source, inferred, and unsettled claims, and report blocked if the assigned scope, expected coverage, or handoff shape is missing. Empty or unstructured output is a failed handoff; return blocked with the missing elements instead.";
16
+ "flow-verifier-worker": "Use Flow verifier mode. Verify only the assigned claims against the provided sources, commands, counts, or current docs. Do not generate new scope, do not edit files, do not call state-changing Flow tools, and return supported, partly-supported, unsupported, or source-not-found per claim with evidence, confidence, gaps, and manager follow-ups. Return only the assigned Flow handoff. Cite or drop every claim, label single-source, inferred, and unsettled claims, and report blocked if the assigned scope, expected coverage, or handoff shape is missing. Empty or unstructured output is a failed handoff; return blocked with the missing elements instead.";
17
+ }>;
18
+ reviewerSections: readonly string[];
19
+ }>;
@@ -0,0 +1,88 @@
1
+ import { z } from "zod";
2
+ import { type FlowPromptVariant } from "./prompt-surfaces.js";
3
+ declare const ModelDecisionSchema: z.ZodObject<{
4
+ id: z.ZodString;
5
+ route: z.ZodEnum<{
6
+ "flow-audit-worker": "flow-audit-worker";
7
+ "flow-auto": "flow-auto";
8
+ "flow-candidate-worker": "flow-candidate-worker";
9
+ "flow-evidence-worker": "flow-evidence-worker";
10
+ "flow-plan": "flow-plan";
11
+ "flow-review": "flow-review";
12
+ "flow-reviewer": "flow-reviewer";
13
+ "flow-run": "flow-run";
14
+ "flow-status": "flow-status";
15
+ "flow-validation-worker": "flow-validation-worker";
16
+ "flow-verifier-worker": "flow-verifier-worker";
17
+ }>;
18
+ executionMode: z.ZodEnum<{
19
+ blocked: "blocked";
20
+ candidate_worker: "candidate_worker";
21
+ readonly_parallel: "readonly_parallel";
22
+ serial: "serial";
23
+ }>;
24
+ workers: z.ZodArray<z.ZodString>;
25
+ stateOwner: z.ZodEnum<{
26
+ "root-manager": "root-manager";
27
+ worker: "worker";
28
+ }>;
29
+ callsStatusFirst: z.ZodBoolean;
30
+ planOnly: z.ZodBoolean;
31
+ reviewFirst: z.ZodBoolean;
32
+ validation: z.ZodArray<z.ZodEnum<{
33
+ behavioral: "behavioral";
34
+ broad: "broad";
35
+ browser: "browser";
36
+ focused: "focused";
37
+ ui: "ui";
38
+ }>>;
39
+ independentReview: z.ZodBoolean;
40
+ reviewDepth: z.ZodEnum<{
41
+ broad: "broad";
42
+ detailed: "detailed";
43
+ not_applicable: "not_applicable";
44
+ quick: "quick";
45
+ standard: "standard";
46
+ }>;
47
+ manifestComplete: z.ZodBoolean;
48
+ coverage: z.ZodEnum<{
49
+ complete: "complete";
50
+ missing: "missing";
51
+ not_applicable: "not_applicable";
52
+ partial: "partial";
53
+ }>;
54
+ handoffStatus: z.ZodEnum<{
55
+ blocked: "blocked";
56
+ not_applicable: "not_applicable";
57
+ partial: "partial";
58
+ success: "success";
59
+ }>;
60
+ handoffHasRequiredSections: z.ZodBoolean;
61
+ retryReviews: z.ZodNumber;
62
+ stopsAfterRetryFailure: z.ZodBoolean;
63
+ candidateDecision: z.ZodEnum<{
64
+ not_applicable: "not_applicable";
65
+ serial_required: "serial_required";
66
+ used: "used";
67
+ }>;
68
+ completionClaimed: z.ZodBoolean;
69
+ reason: z.ZodString;
70
+ }, z.core.$strict>;
71
+ export type ModelDecision = z.infer<typeof ModelDecisionSchema>;
72
+ export type ModelEvaluationGrade = {
73
+ passedScenarios: number;
74
+ totalScenarios: number;
75
+ passedCriteria: number;
76
+ totalCriteria: number;
77
+ scenarios: Array<{
78
+ id: string;
79
+ passed: boolean;
80
+ passedCriteria: number;
81
+ totalCriteria: number;
82
+ failures: string[];
83
+ }>;
84
+ };
85
+ export declare function buildPromptModelEvaluationPacket(variant: FlowPromptVariant): string;
86
+ export declare function parseModelDecisionResponse(text: string): ModelDecision[];
87
+ export declare function gradeModelDecisions(decisions: readonly ModelDecision[]): ModelEvaluationGrade;
88
+ export {};
@@ -0,0 +1,73 @@
1
+ import { type CompiledFlowPrompt, type FlowPromptSurfaceName, type FlowPromptVariant } from "./prompt-surfaces.js";
2
+ export type PromptMetric = {
3
+ surface: string;
4
+ variant: FlowPromptVariant | "runtime";
5
+ sources: string[];
6
+ characters: number;
7
+ words: number;
8
+ approximateTokens: number;
9
+ actionableInstructions: number;
10
+ exactDuplicateLines: number;
11
+ repeatedFiveGrams: number;
12
+ nearDuplicateLinePairs: number;
13
+ negativeInstructions: number;
14
+ negativeInstructionDensity: number;
15
+ codeFences: number;
16
+ conditionalFragments: string[];
17
+ roleInapplicableFragments: string[];
18
+ roleInapplicableLines: number;
19
+ criticalRulePositions: Record<string, number | null>;
20
+ structurallyEnforcedRulesPresent: string[];
21
+ terminologyWarnings: string[];
22
+ };
23
+ export type PromptEvaluationResult = {
24
+ variant: FlowPromptVariant;
25
+ scenariosPassed: number;
26
+ scenariosTotal: number;
27
+ criteriaPassed: number;
28
+ criteriaTotal: number;
29
+ staticApproximateTokens: number;
30
+ roleInapplicableLines: number;
31
+ exactDuplicateLines: number;
32
+ scenarios: Array<{
33
+ id: string;
34
+ name: string;
35
+ passed: boolean;
36
+ passedCriteria: number;
37
+ totalCriteria: number;
38
+ failures: string[];
39
+ }>;
40
+ };
41
+ export type PromptRepetitionClassification = {
42
+ id: string;
43
+ classification: "keep" | "consolidate" | "enforce-structurally" | "load-conditionally" | "remove" | "evaluate";
44
+ occurrences: string[];
45
+ rationale: string;
46
+ };
47
+ export declare function measurePromptText(options: {
48
+ surface: string;
49
+ variant: FlowPromptVariant | "runtime";
50
+ text: string;
51
+ compiled?: CompiledFlowPrompt;
52
+ }): PromptMetric;
53
+ export declare function measureCompiledPrompt(compiled: CompiledFlowPrompt): PromptMetric;
54
+ type PromptScenario = {
55
+ id: string;
56
+ name: string;
57
+ input: string;
58
+ expectedRoute: FlowPromptSurfaceName;
59
+ surface: FlowPromptSurfaceName;
60
+ required: Array<{
61
+ label: string;
62
+ pattern: RegExp;
63
+ }>;
64
+ forbidden?: Array<{
65
+ label: string;
66
+ pattern: RegExp;
67
+ }>;
68
+ };
69
+ export declare const PROMPT_EVALUATION_SCENARIOS: readonly PromptScenario[];
70
+ export declare function evaluatePromptVariant(variant: FlowPromptVariant): PromptEvaluationResult;
71
+ export declare const PROMPT_REPETITION_CLASSIFICATIONS: readonly PromptRepetitionClassification[];
72
+ export declare function promptInventoryForVariant(variant: FlowPromptVariant): PromptMetric[];
73
+ export {};
@@ -0,0 +1,28 @@
1
+ export type FlowPromptVariant = "baseline" | "lexically-deduplicated" | "surface-specific" | "surface-specific-bookended";
2
+ export type FlowPromptSurfaceName = "flow-auto" | "flow-plan" | "flow-run" | "flow-review" | "flow-status" | "flow-reviewer" | "flow-evidence-worker" | "flow-validation-worker" | "flow-audit-worker" | "flow-candidate-worker" | "flow-verifier-worker";
3
+ export type FlowPromptRole = "manager" | "reviewer" | "evidence-worker" | "validation-worker" | "audit-worker" | "candidate-worker" | "verifier-worker";
4
+ export type FlowPromptFragmentKind = "purpose" | "invariant" | "procedure" | "reference" | "schema" | "checkpoint";
5
+ export type FlowPromptFragment = {
6
+ id: string;
7
+ source: string;
8
+ origin: "skill-source" | "compiler";
9
+ kind: FlowPromptFragmentKind;
10
+ text: string;
11
+ roles: readonly FlowPromptRole[];
12
+ conditional?: boolean;
13
+ };
14
+ export type CompiledFlowPrompt = {
15
+ surface: FlowPromptSurfaceName;
16
+ variant: FlowPromptVariant;
17
+ role: FlowPromptRole;
18
+ text: string;
19
+ fragments: readonly FlowPromptFragment[];
20
+ };
21
+ export type FlowWorkerHandoffKind = "evidence" | "validation" | "audit" | "review-slice" | "verifier" | "candidate";
22
+ export declare function compileFlowPromptSurface(surface: FlowPromptSurfaceName, variant?: FlowPromptVariant): CompiledFlowPrompt;
23
+ export declare const FLOW_STATIC_PROMPT_SURFACES: readonly FlowPromptSurfaceName[];
24
+ export declare function compiledFlowPromptSurfaces(variant?: FlowPromptVariant): Record<FlowPromptSurfaceName, CompiledFlowPrompt>;
25
+ export declare function validateFlowWorkerHandoff(kind: FlowWorkerHandoffKind, text: string): {
26
+ ok: boolean;
27
+ errors: string[];
28
+ };
@@ -0,0 +1 @@
1
+ export declare function resolveFlowPluginVersion(): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-plugin-flow",
3
- "version": "4.3.9",
3
+ "version": "5.0.0",
4
4
  "description": "Stateful planning and execution workflow plugin for OpenCode",
5
5
  "type": "module",
6
6
  "repository": {
@@ -26,18 +26,20 @@
26
26
  "CHANGELOG.md"
27
27
  ],
28
28
  "scripts": {
29
- "build": "bun run build:plugin && bun run build:cli && bun run build:types",
29
+ "build": "bun run clean && bun run build:plugin && bun run build:cli && bun run build:types",
30
30
  "build:plugin": "bun build --target=node --outdir=./dist --entry-naming=index.js --external=@opencode-ai/plugin --external=zod --sourcemap=external ./src/index.ts",
31
31
  "build:cli": "bun build --target=node --outdir=./dist --entry-naming=cli.js --banner='#!/usr/bin/env node' --sourcemap=external ./src/cli.ts",
32
32
  "build:types": "tsc -p tsconfig.types.json",
33
- "lint": "bunx biome check src tests --files-ignore-unknown=true --vcs-use-ignore-file=true",
33
+ "clean": "bun run scripts/clean-dist.ts",
34
+ "lint": "bunx biome check src tests scripts --files-ignore-unknown=true --vcs-use-ignore-file=true",
35
+ "prompt:quality": "bun run scripts/prompt-quality.ts",
36
+ "prompt:model-eval": "bun run scripts/prompt-model-eval.ts",
34
37
  "package:smoke": "bun test tests/package-smoke.test.ts",
35
38
  "release:monitor": "node scripts/release-monitor.mjs",
36
39
  "smoke:live": "FLOW_LIVE_SMOKE=1 bun test tests/live-opencode-smoke.test.ts",
37
40
  "test": "bun test tests",
38
41
  "typecheck": "tsc --noEmit",
39
- "uninstall:opencode": "bun run ./src/cli.ts uninstall",
40
- "check": "bun run typecheck && bun run lint && bun run build && bun run test"
42
+ "check": "bun run typecheck && bun run lint && bun run prompt:quality && bun run build && bun run test"
41
43
  },
42
44
  "keywords": [
43
45
  "opencode",
@@ -48,19 +50,24 @@
48
50
  ],
49
51
  "author": "Douwe de Vries",
50
52
  "license": "MIT",
53
+ "packageManager": "bun@1.3.14",
51
54
  "engines": {
52
- "node": ">=20.12.0"
55
+ "node": ">=24"
53
56
  },
54
57
  "peerDependencies": {
55
- "@opencode-ai/plugin": ">=1.17.3 <2"
58
+ "@opencode-ai/plugin": ">=1.18.3 <2"
56
59
  },
57
60
  "dependencies": {
58
- "zod": "4.1.8"
61
+ "zod": "4.4.3"
59
62
  },
60
63
  "devDependencies": {
61
- "@biomejs/biome": "^2.2.6",
62
- "@opencode-ai/plugin": "1.17.3",
63
- "bun-types": "latest",
64
- "typescript": "^6.0.2"
64
+ "@biomejs/biome": "2.5.4",
65
+ "@opencode-ai/plugin": "1.18.3",
66
+ "@types/bun": "1.3.14",
67
+ "@types/node": "24.13.3",
68
+ "typescript": "7.0.2"
69
+ },
70
+ "overrides": {
71
+ "@types/node": "24.13.3"
65
72
  }
66
73
  }
@@ -1,3 +0,0 @@
1
- import { type MutableFlowConfig } from "../../config-shared";
2
- import type { ToolContext } from "./sdk";
3
- export declare function createConfigHook(ctx: Pick<ToolContext, "worktree" | "directory">): (config: MutableFlowConfig) => Promise<void>;