@generacy-ai/generacy 0.3.4 → 0.5.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/README.md +153 -0
- package/dist/cli/commands/cluster/scaffolder.d.ts.map +1 -1
- package/dist/cli/commands/cluster/scaffolder.js +2 -0
- package/dist/cli/commands/cluster/scaffolder.js.map +1 -1
- package/dist/cli/commands/cockpit/advance.d.ts +42 -0
- package/dist/cli/commands/cockpit/advance.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/advance.js +136 -0
- package/dist/cli/commands/cockpit/advance.js.map +1 -0
- package/dist/cli/commands/cockpit/clarification-comment-finder.d.ts +13 -0
- package/dist/cli/commands/cockpit/clarification-comment-finder.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/clarification-comment-finder.js +31 -0
- package/dist/cli/commands/cockpit/clarification-comment-finder.js.map +1 -0
- package/dist/cli/commands/cockpit/code-references.d.ts +27 -0
- package/dist/cli/commands/cockpit/code-references.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/code-references.js +48 -0
- package/dist/cli/commands/cockpit/code-references.js.map +1 -0
- package/dist/cli/commands/cockpit/context.d.ts +90 -0
- package/dist/cli/commands/cockpit/context.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/context.js +280 -0
- package/dist/cli/commands/cockpit/context.js.map +1 -0
- package/dist/cli/commands/cockpit/exit.d.ts +12 -0
- package/dist/cli/commands/cockpit/exit.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/exit.js +18 -0
- package/dist/cli/commands/cockpit/exit.js.map +1 -0
- package/dist/cli/commands/cockpit/gate-vocabulary.d.ts +48 -0
- package/dist/cli/commands/cockpit/gate-vocabulary.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/gate-vocabulary.js +96 -0
- package/dist/cli/commands/cockpit/gate-vocabulary.js.map +1 -0
- package/dist/cli/commands/cockpit/index.d.ts +20 -0
- package/dist/cli/commands/cockpit/index.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/index.js +42 -0
- package/dist/cli/commands/cockpit/index.js.map +1 -0
- package/dist/cli/commands/cockpit/manual-advance-marker.d.ts +18 -0
- package/dist/cli/commands/cockpit/manual-advance-marker.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/manual-advance-marker.js +43 -0
- package/dist/cli/commands/cockpit/manual-advance-marker.js.map +1 -0
- package/dist/cli/commands/cockpit/mcp/errors.d.ts +54 -0
- package/dist/cli/commands/cockpit/mcp/errors.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/mcp/errors.js +190 -0
- package/dist/cli/commands/cockpit/mcp/errors.js.map +1 -0
- package/dist/cli/commands/cockpit/mcp/event-bus-registry.d.ts +59 -0
- package/dist/cli/commands/cockpit/mcp/event-bus-registry.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/mcp/event-bus-registry.js +305 -0
- package/dist/cli/commands/cockpit/mcp/event-bus-registry.js.map +1 -0
- package/dist/cli/commands/cockpit/mcp/event-bus.d.ts +82 -0
- package/dist/cli/commands/cockpit/mcp/event-bus.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/mcp/event-bus.js +230 -0
- package/dist/cli/commands/cockpit/mcp/event-bus.js.map +1 -0
- package/dist/cli/commands/cockpit/mcp/index.d.ts +17 -0
- package/dist/cli/commands/cockpit/mcp/index.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/mcp/index.js +37 -0
- package/dist/cli/commands/cockpit/mcp/index.js.map +1 -0
- package/dist/cli/commands/cockpit/mcp/ref-input.d.ts +52 -0
- package/dist/cli/commands/cockpit/mcp/ref-input.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/mcp/ref-input.js +132 -0
- package/dist/cli/commands/cockpit/mcp/ref-input.js.map +1 -0
- package/dist/cli/commands/cockpit/mcp/schemas.d.ts +422 -0
- package/dist/cli/commands/cockpit/mcp/schemas.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/mcp/schemas.js +97 -0
- package/dist/cli/commands/cockpit/mcp/schemas.js.map +1 -0
- package/dist/cli/commands/cockpit/mcp/server.d.ts +17 -0
- package/dist/cli/commands/cockpit/mcp/server.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/mcp/server.js +72 -0
- package/dist/cli/commands/cockpit/mcp/server.js.map +1 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_advance.d.ts +42 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_advance.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_advance.js +73 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_advance.js.map +1 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_await_events.d.ts +34 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_await_events.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_await_events.js +115 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_await_events.js.map +1 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_context.d.ts +21 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_context.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_context.js +35 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_context.js.map +1 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_merge.d.ts +43 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_merge.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_merge.js +99 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_merge.js.map +1 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_queue.d.ts +59 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_queue.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_queue.js +106 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_queue.js.map +1 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_resume.d.ts +38 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_resume.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_resume.js +79 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_resume.js.map +1 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_scope_add.d.ts +31 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_scope_add.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_scope_add.js +81 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_scope_add.js.map +1 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_scope_remove.d.ts +30 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_scope_remove.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_scope_remove.js +80 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_scope_remove.js.map +1 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_status.d.ts +21 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_status.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_status.js +59 -0
- package/dist/cli/commands/cockpit/mcp/tools/cockpit_status.js.map +1 -0
- package/dist/cli/commands/cockpit/merge.d.ts +42 -0
- package/dist/cli/commands/cockpit/merge.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/merge.js +360 -0
- package/dist/cli/commands/cockpit/merge.js.map +1 -0
- package/dist/cli/commands/cockpit/plan-dependency-extractor.d.ts +30 -0
- package/dist/cli/commands/cockpit/plan-dependency-extractor.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/plan-dependency-extractor.js +135 -0
- package/dist/cli/commands/cockpit/plan-dependency-extractor.js.map +1 -0
- package/dist/cli/commands/cockpit/queue.d.ts +100 -0
- package/dist/cli/commands/cockpit/queue.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/queue.js +551 -0
- package/dist/cli/commands/cockpit/queue.js.map +1 -0
- package/dist/cli/commands/cockpit/resolver.d.ts +70 -0
- package/dist/cli/commands/cockpit/resolver.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/resolver.js +117 -0
- package/dist/cli/commands/cockpit/resolver.js.map +1 -0
- package/dist/cli/commands/cockpit/resume.d.ts +38 -0
- package/dist/cli/commands/cockpit/resume.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/resume.js +167 -0
- package/dist/cli/commands/cockpit/resume.js.map +1 -0
- package/dist/cli/commands/cockpit/scope/errors.d.ts +21 -0
- package/dist/cli/commands/cockpit/scope/errors.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/scope/errors.js +17 -0
- package/dist/cli/commands/cockpit/scope/errors.js.map +1 -0
- package/dist/cli/commands/cockpit/scope/retry.d.ts +24 -0
- package/dist/cli/commands/cockpit/scope/retry.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/scope/retry.js +52 -0
- package/dist/cli/commands/cockpit/scope/retry.js.map +1 -0
- package/dist/cli/commands/cockpit/scope/writer.d.ts +21 -0
- package/dist/cli/commands/cockpit/scope/writer.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/scope/writer.js +141 -0
- package/dist/cli/commands/cockpit/scope/writer.js.map +1 -0
- package/dist/cli/commands/cockpit/scope.d.ts +22 -0
- package/dist/cli/commands/cockpit/scope.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/scope.js +110 -0
- package/dist/cli/commands/cockpit/scope.js.map +1 -0
- package/dist/cli/commands/cockpit/shared/classify-issue.d.ts +12 -0
- package/dist/cli/commands/cockpit/shared/classify-issue.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/shared/classify-issue.js +10 -0
- package/dist/cli/commands/cockpit/shared/classify-issue.js.map +1 -0
- package/dist/cli/commands/cockpit/shared/failing-check-json.d.ts +53 -0
- package/dist/cli/commands/cockpit/shared/failing-check-json.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/shared/failing-check-json.js +170 -0
- package/dist/cli/commands/cockpit/shared/failing-check-json.js.map +1 -0
- package/dist/cli/commands/cockpit/shared/identity.d.ts +54 -0
- package/dist/cli/commands/cockpit/shared/identity.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/shared/identity.js +65 -0
- package/dist/cli/commands/cockpit/shared/identity.js.map +1 -0
- package/dist/cli/commands/cockpit/shared/is-done-snapshot.d.ts +16 -0
- package/dist/cli/commands/cockpit/shared/is-done-snapshot.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/shared/is-done-snapshot.js +17 -0
- package/dist/cli/commands/cockpit/shared/is-done-snapshot.js.map +1 -0
- package/dist/cli/commands/cockpit/shared/pagination.d.ts +17 -0
- package/dist/cli/commands/cockpit/shared/pagination.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/shared/pagination.js +50 -0
- package/dist/cli/commands/cockpit/shared/pagination.js.map +1 -0
- package/dist/cli/commands/cockpit/shared/pr-link.d.ts +8 -0
- package/dist/cli/commands/cockpit/shared/pr-link.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/shared/pr-link.js +15 -0
- package/dist/cli/commands/cockpit/shared/pr-link.js.map +1 -0
- package/dist/cli/commands/cockpit/shared/required-checks.d.ts +17 -0
- package/dist/cli/commands/cockpit/shared/required-checks.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/shared/required-checks.js +38 -0
- package/dist/cli/commands/cockpit/shared/required-checks.js.map +1 -0
- package/dist/cli/commands/cockpit/shared/review-context-json.d.ts +29 -0
- package/dist/cli/commands/cockpit/shared/review-context-json.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/shared/review-context-json.js +28 -0
- package/dist/cli/commands/cockpit/shared/review-context-json.js.map +1 -0
- package/dist/cli/commands/cockpit/status/color.d.ts +11 -0
- package/dist/cli/commands/cockpit/status/color.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/status/color.js +33 -0
- package/dist/cli/commands/cockpit/status/color.js.map +1 -0
- package/dist/cli/commands/cockpit/status/group.d.ts +10 -0
- package/dist/cli/commands/cockpit/status/group.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/status/group.js +50 -0
- package/dist/cli/commands/cockpit/status/group.js.map +1 -0
- package/dist/cli/commands/cockpit/status/render-table.d.ts +24 -0
- package/dist/cli/commands/cockpit/status/render-table.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/status/render-table.js +71 -0
- package/dist/cli/commands/cockpit/status/render-table.js.map +1 -0
- package/dist/cli/commands/cockpit/status/row.d.ts +18 -0
- package/dist/cli/commands/cockpit/status/row.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/status/row.js +17 -0
- package/dist/cli/commands/cockpit/status/row.js.map +1 -0
- package/dist/cli/commands/cockpit/status.d.ts +18 -0
- package/dist/cli/commands/cockpit/status.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/status.js +153 -0
- package/dist/cli/commands/cockpit/status.js.map +1 -0
- package/dist/cli/commands/cockpit/watch/actionable.d.ts +15 -0
- package/dist/cli/commands/cockpit/watch/actionable.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/watch/actionable.js +32 -0
- package/dist/cli/commands/cockpit/watch/actionable.js.map +1 -0
- package/dist/cli/commands/cockpit/watch/aggregate-emit.d.ts +107 -0
- package/dist/cli/commands/cockpit/watch/aggregate-emit.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/watch/aggregate-emit.js +41 -0
- package/dist/cli/commands/cockpit/watch/aggregate-emit.js.map +1 -0
- package/dist/cli/commands/cockpit/watch/aggregate.d.ts +25 -0
- package/dist/cli/commands/cockpit/watch/aggregate.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/watch/aggregate.js +67 -0
- package/dist/cli/commands/cockpit/watch/aggregate.js.map +1 -0
- package/dist/cli/commands/cockpit/watch/check-rollup.d.ts +9 -0
- package/dist/cli/commands/cockpit/watch/check-rollup.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/watch/check-rollup.js +22 -0
- package/dist/cli/commands/cockpit/watch/check-rollup.js.map +1 -0
- package/dist/cli/commands/cockpit/watch/diff.d.ts +33 -0
- package/dist/cli/commands/cockpit/watch/diff.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/watch/diff.js +93 -0
- package/dist/cli/commands/cockpit/watch/diff.js.map +1 -0
- package/dist/cli/commands/cockpit/watch/emit.d.ts +58 -0
- package/dist/cli/commands/cockpit/watch/emit.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/watch/emit.js +30 -0
- package/dist/cli/commands/cockpit/watch/emit.js.map +1 -0
- package/dist/cli/commands/cockpit/watch/poll-loop.d.ts +29 -0
- package/dist/cli/commands/cockpit/watch/poll-loop.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/watch/poll-loop.js +81 -0
- package/dist/cli/commands/cockpit/watch/poll-loop.js.map +1 -0
- package/dist/cli/commands/cockpit/watch/pr-state.d.ts +17 -0
- package/dist/cli/commands/cockpit/watch/pr-state.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/watch/pr-state.js +33 -0
- package/dist/cli/commands/cockpit/watch/pr-state.js.map +1 -0
- package/dist/cli/commands/cockpit/watch/snapshot.d.ts +33 -0
- package/dist/cli/commands/cockpit/watch/snapshot.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/watch/snapshot.js +30 -0
- package/dist/cli/commands/cockpit/watch/snapshot.js.map +1 -0
- package/dist/cli/commands/cockpit/watch/stream-event.d.ts +82 -0
- package/dist/cli/commands/cockpit/watch/stream-event.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/watch/stream-event.js +9 -0
- package/dist/cli/commands/cockpit/watch/stream-event.js.map +1 -0
- package/dist/cli/commands/cockpit/watch.d.ts +22 -0
- package/dist/cli/commands/cockpit/watch.d.ts.map +1 -0
- package/dist/cli/commands/cockpit/watch.js +186 -0
- package/dist/cli/commands/cockpit/watch.js.map +1 -0
- package/dist/cli/commands/setup/build.d.ts.map +1 -1
- package/dist/cli/commands/setup/build.js +59 -0
- package/dist/cli/commands/setup/build.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/config/schema.d.ts +788 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +12 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +12 -6
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cockpit resolver — parses issue arguments and resolves them to a live
|
|
3
|
+
* `{ ref, repo, gh }` bundle:
|
|
4
|
+
*
|
|
5
|
+
* - `IssueRef` — owner/repo/number/nwo
|
|
6
|
+
* - `parseIssueRef(input)` — @internal; strict qualified-forms parser
|
|
7
|
+
* (owner/repo#N and URL only). Cockpit callers
|
|
8
|
+
* MUST go through `resolveIssueContext`.
|
|
9
|
+
* - `resolveIssueContext(x)` — gates bare numbers via cwd-origin inference,
|
|
10
|
+
* delegates qualified forms to `parseIssueRef`,
|
|
11
|
+
* and returns a live `{ ref, repo, gh }` bundle.
|
|
12
|
+
*
|
|
13
|
+
* Errors are loud (`parse issue: <reason>`) so callers can prefix
|
|
14
|
+
* `Error: cockpit <verb>: ` per cli-surface.md.
|
|
15
|
+
*/
|
|
16
|
+
import { GhCliWrapper, nodeChildProcessRunner, } from '@generacy-ai/cockpit';
|
|
17
|
+
const OWNER_REPO_HASH = /^([^/\s]+)\/([^/\s#]+)#(\d+)$/;
|
|
18
|
+
const ISSUE_URL = /^https?:\/\/github\.com\/([^/\s]+)\/([^/\s]+)\/(?:issues|pull)\/(\d+)(?:[/?#].*)?$/;
|
|
19
|
+
const BARE_NUMBER = /^\d+$/;
|
|
20
|
+
function fail(reason) {
|
|
21
|
+
throw new Error(`parse issue: ${reason}`);
|
|
22
|
+
}
|
|
23
|
+
function makeRef(owner, repo, number) {
|
|
24
|
+
if (!owner || owner.includes('/') || /\s/.test(owner)) {
|
|
25
|
+
fail(`invalid owner "${owner}"`);
|
|
26
|
+
}
|
|
27
|
+
if (!repo || repo.includes('/') || /\s/.test(repo)) {
|
|
28
|
+
fail(`invalid repo "${repo}"`);
|
|
29
|
+
}
|
|
30
|
+
if (!Number.isInteger(number) || number <= 0) {
|
|
31
|
+
fail(`issue number must be a positive integer, got "${number}"`);
|
|
32
|
+
}
|
|
33
|
+
return { owner, repo, number, nwo: `${owner}/${repo}` };
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* @internal — cockpit callers MUST use `resolveIssueContext` instead. This
|
|
37
|
+
* function is exported only for its unit tests. Enforced by ESLint
|
|
38
|
+
* `no-restricted-imports` (see `.eslintrc.json`). See #850.
|
|
39
|
+
*
|
|
40
|
+
* Strict qualified-forms parser. Accepts:
|
|
41
|
+
* - `owner/repo#123`
|
|
42
|
+
* - `https://github.com/owner/repo/issues/123`
|
|
43
|
+
* - `https://github.com/owner/repo/pull/123`
|
|
44
|
+
*
|
|
45
|
+
* Bare numbers ("123") fall through to the `unrecognized issue ref` throw —
|
|
46
|
+
* they are NOT a special case here. The bare-number remedy (cwd-origin
|
|
47
|
+
* inference) lives in `resolveIssueContext`.
|
|
48
|
+
*/
|
|
49
|
+
export function parseIssueRef(input) {
|
|
50
|
+
const trimmed = input.trim();
|
|
51
|
+
if (trimmed === '') {
|
|
52
|
+
fail('issue argument is required');
|
|
53
|
+
}
|
|
54
|
+
const ownerRepoHash = OWNER_REPO_HASH.exec(trimmed);
|
|
55
|
+
if (ownerRepoHash) {
|
|
56
|
+
const [, owner, repo, num] = ownerRepoHash;
|
|
57
|
+
return makeRef(owner, repo, Number.parseInt(num, 10));
|
|
58
|
+
}
|
|
59
|
+
const url = ISSUE_URL.exec(trimmed);
|
|
60
|
+
if (url) {
|
|
61
|
+
const [, owner, repo, num] = url;
|
|
62
|
+
return makeRef(owner, repo, Number.parseInt(num, 10));
|
|
63
|
+
}
|
|
64
|
+
fail(`unrecognized issue ref "${input}". ` +
|
|
65
|
+
`Use <n>, <owner>/<repo>#<n>, or https://github.com/<owner>/<repo>/issues/<n>.`);
|
|
66
|
+
}
|
|
67
|
+
async function inferRepoFromGitOrigin(runner, cwd) {
|
|
68
|
+
const result = await runner('git', ['remote', 'get-url', 'origin'], cwd != null ? { cwd } : {});
|
|
69
|
+
if (result.exitCode !== 0) {
|
|
70
|
+
fail(`could not infer owner/repo: 'git remote get-url origin' failed ` +
|
|
71
|
+
`(exit ${result.exitCode}): ${result.stderr.trim()}`);
|
|
72
|
+
}
|
|
73
|
+
const url = result.stdout.trim();
|
|
74
|
+
const match = /github\.com[/:]([^/]+)\/([^/.]+?)(?:\.git)?\/?$/.exec(url);
|
|
75
|
+
if (!match || !match[1] || !match[2]) {
|
|
76
|
+
fail(`could not infer owner/repo from git origin URL: ${url}`);
|
|
77
|
+
}
|
|
78
|
+
return `${match[1]}/${match[2]}`;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Resolve an issue argument to a full `{ ref, repo, gh }` bundle.
|
|
82
|
+
*
|
|
83
|
+
* Strategy:
|
|
84
|
+
* 1. Bare numbers ("123"): resolve owner/repo from `input.repo` or cwd git
|
|
85
|
+
* origin inference, then build the ref directly via `makeRef`.
|
|
86
|
+
* 2. Qualified forms (`owner/repo#N`, URLs): delegate to `parseIssueRef`.
|
|
87
|
+
*
|
|
88
|
+
* The `input.repo` override exists for programmatic callers; the `context`
|
|
89
|
+
* verb intentionally does not expose it as a CLI flag (spec Q5 → A).
|
|
90
|
+
*/
|
|
91
|
+
export async function resolveIssueContext(input) {
|
|
92
|
+
const runner = input.runner ?? nodeChildProcessRunner;
|
|
93
|
+
const trimmed = input.issue.trim();
|
|
94
|
+
if (BARE_NUMBER.test(trimmed)) {
|
|
95
|
+
const number = Number.parseInt(trimmed, 10);
|
|
96
|
+
let repoNwo;
|
|
97
|
+
try {
|
|
98
|
+
repoNwo = input.repo ?? (await inferRepoFromGitOrigin(runner, input.cwd));
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
const innerReason = err.message.replace(/^parse issue: /, '');
|
|
102
|
+
throw new Error(`parse issue: bare issue number "${trimmed}" is not accepted here. ` +
|
|
103
|
+
`Accepted: <owner>/<repo>#${trimmed}, a full issue URL, or a bare number inside a ` +
|
|
104
|
+
`checkout with a resolvable GitHub origin. ` +
|
|
105
|
+
`(cwd-origin inference failed: ${innerReason})`);
|
|
106
|
+
}
|
|
107
|
+
const parts = repoNwo.split('/');
|
|
108
|
+
if (parts.length !== 2 || !parts[0] || !parts[1]) {
|
|
109
|
+
fail(`inferred repo "${repoNwo}" is not in <owner>/<repo> form`);
|
|
110
|
+
}
|
|
111
|
+
const ref = makeRef(parts[0], parts[1], number);
|
|
112
|
+
return { ref, repo: ref.nwo, gh: new GhCliWrapper(runner) };
|
|
113
|
+
}
|
|
114
|
+
const ref = parseIssueRef(input.issue);
|
|
115
|
+
return { ref, repo: ref.nwo, gh: new GhCliWrapper(runner) };
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../../../src/cli/commands/cockpit/resolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `generacy cockpit resume <issue>` — re-arm a failed phase in place.
|
|
3
|
+
*
|
|
4
|
+
* Engine-owned label surgery: on an issue carrying `failed:<phase>` (with or
|
|
5
|
+
* without `agent:error`), applies the additions `waiting-for:<preceding-gate>`
|
|
6
|
+
* + `completed:<preceding-gate>` + `agent:paused` FIRST, then removes
|
|
7
|
+
* `failed:<phase>` plus defensive `agent:error` / `phase:<phase>` when
|
|
8
|
+
* present. The terminal on-issue state is byte-identical to a
|
|
9
|
+
* naturally-paused-then-completed gate — the label monitor's next poll emits
|
|
10
|
+
* a resume event, and the worker's `PhaseResolver.resolveFromContinue` walks
|
|
11
|
+
* the preserved `completed:<earlier-phase>` chain to pick `<phase>` as the
|
|
12
|
+
* start phase.
|
|
13
|
+
*
|
|
14
|
+
* Side effects (in order):
|
|
15
|
+
* 1. gh addLabels [waiting-for:<G>, completed:<G>, agent:paused]
|
|
16
|
+
* 2. gh removeLabels [failed:<phase>, ...conditional]
|
|
17
|
+
*
|
|
18
|
+
* Idempotent (FR-003): no `failed:*` → no-op with single-line stdout, exit 0.
|
|
19
|
+
* Refuses (FR-004) with evidence and zero mutations when the state is
|
|
20
|
+
* ambiguous or non-re-armable. No `--force` in v1 (parity with `advance`).
|
|
21
|
+
*/
|
|
22
|
+
import { Command } from 'commander';
|
|
23
|
+
import { loadCockpitConfig, type CommandRunner, type GhWrapper } from '@generacy-ai/cockpit';
|
|
24
|
+
export interface ResumeCommandDeps {
|
|
25
|
+
runner?: CommandRunner;
|
|
26
|
+
gh?: GhWrapper;
|
|
27
|
+
loadConfig?: typeof loadCockpitConfig;
|
|
28
|
+
env?: NodeJS.ProcessEnv;
|
|
29
|
+
now?: () => Date;
|
|
30
|
+
stdout?: (line: string) => void;
|
|
31
|
+
stderr?: (line: string) => void;
|
|
32
|
+
}
|
|
33
|
+
export interface ResumeOptions {
|
|
34
|
+
workflow?: string;
|
|
35
|
+
}
|
|
36
|
+
export declare function resumeCommand(deps?: ResumeCommandDeps): Command;
|
|
37
|
+
export declare function runResume(issue: string | undefined, opts: ResumeOptions, deps: ResumeCommandDeps): Promise<void>;
|
|
38
|
+
//# sourceMappingURL=resume.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resume.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/cockpit/resume.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EACL,iBAAiB,EACjB,KAAK,aAAa,EAClB,KAAK,SAAS,EACf,MAAM,sBAAsB,CAAC;AAO9B,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,EAAE,CAAC,EAAE,SAAS,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,iBAAiB,CAAC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAwFD,wBAAgB,aAAa,CAAC,IAAI,GAAE,iBAAsB,GAAG,OAAO,CAmBnE;AAED,wBAAsB,SAAS,CAC7B,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,IAAI,CAAC,CA2Ff"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `generacy cockpit resume <issue>` — re-arm a failed phase in place.
|
|
3
|
+
*
|
|
4
|
+
* Engine-owned label surgery: on an issue carrying `failed:<phase>` (with or
|
|
5
|
+
* without `agent:error`), applies the additions `waiting-for:<preceding-gate>`
|
|
6
|
+
* + `completed:<preceding-gate>` + `agent:paused` FIRST, then removes
|
|
7
|
+
* `failed:<phase>` plus defensive `agent:error` / `phase:<phase>` when
|
|
8
|
+
* present. The terminal on-issue state is byte-identical to a
|
|
9
|
+
* naturally-paused-then-completed gate — the label monitor's next poll emits
|
|
10
|
+
* a resume event, and the worker's `PhaseResolver.resolveFromContinue` walks
|
|
11
|
+
* the preserved `completed:<earlier-phase>` chain to pick `<phase>` as the
|
|
12
|
+
* start phase.
|
|
13
|
+
*
|
|
14
|
+
* Side effects (in order):
|
|
15
|
+
* 1. gh addLabels [waiting-for:<G>, completed:<G>, agent:paused]
|
|
16
|
+
* 2. gh removeLabels [failed:<phase>, ...conditional]
|
|
17
|
+
*
|
|
18
|
+
* Idempotent (FR-003): no `failed:*` → no-op with single-line stdout, exit 0.
|
|
19
|
+
* Refuses (FR-004) with evidence and zero mutations when the state is
|
|
20
|
+
* ambiguous or non-re-armable. No `--force` in v1 (parity with `advance`).
|
|
21
|
+
*/
|
|
22
|
+
import { Command } from 'commander';
|
|
23
|
+
import { loadCockpitConfig, } from '@generacy-ai/cockpit';
|
|
24
|
+
import { getLogger } from '../../utils/logger.js';
|
|
25
|
+
import { resolveIssueContext } from './resolver.js';
|
|
26
|
+
import { resolvePrecedingGate } from './gate-vocabulary.js';
|
|
27
|
+
import { CockpitExit, isCockpitExit } from './exit.js';
|
|
28
|
+
const KNOWN_PHASES = [
|
|
29
|
+
'specify',
|
|
30
|
+
'clarify',
|
|
31
|
+
'plan',
|
|
32
|
+
'tasks',
|
|
33
|
+
'implement',
|
|
34
|
+
'validate',
|
|
35
|
+
];
|
|
36
|
+
function isKnownPhase(candidate) {
|
|
37
|
+
return KNOWN_PHASES.includes(candidate);
|
|
38
|
+
}
|
|
39
|
+
function resolveWorkflowFromLabels(labels) {
|
|
40
|
+
const workflowLabel = labels.find((l) => l.startsWith('workflow:'));
|
|
41
|
+
if (workflowLabel) {
|
|
42
|
+
return workflowLabel.slice('workflow:'.length);
|
|
43
|
+
}
|
|
44
|
+
return 'speckit-feature';
|
|
45
|
+
}
|
|
46
|
+
function classify(labels, workflowOverride) {
|
|
47
|
+
const failedLabels = labels.filter((l) => l.startsWith('failed:')).sort();
|
|
48
|
+
if (failedLabels.length === 0) {
|
|
49
|
+
return { kind: 'no-op' };
|
|
50
|
+
}
|
|
51
|
+
if (failedLabels.length > 1) {
|
|
52
|
+
return { kind: 'refuse-multiple-failed', failedLabels };
|
|
53
|
+
}
|
|
54
|
+
const failedLabel = failedLabels[0];
|
|
55
|
+
const phaseSuffix = failedLabel.slice('failed:'.length);
|
|
56
|
+
if (!isKnownPhase(phaseSuffix)) {
|
|
57
|
+
return { kind: 'refuse-unknown-phase', failedLabel, phaseSuffix };
|
|
58
|
+
}
|
|
59
|
+
const failedPhase = phaseSuffix;
|
|
60
|
+
const workflowName = workflowOverride ?? resolveWorkflowFromLabels(labels);
|
|
61
|
+
const gateResult = resolvePrecedingGate(failedPhase, workflowName);
|
|
62
|
+
if (gateResult.kind === 'no-preceding-gate') {
|
|
63
|
+
return { kind: 'refuse-no-preceding-gate', failedPhase, workflowName };
|
|
64
|
+
}
|
|
65
|
+
const gate = gateResult.gate;
|
|
66
|
+
const conflictingWaiting = labels.find((l) => l.startsWith('waiting-for:') && l !== gate.waitingLabel);
|
|
67
|
+
if (conflictingWaiting) {
|
|
68
|
+
return {
|
|
69
|
+
kind: 'refuse-conflicting-waiting',
|
|
70
|
+
failedPhase,
|
|
71
|
+
conflictingLabel: conflictingWaiting,
|
|
72
|
+
expectedLabel: gate.waitingLabel,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
const labelsToAdd = [gate.waitingLabel, gate.completedLabel, 'agent:paused'];
|
|
76
|
+
const labelsToRemove = [failedLabel];
|
|
77
|
+
if (labels.includes('agent:error'))
|
|
78
|
+
labelsToRemove.push('agent:error');
|
|
79
|
+
const phaseLabel = `phase:${failedPhase}`;
|
|
80
|
+
if (labels.includes(phaseLabel))
|
|
81
|
+
labelsToRemove.push(phaseLabel);
|
|
82
|
+
return { kind: 'happy-path', failedPhase, gate, labelsToAdd, labelsToRemove };
|
|
83
|
+
}
|
|
84
|
+
export function resumeCommand(deps = {}) {
|
|
85
|
+
const cmd = new Command('resume');
|
|
86
|
+
cmd
|
|
87
|
+
.description('Re-arm a failed phase in place so the next poll re-runs it.')
|
|
88
|
+
.argument('[issue]', 'Issue ref — <number>, <owner>/<repo>#<n>, or full URL.')
|
|
89
|
+
.option('--workflow <name>', 'Workflow name override (defaults to the issue\'s workflow:<name> label).')
|
|
90
|
+
.action(async (issue, opts) => {
|
|
91
|
+
try {
|
|
92
|
+
await runResume(issue, opts, deps);
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
if (isCockpitExit(err)) {
|
|
96
|
+
const stderr = deps.stderr ?? ((line) => process.stderr.write(`${line}\n`));
|
|
97
|
+
stderr(err.message);
|
|
98
|
+
process.exit(err.code);
|
|
99
|
+
}
|
|
100
|
+
throw err;
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
return cmd;
|
|
104
|
+
}
|
|
105
|
+
export async function runResume(issue, opts, deps) {
|
|
106
|
+
const log = getLogger();
|
|
107
|
+
const print = deps.stdout ?? ((line) => process.stdout.write(`${line}\n`));
|
|
108
|
+
if (issue == null || issue.trim() === '') {
|
|
109
|
+
throw new CockpitExit(2, 'Error: cockpit resume: missing required argument <issue>');
|
|
110
|
+
}
|
|
111
|
+
const loaded = await (deps.loadConfig ?? loadCockpitConfig)({});
|
|
112
|
+
for (const w of loaded.warnings)
|
|
113
|
+
log.warn(w);
|
|
114
|
+
let ref;
|
|
115
|
+
let gh;
|
|
116
|
+
try {
|
|
117
|
+
const resolvedCtx = await resolveIssueContext({ issue, runner: deps.runner });
|
|
118
|
+
ref = resolvedCtx.ref;
|
|
119
|
+
gh = deps.gh ?? resolvedCtx.gh;
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
throw new CockpitExit(2, `Error: cockpit resume: ${err.message}`);
|
|
123
|
+
}
|
|
124
|
+
let labels;
|
|
125
|
+
try {
|
|
126
|
+
labels = (await gh.fetchIssueLabels(ref.nwo, ref.number)).labels;
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
throw new CockpitExit(1, `Error: cockpit resume: gh issue view: ${err.message}`);
|
|
130
|
+
}
|
|
131
|
+
const decision = classify(labels, opts.workflow);
|
|
132
|
+
switch (decision.kind) {
|
|
133
|
+
case 'no-op':
|
|
134
|
+
print(`issue ${ref.nwo}#${ref.number} is not in a failed state (no failed:<phase> label); nothing to re-arm`);
|
|
135
|
+
return;
|
|
136
|
+
case 'refuse-multiple-failed':
|
|
137
|
+
throw new CockpitExit(3, `Error: cockpit resume: refusing to resume: multiple failed:* labels present: [${decision.failedLabels.join(', ')}]`);
|
|
138
|
+
case 'refuse-unknown-phase':
|
|
139
|
+
throw new CockpitExit(3, `Error: cockpit resume: refusing to resume: unknown phase "${decision.phaseSuffix}" in label "${decision.failedLabel}"`);
|
|
140
|
+
case 'refuse-no-preceding-gate':
|
|
141
|
+
throw new CockpitExit(3, `Error: cockpit resume: refusing to resume: phase "${decision.failedPhase}" has no preceding gate; ` +
|
|
142
|
+
`use \`process:${decision.workflowName}\` label to re-queue from the beginning instead`);
|
|
143
|
+
case 'refuse-conflicting-waiting':
|
|
144
|
+
throw new CockpitExit(3, `Error: cockpit resume: refusing to resume: conflicting ${decision.conflictingLabel} already present; ` +
|
|
145
|
+
`derived preceding-gate is ${decision.expectedLabel.slice('waiting-for:'.length)}`);
|
|
146
|
+
case 'happy-path': {
|
|
147
|
+
try {
|
|
148
|
+
await gh.addLabels(ref.nwo, ref.number, decision.labelsToAdd);
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
throw new CockpitExit(1, `Error: cockpit resume: gh issue edit (add ${decision.labelsToAdd.join(',')}): ${err.message}`);
|
|
152
|
+
}
|
|
153
|
+
try {
|
|
154
|
+
await gh.removeLabels(ref.nwo, ref.number, decision.labelsToRemove);
|
|
155
|
+
}
|
|
156
|
+
catch (err) {
|
|
157
|
+
throw new CockpitExit(1, `Error: cockpit resume: gh issue edit (remove ${decision.labelsToRemove.join(',')}): ${err.message}`);
|
|
158
|
+
}
|
|
159
|
+
print(`resumed ${ref.nwo}#${ref.number}: re-armed phase=${decision.failedPhase} ` +
|
|
160
|
+
`via preceding-gate=${decision.gate.name}; ` +
|
|
161
|
+
`added=[${decision.labelsToAdd.join(',')}] ` +
|
|
162
|
+
`removed=[${decision.labelsToRemove.join(',')}]`);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=resume.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resume.js","sourceRoot":"","sources":["../../../../src/cli/commands/cockpit/resume.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { IssueRef } from '@generacy-ai/cockpit';
|
|
2
|
+
export declare class ScopeContendedError extends Error {
|
|
3
|
+
readonly code: "SCOPE_ADD_CONTENDED";
|
|
4
|
+
readonly attempts: number;
|
|
5
|
+
readonly ref: IssueRef;
|
|
6
|
+
readonly mutation: 'add' | 'remove';
|
|
7
|
+
readonly scope: {
|
|
8
|
+
repo: string;
|
|
9
|
+
number: number;
|
|
10
|
+
};
|
|
11
|
+
constructor(opts: {
|
|
12
|
+
attempts: number;
|
|
13
|
+
ref: IssueRef;
|
|
14
|
+
mutation: 'add' | 'remove';
|
|
15
|
+
scope: {
|
|
16
|
+
repo: string;
|
|
17
|
+
number: number;
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/cockpit/scope/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,IAAI,EAAG,qBAAqB,CAAU;IAC/C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,KAAK,GAAG,QAAQ,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;gBAErC,IAAI,EAAE;QAChB,QAAQ,EAAE,MAAM,CAAC;QACjB,GAAG,EAAE,QAAQ,CAAC;QACd,QAAQ,EAAE,KAAK,GAAG,QAAQ,CAAC;QAC3B,KAAK,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC;KACzC;CAWF"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export class ScopeContendedError extends Error {
|
|
2
|
+
code = 'SCOPE_ADD_CONTENDED';
|
|
3
|
+
attempts;
|
|
4
|
+
ref;
|
|
5
|
+
mutation;
|
|
6
|
+
scope;
|
|
7
|
+
constructor(opts) {
|
|
8
|
+
super(`SCOPE_ADD_CONTENDED: ${opts.mutation} ${opts.ref.repo}#${opts.ref.number} on ` +
|
|
9
|
+
`${opts.scope.repo}#${opts.scope.number} exhausted retry budget after ${opts.attempts} attempts`);
|
|
10
|
+
this.name = 'ScopeContendedError';
|
|
11
|
+
this.attempts = opts.attempts;
|
|
12
|
+
this.ref = opts.ref;
|
|
13
|
+
this.mutation = opts.mutation;
|
|
14
|
+
this.scope = opts.scope;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../../../src/cli/commands/cockpit/scope/errors.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IACnC,IAAI,GAAG,qBAA8B,CAAC;IACtC,QAAQ,CAAS;IACjB,GAAG,CAAW;IACd,QAAQ,CAAmB;IAC3B,KAAK,CAAmC;IAEjD,YAAY,IAKX;QACC,KAAK,CACH,wBAAwB,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,MAAM;YAC7E,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,iCAAiC,IAAI,CAAC,QAAQ,WAAW,CACnG,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;QAClC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC9B,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;QACpB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC9B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;IAC1B,CAAC;CACF"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { GhWrapper, IssueRef } from '@generacy-ai/cockpit';
|
|
2
|
+
import { type BodyShape, type ScopeMutation } from './writer.js';
|
|
3
|
+
export interface WriteScopeOptions {
|
|
4
|
+
gh: GhWrapper;
|
|
5
|
+
scope: IssueRef;
|
|
6
|
+
mutation: ScopeMutation;
|
|
7
|
+
maxAttempts?: number;
|
|
8
|
+
backoffMs?: number[];
|
|
9
|
+
sleep?: (ms: number) => Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
export interface WriteScopeResult {
|
|
12
|
+
noop: boolean;
|
|
13
|
+
attempts: number;
|
|
14
|
+
finalBody: string;
|
|
15
|
+
shape: BodyShape;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Read-modify-write-verify loop for concurrent-safe scope body mutations.
|
|
19
|
+
* `applyScopeMutation` is idempotent, so a competing writer that already
|
|
20
|
+
* applied our mutation causes the next retry to short-circuit as noop.
|
|
21
|
+
* Terminal exhaustion throws `ScopeContendedError`.
|
|
22
|
+
*/
|
|
23
|
+
export declare function writeScopeWithRetry(opts: WriteScopeOptions): Promise<WriteScopeResult>;
|
|
24
|
+
//# sourceMappingURL=retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/cockpit/scope/retry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEhE,OAAO,EAAsB,KAAK,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAErF,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,SAAS,CAAC;IACd,KAAK,EAAE,QAAQ,CAAC;IAChB,QAAQ,EAAE,aAAa,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,SAAS,CAAC;CAClB;AASD;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,gBAAgB,CAAC,CA4C3B"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { ScopeContendedError } from './errors.js';
|
|
2
|
+
import { applyScopeMutation } from './writer.js';
|
|
3
|
+
const DEFAULT_MAX_ATTEMPTS = 5;
|
|
4
|
+
const DEFAULT_BACKOFF_MS = [100, 250, 500, 1000, 2000];
|
|
5
|
+
function defaultSleep(ms) {
|
|
6
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Read-modify-write-verify loop for concurrent-safe scope body mutations.
|
|
10
|
+
* `applyScopeMutation` is idempotent, so a competing writer that already
|
|
11
|
+
* applied our mutation causes the next retry to short-circuit as noop.
|
|
12
|
+
* Terminal exhaustion throws `ScopeContendedError`.
|
|
13
|
+
*/
|
|
14
|
+
export async function writeScopeWithRetry(opts) {
|
|
15
|
+
const maxAttempts = opts.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
|
|
16
|
+
const backoffMs = opts.backoffMs ?? DEFAULT_BACKOFF_MS;
|
|
17
|
+
const sleep = opts.sleep ?? defaultSleep;
|
|
18
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
19
|
+
const issue = await opts.gh.getIssue(opts.scope.repo, opts.scope.number);
|
|
20
|
+
const body = issue.body ?? '';
|
|
21
|
+
const result = applyScopeMutation(body, opts.mutation);
|
|
22
|
+
if (result.noop) {
|
|
23
|
+
return {
|
|
24
|
+
noop: true,
|
|
25
|
+
attempts: attempt,
|
|
26
|
+
finalBody: body,
|
|
27
|
+
shape: result.shape,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
await opts.gh.updateIssueBody(opts.scope.repo, opts.scope.number, result.body);
|
|
31
|
+
const readback = await opts.gh.getIssue(opts.scope.repo, opts.scope.number);
|
|
32
|
+
const verifyBody = readback.body ?? '';
|
|
33
|
+
if (verifyBody === result.body) {
|
|
34
|
+
return {
|
|
35
|
+
noop: false,
|
|
36
|
+
attempts: attempt,
|
|
37
|
+
finalBody: verifyBody,
|
|
38
|
+
shape: result.shape,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (attempt < maxAttempts) {
|
|
42
|
+
await sleep(backoffMs[attempt - 1]);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
throw new ScopeContendedError({
|
|
46
|
+
attempts: maxAttempts,
|
|
47
|
+
ref: opts.mutation.ref,
|
|
48
|
+
mutation: opts.mutation.kind,
|
|
49
|
+
scope: opts.scope,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=retry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../../../../../src/cli/commands/cockpit/scope/retry.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAsC,MAAM,aAAa,CAAC;AAkBrF,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAC/B,MAAM,kBAAkB,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAEvD,SAAS,YAAY,CAAC,EAAU;IAC9B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,IAAuB;IAEvB,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,oBAAoB,CAAC;IAC7D,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,kBAAkB,CAAC;IACvD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,YAAY,CAAC;IAEzC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;QACxD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACzE,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,kBAAkB,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAEvD,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YAChB,OAAO;gBACL,IAAI,EAAE,IAAI;gBACV,QAAQ,EAAE,OAAO;gBACjB,SAAS,EAAE,IAAI;gBACf,KAAK,EAAE,MAAM,CAAC,KAAK;aACpB,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QAE/E,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC5E,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC;QAEvC,IAAI,UAAU,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC;YAC/B,OAAO;gBACL,IAAI,EAAE,KAAK;gBACX,QAAQ,EAAE,OAAO;gBACjB,SAAS,EAAE,UAAU;gBACrB,KAAK,EAAE,MAAM,CAAC,KAAK;aACpB,CAAC;QACJ,CAAC;QAED,IAAI,OAAO,GAAG,WAAW,EAAE,CAAC;YAC1B,MAAM,KAAK,CAAC,SAAS,CAAC,OAAO,GAAG,CAAC,CAAE,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IAED,MAAM,IAAI,mBAAmB,CAAC;QAC5B,QAAQ,EAAE,WAAW;QACrB,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG;QACtB,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI;QAC5B,KAAK,EAAE,IAAI,CAAC,KAAK;KAClB,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { IssueRef } from '@generacy-ai/cockpit';
|
|
2
|
+
export type BodyShape = 'phased' | 'flat';
|
|
3
|
+
export type ScopeMutation = {
|
|
4
|
+
kind: 'add';
|
|
5
|
+
ref: IssueRef;
|
|
6
|
+
} | {
|
|
7
|
+
kind: 'remove';
|
|
8
|
+
ref: IssueRef;
|
|
9
|
+
};
|
|
10
|
+
export interface ScopeWriteResult {
|
|
11
|
+
noop: boolean;
|
|
12
|
+
body: string;
|
|
13
|
+
shape: BodyShape;
|
|
14
|
+
}
|
|
15
|
+
export declare function detectShape(body: string): BodyShape;
|
|
16
|
+
/**
|
|
17
|
+
* Pure body writer. Applies the mutation according to shape rules described
|
|
18
|
+
* in contracts/scope-writer.md. Idempotent in both directions.
|
|
19
|
+
*/
|
|
20
|
+
export declare function applyScopeMutation(body: string, mutation: ScopeMutation): ScopeWriteResult;
|
|
21
|
+
//# sourceMappingURL=writer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/cockpit/scope/writer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE1C,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,QAAQ,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEtC,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,SAAS,CAAC;CAClB;AAiBD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAMnD;AA4GD;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,aAAa,GACtB,gBAAgB,CAoBlB"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { parseRef } from '@generacy-ai/cockpit';
|
|
2
|
+
// Byte-exact against parseEpicBody's HEADING_L3_RE (invariant I-1).
|
|
3
|
+
const HEADING_L3_RE = /^###\s+/;
|
|
4
|
+
const AD_HOC_HEADING_RE = /^##\s+ad-hoc\s*$/i;
|
|
5
|
+
const HEADING_L2_RE = /^##\s+/;
|
|
6
|
+
const HEADING_L1_RE = /^#\s+/;
|
|
7
|
+
const TASK_LIST_RE = /^\s*-\s*\[[ xX]\]\s+(.+?)\s*$/;
|
|
8
|
+
function refKey(ref) {
|
|
9
|
+
return `${ref.repo}#${ref.number}`;
|
|
10
|
+
}
|
|
11
|
+
function formatRefLine(ref) {
|
|
12
|
+
return `- [ ] ${ref.repo}#${ref.number}`;
|
|
13
|
+
}
|
|
14
|
+
export function detectShape(body) {
|
|
15
|
+
const lines = body.split(/\r?\n/);
|
|
16
|
+
for (const line of lines) {
|
|
17
|
+
if (HEADING_L3_RE.test(line))
|
|
18
|
+
return 'phased';
|
|
19
|
+
}
|
|
20
|
+
return 'flat';
|
|
21
|
+
}
|
|
22
|
+
function lineMatchesRef(line, ref) {
|
|
23
|
+
const m = TASK_LIST_RE.exec(line);
|
|
24
|
+
if (m == null)
|
|
25
|
+
return false;
|
|
26
|
+
const refText = m[1].trim();
|
|
27
|
+
const refToken = refText.split(/\s+/)[0];
|
|
28
|
+
const parsed = parseRef(refToken);
|
|
29
|
+
if (parsed == null)
|
|
30
|
+
return false;
|
|
31
|
+
return parsed.repo === ref.repo && parsed.number === ref.number;
|
|
32
|
+
}
|
|
33
|
+
function bodyContainsRef(body, ref) {
|
|
34
|
+
const lines = body.split(/\r?\n/);
|
|
35
|
+
return lines.some((l) => lineMatchesRef(l, ref));
|
|
36
|
+
}
|
|
37
|
+
function joinLines(lines) {
|
|
38
|
+
return lines.join('\n');
|
|
39
|
+
}
|
|
40
|
+
function ensureTrailingNewline(body) {
|
|
41
|
+
return body.endsWith('\n') ? body : body + '\n';
|
|
42
|
+
}
|
|
43
|
+
// Section boundary: a heading at level <= 2 (## or #), or another ## Ad-hoc,
|
|
44
|
+
// terminates the Ad-hoc section. #### and #####+ do not terminate (they're
|
|
45
|
+
// subsections of the Ad-hoc section).
|
|
46
|
+
function isAdhocSectionBoundary(line) {
|
|
47
|
+
return HEADING_L1_RE.test(line) || HEADING_L2_RE.test(line);
|
|
48
|
+
}
|
|
49
|
+
function findAdhocRange(lines) {
|
|
50
|
+
for (let i = 0; i < lines.length; i++) {
|
|
51
|
+
if (AD_HOC_HEADING_RE.test(lines[i])) {
|
|
52
|
+
let end = lines.length;
|
|
53
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
54
|
+
if (isAdhocSectionBoundary(lines[j])) {
|
|
55
|
+
end = j;
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return { headingIdx: i, endIdx: end };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
function findLastTaskListInRange(lines, startIdx, endIdx) {
|
|
65
|
+
for (let i = endIdx - 1; i > startIdx; i--) {
|
|
66
|
+
if (TASK_LIST_RE.test(lines[i]))
|
|
67
|
+
return i;
|
|
68
|
+
}
|
|
69
|
+
return -1;
|
|
70
|
+
}
|
|
71
|
+
function addToPhased(body, ref) {
|
|
72
|
+
// Strip trailing newline so split('\n') doesn't produce a phantom empty
|
|
73
|
+
// element that scrambles insertion positions. Reattach on the way out.
|
|
74
|
+
const hadTrailingNewline = body.endsWith('\n');
|
|
75
|
+
const workBody = hadTrailingNewline ? body.slice(0, -1) : body;
|
|
76
|
+
const lines = workBody.length === 0 ? [] : workBody.split('\n');
|
|
77
|
+
const range = findAdhocRange(lines);
|
|
78
|
+
const newLine = formatRefLine(ref);
|
|
79
|
+
let outLines;
|
|
80
|
+
if (range != null) {
|
|
81
|
+
const lastTask = findLastTaskListInRange(lines, range.headingIdx, range.endIdx);
|
|
82
|
+
if (lastTask >= 0) {
|
|
83
|
+
outLines = [...lines.slice(0, lastTask + 1), newLine, ...lines.slice(lastTask + 1)];
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
const insertAt = range.headingIdx + 1;
|
|
87
|
+
const next = lines[insertAt];
|
|
88
|
+
if (next == null) {
|
|
89
|
+
outLines = [...lines, '', newLine];
|
|
90
|
+
}
|
|
91
|
+
else if (next.trim() === '') {
|
|
92
|
+
outLines = [...lines.slice(0, insertAt + 1), newLine, ...lines.slice(insertAt + 1)];
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
outLines = [...lines.slice(0, insertAt), '', newLine, '', ...lines.slice(insertAt)];
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
outLines = [...lines, '', '## Ad-hoc', '', newLine];
|
|
101
|
+
}
|
|
102
|
+
const joined = joinLines(outLines);
|
|
103
|
+
return hadTrailingNewline ? joined + '\n' : joined;
|
|
104
|
+
}
|
|
105
|
+
function addToFlat(body, ref) {
|
|
106
|
+
const newLine = formatRefLine(ref);
|
|
107
|
+
if (body.length === 0)
|
|
108
|
+
return `${newLine}\n`;
|
|
109
|
+
const withNewline = ensureTrailingNewline(body);
|
|
110
|
+
return `${withNewline}${newLine}\n`;
|
|
111
|
+
}
|
|
112
|
+
function removeMatchingLine(body, ref) {
|
|
113
|
+
const lines = body.split('\n');
|
|
114
|
+
const idx = lines.findIndex((l) => lineMatchesRef(l, ref));
|
|
115
|
+
if (idx < 0)
|
|
116
|
+
return body;
|
|
117
|
+
return joinLines([...lines.slice(0, idx), ...lines.slice(idx + 1)]);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Pure body writer. Applies the mutation according to shape rules described
|
|
121
|
+
* in contracts/scope-writer.md. Idempotent in both directions.
|
|
122
|
+
*/
|
|
123
|
+
export function applyScopeMutation(body, mutation) {
|
|
124
|
+
const shape = detectShape(body);
|
|
125
|
+
if (mutation.kind === 'add') {
|
|
126
|
+
if (bodyContainsRef(body, mutation.ref)) {
|
|
127
|
+
return { noop: true, body, shape };
|
|
128
|
+
}
|
|
129
|
+
const next = shape === 'phased'
|
|
130
|
+
? addToPhased(body, mutation.ref)
|
|
131
|
+
: addToFlat(body, mutation.ref);
|
|
132
|
+
return { noop: false, body: next, shape };
|
|
133
|
+
}
|
|
134
|
+
// remove
|
|
135
|
+
if (!bodyContainsRef(body, mutation.ref)) {
|
|
136
|
+
return { noop: true, body, shape };
|
|
137
|
+
}
|
|
138
|
+
const next = removeMatchingLine(body, mutation.ref);
|
|
139
|
+
return { noop: false, body: next, shape };
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=writer.js.map
|