@h-rig/cli-surface-plugin 0.0.6-alpha.146

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 (94) hide show
  1. package/README.md +1 -0
  2. package/dist/src/app/drone-ui.d.ts +34 -0
  3. package/dist/src/app/drone-ui.js +278 -0
  4. package/dist/src/commands/_async-ui.d.ts +10 -0
  5. package/dist/src/commands/_async-ui.js +121 -0
  6. package/dist/src/commands/_cli-format.d.ts +56 -0
  7. package/dist/src/commands/_cli-format.js +332 -0
  8. package/dist/src/commands/_connection-state.d.ts +54 -0
  9. package/dist/src/commands/_connection-state.js +187 -0
  10. package/dist/src/commands/_doctor-checks.d.ts +9 -0
  11. package/dist/src/commands/_doctor-checks.js +24 -0
  12. package/dist/src/commands/_help-catalog.d.ts +29 -0
  13. package/dist/src/commands/_help-catalog.js +157 -0
  14. package/dist/src/commands/_inprocess-services.d.ts +33 -0
  15. package/dist/src/commands/_inprocess-services.js +102 -0
  16. package/dist/src/commands/_json-output.d.ts +11 -0
  17. package/dist/src/commands/_json-output.js +54 -0
  18. package/dist/src/commands/_parsers.d.ts +15 -0
  19. package/dist/src/commands/_parsers.js +114 -0
  20. package/dist/src/commands/_paths.d.ts +11 -0
  21. package/dist/src/commands/_paths.js +50 -0
  22. package/dist/src/commands/_pi-frontend.d.ts +35 -0
  23. package/dist/src/commands/_pi-frontend.js +64 -0
  24. package/dist/src/commands/_pi-install.d.ts +42 -0
  25. package/dist/src/commands/_pi-install.js +167 -0
  26. package/dist/src/commands/_policy.d.ts +8 -0
  27. package/dist/src/commands/_policy.js +138 -0
  28. package/dist/src/commands/_probes.d.ts +1 -0
  29. package/dist/src/commands/_probes.js +13 -0
  30. package/dist/src/commands/_run-driver-helpers.d.ts +26 -0
  31. package/dist/src/commands/_run-driver-helpers.js +132 -0
  32. package/dist/src/commands/_run-subcommands.d.ts +3 -0
  33. package/dist/src/commands/_run-subcommands.js +31 -0
  34. package/dist/src/commands/_spinner.d.ts +25 -0
  35. package/dist/src/commands/_spinner.js +65 -0
  36. package/dist/src/commands/agent.d.ts +3 -0
  37. package/dist/src/commands/agent.js +322 -0
  38. package/dist/src/commands/config.d.ts +3 -0
  39. package/dist/src/commands/config.js +193 -0
  40. package/dist/src/commands/dist.d.ts +28 -0
  41. package/dist/src/commands/dist.js +435 -0
  42. package/dist/src/commands/doctor.d.ts +3 -0
  43. package/dist/src/commands/doctor.js +171 -0
  44. package/dist/src/commands/github.d.ts +3 -0
  45. package/dist/src/commands/github.js +342 -0
  46. package/dist/src/commands/inbox.d.ts +19 -0
  47. package/dist/src/commands/inbox.js +241 -0
  48. package/dist/src/commands/init.d.ts +64 -0
  49. package/dist/src/commands/init.js +1449 -0
  50. package/dist/src/commands/inspect.d.ts +20 -0
  51. package/dist/src/commands/inspect.js +337 -0
  52. package/dist/src/commands/pi.d.ts +3 -0
  53. package/dist/src/commands/pi.js +177 -0
  54. package/dist/src/commands/plugin.d.ts +20 -0
  55. package/dist/src/commands/plugin.js +238 -0
  56. package/dist/src/commands/profile-and-review.d.ts +4 -0
  57. package/dist/src/commands/profile-and-review.js +223 -0
  58. package/dist/src/commands/queue.d.ts +3 -0
  59. package/dist/src/commands/queue.js +197 -0
  60. package/dist/src/commands/remote.d.ts +3 -0
  61. package/dist/src/commands/remote.js +516 -0
  62. package/dist/src/commands/repo-git-harness.d.ts +5 -0
  63. package/dist/src/commands/repo-git-harness.js +282 -0
  64. package/dist/src/commands/run.d.ts +22 -0
  65. package/dist/src/commands/run.js +645 -0
  66. package/dist/src/commands/server.d.ts +3 -0
  67. package/dist/src/commands/server.js +155 -0
  68. package/dist/src/commands/setup.d.ts +16 -0
  69. package/dist/src/commands/setup.js +356 -0
  70. package/dist/src/commands/stats.d.ts +11 -0
  71. package/dist/src/commands/stats.js +219 -0
  72. package/dist/src/commands/task-run-driver.d.ts +93 -0
  73. package/dist/src/commands/task-run-driver.js +136 -0
  74. package/dist/src/commands/task.d.ts +46 -0
  75. package/dist/src/commands/task.js +555 -0
  76. package/dist/src/commands/test.d.ts +3 -0
  77. package/dist/src/commands/test.js +46 -0
  78. package/dist/src/commands/triage.d.ts +11 -0
  79. package/dist/src/commands/triage.js +224 -0
  80. package/dist/src/commands/workspace.d.ts +3 -0
  81. package/dist/src/commands/workspace.js +130 -0
  82. package/dist/src/kernel-dispatch.d.ts +15 -0
  83. package/dist/src/kernel-dispatch.js +16 -0
  84. package/dist/src/plugin.d.ts +3 -0
  85. package/dist/src/plugin.js +5440 -0
  86. package/dist/src/rig-config-package-deps.d.ts +10 -0
  87. package/dist/src/rig-config-package-deps.js +272 -0
  88. package/dist/src/runner.d.ts +47 -0
  89. package/dist/src/runner.js +267 -0
  90. package/dist/src/version.d.ts +8 -0
  91. package/dist/src/version.js +47 -0
  92. package/dist/src/withMutedConsole.d.ts +2 -0
  93. package/dist/src/withMutedConsole.js +42 -0
  94. package/package.json +34 -0
@@ -0,0 +1,219 @@
1
+ // @bun
2
+ // packages/cli-surface-plugin/src/commands/stats.ts
3
+ import { computeStats } from "@rig/client";
4
+
5
+ // packages/cli-surface-plugin/src/runner.ts
6
+ import { EventBus } from "@rig/runtime/control-plane/runtime/events";
7
+ import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
8
+ import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
9
+ import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
10
+
11
+ class CliError extends RuntimeCliError {
12
+ hint;
13
+ constructor(message, exitCode = 1, options = {}) {
14
+ super(message, exitCode);
15
+ if (options.hint?.trim()) {
16
+ this.hint = options.hint.trim();
17
+ }
18
+ }
19
+ }
20
+ function takeOption(args, option) {
21
+ const rest = [];
22
+ let value;
23
+ for (let index = 0;index < args.length; index += 1) {
24
+ const current = args[index];
25
+ if (current === option) {
26
+ const next = args[index + 1];
27
+ if (!next || next.startsWith("-")) {
28
+ throw new CliError(`Missing value for ${option}`, 1, { hint: `Provide a value after ${option}, e.g. \`${option} <value>\`.` });
29
+ }
30
+ value = next;
31
+ index += 1;
32
+ continue;
33
+ }
34
+ if (current !== undefined) {
35
+ rest.push(current);
36
+ }
37
+ }
38
+ return { value, rest };
39
+ }
40
+ function requireNoExtraArgs(args, usage) {
41
+ if (args.length > 0) {
42
+ throw new CliError(`Unexpected arguments: ${args.join(" ")}
43
+ Usage: ${usage}`);
44
+ }
45
+ }
46
+
47
+ // packages/cli-surface-plugin/src/commands/_cli-format.ts
48
+ import pc from "picocolors";
49
+ import { runStatusColorRole, runStatusText, statusColorRole } from "@rig/client";
50
+ var dim = pc.dim;
51
+ var faintBar = pc.dim("\u2502");
52
+ var accent = pc.cyan;
53
+ function compactValue(value) {
54
+ if (value === null || value === undefined)
55
+ return "\u2014";
56
+ if (typeof value === "string")
57
+ return value;
58
+ if (typeof value === "number" || typeof value === "boolean")
59
+ return String(value);
60
+ return JSON.stringify(value);
61
+ }
62
+ function printFormattedOutput(message) {
63
+ console.log(message);
64
+ }
65
+ function formatStatsTable(rows) {
66
+ return rows.map(([label, value]) => `${faintBar} ${dim(label.padEnd(20))} ${compactValue(value)}`).join(`
67
+ `);
68
+ }
69
+
70
+ // packages/cli-surface-plugin/src/commands/_help-catalog.ts
71
+ import pc2 from "picocolors";
72
+ import {
73
+ ADVANCED_COMMANDS,
74
+ ADVANCED_GROUPS,
75
+ ALL_GROUPS,
76
+ helpCatalog,
77
+ TOP_LEVEL_SECTIONS
78
+ } from "@rig/contracts";
79
+ function heading(title) {
80
+ return pc2.bold(pc2.cyan(title));
81
+ }
82
+ function commandLine(command, description) {
83
+ const commandColumn = command.length >= 38 ? `${command} ` : command.padEnd(38);
84
+ return `${pc2.dim("\u2502")} ${pc2.bold(commandColumn)} ${description}`;
85
+ }
86
+ function renderCommandBlock(commands) {
87
+ const indent = `${pc2.dim("\u2502")} ${" ".repeat(38)} `;
88
+ return commands.map((entry) => {
89
+ const lines = [commandLine(entry.command, entry.description)];
90
+ if (entry.usecase) {
91
+ lines.push(`${indent}${pc2.dim("when:")} ${pc2.dim(entry.usecase)}`);
92
+ }
93
+ for (const example of entry.examples ?? []) {
94
+ lines.push(`${indent}${pc2.dim("$")} ${pc2.cyan(example)}`);
95
+ }
96
+ return lines.join(`
97
+ `);
98
+ }).join(`
99
+ `);
100
+ }
101
+ function renderGroup(group) {
102
+ const lines = [
103
+ `${heading(`rig ${group.name}`)} \u2014 ${group.summary}`,
104
+ "",
105
+ pc2.bold("Usage"),
106
+ ...group.usage.map((line) => ` ${line}`),
107
+ "",
108
+ pc2.bold("Commands"),
109
+ ...group.commands.map((entry) => commandLine(entry.command, entry.description))
110
+ ];
111
+ if (group.examples?.length) {
112
+ lines.push("", pc2.bold("Examples"), ...group.examples.map((line) => ` ${pc2.dim("$")} ${line}`));
113
+ }
114
+ if (group.next?.length) {
115
+ lines.push("", pc2.bold("Next steps"), ...group.next.map((line) => ` ${pc2.dim("\u203A")} ${line}`));
116
+ }
117
+ if (group.advanced?.length) {
118
+ lines.push("", pc2.bold("Compatibility / advanced"), ...group.advanced.map((line) => ` ${pc2.dim("\u203A")} ${line}`));
119
+ }
120
+ return lines.join(`
121
+ `);
122
+ }
123
+ function renderTopLevelHelp() {
124
+ return [
125
+ `${heading("rig")} ${pc2.dim("\u2014 Rig Cockpit for autonomous coding agents")}`,
126
+ pc2.dim("The loop: bare `rig` \u2192 Cockpit \u2192 Server target \u2192 Tasks \u2192 Task detail \u2192 Dispatch/Attach; every run uses OMP collaboration as the session substrate."),
127
+ "",
128
+ ...TOP_LEVEL_SECTIONS.flatMap((section) => [
129
+ `${pc2.bold(pc2.magenta(`\u25C7 ${section.title}`))} \u2014 ${pc2.dim(section.subtitle)}`,
130
+ renderCommandBlock(section.commands),
131
+ ""
132
+ ]),
133
+ pc2.dim("More: `rig help --advanced` for fenced legacy/diagnostic commands; `rig <group> --help` for per-group compatibility help; `rig --version` for the installed version."),
134
+ "",
135
+ pc2.bold("Root options"),
136
+ commandLine("--workspace <path>", "Open Rig Cockpit for a workspace instead of the current directory."),
137
+ commandLine("--json", "Compatibility flag for fenced legacy/diagnostic subcommands."),
138
+ commandLine("--dry-run", "Compatibility flag for fenced legacy/diagnostic subcommands.")
139
+ ].join(`
140
+ `).trimEnd();
141
+ }
142
+ function renderGroupHelp(groupName) {
143
+ const group = ALL_GROUPS.find((candidate) => candidate.name === groupName);
144
+ return group ? renderGroup(group) : null;
145
+ }
146
+ function printGroupHelpDocument(groupName) {
147
+ console.log(renderGroupHelp(groupName) ?? renderTopLevelHelp());
148
+ }
149
+
150
+ // packages/cli-surface-plugin/src/commands/stats.ts
151
+ var DAY_MS = 24 * 60 * 60 * 1000;
152
+ function parseSinceOption(value, now = new Date) {
153
+ if (!value?.trim())
154
+ return null;
155
+ const trimmed = value.trim();
156
+ const relative = trimmed.match(/^(\d+)d$/i);
157
+ if (relative?.[1]) {
158
+ const days = Number.parseInt(relative[1], 10);
159
+ if (!Number.isFinite(days) || days <= 0)
160
+ throw new CliError(`Invalid --since value: ${value}`, 2, { hint: "Use an ISO date or a relative window like `7d`." });
161
+ return new Date(now.getTime() - days * DAY_MS);
162
+ }
163
+ const parsed = Date.parse(trimmed);
164
+ if (!Number.isFinite(parsed))
165
+ throw new CliError(`Invalid --since value: ${value}`, 2, { hint: "Use an ISO date or a relative window like `7d`." });
166
+ return new Date(parsed);
167
+ }
168
+ function formatPercent(value) {
169
+ return value === null ? "\u2014" : `${Math.round(value * 100)}%`;
170
+ }
171
+ function formatDuration(ms) {
172
+ if (ms === null)
173
+ return "\u2014";
174
+ const seconds = Math.round(ms / 1000);
175
+ if (seconds < 60)
176
+ return `${seconds}s`;
177
+ const minutes = Math.round(ms / 60000);
178
+ if (minutes < 60)
179
+ return `${minutes}m`;
180
+ const hours = Math.floor(minutes / 60);
181
+ const remainder = minutes % 60;
182
+ return remainder === 0 ? `${hours}h` : `${hours}h ${remainder}m`;
183
+ }
184
+ function formatStatsRows(stats) {
185
+ return [
186
+ ["window", stats.since ? `since ${stats.since}` : "all runs"],
187
+ ["total runs", stats.totalRuns],
188
+ ["completed", `${stats.completedRuns} (${formatPercent(stats.completionRate)})`],
189
+ ["failed", `${stats.failedRuns} (${formatPercent(stats.failureRate)})`],
190
+ ["needs attention", `${stats.needsAttentionRuns} (${formatPercent(stats.needsAttentionRate)})`],
191
+ ["median run time", formatDuration(stats.medianCompletionMs)],
192
+ ["steering", stats.steeringTotal],
193
+ ["stalls", stats.stallTotal],
194
+ ["pending approvals", stats.approvalsPending]
195
+ ];
196
+ }
197
+ async function executeStats(context, args, deps = {}) {
198
+ const [first = "show", ...rest] = args;
199
+ const command = first.startsWith("-") ? "show" : first;
200
+ const commandArgs = first.startsWith("-") ? args : rest;
201
+ if (command === "help") {
202
+ printGroupHelpDocument("stats");
203
+ return { ok: true, group: "stats", command };
204
+ }
205
+ if (command !== "show")
206
+ throw new CliError(`Unknown stats command: ${command}`, 1, { hint: "Run `rig stats --help` \u2014 the default command is `show`." });
207
+ const sinceResult = takeOption(commandArgs, "--since");
208
+ requireNoExtraArgs(sinceResult.rest, "rig stats [show] [--since <7d|30d|ISO date>]");
209
+ const statsOptions = deps.listRuns ? { since: parseSinceOption(sinceResult.value), listRuns: deps.listRuns } : { since: parseSinceOption(sinceResult.value) };
210
+ const details = await computeStats(context.projectRoot, statsOptions);
211
+ if (context.outputMode === "text")
212
+ printFormattedOutput(formatStatsTable(formatStatsRows(details)));
213
+ return { ok: true, group: "stats", command, details };
214
+ }
215
+ export {
216
+ parseSinceOption,
217
+ formatStatsRows,
218
+ executeStats
219
+ };
@@ -0,0 +1,93 @@
1
+ export type TaskRunReviewState = Record<string, unknown>;
2
+ export type TaskRunStageName = "Connect" | "Prepare" | "Execute" | "Validate" | "Review" | "Publish" | "Complete" | "Needs attention" | "Failed";
3
+ export type SubmitTaskRunInput = {
4
+ runId: string;
5
+ taskId?: string;
6
+ title?: string;
7
+ runtimeAdapter: "pi";
8
+ model?: string;
9
+ runtimeMode: string;
10
+ interactionMode: string;
11
+ initialPrompt?: string;
12
+ baselineMode?: "head" | "dirty-snapshot";
13
+ prMode?: "auto" | "ask" | "off";
14
+ };
15
+ type TaskRunAutomationConfig = {
16
+ review?: {
17
+ mode?: string;
18
+ provider?: string;
19
+ };
20
+ automation?: {
21
+ maxValidationAttempts?: number;
22
+ maxPrFixIterations?: number;
23
+ };
24
+ };
25
+ export declare function canonicalPiRunStages(): string[];
26
+ export declare function buildPiRigBridgeEnv(input: {
27
+ projectRoot: string;
28
+ runId: string;
29
+ taskId?: string | null;
30
+ runtimeMode?: string | null;
31
+ model?: string | null;
32
+ }): Record<string, string>;
33
+ export declare function applyDirtyBaselineSnapshot(input: {
34
+ sourceRoot: string;
35
+ targetRoot: string;
36
+ }): {
37
+ applied: boolean;
38
+ copiedUntracked: number;
39
+ detail: string;
40
+ };
41
+ export declare function buildTaskRunReviewEnv(config?: TaskRunAutomationConfig | null): Record<string, string>;
42
+ export declare function buildDirtyBaselineHandshakeEnv(input: {
43
+ projectRoot: string;
44
+ runId: string;
45
+ baselineMode: "head" | "dirty-snapshot";
46
+ }): Record<string, string>;
47
+ export declare function resolveTaskRunAutomationLimits(config?: TaskRunAutomationConfig | null, env?: Record<string, string | undefined>): {
48
+ maxValidationAttempts: number;
49
+ maxPrFixIterations: number;
50
+ };
51
+ export type PlanningClassification = {
52
+ needsPlanning: boolean;
53
+ reason: string;
54
+ };
55
+ export declare function classifyPlanningNeed(input: {
56
+ prompt: string;
57
+ acceptanceCriteria?: string | null;
58
+ }): PlanningClassification;
59
+ export declare function buildPiValidationRetrySteeringPrompt(input: {
60
+ taskId?: string | null;
61
+ attempt: number;
62
+ failureDetail: string;
63
+ }): string;
64
+ export declare function classifyValidationRetryOutcome(input: {
65
+ attempt: number;
66
+ maxAttempts: number;
67
+ failureDetail: string;
68
+ }): {
69
+ stage: "Validate failed";
70
+ status: "retry" | "needs_attention";
71
+ failureDetail: string;
72
+ };
73
+ export declare function taskRunStageLogId(runId: string, stage: TaskRunStageName): string;
74
+ export declare function createRunLogIdFactory(runId: string): () => string;
75
+ export declare function summarizeTaskRunProcessFailure(input: {
76
+ stage: string;
77
+ exitCode?: number | null;
78
+ stderr?: string | null;
79
+ stdout?: string | null;
80
+ fallback?: string | null;
81
+ }): string;
82
+ export declare function classifyCompletionVerificationLine(line: string): {
83
+ isCompletionLine: boolean;
84
+ stage: string | null;
85
+ status: "started" | "passed" | "failed" | null;
86
+ };
87
+ export declare function readTaskRunAcceptedArtifactState(input: {
88
+ artifactPath: string;
89
+ }): {
90
+ accepted: boolean;
91
+ reason: string | null;
92
+ };
93
+ export {};
@@ -0,0 +1,136 @@
1
+ // @bun
2
+ // packages/cli-surface-plugin/src/commands/task-run-driver.ts
3
+ import { copyFileSync, existsSync, mkdirSync, readdirSync, readFileSync } from "fs";
4
+ import { resolve } from "path";
5
+ var PI_CANONICAL_RUN_STAGES = ["Connect", "Prepare", "Execute", "Validate", "Review", "Publish", "Complete"];
6
+ function canonicalPiRunStages() {
7
+ return [...PI_CANONICAL_RUN_STAGES];
8
+ }
9
+ function buildPiRigBridgeEnv(input) {
10
+ return {
11
+ PROJECT_RIG_ROOT: input.projectRoot,
12
+ RIG_RUN_ID: input.runId,
13
+ ...input.taskId ? { RIG_TASK_ID: input.taskId } : {},
14
+ ...input.runtimeMode ? { RIG_RUNTIME_MODE: input.runtimeMode } : {},
15
+ ...input.model ? { RIG_MODEL: input.model } : {}
16
+ };
17
+ }
18
+ function copyTree(sourceRoot, targetRoot) {
19
+ if (!existsSync(sourceRoot))
20
+ return 0;
21
+ let copied = 0;
22
+ for (const entry of readdirSync(sourceRoot, { withFileTypes: true })) {
23
+ const sourcePath = resolve(sourceRoot, entry.name);
24
+ const targetPath = resolve(targetRoot, entry.name);
25
+ if (entry.isDirectory()) {
26
+ mkdirSync(targetPath, { recursive: true });
27
+ copied += copyTree(sourcePath, targetPath);
28
+ continue;
29
+ }
30
+ mkdirSync(resolve(targetPath, ".."), { recursive: true });
31
+ copyFileSync(sourcePath, targetPath);
32
+ copied += 1;
33
+ }
34
+ return copied;
35
+ }
36
+ function applyDirtyBaselineSnapshot(input) {
37
+ mkdirSync(input.targetRoot, { recursive: true });
38
+ const copied = copyTree(input.sourceRoot, input.targetRoot);
39
+ return {
40
+ applied: copied > 0,
41
+ copiedUntracked: copied,
42
+ detail: copied > 0 ? `Copied ${copied} file(s) into the runtime workspace.` : "No files copied."
43
+ };
44
+ }
45
+ function buildTaskRunReviewEnv(config) {
46
+ return {
47
+ ...config?.review?.mode ? { AI_REVIEW_MODE: config.review.mode } : {},
48
+ ...config?.review?.provider ? { AI_REVIEW_PROVIDER: config.review.provider } : {}
49
+ };
50
+ }
51
+ function buildDirtyBaselineHandshakeEnv(input) {
52
+ return {
53
+ RIG_DIRTY_BASELINE_MODE: input.baselineMode,
54
+ RIG_DIRTY_BASELINE_READY_FILE: resolve(input.projectRoot, ".rig", "state", `${input.runId}.dirty-ready`)
55
+ };
56
+ }
57
+ function resolveTaskRunAutomationLimits(config, env = process.env) {
58
+ const maxValidationAttempts = Number.parseInt(env.RIG_MAX_VALIDATION_ATTEMPTS ?? "", 10);
59
+ const maxPrFixIterations = Number.parseInt(env.RIG_MAX_PR_FIX_ITERATIONS ?? "", 10);
60
+ return {
61
+ maxValidationAttempts: Number.isFinite(maxValidationAttempts) && maxValidationAttempts > 0 ? maxValidationAttempts : config?.automation?.maxValidationAttempts ?? 30,
62
+ maxPrFixIterations: Number.isFinite(maxPrFixIterations) && maxPrFixIterations > 0 ? maxPrFixIterations : config?.automation?.maxPrFixIterations ?? 100500
63
+ };
64
+ }
65
+ function classifyPlanningNeed(input) {
66
+ const text = `${input.prompt}
67
+ ${input.acceptanceCriteria ?? ""}`.toLowerCase();
68
+ const needsPlanning = /plan|design|approach|architecture|multi-step/.test(text);
69
+ return { needsPlanning, reason: needsPlanning ? "operator requested a planning pass" : "no planning trigger detected" };
70
+ }
71
+ function buildPiValidationRetrySteeringPrompt(input) {
72
+ return [
73
+ `Validation failed on attempt ${input.attempt}${input.taskId ? ` for task ${input.taskId}` : ""}.`,
74
+ input.failureDetail.trim(),
75
+ "Fix the issue, rerun validation, and continue only after it passes."
76
+ ].join(`
77
+
78
+ `);
79
+ }
80
+ function classifyValidationRetryOutcome(input) {
81
+ return {
82
+ stage: "Validate failed",
83
+ status: input.attempt < input.maxAttempts ? "retry" : "needs_attention",
84
+ failureDetail: input.failureDetail
85
+ };
86
+ }
87
+ function taskRunStageLogId(runId, stage) {
88
+ return `log:${runId}:stage:${stage.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
89
+ }
90
+ function createRunLogIdFactory(runId) {
91
+ let next = 0;
92
+ return () => `${runId}:log:${++next}`;
93
+ }
94
+ function summarizeTaskRunProcessFailure(input) {
95
+ const detail = [input.stderr?.trim(), input.stdout?.trim()].filter(Boolean)[0];
96
+ return `${input.stage} failed${input.exitCode !== null && input.exitCode !== undefined ? ` (exit ${input.exitCode})` : ""}${detail ? `: ${detail}` : input.fallback ? `: ${input.fallback}` : ""}`;
97
+ }
98
+ function classifyCompletionVerificationLine(line) {
99
+ if (line.startsWith("=== Completion Verification:")) {
100
+ return { isCompletionLine: true, stage: line.replace(/^=== Completion Verification:\s*/, "").replace(/\s*=+$/, "").trim(), status: "started" };
101
+ }
102
+ if (/^PASS\b/.test(line))
103
+ return { isCompletionLine: true, stage: null, status: "passed" };
104
+ if (/^FAIL\b/.test(line))
105
+ return { isCompletionLine: true, stage: null, status: "failed" };
106
+ return { isCompletionLine: false, stage: null, status: null };
107
+ }
108
+ function readTaskRunAcceptedArtifactState(input) {
109
+ if (!existsSync(input.artifactPath))
110
+ return { accepted: false, reason: null };
111
+ try {
112
+ const parsed = JSON.parse(readFileSync(input.artifactPath, "utf8"));
113
+ return {
114
+ accepted: parsed.accepted === true,
115
+ reason: typeof parsed.reason === "string" ? parsed.reason : null
116
+ };
117
+ } catch {
118
+ return { accepted: false, reason: null };
119
+ }
120
+ }
121
+ export {
122
+ taskRunStageLogId,
123
+ summarizeTaskRunProcessFailure,
124
+ resolveTaskRunAutomationLimits,
125
+ readTaskRunAcceptedArtifactState,
126
+ createRunLogIdFactory,
127
+ classifyValidationRetryOutcome,
128
+ classifyPlanningNeed,
129
+ classifyCompletionVerificationLine,
130
+ canonicalPiRunStages,
131
+ buildTaskRunReviewEnv,
132
+ buildPiValidationRetrySteeringPrompt,
133
+ buildPiRigBridgeEnv,
134
+ buildDirtyBaselineHandshakeEnv,
135
+ applyDirtyBaselineSnapshot
136
+ };
@@ -0,0 +1,46 @@
1
+ import type { RegisteredTaskSource } from "@rig/contracts";
2
+ import type { CommandOutcome } from "@rig/runtime/control-plane/runtime/types";
3
+ import type { TaskLike } from "@rig/client";
4
+ import { type RunnerContext } from "../runner";
5
+ export type { TaskLike } from "@rig/client";
6
+ type TaskDispatch = (input: {
7
+ readonly projectRoot: string;
8
+ readonly taskId: string;
9
+ readonly title?: string | null;
10
+ readonly model?: string | null;
11
+ readonly prompt?: string | null;
12
+ }) => Promise<{
13
+ readonly runId: string;
14
+ }>;
15
+ export type TaskCommandDeps = {
16
+ readonly listTasks?: (projectRoot: string) => Promise<readonly TaskLike[]>;
17
+ readonly getTask?: (projectRoot: string, taskId: string) => Promise<TaskLike | null>;
18
+ readonly dispatch?: TaskDispatch;
19
+ readonly spawnRun?: TaskDispatch;
20
+ readonly taskReady?: (projectRoot: string) => Promise<void> | void;
21
+ readonly taskValidate?: (projectRoot: string, taskId?: string) => Promise<boolean> | boolean;
22
+ readonly taskVerify?: (projectRoot: string, taskId?: string) => Promise<boolean> | boolean;
23
+ readonly taskReopen?: (projectRoot: string, options: {
24
+ all: boolean;
25
+ taskId?: string;
26
+ dryRun?: boolean;
27
+ }) => Promise<{
28
+ reopened?: readonly string[];
29
+ kept?: readonly string[];
30
+ [key: string]: unknown;
31
+ }>;
32
+ readonly taskArtifacts?: (projectRoot: string, taskId?: string) => void;
33
+ readonly taskArtifactDir?: (projectRoot: string, taskId?: string) => string;
34
+ readonly taskArtifactWrite?: (projectRoot: string, filename: string, content: string, taskId?: string) => void;
35
+ readonly taskInfo?: (projectRoot: string, taskId?: string) => void;
36
+ readonly taskScope?: (projectRoot: string, includeFiles: boolean, taskId?: string) => void;
37
+ readonly taskDeps?: (projectRoot: string, taskId?: string) => void;
38
+ readonly taskStatus?: (projectRoot: string) => void;
39
+ readonly taskLookup?: (projectRoot: string, taskId: string) => string;
40
+ readonly taskRecord?: (projectRoot: string, type: string, text: string, taskId?: string) => void;
41
+ readonly loadTaskSource?: (projectRoot: string) => Promise<{
42
+ readonly kind: string;
43
+ readonly source: RegisteredTaskSource;
44
+ }>;
45
+ };
46
+ export declare function executeTask(context: RunnerContext, args: string[], deps?: TaskCommandDeps): Promise<CommandOutcome>;