dev-loops 0.2.6 → 0.2.7
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/.claude/.claude-plugin/plugin.json +1 -1
- package/.claude/agents/dev-loop.md +2 -1
- package/.claude/skills/dev-loop/SKILL.md +5 -5
- package/CHANGELOG.md +17 -0
- package/agents/dev-loop.agent.md +5 -1
- package/cli/index.mjs +3 -1
- package/package.json +2 -2
- package/scripts/_cli-primitives.mjs +2 -0
- package/scripts/claude/generate-claude-assets.mjs +12 -2
- package/scripts/docs/validate-links.mjs +20 -11
- package/scripts/github/capture-review-threads.mjs +32 -14
- package/scripts/github/detect-checkpoint-evidence.mjs +28 -11
- package/scripts/github/detect-linked-issue-pr.mjs +22 -10
- package/scripts/github/manage-sub-issues.mjs +37 -16
- package/scripts/github/probe-copilot-review.mjs +24 -12
- package/scripts/github/ready-for-review.mjs +17 -8
- package/scripts/github/reconcile-draft-gate.mjs +22 -10
- package/scripts/github/reply-resolve-review-threads.mjs +34 -15
- package/scripts/github/request-copilot-review.mjs +28 -11
- package/scripts/github/resolve-tracker-local-spec.mjs +29 -12
- package/scripts/github/stage-reviewer-draft.mjs +32 -14
- package/scripts/github/upsert-checkpoint-verdict.mjs +49 -26
- package/scripts/github/write-gate-findings-log.mjs +41 -20
- package/scripts/loop/build-handoff-envelope.mjs +32 -14
- package/scripts/loop/conductor-monitor.mjs +25 -9
- package/scripts/loop/conductor.mjs +31 -12
- package/scripts/loop/copilot-pr-handoff.mjs +31 -14
- package/scripts/loop/debt-remediate.mjs +28 -11
- package/scripts/loop/detect-copilot-loop-state.mjs +29 -12
- package/scripts/loop/detect-copilot-session-activity.mjs +29 -12
- package/scripts/loop/detect-initial-copilot-pr-state.mjs +26 -10
- package/scripts/loop/detect-internal-only-pr.mjs +31 -13
- package/scripts/loop/detect-issue-refinement-artifact.mjs +29 -12
- package/scripts/loop/detect-pr-gate-coordination-state.mjs +26 -10
- package/scripts/loop/detect-reviewer-loop-state.mjs +35 -16
- package/scripts/loop/detect-stale-runner.mjs +32 -14
- package/scripts/loop/detect-tracker-pr-state.mjs +23 -8
- package/scripts/loop/info.mjs +28 -10
- package/scripts/loop/inspect-run-viewer/cli.mjs +44 -21
- package/scripts/loop/inspect-run.mjs +35 -16
- package/scripts/loop/outer-loop.mjs +35 -16
- package/scripts/loop/pr-runner-coordination.mjs +31 -12
- package/scripts/loop/pre-commit-branch-guard.mjs +26 -9
- package/scripts/loop/pre-flight-gate.mjs +25 -9
- package/scripts/loop/pre-pr-ready-gate.mjs +24 -8
- package/scripts/loop/pre-push-main-guard.mjs +19 -5
- package/scripts/loop/pre-write-remote-freshness-guard.mjs +23 -7
- package/scripts/loop/resolve-dev-loop-startup.mjs +29 -12
- package/scripts/loop/run-conductor-cycle.mjs +23 -8
- package/scripts/loop/run-refinement-audit.mjs +44 -22
- package/scripts/loop/run-watch-cycle.mjs +28 -12
- package/scripts/loop/steer-loop.mjs +122 -62
- package/scripts/loop/watch-initial-copilot-pr.mjs +28 -12
- package/scripts/projects/archive-done-items.mjs +410 -0
- package/scripts/projects/reorder-queue-item.mjs +334 -76
- package/scripts/refine/_refine-helpers.mjs +21 -9
- package/scripts/refine/verify.mjs +31 -13
- package/skills/dev-loop/SKILL.md +9 -5
|
@@ -18,10 +18,11 @@ import { readFile } from "node:fs/promises";
|
|
|
18
18
|
import { detectRepoSlug } from "@dev-loops/core/github/repo-slug";
|
|
19
19
|
import path from "node:path";
|
|
20
20
|
import { buildParseError, formatCliError, isDirectCliRun, parseJsonText } from "../_core-helpers.mjs";
|
|
21
|
-
import {
|
|
21
|
+
import { requireTokenValue } from "../_cli-primitives.mjs";
|
|
22
22
|
import { buildDevLoopHandoffEnvelope } from "@dev-loops/core/loop/handoff-envelope";
|
|
23
23
|
import { loadDevLoopConfig } from "@dev-loops/core/config";
|
|
24
24
|
import { createPiAdapter } from "@dev-loops/core/harness";
|
|
25
|
+
import { parseArgs } from "node:util";
|
|
25
26
|
|
|
26
27
|
const USAGE = `Usage: build-handoff-envelope.mjs --input <path>
|
|
27
28
|
Build a deterministic handoff envelope from startup resolver output and settings.
|
|
@@ -56,7 +57,6 @@ function parseFlagJson(raw, flagName, parseErrorFn) {
|
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
export function parseBuildHandoffEnvelopeCliArgs(argv) {
|
|
59
|
-
const args = [...argv];
|
|
60
60
|
const options = {
|
|
61
61
|
help: false,
|
|
62
62
|
inputPath: undefined,
|
|
@@ -65,29 +65,47 @@ export function parseBuildHandoffEnvelopeCliArgs(argv) {
|
|
|
65
65
|
repo: undefined,
|
|
66
66
|
};
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
const { tokens } = parseArgs({
|
|
69
|
+
args: [...argv],
|
|
70
|
+
options: {
|
|
71
|
+
help: { type: "boolean", short: "h" },
|
|
72
|
+
input: { type: "string" },
|
|
73
|
+
"gate-state": { type: "string" },
|
|
74
|
+
overrides: { type: "string" },
|
|
75
|
+
repo: { type: "string" },
|
|
76
|
+
},
|
|
77
|
+
allowPositionals: true,
|
|
78
|
+
strict: false,
|
|
79
|
+
tokens: true,
|
|
80
|
+
});
|
|
81
|
+
for (const token of tokens) {
|
|
82
|
+
if (token.kind === "positional") {
|
|
83
|
+
throw parseError(`Unknown argument: ${token.value}`);
|
|
84
|
+
}
|
|
85
|
+
if (token.kind !== "option") {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (token.name === "help") {
|
|
71
89
|
options.help = true;
|
|
72
90
|
return options;
|
|
73
91
|
}
|
|
74
|
-
if (token === "
|
|
75
|
-
options.inputPath =
|
|
92
|
+
if (token.name === "input") {
|
|
93
|
+
options.inputPath = requireTokenValue(token, parseError);
|
|
76
94
|
continue;
|
|
77
95
|
}
|
|
78
|
-
if (token === "
|
|
79
|
-
options.gateState =
|
|
96
|
+
if (token.name === "gate-state") {
|
|
97
|
+
options.gateState = requireTokenValue(token, parseError);
|
|
80
98
|
continue;
|
|
81
99
|
}
|
|
82
|
-
if (token === "
|
|
83
|
-
options.overrides =
|
|
100
|
+
if (token.name === "overrides") {
|
|
101
|
+
options.overrides = requireTokenValue(token, parseError);
|
|
84
102
|
continue;
|
|
85
103
|
}
|
|
86
|
-
if (token === "
|
|
87
|
-
options.repo =
|
|
104
|
+
if (token.name === "repo") {
|
|
105
|
+
options.repo = requireTokenValue(token, parseError);
|
|
88
106
|
continue;
|
|
89
107
|
}
|
|
90
|
-
throw parseError(`Unknown argument: ${token}`);
|
|
108
|
+
throw parseError(`Unknown argument: ${token.rawName}`);
|
|
91
109
|
}
|
|
92
110
|
|
|
93
111
|
if (!options.inputPath) {
|
|
@@ -3,7 +3,7 @@ import { existsSync } from "node:fs";
|
|
|
3
3
|
import { access, open, readFile, readdir } from "node:fs/promises";
|
|
4
4
|
import os from "node:os";
|
|
5
5
|
import path from "node:path";
|
|
6
|
-
import {
|
|
6
|
+
import { requireTokenValue } from "../_cli-primitives.mjs";
|
|
7
7
|
import { buildParseError, formatCliError, isDirectCliRun, parseJsonText } from "../_core-helpers.mjs";
|
|
8
8
|
import { parseRepoSlug } from "@dev-loops/core/github/repo-slug";
|
|
9
9
|
import { autoDetectSnapshot } from "./detect-copilot-loop-state.mjs";
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
} from "./_handoff-contract.mjs";
|
|
15
15
|
import { interpretLoopState, summarizeLoopInterpretation } from "@dev-loops/core/loop/copilot-loop-state";
|
|
16
16
|
import { listOpenPrs } from "./_loop-pr-aggregation.mjs";
|
|
17
|
+
import { parseArgs } from "node:util";
|
|
17
18
|
const USAGE = `Usage: conductor-monitor.mjs --repo <owner/name> [--auto-resume]
|
|
18
19
|
Aggregate Copilot-loop status across all open PRs in one repo.
|
|
19
20
|
Required:
|
|
@@ -113,27 +114,42 @@ const MANUAL_REASON = {
|
|
|
113
114
|
HANDOFF_CONTRACT_MISMATCH: "handoff_contract_mismatch",
|
|
114
115
|
};
|
|
115
116
|
function parseCliArgs(argv) {
|
|
116
|
-
const args = [...argv];
|
|
117
117
|
const options = {
|
|
118
118
|
help: false,
|
|
119
119
|
repo: undefined,
|
|
120
120
|
autoResume: false,
|
|
121
121
|
};
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
122
|
+
const { tokens } = parseArgs({
|
|
123
|
+
args: [...argv],
|
|
124
|
+
options: {
|
|
125
|
+
help: { type: "boolean", short: "h" },
|
|
126
|
+
repo: { type: "string" },
|
|
127
|
+
"auto-resume": { type: "boolean" },
|
|
128
|
+
},
|
|
129
|
+
allowPositionals: true,
|
|
130
|
+
strict: false,
|
|
131
|
+
tokens: true,
|
|
132
|
+
});
|
|
133
|
+
for (const token of tokens) {
|
|
134
|
+
if (token.kind === "positional") {
|
|
135
|
+
throw parseError(`Unknown argument: ${token.value}`);
|
|
136
|
+
}
|
|
137
|
+
if (token.kind !== "option") {
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (token.name === "help") {
|
|
125
141
|
options.help = true;
|
|
126
142
|
return options;
|
|
127
143
|
}
|
|
128
|
-
if (token === "
|
|
129
|
-
options.repo =
|
|
144
|
+
if (token.name === "repo") {
|
|
145
|
+
options.repo = requireTokenValue(token, parseError).trim();
|
|
130
146
|
continue;
|
|
131
147
|
}
|
|
132
|
-
if (token === "
|
|
148
|
+
if (token.name === "auto-resume") {
|
|
133
149
|
options.autoResume = true;
|
|
134
150
|
continue;
|
|
135
151
|
}
|
|
136
|
-
throw parseError(`Unknown argument: ${token}`);
|
|
152
|
+
throw parseError(`Unknown argument: ${token.rawName}`);
|
|
137
153
|
}
|
|
138
154
|
if (options.repo === undefined) {
|
|
139
155
|
throw parseError("conductor-monitor requires --repo <owner/name>");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { runConductorCycle } from "./run-conductor-cycle.mjs";
|
|
3
3
|
import { runConductorMonitor } from "./conductor-monitor.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { requireTokenValue } from "../_cli-primitives.mjs";
|
|
5
5
|
import { buildParseError, formatCliError, isDirectCliRun } from "../_core-helpers.mjs";
|
|
6
6
|
import { parseRepoSlug } from "@dev-loops/core/github/repo-slug";
|
|
7
7
|
import {
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
} from "@dev-loops/core/config";
|
|
13
13
|
import { readFileSync } from "node:fs";
|
|
14
14
|
import path from "node:path";
|
|
15
|
+
import { parseArgs } from "node:util";
|
|
15
16
|
const USAGE = `Usage: conductor.mjs --repo <owner/name> [--auto-resume] [--cycle-only] [--monitor-only] [--require-retrospective]
|
|
16
17
|
Unified conductor entrypoint for dev-loop lifecycle orchestration.`.trim();
|
|
17
18
|
const parseError = buildParseError(USAGE);
|
|
@@ -43,7 +44,6 @@ function checkRetrospectiveGate(cwd, requireRetrospective) {
|
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
46
|
function parseCliArgs(argv) {
|
|
46
|
-
const args = [...argv];
|
|
47
47
|
const options = {
|
|
48
48
|
help: false,
|
|
49
49
|
repo: undefined,
|
|
@@ -52,33 +52,52 @@ function parseCliArgs(argv) {
|
|
|
52
52
|
monitorOnly: false,
|
|
53
53
|
requireRetrospective: false,
|
|
54
54
|
};
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
const { tokens } = parseArgs({
|
|
56
|
+
args: [...argv],
|
|
57
|
+
options: {
|
|
58
|
+
help: { type: "boolean", short: "h" },
|
|
59
|
+
repo: { type: "string" },
|
|
60
|
+
"auto-resume": { type: "boolean" },
|
|
61
|
+
"cycle-only": { type: "boolean" },
|
|
62
|
+
"monitor-only": { type: "boolean" },
|
|
63
|
+
"require-retrospective": { type: "boolean" },
|
|
64
|
+
},
|
|
65
|
+
allowPositionals: true,
|
|
66
|
+
strict: false,
|
|
67
|
+
tokens: true,
|
|
68
|
+
});
|
|
69
|
+
for (const token of tokens) {
|
|
70
|
+
if (token.kind === "positional") {
|
|
71
|
+
throw parseError(`Unknown argument: ${token.value}`);
|
|
72
|
+
}
|
|
73
|
+
if (token.kind !== "option") {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (token.name === "help") {
|
|
58
77
|
options.help = true;
|
|
59
78
|
return options;
|
|
60
79
|
}
|
|
61
|
-
if (token === "
|
|
62
|
-
options.repo =
|
|
80
|
+
if (token.name === "repo") {
|
|
81
|
+
options.repo = requireTokenValue(token, parseError).trim();
|
|
63
82
|
continue;
|
|
64
83
|
}
|
|
65
|
-
if (token === "
|
|
84
|
+
if (token.name === "auto-resume") {
|
|
66
85
|
options.autoResume = true;
|
|
67
86
|
continue;
|
|
68
87
|
}
|
|
69
|
-
if (token === "
|
|
88
|
+
if (token.name === "cycle-only") {
|
|
70
89
|
options.cycleOnly = true;
|
|
71
90
|
continue;
|
|
72
91
|
}
|
|
73
|
-
if (token === "
|
|
92
|
+
if (token.name === "monitor-only") {
|
|
74
93
|
options.monitorOnly = true;
|
|
75
94
|
continue;
|
|
76
95
|
}
|
|
77
|
-
if (token === "
|
|
96
|
+
if (token.name === "require-retrospective") {
|
|
78
97
|
options.requireRetrospective = true;
|
|
79
98
|
continue;
|
|
80
99
|
}
|
|
81
|
-
throw parseError(`Unknown argument: ${token}`);
|
|
100
|
+
throw parseError(`Unknown argument: ${token.rawName}`);
|
|
82
101
|
}
|
|
83
102
|
if (options.repo === undefined) {
|
|
84
103
|
throw parseError("conductor requires --repo <owner/name>");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { buildParseError, formatCliError, isCopilotLogin, isDirectCliRun, normalizeTimestamp } from "../_core-helpers.mjs";
|
|
3
|
-
import { parsePrNumber,
|
|
3
|
+
import { parsePrNumber, requireTokenValue, runChild } from "../_cli-primitives.mjs";
|
|
4
4
|
import { detectRepoSlug, parseRepoSlug } from "@dev-loops/core/github/repo-slug";
|
|
5
5
|
import { resolveRunId } from "@dev-loops/core/loop/run-context";
|
|
6
6
|
import path from "node:path";
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
EXTERNAL_HEALTHY_WAIT_TIMEOUT_POLICY,
|
|
17
17
|
enforceExternalHealthyWaitTimeout,
|
|
18
18
|
} from "@dev-loops/core/loop/timeout-policy";
|
|
19
|
+
import { parseArgs } from "node:util";
|
|
19
20
|
import {
|
|
20
21
|
DEFAULT_POLL_INTERVAL_MS,
|
|
21
22
|
COPILOT_REVIEW_WAIT_TIMEOUT_MS,
|
|
@@ -128,39 +129,55 @@ function rejectRemovedFlag(token) {
|
|
|
128
129
|
);
|
|
129
130
|
}
|
|
130
131
|
export function parseHandoffCliArgs(argv, { cwd = process.cwd() } = {}) {
|
|
131
|
-
const args = [...argv];
|
|
132
132
|
const options = {
|
|
133
133
|
help: false,
|
|
134
134
|
repo: undefined,
|
|
135
135
|
pr: undefined,
|
|
136
136
|
watchStatus: undefined,
|
|
137
137
|
};
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
138
|
+
const { tokens } = parseArgs({
|
|
139
|
+
args: [...argv],
|
|
140
|
+
options: {
|
|
141
|
+
help: { type: "boolean", short: "h" },
|
|
142
|
+
repo: { type: "string" },
|
|
143
|
+
pr: { type: "string" },
|
|
144
|
+
"watch-status": { type: "string" },
|
|
145
|
+
},
|
|
146
|
+
allowPositionals: true,
|
|
147
|
+
strict: false,
|
|
148
|
+
tokens: true,
|
|
149
|
+
});
|
|
150
|
+
for (const token of tokens) {
|
|
151
|
+
if (token.kind === "positional") {
|
|
152
|
+
throw parseError(`Unknown argument: ${token.value}`);
|
|
153
|
+
}
|
|
154
|
+
if (token.kind !== "option") {
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
if (token.name === "help") {
|
|
141
158
|
options.help = true;
|
|
142
159
|
return options;
|
|
143
160
|
}
|
|
144
|
-
if (REMOVED_FLAGS.has(token)) {
|
|
145
|
-
rejectRemovedFlag(token);
|
|
161
|
+
if (REMOVED_FLAGS.has(token.rawName)) {
|
|
162
|
+
rejectRemovedFlag(token.rawName);
|
|
146
163
|
}
|
|
147
|
-
if (token === "
|
|
148
|
-
options.repo =
|
|
164
|
+
if (token.name === "repo") {
|
|
165
|
+
options.repo = requireTokenValue(token, parseError).trim();
|
|
149
166
|
continue;
|
|
150
167
|
}
|
|
151
|
-
if (token === "
|
|
152
|
-
options.pr = parsePrNumber(
|
|
168
|
+
if (token.name === "pr") {
|
|
169
|
+
options.pr = parsePrNumber(requireTokenValue(token, parseError), parseError);
|
|
153
170
|
continue;
|
|
154
171
|
}
|
|
155
|
-
if (token === "
|
|
156
|
-
const watchStatus =
|
|
172
|
+
if (token.name === "watch-status") {
|
|
173
|
+
const watchStatus = requireTokenValue(token, parseError).trim().toLowerCase();
|
|
157
174
|
if (!VALID_WATCH_STATUSES.has(watchStatus)) {
|
|
158
175
|
throw parseError(`--watch-status must be one of: ${[...VALID_WATCH_STATUSES].join(", ")}`);
|
|
159
176
|
}
|
|
160
177
|
options.watchStatus = watchStatus;
|
|
161
178
|
continue;
|
|
162
179
|
}
|
|
163
|
-
throw parseError(`Unknown argument: ${token}`);
|
|
180
|
+
throw parseError(`Unknown argument: ${token.rawName}`);
|
|
164
181
|
}
|
|
165
182
|
if (options.pr === undefined) {
|
|
166
183
|
throw parseError("copilot-pr-handoff requires --pr <number>");
|
|
@@ -15,9 +15,10 @@ import { readFile } from "node:fs/promises";
|
|
|
15
15
|
import path from "node:path";
|
|
16
16
|
import { fileURLToPath } from "node:url";
|
|
17
17
|
import { execFileSync } from "node:child_process";
|
|
18
|
+
import { parseArgs } from "node:util";
|
|
18
19
|
|
|
19
20
|
import { buildParseError, formatCliError, isDirectCliRun } from "../_core-helpers.mjs";
|
|
20
|
-
import {
|
|
21
|
+
import { requireTokenValue } from "../_cli-primitives.mjs";
|
|
21
22
|
import { parseRepoSlug } from "@dev-loops/core/github/repo-slug";
|
|
22
23
|
import { DebtSignalSchema } from "@dev-loops/core/debt/signal";
|
|
23
24
|
import { clusterSignalsEnriched } from "@dev-loops/core/debt/cluster";
|
|
@@ -150,28 +151,44 @@ function buildReport(signalsCount, findingsCount, results) {
|
|
|
150
151
|
// ============================================================================
|
|
151
152
|
|
|
152
153
|
export async function runCli(argv) {
|
|
153
|
-
const args = [...argv];
|
|
154
154
|
const options = { input: undefined, repo: undefined, dryRun: false, help: false };
|
|
155
155
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
156
|
+
const { tokens } = parseArgs({
|
|
157
|
+
args: [...argv],
|
|
158
|
+
options: {
|
|
159
|
+
help: { type: "boolean", short: "h" },
|
|
160
|
+
input: { type: "string" },
|
|
161
|
+
repo: { type: "string" },
|
|
162
|
+
"dry-run": { type: "boolean" },
|
|
163
|
+
},
|
|
164
|
+
allowPositionals: true,
|
|
165
|
+
strict: false,
|
|
166
|
+
tokens: true,
|
|
167
|
+
});
|
|
168
|
+
for (const token of tokens) {
|
|
169
|
+
if (token.kind === "positional") {
|
|
170
|
+
throw parseError(`Unknown flag: ${token.value}`);
|
|
171
|
+
}
|
|
172
|
+
if (token.kind !== "option") {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
if (token.name === "help") {
|
|
159
176
|
options.help = true;
|
|
160
177
|
break;
|
|
161
178
|
}
|
|
162
|
-
if (token === "
|
|
163
|
-
options.input =
|
|
179
|
+
if (token.name === "input") {
|
|
180
|
+
options.input = requireTokenValue(token, parseError);
|
|
164
181
|
continue;
|
|
165
182
|
}
|
|
166
|
-
if (token === "
|
|
167
|
-
options.repo =
|
|
183
|
+
if (token.name === "repo") {
|
|
184
|
+
options.repo = requireTokenValue(token, parseError);
|
|
168
185
|
continue;
|
|
169
186
|
}
|
|
170
|
-
if (token === "
|
|
187
|
+
if (token.name === "dry-run") {
|
|
171
188
|
options.dryRun = true;
|
|
172
189
|
continue;
|
|
173
190
|
}
|
|
174
|
-
throw parseError(`Unknown flag: ${token}`);
|
|
191
|
+
throw parseError(`Unknown flag: ${token.rawName}`);
|
|
175
192
|
}
|
|
176
193
|
|
|
177
194
|
if (options.help) {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { parseArgs } from "node:util";
|
|
5
|
+
import { parsePrNumber, requireTokenValue, runChild } from "../_cli-primitives.mjs";
|
|
5
6
|
import {
|
|
6
7
|
buildParseError,
|
|
7
8
|
formatCliError,
|
|
@@ -58,32 +59,48 @@ Exit codes:
|
|
|
58
59
|
const VALID_OVERRIDE_STATUSES = new Set(["requested", "already-requested", "unavailable", "none", "failed"]);
|
|
59
60
|
const parseError = buildParseError(USAGE);
|
|
60
61
|
export function parseDetectCliArgs(argv) {
|
|
61
|
-
const args = [...argv];
|
|
62
62
|
const options = {
|
|
63
63
|
help: false,
|
|
64
64
|
inputPath: undefined,
|
|
65
65
|
repo: undefined,
|
|
66
66
|
pr: undefined,
|
|
67
67
|
};
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
const { tokens } = parseArgs({
|
|
69
|
+
args: [...argv],
|
|
70
|
+
options: {
|
|
71
|
+
help: { type: "boolean", short: "h" },
|
|
72
|
+
input: { type: "string" },
|
|
73
|
+
repo: { type: "string" },
|
|
74
|
+
pr: { type: "string" },
|
|
75
|
+
},
|
|
76
|
+
allowPositionals: true,
|
|
77
|
+
strict: false,
|
|
78
|
+
tokens: true,
|
|
79
|
+
});
|
|
80
|
+
for (const token of tokens) {
|
|
81
|
+
if (token.kind === "positional") {
|
|
82
|
+
throw parseError(`Unknown argument: ${token.value}`);
|
|
83
|
+
}
|
|
84
|
+
if (token.kind !== "option") {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (token.name === "help") {
|
|
71
88
|
options.help = true;
|
|
72
89
|
return options;
|
|
73
90
|
}
|
|
74
|
-
if (token === "
|
|
75
|
-
options.inputPath =
|
|
91
|
+
if (token.name === "input") {
|
|
92
|
+
options.inputPath = requireTokenValue(token, parseError);
|
|
76
93
|
continue;
|
|
77
94
|
}
|
|
78
|
-
if (token === "
|
|
79
|
-
options.repo =
|
|
95
|
+
if (token.name === "repo") {
|
|
96
|
+
options.repo = requireTokenValue(token, parseError).trim();
|
|
80
97
|
continue;
|
|
81
98
|
}
|
|
82
|
-
if (token === "
|
|
83
|
-
options.pr = parsePrNumber(
|
|
99
|
+
if (token.name === "pr") {
|
|
100
|
+
options.pr = parsePrNumber(requireTokenValue(token, parseError), parseError);
|
|
84
101
|
continue;
|
|
85
102
|
}
|
|
86
|
-
throw parseError(`Unknown argument: ${token}`);
|
|
103
|
+
throw parseError(`Unknown argument: ${token.rawName}`);
|
|
87
104
|
}
|
|
88
105
|
if (options.inputPath !== undefined) {
|
|
89
106
|
if (options.repo !== undefined || options.pr !== undefined) {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { buildParseError, formatCliError, isDirectCliRun, parseJsonText } from "../_core-helpers.mjs";
|
|
3
|
-
import { parsePositiveInteger,
|
|
3
|
+
import { parsePositiveInteger, requireTokenValue, runChild } from "../_cli-primitives.mjs";
|
|
4
4
|
import { parseRepoSlug } from "@dev-loops/core/github/repo-slug";
|
|
5
|
+
import { parseArgs } from "node:util";
|
|
5
6
|
const USAGE = `Usage: detect-copilot-session-activity.mjs --repo <owner/name> --branch <name> [--limit <number>]
|
|
6
7
|
Detect Copilot GitHub Actions session activity on a branch.
|
|
7
8
|
Required:
|
|
@@ -41,32 +42,48 @@ const COPILOT_RUN_NAME_PATTERNS = Object.freeze([
|
|
|
41
42
|
]);
|
|
42
43
|
const parseError = buildParseError(USAGE);
|
|
43
44
|
export function parseDetectCopilotSessionActivityCliArgs(argv) {
|
|
44
|
-
const args = [...argv];
|
|
45
45
|
const options = {
|
|
46
46
|
help: false,
|
|
47
47
|
repo: undefined,
|
|
48
48
|
branch: undefined,
|
|
49
49
|
limit: DEFAULT_LIMIT,
|
|
50
50
|
};
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
const { tokens } = parseArgs({
|
|
52
|
+
args: [...argv],
|
|
53
|
+
options: {
|
|
54
|
+
help: { type: "boolean", short: "h" },
|
|
55
|
+
repo: { type: "string" },
|
|
56
|
+
branch: { type: "string" },
|
|
57
|
+
limit: { type: "string" },
|
|
58
|
+
},
|
|
59
|
+
allowPositionals: true,
|
|
60
|
+
strict: false,
|
|
61
|
+
tokens: true,
|
|
62
|
+
});
|
|
63
|
+
for (const token of tokens) {
|
|
64
|
+
if (token.kind === "positional") {
|
|
65
|
+
throw parseError(`Unknown argument: ${token.value}`);
|
|
66
|
+
}
|
|
67
|
+
if (token.kind !== "option") {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (token.name === "help") {
|
|
54
71
|
options.help = true;
|
|
55
72
|
return options;
|
|
56
73
|
}
|
|
57
|
-
if (token === "
|
|
58
|
-
options.repo =
|
|
74
|
+
if (token.name === "repo") {
|
|
75
|
+
options.repo = requireTokenValue(token, parseError).trim();
|
|
59
76
|
continue;
|
|
60
77
|
}
|
|
61
|
-
if (token === "
|
|
62
|
-
options.branch =
|
|
78
|
+
if (token.name === "branch") {
|
|
79
|
+
options.branch = requireTokenValue(token, parseError).trim();
|
|
63
80
|
continue;
|
|
64
81
|
}
|
|
65
|
-
if (token === "
|
|
66
|
-
options.limit = parsePositiveInteger(
|
|
82
|
+
if (token.name === "limit") {
|
|
83
|
+
options.limit = parsePositiveInteger(requireTokenValue(token, parseError), "--limit", parseError);
|
|
67
84
|
continue;
|
|
68
85
|
}
|
|
69
|
-
throw parseError(`Unknown argument: ${token}`);
|
|
86
|
+
throw parseError(`Unknown argument: ${token.rawName}`);
|
|
70
87
|
}
|
|
71
88
|
if (options.repo === undefined || options.branch === undefined || options.branch.length === 0) {
|
|
72
89
|
throw parseError("detect-copilot-session-activity requires both --repo <owner/name> and --branch <name>");
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { buildParseError, formatCliError, isDirectCliRun, parseJsonText } from "../_core-helpers.mjs";
|
|
3
|
-
import { parseIssueNumber,
|
|
3
|
+
import { parseIssueNumber, requireTokenValue, runChild } from "../_cli-primitives.mjs";
|
|
4
4
|
import { parseRepoSlug } from "@dev-loops/core/github/repo-slug";
|
|
5
5
|
import { detectLinkedIssuePr } from "../github/detect-linked-issue-pr.mjs";
|
|
6
6
|
import { detectCopilotSessionActivity } from "./detect-copilot-session-activity.mjs";
|
|
7
|
+
import { parseArgs } from "node:util";
|
|
7
8
|
const USAGE = `Usage: detect-initial-copilot-pr-state.mjs --repo <owner/name> --issue <number>
|
|
8
9
|
Detect whether an assigned issue is still on the bootstrap-only Copilot draft PR
|
|
9
10
|
or has moved into normal linked-PR follow-up.
|
|
@@ -79,27 +80,42 @@ const INITIAL_COPILOT_PR_FACTS_QUERY = [
|
|
|
79
80
|
].join("\n");
|
|
80
81
|
const parseError = buildParseError(USAGE);
|
|
81
82
|
export function parseDetectInitialCopilotPrStateCliArgs(argv) {
|
|
82
|
-
const args = [...argv];
|
|
83
83
|
const options = {
|
|
84
84
|
help: false,
|
|
85
85
|
repo: undefined,
|
|
86
86
|
issue: undefined,
|
|
87
87
|
};
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
const { tokens } = parseArgs({
|
|
89
|
+
args: [...argv],
|
|
90
|
+
options: {
|
|
91
|
+
help: { type: "boolean", short: "h" },
|
|
92
|
+
repo: { type: "string" },
|
|
93
|
+
issue: { type: "string" },
|
|
94
|
+
},
|
|
95
|
+
allowPositionals: true,
|
|
96
|
+
strict: false,
|
|
97
|
+
tokens: true,
|
|
98
|
+
});
|
|
99
|
+
for (const token of tokens) {
|
|
100
|
+
if (token.kind === "positional") {
|
|
101
|
+
throw parseError(`Unknown argument: ${token.value}`);
|
|
102
|
+
}
|
|
103
|
+
if (token.kind !== "option") {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (token.name === "help") {
|
|
91
107
|
options.help = true;
|
|
92
108
|
return options;
|
|
93
109
|
}
|
|
94
|
-
if (token === "
|
|
95
|
-
options.repo =
|
|
110
|
+
if (token.name === "repo") {
|
|
111
|
+
options.repo = requireTokenValue(token, parseError).trim();
|
|
96
112
|
continue;
|
|
97
113
|
}
|
|
98
|
-
if (token === "
|
|
99
|
-
options.issue = parseIssueNumber(
|
|
114
|
+
if (token.name === "issue") {
|
|
115
|
+
options.issue = parseIssueNumber(requireTokenValue(token, parseError), parseError);
|
|
100
116
|
continue;
|
|
101
117
|
}
|
|
102
|
-
throw parseError(`Unknown argument: ${token}`);
|
|
118
|
+
throw parseError(`Unknown argument: ${token.rawName}`);
|
|
103
119
|
}
|
|
104
120
|
if (options.repo === undefined || options.issue === undefined) {
|
|
105
121
|
throw parseError("detect-initial-copilot-pr-state requires both --repo <owner/name> and --issue <number>");
|
|
@@ -3,8 +3,9 @@ import { statSync, readFileSync } from "node:fs";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { parse as parseYaml } from "yaml";
|
|
5
5
|
import { buildParseError, formatCliError, isDirectCliRun } from "../_core-helpers.mjs";
|
|
6
|
-
import { parsePrNumber,
|
|
6
|
+
import { parsePrNumber, requireTokenValue, runChild } from "../_cli-primitives.mjs";
|
|
7
7
|
import { parseRepoSlug } from "@dev-loops/core/github/repo-slug";
|
|
8
|
+
import { parseArgs } from "node:util";
|
|
8
9
|
|
|
9
10
|
const USAGE = `Usage: detect-internal-only-pr.mjs --repo <owner/name> --pr <number> [--config <path>]
|
|
10
11
|
Detect whether a PR only touches internal tooling files (scripts, docs, tests, config)
|
|
@@ -118,7 +119,6 @@ function buildPatternMatchers(patterns) {
|
|
|
118
119
|
}
|
|
119
120
|
|
|
120
121
|
export function parseCliArgs(argv) {
|
|
121
|
-
const args = [...argv];
|
|
122
122
|
const options = {
|
|
123
123
|
help: false,
|
|
124
124
|
repo: undefined,
|
|
@@ -126,29 +126,47 @@ export function parseCliArgs(argv) {
|
|
|
126
126
|
config: undefined,
|
|
127
127
|
labelCheck: false,
|
|
128
128
|
};
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
129
|
+
const { tokens } = parseArgs({
|
|
130
|
+
args: [...argv],
|
|
131
|
+
options: {
|
|
132
|
+
help: { type: "boolean", short: "h" },
|
|
133
|
+
repo: { type: "string" },
|
|
134
|
+
pr: { type: "string" },
|
|
135
|
+
config: { type: "string" },
|
|
136
|
+
"label-check": { type: "boolean" },
|
|
137
|
+
},
|
|
138
|
+
allowPositionals: true,
|
|
139
|
+
strict: false,
|
|
140
|
+
tokens: true,
|
|
141
|
+
});
|
|
142
|
+
for (const token of tokens) {
|
|
143
|
+
if (token.kind === "positional") {
|
|
144
|
+
throw parseError(`Unknown argument: ${token.value}`);
|
|
145
|
+
}
|
|
146
|
+
if (token.kind !== "option") {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (token.name === "help") {
|
|
132
150
|
options.help = true;
|
|
133
151
|
return options;
|
|
134
152
|
}
|
|
135
|
-
if (token === "
|
|
136
|
-
options.repo =
|
|
153
|
+
if (token.name === "repo") {
|
|
154
|
+
options.repo = requireTokenValue(token, parseError).trim();
|
|
137
155
|
continue;
|
|
138
156
|
}
|
|
139
|
-
if (token === "
|
|
140
|
-
options.pr = parsePrNumber(
|
|
157
|
+
if (token.name === "pr") {
|
|
158
|
+
options.pr = parsePrNumber(requireTokenValue(token, parseError), parseError);
|
|
141
159
|
continue;
|
|
142
160
|
}
|
|
143
|
-
if (token === "
|
|
144
|
-
options.config =
|
|
161
|
+
if (token.name === "config") {
|
|
162
|
+
options.config = requireTokenValue(token, parseError).trim();
|
|
145
163
|
continue;
|
|
146
164
|
}
|
|
147
|
-
if (token === "
|
|
165
|
+
if (token.name === "label-check") {
|
|
148
166
|
options.labelCheck = true;
|
|
149
167
|
continue;
|
|
150
168
|
}
|
|
151
|
-
throw parseError(`Unknown argument: ${token}`);
|
|
169
|
+
throw parseError(`Unknown argument: ${token.rawName}`);
|
|
152
170
|
}
|
|
153
171
|
if (options.repo === undefined || options.pr === undefined) {
|
|
154
172
|
throw parseError("detect-internal-only-pr requires both --repo <owner/name> and --pr <number>");
|