@generacy-ai/orchestrator 0.5.1 → 0.7.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/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +25 -0
- package/dist/config/loader.js.map +1 -1
- package/dist/config/schema.d.ts +54 -7
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/routes/health.d.ts.map +1 -1
- package/dist/routes/health.js +5 -0
- package/dist/routes/health.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +130 -26
- package/dist/server.js.map +1 -1
- package/dist/services/base-advance-monitor-service.d.ts +78 -0
- package/dist/services/base-advance-monitor-service.d.ts.map +1 -0
- package/dist/services/base-advance-monitor-service.js +233 -0
- package/dist/services/base-advance-monitor-service.js.map +1 -0
- package/dist/services/boot-resume-service.d.ts +19 -0
- package/dist/services/boot-resume-service.d.ts.map +1 -0
- package/dist/services/boot-resume-service.js +87 -0
- package/dist/services/boot-resume-service.js.map +1 -0
- package/dist/services/epic-completion-monitor-service.d.ts.map +1 -1
- package/dist/services/epic-completion-monitor-service.js +2 -0
- package/dist/services/epic-completion-monitor-service.js.map +1 -1
- package/dist/services/in-memory-queue-adapter.d.ts +4 -0
- package/dist/services/in-memory-queue-adapter.d.ts.map +1 -1
- package/dist/services/in-memory-queue-adapter.js +30 -3
- package/dist/services/in-memory-queue-adapter.js.map +1 -1
- package/dist/services/label-monitor-service.d.ts +3 -3
- package/dist/services/label-monitor-service.d.ts.map +1 -1
- package/dist/services/label-monitor-service.js +58 -41
- package/dist/services/label-monitor-service.js.map +1 -1
- package/dist/services/label-sync-service.d.ts.map +1 -1
- package/dist/services/label-sync-service.js +45 -10
- package/dist/services/label-sync-service.js.map +1 -1
- package/dist/services/merge-conflict-monitor-service.d.ts +73 -0
- package/dist/services/merge-conflict-monitor-service.d.ts.map +1 -0
- package/dist/services/merge-conflict-monitor-service.js +295 -0
- package/dist/services/merge-conflict-monitor-service.js.map +1 -0
- package/dist/services/orchestrator-version.d.ts +2 -0
- package/dist/services/orchestrator-version.d.ts.map +1 -0
- package/dist/services/orchestrator-version.js +23 -0
- package/dist/services/orchestrator-version.js.map +1 -0
- package/dist/services/phase-tracker-service.d.ts +10 -0
- package/dist/services/phase-tracker-service.d.ts.map +1 -1
- package/dist/services/phase-tracker-service.js +38 -0
- package/dist/services/phase-tracker-service.js.map +1 -1
- package/dist/services/post-activation-dispatch.d.ts +18 -0
- package/dist/services/post-activation-dispatch.d.ts.map +1 -0
- package/dist/services/post-activation-dispatch.js +30 -0
- package/dist/services/post-activation-dispatch.js.map +1 -0
- package/dist/services/pr-feedback-monitor-service.d.ts +13 -4
- package/dist/services/pr-feedback-monitor-service.d.ts.map +1 -1
- package/dist/services/pr-feedback-monitor-service.js +212 -26
- package/dist/services/pr-feedback-monitor-service.js.map +1 -1
- package/dist/services/redis-queue-adapter.d.ts +4 -0
- package/dist/services/redis-queue-adapter.d.ts.map +1 -1
- package/dist/services/redis-queue-adapter.js +90 -10
- package/dist/services/redis-queue-adapter.js.map +1 -1
- package/dist/services/worker-dispatcher.d.ts +14 -2
- package/dist/services/worker-dispatcher.d.ts.map +1 -1
- package/dist/services/worker-dispatcher.js +55 -2
- package/dist/services/worker-dispatcher.js.map +1 -1
- package/dist/types/api.d.ts +3 -0
- package/dist/types/api.d.ts.map +1 -1
- package/dist/types/api.js +1 -0
- package/dist/types/api.js.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/monitor.d.ts +72 -4
- package/dist/types/monitor.d.ts.map +1 -1
- package/dist/worker/base-merge.d.ts +54 -0
- package/dist/worker/base-merge.d.ts.map +1 -0
- package/dist/worker/base-merge.js +99 -0
- package/dist/worker/base-merge.js.map +1 -0
- package/dist/worker/clarification-markers.d.ts +29 -0
- package/dist/worker/clarification-markers.d.ts.map +1 -0
- package/dist/worker/clarification-markers.js +44 -0
- package/dist/worker/clarification-markers.js.map +1 -0
- package/dist/worker/clarification-poster.d.ts.map +1 -1
- package/dist/worker/clarification-poster.js +266 -25
- package/dist/worker/clarification-poster.js.map +1 -1
- package/dist/worker/claude-cli-worker.d.ts +21 -2
- package/dist/worker/claude-cli-worker.d.ts.map +1 -1
- package/dist/worker/claude-cli-worker.js +149 -4
- package/dist/worker/claude-cli-worker.js.map +1 -1
- package/dist/worker/cli-spawner.d.ts +4 -0
- package/dist/worker/cli-spawner.d.ts.map +1 -1
- package/dist/worker/cli-spawner.js +51 -7
- package/dist/worker/cli-spawner.js.map +1 -1
- package/dist/worker/config.d.ts +101 -9
- package/dist/worker/config.d.ts.map +1 -1
- package/dist/worker/config.js +75 -4
- package/dist/worker/config.js.map +1 -1
- package/dist/worker/evidence-hash.d.ts +32 -0
- package/dist/worker/evidence-hash.d.ts.map +1 -0
- package/dist/worker/evidence-hash.js +139 -0
- package/dist/worker/evidence-hash.js.map +1 -0
- package/dist/worker/handler-outcome-assertion.d.ts +38 -0
- package/dist/worker/handler-outcome-assertion.d.ts.map +1 -0
- package/dist/worker/handler-outcome-assertion.js +58 -0
- package/dist/worker/handler-outcome-assertion.js.map +1 -0
- package/dist/worker/handler-outcome.d.ts +50 -0
- package/dist/worker/handler-outcome.d.ts.map +1 -0
- package/dist/worker/handler-outcome.js +2 -0
- package/dist/worker/handler-outcome.js.map +1 -0
- package/dist/worker/label-manager.d.ts +58 -2
- package/dist/worker/label-manager.d.ts.map +1 -1
- package/dist/worker/label-manager.js +225 -27
- package/dist/worker/label-manager.js.map +1 -1
- package/dist/worker/merge-conflict-handler.d.ts +141 -0
- package/dist/worker/merge-conflict-handler.d.ts.map +1 -0
- package/dist/worker/merge-conflict-handler.js +642 -0
- package/dist/worker/merge-conflict-handler.js.map +1 -0
- package/dist/worker/merge-conflict-prompt.d.ts +35 -0
- package/dist/worker/merge-conflict-prompt.d.ts.map +1 -0
- package/dist/worker/merge-conflict-prompt.js +71 -0
- package/dist/worker/merge-conflict-prompt.js.map +1 -0
- package/dist/worker/merge-conflict-remedy.d.ts +42 -0
- package/dist/worker/merge-conflict-remedy.d.ts.map +1 -0
- package/dist/worker/merge-conflict-remedy.js +28 -0
- package/dist/worker/merge-conflict-remedy.js.map +1 -0
- package/dist/worker/output-tail-synthesis.d.ts +15 -0
- package/dist/worker/output-tail-synthesis.d.ts.map +1 -0
- package/dist/worker/output-tail-synthesis.js +25 -0
- package/dist/worker/output-tail-synthesis.js.map +1 -0
- package/dist/worker/output-tail.d.ts +13 -0
- package/dist/worker/output-tail.d.ts.map +1 -0
- package/dist/worker/output-tail.js +31 -0
- package/dist/worker/output-tail.js.map +1 -0
- package/dist/worker/pause-context.d.ts +30 -0
- package/dist/worker/pause-context.d.ts.map +1 -0
- package/dist/worker/pause-context.js +98 -0
- package/dist/worker/pause-context.js.map +1 -0
- package/dist/worker/phase-loop.d.ts +66 -0
- package/dist/worker/phase-loop.d.ts.map +1 -1
- package/dist/worker/phase-loop.js +299 -31
- package/dist/worker/phase-loop.js.map +1 -1
- package/dist/worker/pr-feedback-handler.d.ts +46 -46
- package/dist/worker/pr-feedback-handler.d.ts.map +1 -1
- package/dist/worker/pr-feedback-handler.js +276 -105
- package/dist/worker/pr-feedback-handler.js.map +1 -1
- package/dist/worker/pr-manager.d.ts +5 -0
- package/dist/worker/pr-manager.d.ts.map +1 -1
- package/dist/worker/pr-manager.js +7 -0
- package/dist/worker/pr-manager.js.map +1 -1
- package/dist/worker/product-diff.d.ts +39 -0
- package/dist/worker/product-diff.d.ts.map +1 -0
- package/dist/worker/product-diff.js +43 -0
- package/dist/worker/product-diff.js.map +1 -0
- package/dist/worker/provisioning-failure.d.ts +14 -0
- package/dist/worker/provisioning-failure.d.ts.map +1 -0
- package/dist/worker/provisioning-failure.js +2 -0
- package/dist/worker/provisioning-failure.js.map +1 -0
- package/dist/worker/repo-checkout.d.ts +14 -0
- package/dist/worker/repo-checkout.d.ts.map +1 -1
- package/dist/worker/repo-checkout.js +19 -1
- package/dist/worker/repo-checkout.js.map +1 -1
- package/dist/worker/stage-comment-manager.d.ts +42 -1
- package/dist/worker/stage-comment-manager.d.ts.map +1 -1
- package/dist/worker/stage-comment-manager.js +205 -1
- package/dist/worker/stage-comment-manager.js.map +1 -1
- package/dist/worker/terminal-label-op-error.d.ts +23 -0
- package/dist/worker/terminal-label-op-error.d.ts.map +1 -0
- package/dist/worker/terminal-label-op-error.js +27 -0
- package/dist/worker/terminal-label-op-error.js.map +1 -0
- package/dist/worker/types.d.ts +161 -2
- package/dist/worker/types.d.ts.map +1 -1
- package/dist/worker/types.js +11 -0
- package/dist/worker/types.js.map +1 -1
- package/dist/worker/validate-fix-handler.d.ts +79 -0
- package/dist/worker/validate-fix-handler.d.ts.map +1 -0
- package/dist/worker/validate-fix-handler.js +320 -0
- package/dist/worker/validate-fix-handler.js.map +1 -0
- package/dist/worker/worker-result.d.ts +39 -0
- package/dist/worker/worker-result.d.ts.map +1 -0
- package/dist/worker/worker-result.js +10 -0
- package/dist/worker/worker-result.js.map +1 -0
- package/package.json +7 -6
package/dist/worker/config.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import type { OrchestratorSettings } from '@generacy-ai/config';
|
|
3
|
+
import type { WorkflowPhase } from './types.js';
|
|
2
4
|
/**
|
|
3
5
|
* Gate definition schema for pausing workflow at review checkpoints
|
|
4
6
|
*/
|
|
@@ -8,22 +10,78 @@ export declare const GateDefinitionSchema: z.ZodObject<{
|
|
|
8
10
|
/** Label to add when gate is active */
|
|
9
11
|
gateLabel: z.ZodString;
|
|
10
12
|
/** When to activate the gate */
|
|
11
|
-
condition: z.ZodEnum<["always", "on-request", "on-questions", "on-failure", "on-sibling-review"]>;
|
|
13
|
+
condition: z.ZodEnum<["always", "on-request", "on-questions", "on-failure", "on-sibling-review", "on-merge-conflict"]>;
|
|
12
14
|
}, "strip", z.ZodTypeAny, {
|
|
13
15
|
phase: "specify" | "clarify" | "plan" | "tasks" | "implement" | "validate";
|
|
14
16
|
gateLabel: string;
|
|
15
|
-
condition: "always" | "on-request" | "on-questions" | "on-failure" | "on-sibling-review";
|
|
17
|
+
condition: "always" | "on-request" | "on-questions" | "on-failure" | "on-sibling-review" | "on-merge-conflict";
|
|
16
18
|
}, {
|
|
17
19
|
phase: "specify" | "clarify" | "plan" | "tasks" | "implement" | "validate";
|
|
18
20
|
gateLabel: string;
|
|
19
|
-
condition: "always" | "on-request" | "on-questions" | "on-failure" | "on-sibling-review";
|
|
21
|
+
condition: "always" | "on-request" | "on-questions" | "on-failure" | "on-sibling-review" | "on-merge-conflict";
|
|
20
22
|
}>;
|
|
23
|
+
/**
|
|
24
|
+
* Per-phase wall-clock timeout overrides (milliseconds).
|
|
25
|
+
*
|
|
26
|
+
* Each CLI phase is killed (SIGTERM → grace → SIGKILL) once its wall-clock
|
|
27
|
+
* runtime exceeds its timeout. The `plan` and `implement` phases are
|
|
28
|
+
* structurally heavier than the others — `plan` fans out research subagents,
|
|
29
|
+
* `implement` writes code — so they default to a larger budget than the flat
|
|
30
|
+
* `phaseTimeoutMs`. Any phase without an override falls back to `phaseTimeoutMs`.
|
|
31
|
+
*
|
|
32
|
+
* Defined per-field (rather than as a `z.record`) so that overriding one phase
|
|
33
|
+
* via config/env does not drop the defaults for the others — Zod applies the
|
|
34
|
+
* remaining field defaults when the object is present but partial.
|
|
35
|
+
*
|
|
36
|
+
* `validate` is intentionally excluded: that phase runs a shell command via a
|
|
37
|
+
* separate code path with its own timeout, not `phaseTimeoutMs`.
|
|
38
|
+
*/
|
|
39
|
+
export declare const PhaseTimeoutOverridesSchema: z.ZodDefault<z.ZodObject<{
|
|
40
|
+
specify: z.ZodOptional<z.ZodNumber>;
|
|
41
|
+
clarify: z.ZodOptional<z.ZodNumber>;
|
|
42
|
+
plan: z.ZodDefault<z.ZodNumber>;
|
|
43
|
+
tasks: z.ZodOptional<z.ZodNumber>;
|
|
44
|
+
implement: z.ZodDefault<z.ZodNumber>;
|
|
45
|
+
}, "strip", z.ZodTypeAny, {
|
|
46
|
+
plan: number;
|
|
47
|
+
implement: number;
|
|
48
|
+
specify?: number | undefined;
|
|
49
|
+
clarify?: number | undefined;
|
|
50
|
+
tasks?: number | undefined;
|
|
51
|
+
}, {
|
|
52
|
+
specify?: number | undefined;
|
|
53
|
+
clarify?: number | undefined;
|
|
54
|
+
plan?: number | undefined;
|
|
55
|
+
tasks?: number | undefined;
|
|
56
|
+
implement?: number | undefined;
|
|
57
|
+
}>>;
|
|
58
|
+
export type PhaseTimeoutOverrides = z.infer<typeof PhaseTimeoutOverridesSchema>;
|
|
21
59
|
/**
|
|
22
60
|
* Worker configuration schema
|
|
23
61
|
*/
|
|
24
62
|
export declare const WorkerConfigSchema: z.ZodObject<{
|
|
25
|
-
/**
|
|
63
|
+
/** Fallback timeout per phase in milliseconds (used when no per-phase override applies) */
|
|
26
64
|
phaseTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
65
|
+
/** Per-phase timeout overrides keyed by phase name */
|
|
66
|
+
phaseTimeoutOverrides: z.ZodDefault<z.ZodObject<{
|
|
67
|
+
specify: z.ZodOptional<z.ZodNumber>;
|
|
68
|
+
clarify: z.ZodOptional<z.ZodNumber>;
|
|
69
|
+
plan: z.ZodDefault<z.ZodNumber>;
|
|
70
|
+
tasks: z.ZodOptional<z.ZodNumber>;
|
|
71
|
+
implement: z.ZodDefault<z.ZodNumber>;
|
|
72
|
+
}, "strip", z.ZodTypeAny, {
|
|
73
|
+
plan: number;
|
|
74
|
+
implement: number;
|
|
75
|
+
specify?: number | undefined;
|
|
76
|
+
clarify?: number | undefined;
|
|
77
|
+
tasks?: number | undefined;
|
|
78
|
+
}, {
|
|
79
|
+
specify?: number | undefined;
|
|
80
|
+
clarify?: number | undefined;
|
|
81
|
+
plan?: number | undefined;
|
|
82
|
+
tasks?: number | undefined;
|
|
83
|
+
implement?: number | undefined;
|
|
84
|
+
}>>;
|
|
27
85
|
/** Base directory for repo checkouts */
|
|
28
86
|
workspaceDir: z.ZodDefault<z.ZodString>;
|
|
29
87
|
/** Grace period for shutdown in milliseconds */
|
|
@@ -43,18 +101,25 @@ export declare const WorkerConfigSchema: z.ZodObject<{
|
|
|
43
101
|
/** Label to add when gate is active */
|
|
44
102
|
gateLabel: z.ZodString;
|
|
45
103
|
/** When to activate the gate */
|
|
46
|
-
condition: z.ZodEnum<["always", "on-request", "on-questions", "on-failure", "on-sibling-review"]>;
|
|
104
|
+
condition: z.ZodEnum<["always", "on-request", "on-questions", "on-failure", "on-sibling-review", "on-merge-conflict"]>;
|
|
47
105
|
}, "strip", z.ZodTypeAny, {
|
|
48
106
|
phase: "specify" | "clarify" | "plan" | "tasks" | "implement" | "validate";
|
|
49
107
|
gateLabel: string;
|
|
50
|
-
condition: "always" | "on-request" | "on-questions" | "on-failure" | "on-sibling-review";
|
|
108
|
+
condition: "always" | "on-request" | "on-questions" | "on-failure" | "on-sibling-review" | "on-merge-conflict";
|
|
51
109
|
}, {
|
|
52
110
|
phase: "specify" | "clarify" | "plan" | "tasks" | "implement" | "validate";
|
|
53
111
|
gateLabel: string;
|
|
54
|
-
condition: "always" | "on-request" | "on-questions" | "on-failure" | "on-sibling-review";
|
|
112
|
+
condition: "always" | "on-request" | "on-questions" | "on-failure" | "on-sibling-review" | "on-merge-conflict";
|
|
55
113
|
}>, "many">>>;
|
|
56
114
|
}, "strip", z.ZodTypeAny, {
|
|
57
115
|
phaseTimeoutMs: number;
|
|
116
|
+
phaseTimeoutOverrides: {
|
|
117
|
+
plan: number;
|
|
118
|
+
implement: number;
|
|
119
|
+
specify?: number | undefined;
|
|
120
|
+
clarify?: number | undefined;
|
|
121
|
+
tasks?: number | undefined;
|
|
122
|
+
};
|
|
58
123
|
workspaceDir: string;
|
|
59
124
|
shutdownGracePeriodMs: number;
|
|
60
125
|
validateCommand: string;
|
|
@@ -63,11 +128,18 @@ export declare const WorkerConfigSchema: z.ZodObject<{
|
|
|
63
128
|
gates: Record<string, {
|
|
64
129
|
phase: "specify" | "clarify" | "plan" | "tasks" | "implement" | "validate";
|
|
65
130
|
gateLabel: string;
|
|
66
|
-
condition: "always" | "on-request" | "on-questions" | "on-failure" | "on-sibling-review";
|
|
131
|
+
condition: "always" | "on-request" | "on-questions" | "on-failure" | "on-sibling-review" | "on-merge-conflict";
|
|
67
132
|
}[]>;
|
|
68
133
|
credentialRole?: string | undefined;
|
|
69
134
|
}, {
|
|
70
135
|
phaseTimeoutMs?: number | undefined;
|
|
136
|
+
phaseTimeoutOverrides?: {
|
|
137
|
+
specify?: number | undefined;
|
|
138
|
+
clarify?: number | undefined;
|
|
139
|
+
plan?: number | undefined;
|
|
140
|
+
tasks?: number | undefined;
|
|
141
|
+
implement?: number | undefined;
|
|
142
|
+
} | undefined;
|
|
71
143
|
workspaceDir?: string | undefined;
|
|
72
144
|
shutdownGracePeriodMs?: number | undefined;
|
|
73
145
|
validateCommand?: string | undefined;
|
|
@@ -77,8 +149,28 @@ export declare const WorkerConfigSchema: z.ZodObject<{
|
|
|
77
149
|
gates?: Record<string, {
|
|
78
150
|
phase: "specify" | "clarify" | "plan" | "tasks" | "implement" | "validate";
|
|
79
151
|
gateLabel: string;
|
|
80
|
-
condition: "always" | "on-request" | "on-questions" | "on-failure" | "on-sibling-review";
|
|
152
|
+
condition: "always" | "on-request" | "on-questions" | "on-failure" | "on-sibling-review" | "on-merge-conflict";
|
|
81
153
|
}[]> | undefined;
|
|
82
154
|
}>;
|
|
83
155
|
export type WorkerConfig = z.infer<typeof WorkerConfigSchema>;
|
|
156
|
+
/**
|
|
157
|
+
* Merge per-repo validate-command overrides onto the global worker config.
|
|
158
|
+
*
|
|
159
|
+
* The target repo's `.generacy/config.yaml` `orchestrator` block may set
|
|
160
|
+
* `validateCommand` / `preValidateCommand`. The global defaults are
|
|
161
|
+
* monorepo-shaped (`pnpm test && pnpm build`); single-package repos (e.g. an
|
|
162
|
+
* Astro site with only a `build` script) override them so the validate phase
|
|
163
|
+
* doesn't fail on a missing `test` script before it can reach the build.
|
|
164
|
+
*
|
|
165
|
+
* Only those two fields are overridable per-repo. An explicit empty
|
|
166
|
+
* `preValidateCommand` is preserved (it means "skip the install step"). Returns
|
|
167
|
+
* the original config object unchanged when there are no applicable overrides,
|
|
168
|
+
* so callers can cheaply detect "no override" via reference equality.
|
|
169
|
+
*/
|
|
170
|
+
export declare function applyRepoValidateOverrides(config: WorkerConfig, settings: OrchestratorSettings | null | undefined): WorkerConfig;
|
|
171
|
+
/**
|
|
172
|
+
* Resolve the wall-clock timeout (ms) for a CLI phase: the per-phase override
|
|
173
|
+
* if one is configured, otherwise the flat `phaseTimeoutMs` fallback.
|
|
174
|
+
*/
|
|
175
|
+
export declare function resolvePhaseTimeoutMs(config: WorkerConfig, phase: Exclude<WorkflowPhase, 'validate'>): number;
|
|
84
176
|
//# sourceMappingURL=config.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/worker/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/worker/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;GAEG;AACH,eAAO,MAAM,oBAAoB;IAC/B,qCAAqC;;IAErC,uCAAuC;;IAEvC,gCAAgC;;;;;;;;;;EAEhC,CAAC;AAEH;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;GAQ1B,CAAC;AACf,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAEhF;;GAEG;AACH,eAAO,MAAM,kBAAkB;IAC7B,2FAA2F;;IAE3F,sDAAsD;;;;;;;;;;;;;;;;;;;;IAEtD,wCAAwC;;IAExC,gDAAgD;;IAEhD,+CAA+C;;IAE/C,sFAAsF;;IAMtF,4EAA4E;;IAE5E,wHAAwH;;IAExH,4CAA4C;;QA3D5C,qCAAqC;;QAErC,uCAAuC;;QAEvC,gCAAgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2EhC,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D;;;;;;;;;;;;;GAaG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,oBAAoB,GAAG,IAAI,GAAG,SAAS,GAChD,YAAY,CAgBd;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,OAAO,CAAC,aAAa,EAAE,UAAU,CAAC,GACxC,MAAM,CAIR"}
|
package/dist/worker/config.js
CHANGED
|
@@ -8,14 +8,41 @@ export const GateDefinitionSchema = z.object({
|
|
|
8
8
|
/** Label to add when gate is active */
|
|
9
9
|
gateLabel: z.string(),
|
|
10
10
|
/** When to activate the gate */
|
|
11
|
-
condition: z.enum(['always', 'on-request', 'on-questions', 'on-failure', 'on-sibling-review']),
|
|
11
|
+
condition: z.enum(['always', 'on-request', 'on-questions', 'on-failure', 'on-sibling-review', 'on-merge-conflict']),
|
|
12
12
|
});
|
|
13
|
+
/**
|
|
14
|
+
* Per-phase wall-clock timeout overrides (milliseconds).
|
|
15
|
+
*
|
|
16
|
+
* Each CLI phase is killed (SIGTERM → grace → SIGKILL) once its wall-clock
|
|
17
|
+
* runtime exceeds its timeout. The `plan` and `implement` phases are
|
|
18
|
+
* structurally heavier than the others — `plan` fans out research subagents,
|
|
19
|
+
* `implement` writes code — so they default to a larger budget than the flat
|
|
20
|
+
* `phaseTimeoutMs`. Any phase without an override falls back to `phaseTimeoutMs`.
|
|
21
|
+
*
|
|
22
|
+
* Defined per-field (rather than as a `z.record`) so that overriding one phase
|
|
23
|
+
* via config/env does not drop the defaults for the others — Zod applies the
|
|
24
|
+
* remaining field defaults when the object is present but partial.
|
|
25
|
+
*
|
|
26
|
+
* `validate` is intentionally excluded: that phase runs a shell command via a
|
|
27
|
+
* separate code path with its own timeout, not `phaseTimeoutMs`.
|
|
28
|
+
*/
|
|
29
|
+
export const PhaseTimeoutOverridesSchema = z
|
|
30
|
+
.object({
|
|
31
|
+
specify: z.number().int().min(60_000).optional(),
|
|
32
|
+
clarify: z.number().int().min(60_000).optional(),
|
|
33
|
+
plan: z.number().int().min(60_000).default(3_600_000),
|
|
34
|
+
tasks: z.number().int().min(60_000).optional(),
|
|
35
|
+
implement: z.number().int().min(60_000).default(3_600_000),
|
|
36
|
+
})
|
|
37
|
+
.default({});
|
|
13
38
|
/**
|
|
14
39
|
* Worker configuration schema
|
|
15
40
|
*/
|
|
16
41
|
export const WorkerConfigSchema = z.object({
|
|
17
|
-
/**
|
|
18
|
-
phaseTimeoutMs: z.number().int().min(60_000).default(
|
|
42
|
+
/** Fallback timeout per phase in milliseconds (used when no per-phase override applies) */
|
|
43
|
+
phaseTimeoutMs: z.number().int().min(60_000).default(1_200_000),
|
|
44
|
+
/** Per-phase timeout overrides keyed by phase name */
|
|
45
|
+
phaseTimeoutOverrides: PhaseTimeoutOverridesSchema,
|
|
19
46
|
/** Base directory for repo checkouts */
|
|
20
47
|
workspaceDir: z.string().default('/tmp/orchestrator-workspaces'),
|
|
21
48
|
/** Grace period for shutdown in milliseconds */
|
|
@@ -23,7 +50,9 @@ export const WorkerConfigSchema = z.object({
|
|
|
23
50
|
/** Command to run during the validate phase */
|
|
24
51
|
validateCommand: z.string().default('pnpm test && pnpm build'),
|
|
25
52
|
/** Command to run before validation to install dependencies (empty string to skip) */
|
|
26
|
-
preValidateCommand: z
|
|
53
|
+
preValidateCommand: z
|
|
54
|
+
.string()
|
|
55
|
+
.default("pnpm install && if [ -f pnpm-workspace.yaml ] && ls packages/*/package.json >/dev/null 2>&1; then pnpm -r --filter './packages/*' build; fi"),
|
|
27
56
|
/** Maximum retries for implement phase when partial progress is detected */
|
|
28
57
|
maxImplementRetries: z.number().int().min(0).max(5).default(2),
|
|
29
58
|
/** Credential role from .generacy/config.yaml defaults.role — when set, credentials are populated on launch requests */
|
|
@@ -34,10 +63,14 @@ export const WorkerConfigSchema = z.object({
|
|
|
34
63
|
{ phase: 'clarify', gateLabel: 'waiting-for:clarification', condition: 'on-questions' },
|
|
35
64
|
{ phase: 'implement', gateLabel: 'waiting-for:implementation-review', condition: 'always' },
|
|
36
65
|
{ phase: 'implement', gateLabel: 'waiting-for:sibling-review', condition: 'on-sibling-review' },
|
|
66
|
+
{ phase: 'implement', gateLabel: 'waiting-for:merge-conflicts', condition: 'on-merge-conflict' },
|
|
67
|
+
{ phase: 'validate', gateLabel: 'waiting-for:merge-conflicts', condition: 'on-merge-conflict' },
|
|
37
68
|
],
|
|
38
69
|
'speckit-bugfix': [
|
|
39
70
|
{ phase: 'clarify', gateLabel: 'waiting-for:clarification', condition: 'on-questions' },
|
|
40
71
|
{ phase: 'implement', gateLabel: 'waiting-for:implementation-review', condition: 'on-request' },
|
|
72
|
+
{ phase: 'implement', gateLabel: 'waiting-for:merge-conflicts', condition: 'on-merge-conflict' },
|
|
73
|
+
{ phase: 'validate', gateLabel: 'waiting-for:merge-conflicts', condition: 'on-merge-conflict' },
|
|
41
74
|
],
|
|
42
75
|
'speckit-epic': [
|
|
43
76
|
{ phase: 'clarify', gateLabel: 'waiting-for:clarification', condition: 'on-questions' },
|
|
@@ -45,4 +78,42 @@ export const WorkerConfigSchema = z.object({
|
|
|
45
78
|
],
|
|
46
79
|
}),
|
|
47
80
|
});
|
|
81
|
+
/**
|
|
82
|
+
* Merge per-repo validate-command overrides onto the global worker config.
|
|
83
|
+
*
|
|
84
|
+
* The target repo's `.generacy/config.yaml` `orchestrator` block may set
|
|
85
|
+
* `validateCommand` / `preValidateCommand`. The global defaults are
|
|
86
|
+
* monorepo-shaped (`pnpm test && pnpm build`); single-package repos (e.g. an
|
|
87
|
+
* Astro site with only a `build` script) override them so the validate phase
|
|
88
|
+
* doesn't fail on a missing `test` script before it can reach the build.
|
|
89
|
+
*
|
|
90
|
+
* Only those two fields are overridable per-repo. An explicit empty
|
|
91
|
+
* `preValidateCommand` is preserved (it means "skip the install step"). Returns
|
|
92
|
+
* the original config object unchanged when there are no applicable overrides,
|
|
93
|
+
* so callers can cheaply detect "no override" via reference equality.
|
|
94
|
+
*/
|
|
95
|
+
export function applyRepoValidateOverrides(config, settings) {
|
|
96
|
+
if (settings == null ||
|
|
97
|
+
(settings.validateCommand === undefined && settings.preValidateCommand === undefined)) {
|
|
98
|
+
return config;
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
...config,
|
|
102
|
+
...(settings.validateCommand !== undefined
|
|
103
|
+
? { validateCommand: settings.validateCommand }
|
|
104
|
+
: {}),
|
|
105
|
+
...(settings.preValidateCommand !== undefined
|
|
106
|
+
? { preValidateCommand: settings.preValidateCommand }
|
|
107
|
+
: {}),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Resolve the wall-clock timeout (ms) for a CLI phase: the per-phase override
|
|
112
|
+
* if one is configured, otherwise the flat `phaseTimeoutMs` fallback.
|
|
113
|
+
*/
|
|
114
|
+
export function resolvePhaseTimeoutMs(config, phase) {
|
|
115
|
+
// Optional-chained: configs built by hand (tests, direct construction) bypass
|
|
116
|
+
// Zod and may omit phaseTimeoutOverrides entirely.
|
|
117
|
+
return config.phaseTimeoutOverrides?.[phase] ?? config.phaseTimeoutMs;
|
|
118
|
+
}
|
|
48
119
|
//# sourceMappingURL=config.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/worker/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/worker/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured extract from failing validate CLI stdout.
|
|
3
|
+
* Sorted by `id` (lexicographic) for hash stability.
|
|
4
|
+
* See specs/892-found-during-cockpit-v1/contracts/evidence-hash.md.
|
|
5
|
+
*/
|
|
6
|
+
export interface EvidenceExtract {
|
|
7
|
+
failures: Array<{
|
|
8
|
+
id: string;
|
|
9
|
+
firstError: string;
|
|
10
|
+
}>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Result of hashing validate CLI stdout — SHA-256 hex identity plus the
|
|
14
|
+
* canonical `extract` that was hashed (surfaces in prompt + logs).
|
|
15
|
+
*/
|
|
16
|
+
export interface EvidenceHashResult {
|
|
17
|
+
/** 64-character lower-case hex SHA-256. */
|
|
18
|
+
hash: string;
|
|
19
|
+
/** Canonical input to the hash; included in the fix prompt for debuggability. */
|
|
20
|
+
extract: EvidenceExtract;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Hash validate CLI stdout into a stable identity (#892).
|
|
24
|
+
*
|
|
25
|
+
* Extract categories are tried in order: next-build missing-module, next-build
|
|
26
|
+
* type-error, vitest failures. If none match, falls back to a whole-transcript
|
|
27
|
+
* hash so every stdout produces a well-defined result.
|
|
28
|
+
*
|
|
29
|
+
* See specs/892-found-during-cockpit-v1/contracts/evidence-hash.md.
|
|
30
|
+
*/
|
|
31
|
+
export declare function hashValidationEvidence(stdout: string): EvidenceHashResult;
|
|
32
|
+
//# sourceMappingURL=evidence-hash.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evidence-hash.d.ts","sourceRoot":"","sources":["../../src/worker/evidence-hash.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrD;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,OAAO,EAAE,eAAe,CAAC;CAC1B;AA+HD;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,kBAAkB,CAmBzE"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
/**
|
|
3
|
+
* Normalization pipeline applied to raw stdout before extraction (#892).
|
|
4
|
+
*
|
|
5
|
+
* Idempotent by construction — running the pipeline on already-normalized
|
|
6
|
+
* text yields the same output. Ordering matters: ANSI first (so downstream
|
|
7
|
+
* regexes see clean text), timestamps before paths (so ISO-8601 doesn't
|
|
8
|
+
* partially match path regex), paths before PIDs (so bracket sequences in
|
|
9
|
+
* paths aren't mistaken for PIDs).
|
|
10
|
+
*/
|
|
11
|
+
function normalize(stdout) {
|
|
12
|
+
let out = stdout;
|
|
13
|
+
// 1. ANSI escapes (CSI + OSC). Matching the ESC/BEL control chars is the
|
|
14
|
+
// whole point here, so the no-control-regex rule is intentionally disabled.
|
|
15
|
+
// eslint-disable-next-line no-control-regex
|
|
16
|
+
out = out.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '');
|
|
17
|
+
// eslint-disable-next-line no-control-regex
|
|
18
|
+
out = out.replace(/\x1b\][^\x07]*\x07/g, '');
|
|
19
|
+
// 2. ISO-8601 timestamps → <TS>.
|
|
20
|
+
out = out.replace(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})?/g, '<TS>');
|
|
21
|
+
// 3. Absolute paths → <PATH>. Only strip paths whose leading '/' is at a
|
|
22
|
+
// non-alphanumeric boundary — this preserves import specifiers like
|
|
23
|
+
// `@/components/CopyButton` and relative paths like `src/app/foo.ts` /
|
|
24
|
+
// `./src/foo.ts` while normalizing true absolute paths like
|
|
25
|
+
// `/home/node/workspaces/sniplink/src/app/foo.ts`.
|
|
26
|
+
out = out.replace(/(?<![\w@.])(\/[a-zA-Z0-9._-]+)+/g, '<PATH>');
|
|
27
|
+
// 4. PIDs → <PID>. Three forms: pid=<n>, PID: <n>, [<n>] where n >= 4 digits.
|
|
28
|
+
out = out.replace(/\bpid=\d+\b/g, 'pid=<PID>');
|
|
29
|
+
out = out.replace(/\bPID:\s*\d+\b/g, 'PID: <PID>');
|
|
30
|
+
out = out.replace(/\[\d{4,}\]/g, '[<PID>]');
|
|
31
|
+
// 5. Test-runner tmp identifiers → <TMP>. Absolute /tmp/... already
|
|
32
|
+
// reduced by step 3; T-<hex>{8+} form is the vitest/jest one.
|
|
33
|
+
out = out.replace(/T-[a-zA-Z0-9]{8,}/g, '<TMP>');
|
|
34
|
+
// 6. Ports on localhost/127.0.0.1 → <PORT>.
|
|
35
|
+
out = out.replace(/\b(localhost|127\.0\.0\.1):\d+\b/g, '$1:<PORT>');
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Extract next-build "Cannot find module" failures.
|
|
40
|
+
*/
|
|
41
|
+
function extractNextBuildMissingModule(normalized) {
|
|
42
|
+
const failures = [];
|
|
43
|
+
const re = /Cannot find module '([^']+)'/g;
|
|
44
|
+
let m;
|
|
45
|
+
while ((m = re.exec(normalized)) !== null) {
|
|
46
|
+
const modulePath = m[1];
|
|
47
|
+
failures.push({
|
|
48
|
+
id: `module:${modulePath}`,
|
|
49
|
+
firstError: m[0],
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
return failures;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Extract next-build "Type error" failures.
|
|
56
|
+
*/
|
|
57
|
+
function extractNextBuildTypeError(normalized) {
|
|
58
|
+
const failures = [];
|
|
59
|
+
// Type error line followed (within the same block) by a File: <path> line.
|
|
60
|
+
const re = /Type error: (.+?)(?:\r?\n)[\s\S]{0,200}?File: (\S+)/g;
|
|
61
|
+
let m;
|
|
62
|
+
while ((m = re.exec(normalized)) !== null) {
|
|
63
|
+
const summary = m[1].trim();
|
|
64
|
+
const filePath = m[2];
|
|
65
|
+
failures.push({
|
|
66
|
+
id: `type:${filePath}:${summary.slice(0, 80)}`,
|
|
67
|
+
firstError: `Type error: ${summary}`,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return failures;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Extract vitest failing test lines (` × <name>`).
|
|
74
|
+
* `firstError` is the first indented (≥2 space) line following the × line.
|
|
75
|
+
*/
|
|
76
|
+
function extractVitestFailures(normalized) {
|
|
77
|
+
const failures = [];
|
|
78
|
+
const lines = normalized.split('\n');
|
|
79
|
+
const failedLineRe = /^\s*×\s+(.+?)(?:\s+\d+ms)?$/;
|
|
80
|
+
for (let i = 0; i < lines.length; i++) {
|
|
81
|
+
const m = failedLineRe.exec(lines[i]);
|
|
82
|
+
if (!m)
|
|
83
|
+
continue;
|
|
84
|
+
const testName = m[1].trim();
|
|
85
|
+
let firstError = '';
|
|
86
|
+
for (let j = i + 1; j < Math.min(lines.length, i + 11); j++) {
|
|
87
|
+
const l = lines[j];
|
|
88
|
+
if (/^\s{2,}\S/.test(l)) {
|
|
89
|
+
firstError = l.trim();
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
failures.push({
|
|
94
|
+
id: `test:${testName}`,
|
|
95
|
+
firstError,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return failures;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Fallback path when no known pattern matches.
|
|
102
|
+
* `id` = `hash:<first 16 hex of SHA-256 of full normalized transcript>`.
|
|
103
|
+
* `firstError` = first non-empty line of normalized transcript.
|
|
104
|
+
*/
|
|
105
|
+
function fallbackExtract(normalized) {
|
|
106
|
+
const digest = createHash('sha256').update(normalized, 'utf8').digest('hex');
|
|
107
|
+
const firstLine = normalized.split('\n').find((l) => l.length > 0) ?? '';
|
|
108
|
+
return [
|
|
109
|
+
{
|
|
110
|
+
id: `hash:${digest.slice(0, 16)}`,
|
|
111
|
+
firstError: firstLine,
|
|
112
|
+
},
|
|
113
|
+
];
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Hash validate CLI stdout into a stable identity (#892).
|
|
117
|
+
*
|
|
118
|
+
* Extract categories are tried in order: next-build missing-module, next-build
|
|
119
|
+
* type-error, vitest failures. If none match, falls back to a whole-transcript
|
|
120
|
+
* hash so every stdout produces a well-defined result.
|
|
121
|
+
*
|
|
122
|
+
* See specs/892-found-during-cockpit-v1/contracts/evidence-hash.md.
|
|
123
|
+
*/
|
|
124
|
+
export function hashValidationEvidence(stdout) {
|
|
125
|
+
const normalized = normalize(stdout);
|
|
126
|
+
const raw = [
|
|
127
|
+
...extractNextBuildMissingModule(normalized),
|
|
128
|
+
...extractNextBuildTypeError(normalized),
|
|
129
|
+
...extractVitestFailures(normalized),
|
|
130
|
+
];
|
|
131
|
+
const failures = raw.length > 0 ? raw : fallbackExtract(normalized);
|
|
132
|
+
// Sort by id for determinism (localeCompare with 'variant' avoids locale drift).
|
|
133
|
+
failures.sort((a, b) => a.id.localeCompare(b.id, undefined, { sensitivity: 'variant' }));
|
|
134
|
+
const extract = { failures };
|
|
135
|
+
const canonical = JSON.stringify({ failures: extract.failures });
|
|
136
|
+
const hash = createHash('sha256').update(canonical, 'utf8').digest('hex');
|
|
137
|
+
return { hash, extract };
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=evidence-hash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evidence-hash.js","sourceRoot":"","sources":["../../src/worker/evidence-hash.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `assertHandlerOutcomeMatchesWorld` (#902 FR-006).
|
|
3
|
+
*
|
|
4
|
+
* Post-exit runtime assertion that reads a snapshot of the *real* world
|
|
5
|
+
* (labels + queue state) and refuses to accept "the handler said X" as
|
|
6
|
+
* evidence. Load-bearing enforcement half of the terminal-outcome invariant.
|
|
7
|
+
*
|
|
8
|
+
* Compile-time exhaustiveness would have passed the broken #898 handler
|
|
9
|
+
* (which had a `void` return that ran through the success path without
|
|
10
|
+
* setting anything). The type alone cannot catch this bug class.
|
|
11
|
+
*
|
|
12
|
+
* Pure function — fixture code snapshots the world, then calls the helper.
|
|
13
|
+
* Callable from prod code as a dev-mode assertion (not enabled by default).
|
|
14
|
+
*/
|
|
15
|
+
import type { HandlerOutcome } from './handler-outcome.js';
|
|
16
|
+
import type { QueueItem } from '../types/index.js';
|
|
17
|
+
export interface QueueSnapshot {
|
|
18
|
+
readonly inFlight: boolean;
|
|
19
|
+
readonly pendingItems: readonly Pick<QueueItem, 'command' | 'metadata' | 'workflowName'>[];
|
|
20
|
+
}
|
|
21
|
+
export type AssertionResult = {
|
|
22
|
+
readonly ok: true;
|
|
23
|
+
} | {
|
|
24
|
+
readonly ok: false;
|
|
25
|
+
readonly mismatch: string;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Assert the returned `HandlerOutcome` matches the real world.
|
|
29
|
+
*
|
|
30
|
+
* Rules per variant:
|
|
31
|
+
* - `re-armed`: `queueSnapshot.pendingItems` contains an entry with
|
|
32
|
+
* `command === 'continue'` and `metadata?.startPhase === outcome.startPhase`.
|
|
33
|
+
* - `gated`: `labels` contains a matching `waiting-for:*` label.
|
|
34
|
+
* - `failed`: `labels` contains a `blocked:*` or `failed:*` marker.
|
|
35
|
+
* - `done`: `labels` contains no `waiting-for:*` and no `blocked:*` / `failed:*`.
|
|
36
|
+
*/
|
|
37
|
+
export declare function assertHandlerOutcomeMatchesWorld(outcome: HandlerOutcome, labels: readonly string[], queueSnapshot: QueueSnapshot): AssertionResult;
|
|
38
|
+
//# sourceMappingURL=handler-outcome-assertion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler-outcome-assertion.d.ts","sourceRoot":"","sources":["../../src/worker/handler-outcome-assertion.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEnD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,SAAS,IAAI,CAAC,SAAS,EAAE,SAAS,GAAG,UAAU,GAAG,cAAc,CAAC,EAAE,CAAC;CAC5F;AAED,MAAM,MAAM,eAAe,GACvB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAA;CAAE,GACrB;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtD;;;;;;;;;GASG;AACH,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,aAAa,EAAE,aAAa,GAC3B,eAAe,CAwDjB"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Assert the returned `HandlerOutcome` matches the real world.
|
|
3
|
+
*
|
|
4
|
+
* Rules per variant:
|
|
5
|
+
* - `re-armed`: `queueSnapshot.pendingItems` contains an entry with
|
|
6
|
+
* `command === 'continue'` and `metadata?.startPhase === outcome.startPhase`.
|
|
7
|
+
* - `gated`: `labels` contains a matching `waiting-for:*` label.
|
|
8
|
+
* - `failed`: `labels` contains a `blocked:*` or `failed:*` marker.
|
|
9
|
+
* - `done`: `labels` contains no `waiting-for:*` and no `blocked:*` / `failed:*`.
|
|
10
|
+
*/
|
|
11
|
+
export function assertHandlerOutcomeMatchesWorld(outcome, labels, queueSnapshot) {
|
|
12
|
+
switch (outcome.outcome) {
|
|
13
|
+
case 're-armed': {
|
|
14
|
+
const match = queueSnapshot.pendingItems.find((i) => i.command === 'continue' &&
|
|
15
|
+
i.metadata?.startPhase === outcome.startPhase);
|
|
16
|
+
if (!match) {
|
|
17
|
+
return {
|
|
18
|
+
ok: false,
|
|
19
|
+
mismatch: `re-armed(${outcome.startPhase}): no matching pending item found in queue`,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
return { ok: true };
|
|
23
|
+
}
|
|
24
|
+
case 'gated': {
|
|
25
|
+
const hasMatchingWaitingFor = labels.some((l) => l === outcome.gateLabel && l.startsWith('waiting-for:'));
|
|
26
|
+
if (!hasMatchingWaitingFor) {
|
|
27
|
+
return {
|
|
28
|
+
ok: false,
|
|
29
|
+
mismatch: `gated(${outcome.gateLabel}): no matching waiting-for:* label on issue`,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
return { ok: true };
|
|
33
|
+
}
|
|
34
|
+
case 'failed': {
|
|
35
|
+
const hasBlockedOrFailed = labels.some((l) => l.startsWith('blocked:') || l.startsWith('failed:'));
|
|
36
|
+
if (!hasBlockedOrFailed) {
|
|
37
|
+
return {
|
|
38
|
+
ok: false,
|
|
39
|
+
mismatch: `failed: no blocked:* or failed:* marker on issue`,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return { ok: true };
|
|
43
|
+
}
|
|
44
|
+
case 'done': {
|
|
45
|
+
const terminalBlockers = labels.filter((l) => l.startsWith('waiting-for:') ||
|
|
46
|
+
l.startsWith('blocked:') ||
|
|
47
|
+
l.startsWith('failed:'));
|
|
48
|
+
if (terminalBlockers.length > 0) {
|
|
49
|
+
return {
|
|
50
|
+
ok: false,
|
|
51
|
+
mismatch: `done: unexpected terminal-blocker label(s): ${terminalBlockers.join(', ')}`,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return { ok: true };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=handler-outcome-assertion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler-outcome-assertion.js","sourceRoot":"","sources":["../../src/worker/handler-outcome-assertion.ts"],"names":[],"mappings":"AA0BA;;;;;;;;;GASG;AACH,MAAM,UAAU,gCAAgC,CAC9C,OAAuB,EACvB,MAAyB,EACzB,aAA4B;IAE5B,QAAQ,OAAO,CAAC,OAAO,EAAE,CAAC;QACxB,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,MAAM,KAAK,GAAG,aAAa,CAAC,YAAY,CAAC,IAAI,CAC3C,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,OAAO,KAAK,UAAU;gBACvB,CAAC,CAAC,QAAgD,EAAE,UAAU,KAAK,OAAO,CAAC,UAAU,CACzF,CAAC;YACF,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO;oBACL,EAAE,EAAE,KAAK;oBACT,QAAQ,EAAE,YAAY,OAAO,CAAC,UAAU,4CAA4C;iBACrF,CAAC;YACJ,CAAC;YACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;QACtB,CAAC;QACD,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,qBAAqB,GAAG,MAAM,CAAC,IAAI,CACvC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,OAAO,CAAC,SAAS,IAAI,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,CAC/D,CAAC;YACF,IAAI,CAAC,qBAAqB,EAAE,CAAC;gBAC3B,OAAO;oBACL,EAAE,EAAE,KAAK;oBACT,QAAQ,EAAE,SAAS,OAAO,CAAC,SAAS,6CAA6C;iBAClF,CAAC;YACJ,CAAC;YACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;QACtB,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,kBAAkB,GAAG,MAAM,CAAC,IAAI,CACpC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,CAC3D,CAAC;YACF,IAAI,CAAC,kBAAkB,EAAE,CAAC;gBACxB,OAAO;oBACL,EAAE,EAAE,KAAK;oBACT,QAAQ,EAAE,kDAAkD;iBAC7D,CAAC;YACJ,CAAC;YACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;QACtB,CAAC;QACD,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,CACpC,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC;gBAC5B,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC;gBACxB,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,CAC1B,CAAC;YACF,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAChC,OAAO;oBACL,EAAE,EAAE,KAAK;oBACT,QAAQ,EAAE,+CAA+C,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;iBACvF,CAAC;YACJ,CAAC;YACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;QACtB,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `HandlerOutcome` discriminated union (#902 FR-005).
|
|
3
|
+
*
|
|
4
|
+
* The only legal return shape for `MergeConflictHandler.handle`. Every
|
|
5
|
+
* terminal exit path in the handler maps to exactly one variant; compile-time
|
|
6
|
+
* exhaustiveness enforces this at the type layer.
|
|
7
|
+
*
|
|
8
|
+
* The load-bearing enforcement half is the runtime helper
|
|
9
|
+
* `assertHandlerOutcomeMatchesWorld` in `./handler-outcome-assertion.ts`.
|
|
10
|
+
*
|
|
11
|
+
* Semantics:
|
|
12
|
+
* - `re-armed` — the interrupted phase must be re-entered. Dispatcher enqueues
|
|
13
|
+
* `{command: 'continue', startPhase}` for the same itemKey after
|
|
14
|
+
* `queue.complete()` fires on the current handler item.
|
|
15
|
+
* - `gated` — the issue is now sitting at a `waiting-for:*` label matching
|
|
16
|
+
* `gateLabel`. Detector will pick it up naturally.
|
|
17
|
+
* - `failed` — the issue is now sitting at a `blocked:*` or `failed:*` marker.
|
|
18
|
+
* Operator intervention required.
|
|
19
|
+
* - `done` — the issue is terminal (closed / merged / withdrawn). No detector
|
|
20
|
+
* pickup expected.
|
|
21
|
+
*/
|
|
22
|
+
import type { WorkflowPhase } from './types.js';
|
|
23
|
+
import type { BlockedStuckMergeConflictsEvidence } from './merge-conflict-handler.js';
|
|
24
|
+
export interface ReArmedOutcome {
|
|
25
|
+
readonly outcome: 're-armed';
|
|
26
|
+
/** Phase the interrupted worker should resume at. Threaded to enqueue. */
|
|
27
|
+
readonly startPhase: WorkflowPhase;
|
|
28
|
+
}
|
|
29
|
+
export interface GatedOutcome {
|
|
30
|
+
readonly outcome: 'gated';
|
|
31
|
+
/**
|
|
32
|
+
* The `waiting-for:*` label that MUST be present on the issue at return.
|
|
33
|
+
* Enforced by `assertHandlerOutcomeMatchesWorld`.
|
|
34
|
+
*/
|
|
35
|
+
readonly gateLabel: string;
|
|
36
|
+
}
|
|
37
|
+
export interface FailedOutcome {
|
|
38
|
+
readonly outcome: 'failed';
|
|
39
|
+
/**
|
|
40
|
+
* Evidence blob rendered into the operator-facing stage comment.
|
|
41
|
+
* Shape is handler-specific; `MergeConflictHandler` uses
|
|
42
|
+
* `BlockedStuckMergeConflictsEvidence`.
|
|
43
|
+
*/
|
|
44
|
+
readonly evidence: BlockedStuckMergeConflictsEvidence;
|
|
45
|
+
}
|
|
46
|
+
export interface DoneOutcome {
|
|
47
|
+
readonly outcome: 'done';
|
|
48
|
+
}
|
|
49
|
+
export type HandlerOutcome = ReArmedOutcome | GatedOutcome | FailedOutcome | DoneOutcome;
|
|
50
|
+
//# sourceMappingURL=handler-outcome.d.ts.map
|