@generacy-ai/orchestrator 0.6.0 → 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/schema.d.ts +7 -7
- 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 +24 -8
- package/dist/worker/config.d.ts.map +1 -1
- package/dist/worker/config.js +37 -2
- 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 +295 -29
- 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 +6 -5
package/dist/worker/config.js
CHANGED
|
@@ -8,7 +8,7 @@ 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
13
|
/**
|
|
14
14
|
* Per-phase wall-clock timeout overrides (milliseconds).
|
|
@@ -50,7 +50,9 @@ export const WorkerConfigSchema = z.object({
|
|
|
50
50
|
/** Command to run during the validate phase */
|
|
51
51
|
validateCommand: z.string().default('pnpm test && pnpm build'),
|
|
52
52
|
/** Command to run before validation to install dependencies (empty string to skip) */
|
|
53
|
-
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"),
|
|
54
56
|
/** Maximum retries for implement phase when partial progress is detected */
|
|
55
57
|
maxImplementRetries: z.number().int().min(0).max(5).default(2),
|
|
56
58
|
/** Credential role from .generacy/config.yaml defaults.role — when set, credentials are populated on launch requests */
|
|
@@ -61,10 +63,14 @@ export const WorkerConfigSchema = z.object({
|
|
|
61
63
|
{ phase: 'clarify', gateLabel: 'waiting-for:clarification', condition: 'on-questions' },
|
|
62
64
|
{ phase: 'implement', gateLabel: 'waiting-for:implementation-review', condition: 'always' },
|
|
63
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' },
|
|
64
68
|
],
|
|
65
69
|
'speckit-bugfix': [
|
|
66
70
|
{ phase: 'clarify', gateLabel: 'waiting-for:clarification', condition: 'on-questions' },
|
|
67
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' },
|
|
68
74
|
],
|
|
69
75
|
'speckit-epic': [
|
|
70
76
|
{ phase: 'clarify', gateLabel: 'waiting-for:clarification', condition: 'on-questions' },
|
|
@@ -72,6 +78,35 @@ export const WorkerConfigSchema = z.object({
|
|
|
72
78
|
],
|
|
73
79
|
}),
|
|
74
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
|
+
}
|
|
75
110
|
/**
|
|
76
111
|
* Resolve the wall-clock timeout (ms) for a CLI phase: the per-phase override
|
|
77
112
|
* if one is configured, otherwise the flat `phaseTimeoutMs` fallback.
|
|
@@ -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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler-outcome.d.ts","sourceRoot":"","sources":["../../src/worker/handler-outcome.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,kCAAkC,EAAE,MAAM,6BAA6B,CAAC;AAEtF,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,0EAA0E;IAC1E,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC;CACpC;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,kCAAkC,CAAC;CACvD;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,MAAM,cAAc,GACtB,cAAc,GACd,YAAY,GACZ,aAAa,GACb,WAAW,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler-outcome.js","sourceRoot":"","sources":["../../src/worker/handler-outcome.ts"],"names":[],"mappings":""}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import type { GitHubClient } from '@generacy-ai/workflow-engine';
|
|
2
2
|
import type { WorkflowPhase, Logger } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Callback invoked from `onGateHit` after a pause label pair
|
|
5
|
+
* (`waiting-for:<gate>` + `agent:paused`) has been successfully applied.
|
|
6
|
+
* Used by callers wired to `PhaseTrackerService` to invalidate the paired
|
|
7
|
+
* `resume:<gate>` dedupe key so a subsequent resume can pass through. See #849.
|
|
8
|
+
*/
|
|
9
|
+
export type ClearResumeDedupeCallback = (gate: string) => Promise<void>;
|
|
3
10
|
/**
|
|
4
11
|
* Manages label transitions on GitHub issues throughout the worker's phase loop.
|
|
5
12
|
*
|
|
@@ -17,7 +24,32 @@ export declare class LabelManager {
|
|
|
17
24
|
private readonly repo;
|
|
18
25
|
private readonly issueNumber;
|
|
19
26
|
private readonly logger;
|
|
20
|
-
|
|
27
|
+
private readonly clearResumeDedupe?;
|
|
28
|
+
/**
|
|
29
|
+
* Per-process cache of repos whose workflow labels have been ensured.
|
|
30
|
+
* Key: `"owner/repo"`. Shared across every `LabelManager` instance in the
|
|
31
|
+
* process — one boundary ensure-pass per repo per process lifetime.
|
|
32
|
+
*/
|
|
33
|
+
private static readonly ensuredRepos;
|
|
34
|
+
/**
|
|
35
|
+
* In-flight-Promise dedupe for concurrent first-callers on the same repo.
|
|
36
|
+
* Key: `"owner/repo"`. Ensures the ensure-pass runs at most once
|
|
37
|
+
* concurrently even if multiple issues in the same repo fire simultaneously.
|
|
38
|
+
*/
|
|
39
|
+
private static readonly ensureInFlight;
|
|
40
|
+
/**
|
|
41
|
+
* Lineage map of classified provisioning failures — `"owner/repo"` → labelName → error.
|
|
42
|
+
*
|
|
43
|
+
* Written by the error branch of `ensureRepoLabelsExist` (per FR-008 / #916).
|
|
44
|
+
* Read by `addLabels` on apply-time 404 to enrich the thrown error's message
|
|
45
|
+
* with the provisioning cause so the operator sees inline what actually broke.
|
|
46
|
+
* Per-label entries evict when a subsequent ensure-pass succeeds or races on
|
|
47
|
+
* the same label; whole-repo clear happens on `resetEnsureCacheForTests`.
|
|
48
|
+
*/
|
|
49
|
+
private static readonly provisioningFailures;
|
|
50
|
+
/** Test-only: reset the class-level memoization caches. */
|
|
51
|
+
static resetEnsureCacheForTests(): void;
|
|
52
|
+
constructor(github: GitHubClient, owner: string, repo: string, issueNumber: number, logger: Logger, clearResumeDedupe?: ClearResumeDedupeCallback | undefined);
|
|
21
53
|
/**
|
|
22
54
|
* Called when a phase begins execution.
|
|
23
55
|
*
|
|
@@ -70,6 +102,27 @@ export declare class LabelManager {
|
|
|
70
102
|
* `agent:in-progress` has already been removed will not throw.
|
|
71
103
|
*/
|
|
72
104
|
ensureCleanup(): Promise<void>;
|
|
105
|
+
/**
|
|
106
|
+
* Ensures every label in `WORKFLOW_LABELS` exists on the target repo.
|
|
107
|
+
*
|
|
108
|
+
* Memoized per-process, keyed on `"owner/repo"`. First caller on a given
|
|
109
|
+
* repo runs the pass; concurrent callers await the shared in-flight Promise;
|
|
110
|
+
* subsequent callers return immediately. This is the load-bearing safety net
|
|
111
|
+
* that catches labels not proactively provisioned by `LabelSyncService`.
|
|
112
|
+
*/
|
|
113
|
+
private ensureRepoLabelsExist;
|
|
114
|
+
/**
|
|
115
|
+
* Wrap `github.addLabels` with lineage-map enrichment.
|
|
116
|
+
*
|
|
117
|
+
* On apply-time 404 for a label that failed provisioning in the same process,
|
|
118
|
+
* splice `label "<name>": <cause> (HTTP <statusCode>)` into the thrown error's
|
|
119
|
+
* message so the operator sees the provisioning cause inline instead of a
|
|
120
|
+
* bare 404. Cross-process gaps (map miss) rethrow the raw 404 unchanged —
|
|
121
|
+
* `ensureRepoLabelsExist`'s error log is the trace surface (FR-003 floor).
|
|
122
|
+
*
|
|
123
|
+
* All other error shapes rethrow unchanged.
|
|
124
|
+
*/
|
|
125
|
+
private applyLabels;
|
|
73
126
|
/**
|
|
74
127
|
* Fetch current labels on the issue and return those matching the `phase:*` pattern.
|
|
75
128
|
*/
|
|
@@ -78,7 +131,10 @@ export declare class LabelManager {
|
|
|
78
131
|
* Retry an async operation with exponential backoff.
|
|
79
132
|
*
|
|
80
133
|
* Attempts the operation up to 3 times with delays of 1000ms, 2000ms, and 4000ms
|
|
81
|
-
* between attempts.
|
|
134
|
+
* between attempts. On final-attempt failure, throws `TerminalLabelOpError`
|
|
135
|
+
* carrying the `{ site, labelOp, ghStderr, cause }` context so callers can
|
|
136
|
+
* translate to `WorkerResult.status === 'failed-terminal'` without releasing
|
|
137
|
+
* the item back to the queue (#889 crash-loop fix).
|
|
82
138
|
*/
|
|
83
139
|
private retryWithBackoff;
|
|
84
140
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"label-manager.d.ts","sourceRoot":"","sources":["../../src/worker/label-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"label-manager.d.ts","sourceRoot":"","sources":["../../src/worker/label-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAMxD;;;;;GAKG;AACH,MAAM,MAAM,yBAAyB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAYxE;;;;;;;;;;GAUG;AACH,qBAAa,YAAY;IAkCrB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC;IAtCrC;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAqB;IAEzD;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAoC;IAE1E;;;;;;;;OAQG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAqD;IAEjG,2DAA2D;IAC3D,MAAM,CAAC,wBAAwB,IAAI,IAAI;gBAOpB,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,iBAAiB,CAAC,EAAE,yBAAyB,YAAA;IAGhE;;;;OAIG;IACG,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAyBvD;;;;OAIG;IACG,eAAe,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB1D;;;;OAIG;IACG,SAAS,CAAC,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA4CvE;;;;OAIG;IACG,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBlD;;;;OAIG;IACG,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAezC;;;;;;OAMG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IA0CpC;;;;;;;;;;;;OAYG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAuBpC;;;;;;;OAOG;YACW,qBAAqB;IAuGnC;;;;;;;;;;OAUG;YACW,WAAW;IAyBzB;;OAEG;YACW,qBAAqB;IAOnC;;;;;;;;OAQG;YACW,gBAAgB;IAsC9B;;OAEG;IACH,OAAO,CAAC,KAAK;CAGd"}
|