@idea1/cli 1.8.3 → 1.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/README.md +121 -59
  2. package/dist/cli/resolver.d.ts +1 -0
  3. package/dist/cli/resolver.d.ts.map +1 -1
  4. package/dist/cli/resolver.js +5 -0
  5. package/dist/cli/resolver.js.map +1 -1
  6. package/dist/cli.d.ts.map +1 -1
  7. package/dist/cli.js +2 -1
  8. package/dist/cli.js.map +1 -1
  9. package/dist/commands/approve-pr.d.ts.map +1 -1
  10. package/dist/commands/approve-pr.js +20 -37
  11. package/dist/commands/approve-pr.js.map +1 -1
  12. package/dist/commands/attach-project-item.d.ts.map +1 -1
  13. package/dist/commands/attach-project-item.js +2 -5
  14. package/dist/commands/attach-project-item.js.map +1 -1
  15. package/dist/commands/close-worktree.d.ts.map +1 -1
  16. package/dist/commands/close-worktree.js +4 -3
  17. package/dist/commands/close-worktree.js.map +1 -1
  18. package/dist/commands/help.d.ts.map +1 -1
  19. package/dist/commands/help.js +9 -5
  20. package/dist/commands/help.js.map +1 -1
  21. package/dist/commands/join-project-item.d.ts.map +1 -1
  22. package/dist/commands/join-project-item.js +22 -48
  23. package/dist/commands/join-project-item.js.map +1 -1
  24. package/dist/commands/next-workflow-step.d.ts.map +1 -1
  25. package/dist/commands/next-workflow-step.js +22 -23
  26. package/dist/commands/next-workflow-step.js.map +1 -1
  27. package/dist/commands/ready-for-approval.d.ts.map +1 -1
  28. package/dist/commands/ready-for-approval.js +26 -18
  29. package/dist/commands/ready-for-approval.js.map +1 -1
  30. package/dist/commands/release.d.ts +3 -1
  31. package/dist/commands/release.d.ts.map +1 -1
  32. package/dist/commands/release.js +98 -19
  33. package/dist/commands/release.js.map +1 -1
  34. package/dist/commands/ship-local-changes.d.ts.map +1 -1
  35. package/dist/commands/ship-local-changes.js +4 -3
  36. package/dist/commands/ship-local-changes.js.map +1 -1
  37. package/dist/commands/start-agent-implementation.js +2 -2
  38. package/dist/commands/start-agent-implementation.js.map +1 -1
  39. package/dist/commands/start-dev-implementation.d.ts.map +1 -1
  40. package/dist/commands/start-dev-implementation.js +8 -3
  41. package/dist/commands/start-dev-implementation.js.map +1 -1
  42. package/dist/commands/start.d.ts +2 -2
  43. package/dist/commands/start.d.ts.map +1 -1
  44. package/dist/commands/start.js +27 -21
  45. package/dist/commands/start.js.map +1 -1
  46. package/dist/index.js +0 -0
  47. package/dist/interactive.d.ts.map +1 -1
  48. package/dist/interactive.js +164 -0
  49. package/dist/interactive.js.map +1 -1
  50. package/dist/jobs/job.d.ts +81 -0
  51. package/dist/jobs/job.d.ts.map +1 -0
  52. package/dist/jobs/job.js +258 -0
  53. package/dist/jobs/job.js.map +1 -0
  54. package/dist/jobs/targets.d.ts +58 -0
  55. package/dist/jobs/targets.d.ts.map +1 -0
  56. package/dist/jobs/targets.js +215 -0
  57. package/dist/jobs/targets.js.map +1 -0
  58. package/dist/lib/logger.d.ts +10 -0
  59. package/dist/lib/logger.d.ts.map +1 -1
  60. package/dist/lib/logger.js +16 -0
  61. package/dist/lib/logger.js.map +1 -1
  62. package/dist/lib/prompt.d.ts +7 -0
  63. package/dist/lib/prompt.d.ts.map +1 -1
  64. package/dist/lib/prompt.js +29 -0
  65. package/dist/lib/prompt.js.map +1 -1
  66. package/dist/lib/shell.d.ts +2 -1
  67. package/dist/lib/shell.d.ts.map +1 -1
  68. package/dist/lib/shell.js +17 -1
  69. package/dist/lib/shell.js.map +1 -1
  70. package/dist/services/git.d.ts +7 -0
  71. package/dist/services/git.d.ts.map +1 -1
  72. package/dist/services/git.js +10 -7
  73. package/dist/services/git.js.map +1 -1
  74. package/dist/services/github.d.ts +13 -0
  75. package/dist/services/github.d.ts.map +1 -1
  76. package/dist/services/github.js +35 -3
  77. package/dist/services/github.js.map +1 -1
  78. package/dist/services/setup.d.ts +4 -2
  79. package/dist/services/setup.d.ts.map +1 -1
  80. package/dist/services/setup.js +43 -13
  81. package/dist/services/setup.js.map +1 -1
  82. package/dist/services/worktree.js +1 -1
  83. package/dist/services/worktree.js.map +1 -1
  84. package/dist/types/index.d.ts +7 -0
  85. package/dist/types/index.d.ts.map +1 -1
  86. package/dist/workflow/engine/approval-flow.d.ts +2 -1
  87. package/dist/workflow/engine/approval-flow.d.ts.map +1 -1
  88. package/dist/workflow/engine/approval-flow.js +35 -1
  89. package/dist/workflow/engine/approval-flow.js.map +1 -1
  90. package/dist/workflow/engine/branch-setup.d.ts +8 -2
  91. package/dist/workflow/engine/branch-setup.d.ts.map +1 -1
  92. package/dist/workflow/engine/branch-setup.js +16 -6
  93. package/dist/workflow/engine/branch-setup.js.map +1 -1
  94. package/dist/workflow/engine/handlers/agent-implementation.d.ts.map +1 -1
  95. package/dist/workflow/engine/handlers/agent-implementation.js +3 -10
  96. package/dist/workflow/engine/handlers/agent-implementation.js.map +1 -1
  97. package/dist/workflow/engine/handlers/dev-implementation.d.ts +2 -2
  98. package/dist/workflow/engine/handlers/dev-implementation.d.ts.map +1 -1
  99. package/dist/workflow/engine/handlers/dev-implementation.js +13 -7
  100. package/dist/workflow/engine/handlers/dev-implementation.js.map +1 -1
  101. package/dist/workflow/engine/release-engine.d.ts +7 -1
  102. package/dist/workflow/engine/release-engine.d.ts.map +1 -1
  103. package/dist/workflow/engine/release-engine.js +16 -6
  104. package/dist/workflow/engine/release-engine.js.map +1 -1
  105. package/dist/workflow/engine/ship-flow.d.ts +5 -4
  106. package/dist/workflow/engine/ship-flow.d.ts.map +1 -1
  107. package/dist/workflow/engine/ship-flow.js +8 -13
  108. package/dist/workflow/engine/ship-flow.js.map +1 -1
  109. package/dist/workflow/engine/workflow-engine.d.ts +67 -13
  110. package/dist/workflow/engine/workflow-engine.d.ts.map +1 -1
  111. package/dist/workflow/engine/workflow-engine.js +137 -47
  112. package/dist/workflow/engine/workflow-engine.js.map +1 -1
  113. package/package.json +2 -2
  114. package/dist/commands/integrate.d.ts +0 -13
  115. package/dist/commands/integrate.d.ts.map +0 -1
  116. package/dist/commands/integrate.js +0 -128
  117. package/dist/commands/integrate.js.map +0 -1
  118. package/dist/commands/start-project-item.d.ts +0 -27
  119. package/dist/commands/start-project-item.d.ts.map +0 -1
  120. package/dist/commands/start-project-item.js +0 -325
  121. package/dist/commands/start-project-item.js.map +0 -1
  122. package/dist/services/hooks.d.ts +0 -8
  123. package/dist/services/hooks.d.ts.map +0 -1
  124. package/dist/services/hooks.js +0 -72
  125. package/dist/services/hooks.js.map +0 -1
  126. package/dist/services/workflow.d.ts +0 -17
  127. package/dist/services/workflow.d.ts.map +0 -1
  128. package/dist/services/workflow.js +0 -39
  129. package/dist/services/workflow.js.map +0 -1
@@ -0,0 +1,258 @@
1
+ import { EventEmitter } from 'events';
2
+ import { createWriteStream, existsSync, mkdirSync, readdirSync, rmSync, statSync } from 'fs';
3
+ import { join } from 'path';
4
+ import { createInterface } from 'readline';
5
+ import { fileURLToPath } from 'url';
6
+ import { execa } from 'execa';
7
+ import chalk from 'chalk';
8
+ import { STATUS_LINE_PREFIX, logger } from '../lib/logger.js';
9
+ import { UNATTENDED_ENV } from '../lib/prompt.js';
10
+ import * as git from '../services/git.js';
11
+ /**
12
+ * A job: one CLI command run on several targets at once, each target in its own unattended CLI
13
+ * process, optionally followed by one more command once every target has succeeded (the release a
14
+ * batch of approvals leads to). Each run's output goes to a log file and an in-memory tail; the
15
+ * `::idea1-status::` lines it writes (`logger.status`) are its current step. A job runs in the
16
+ * background of the interactive CLI, which registers itself as the background host, and in the
17
+ * foreground otherwise. Logs are kept in the main clone's `.idea1/jobs` folder, which git ignores,
18
+ * and pruned as new jobs start.
19
+ */
20
+ /** The CLI entry point the runs are started with: this CLI's own. */
21
+ const CLI_ENTRY = fileURLToPath(new URL('../index.js', import.meta.url));
22
+ /** How many of a run's most recent output lines are kept in memory for watching it live. */
23
+ const TAIL_LINES = 500;
24
+ /** The prefix `logger.error` writes, which marks a run's failure message in its output. */
25
+ const ERROR_LINE_PREFIX = '✗ ';
26
+ /** One run of a job: its process, where it is, and how it ended. */
27
+ export class JobRun {
28
+ spec;
29
+ logPath;
30
+ status = 'running';
31
+ /** The last step the run reported. */
32
+ step = 'Starting';
33
+ /** Why the run failed: the last error it reported, or its exit code. */
34
+ error = null;
35
+ /** The run's most recent output lines. */
36
+ tail = [];
37
+ child = null;
38
+ stopRequested = false;
39
+ constructor(spec, logPath) {
40
+ this.spec = spec;
41
+ this.logPath = logPath;
42
+ }
43
+ get label() {
44
+ return this.spec.label;
45
+ }
46
+ /** Start the run and settle once it has exited, reporting each step and output line. */
47
+ async run(cwd, onStep, onOutput) {
48
+ const log = createWriteStream(this.logPath, { flags: 'a' });
49
+ log.write(`$ idea1 ${this.spec.args.join(' ')}\n`);
50
+ this.child = execa(process.execPath, [CLI_ENTRY, ...this.spec.args], {
51
+ cwd,
52
+ env: { ...process.env, [UNATTENDED_ENV]: '1', FORCE_COLOR: '0' },
53
+ stdin: 'ignore',
54
+ all: true,
55
+ buffer: false,
56
+ reject: false
57
+ });
58
+ const output = this.child.all;
59
+ if (!output) {
60
+ throw new Error(`Could not read the output of idea1 ${this.spec.args[0]}.`);
61
+ }
62
+ const lines = createInterface({ input: output });
63
+ const linesClosed = new Promise(resolve => lines.once('close', resolve));
64
+ lines.on('line', line => {
65
+ if (line.startsWith(STATUS_LINE_PREFIX)) {
66
+ this.step = line.slice(STATUS_LINE_PREFIX.length);
67
+ onStep();
68
+ return;
69
+ }
70
+ if (line.startsWith(ERROR_LINE_PREFIX)) {
71
+ this.error = line.slice(ERROR_LINE_PREFIX.length);
72
+ }
73
+ log.write(`${line}\n`);
74
+ this.tail.push(line);
75
+ if (this.tail.length > TAIL_LINES) {
76
+ this.tail.shift();
77
+ }
78
+ onOutput(line);
79
+ });
80
+ const result = await this.child;
81
+ await linesClosed;
82
+ await new Promise(resolve => log.end(resolve));
83
+ if (this.stopRequested) {
84
+ this.status = 'stopped';
85
+ }
86
+ else if (result.exitCode === 0) {
87
+ this.status = 'succeeded';
88
+ }
89
+ else {
90
+ this.status = 'failed';
91
+ this.error ??= `exited with code ${result.exitCode ?? result.signal ?? 'unknown'}`;
92
+ }
93
+ onStep();
94
+ }
95
+ stop() {
96
+ if (this.status === 'running' && this.child) {
97
+ this.stopRequested = true;
98
+ this.child.kill('SIGTERM');
99
+ }
100
+ }
101
+ skip() {
102
+ this.status = 'skipped';
103
+ }
104
+ }
105
+ let nextJobId = 1;
106
+ /** Where job logs are kept, relative to the main clone's root. */
107
+ const JOBS_DIRECTORY = '.idea1/jobs';
108
+ /** Job logs are kept for this long, and at most this many of them. */
109
+ const JOB_LOG_RETENTION_DAYS = 14;
110
+ const JOB_LOG_RETENTION_COUNT = 50;
111
+ /**
112
+ * Delete the log folders of jobs older than the retention period, and of every job beyond the most
113
+ * recent ones kept. Job folders are named from their start time, so they sort oldest first.
114
+ */
115
+ function pruneJobLogs(jobsDirectory) {
116
+ if (!existsSync(jobsDirectory)) {
117
+ return;
118
+ }
119
+ const cutoff = Date.now() - JOB_LOG_RETENTION_DAYS * 24 * 60 * 60 * 1000;
120
+ const folders = readdirSync(jobsDirectory, { withFileTypes: true })
121
+ .filter(entry => entry.isDirectory())
122
+ .map(entry => entry.name)
123
+ .sort();
124
+ folders.forEach((name, index) => {
125
+ const path = join(jobsDirectory, name);
126
+ if (index < folders.length - JOB_LOG_RETENTION_COUNT || statSync(path).mtimeMs < cutoff) {
127
+ rmSync(path, { recursive: true, force: true });
128
+ }
129
+ });
130
+ }
131
+ /**
132
+ * A running job. Emits `step` (run) when a run reports a step or ends, `output` (run, line) for
133
+ * every line a run writes, and `done` once every run has ended.
134
+ */
135
+ export class Job extends EventEmitter {
136
+ spec;
137
+ id = nextJobId++;
138
+ runs;
139
+ followUp;
140
+ done;
141
+ /** Where the runs' log files are. */
142
+ logDirectory;
143
+ constructor(spec, logDirectory, cwd) {
144
+ super();
145
+ this.spec = spec;
146
+ this.logDirectory = logDirectory;
147
+ const logPath = (run, index) => join(logDirectory, `${index + 1}-${run.label.replace(/[^A-Za-z0-9#._-]+/g, '-').slice(0, 60)}.log`);
148
+ this.runs = spec.runs.map((run, index) => new JobRun(run, logPath(run, index)));
149
+ this.followUp = spec.followUp ? new JobRun(spec.followUp, logPath(spec.followUp, spec.runs.length)) : null;
150
+ this.done = this.runAll(cwd);
151
+ }
152
+ /**
153
+ * Start a job in the main clone, its logs kept in the clone's `.idea1/jobs` folder - one folder
154
+ * per job; the CLI's setup keeps the folder in `.idea1/.gitignore` - after pruning the logs of
155
+ * old jobs.
156
+ */
157
+ static async start(spec) {
158
+ const mainRepoRoot = (await git.getMainRepoRoot()).trim();
159
+ const jobsDirectory = join(mainRepoRoot, JOBS_DIRECTORY);
160
+ pruneJobLogs(jobsDirectory);
161
+ const stamp = new Date().toISOString().replace(/[:.]/g, '-');
162
+ const logDirectory = join(jobsDirectory, `${stamp}-${process.pid}-${nextJobId}`);
163
+ mkdirSync(logDirectory, { recursive: true });
164
+ return new Job(spec, logDirectory, mainRepoRoot);
165
+ }
166
+ get isRunning() {
167
+ return [...this.runs, ...(this.followUp ? [this.followUp] : [])].some(run => run.status === 'running');
168
+ }
169
+ /** Whether every run, and the follow-up, succeeded. */
170
+ get succeeded() {
171
+ return this.runs.every(run => run.status === 'succeeded') && (this.followUp?.status ?? 'succeeded') === 'succeeded';
172
+ }
173
+ /** Every run, the follow-up last. */
174
+ get allRuns() {
175
+ return this.followUp ? [...this.runs, this.followUp] : this.runs;
176
+ }
177
+ stop() {
178
+ for (const run of this.allRuns) {
179
+ run.stop();
180
+ }
181
+ }
182
+ async runAll(cwd) {
183
+ const onStep = (run) => () => this.emit('step', run);
184
+ const onOutput = (run) => (line) => this.emit('output', run, line);
185
+ await Promise.all(this.runs.map(async (run) => {
186
+ await run.run(cwd, onStep(run), onOutput(run));
187
+ if (run.status === 'failed' && this.spec.failFast) {
188
+ this.stop();
189
+ }
190
+ }));
191
+ if (this.followUp) {
192
+ if (this.runs.every(run => run.status === 'succeeded')) {
193
+ await this.followUp.run(cwd, onStep(this.followUp), onOutput(this.followUp));
194
+ }
195
+ else {
196
+ this.followUp.skip();
197
+ this.emit('step', this.followUp);
198
+ }
199
+ }
200
+ this.emit('done');
201
+ }
202
+ }
203
+ /** One line saying where a run is, or how it ended. */
204
+ export function describeRun(run) {
205
+ switch (run.status) {
206
+ case 'running': return `${chalk.cyan('…')} ${run.label}: ${run.step}`;
207
+ case 'succeeded': return `${chalk.green('✓')} ${run.label}`;
208
+ case 'failed': return `${chalk.red('✗')} ${run.label}: ${run.error ?? 'failed'}`;
209
+ case 'stopped': return `${chalk.yellow('■')} ${run.label}: stopped`;
210
+ case 'skipped': return `${chalk.dim('-')} ${run.label}: skipped`;
211
+ }
212
+ }
213
+ /** The job's outcome: a headline and one line per run, with the log of each run that failed. */
214
+ export function summarizeJob(job) {
215
+ const counts = new Map();
216
+ for (const run of job.runs) {
217
+ counts.set(run.status, (counts.get(run.status) ?? 0) + 1);
218
+ }
219
+ const tally = [...counts].map(([status, count]) => `${count} ${status}`).join(', ');
220
+ const lines = [`Job ${job.id} - ${job.spec.title}: ${tally}`];
221
+ for (const run of job.allRuns) {
222
+ lines.push(` ${describeRun(run)}`);
223
+ if (run.status === 'failed') {
224
+ lines.push(chalk.dim(` log: ${run.logPath}`));
225
+ }
226
+ }
227
+ return lines;
228
+ }
229
+ let backgroundHost = null;
230
+ export function setBackgroundJobHost(host) {
231
+ backgroundHost = host;
232
+ }
233
+ /**
234
+ * Run a job: in the background when the interactive CLI hosts it, which tells the user when it is
235
+ * done; otherwise in the foreground, reporting each run's steps as they happen and the outcome at
236
+ * the end. A foreground job that did not succeed throws, so the command fails.
237
+ */
238
+ export async function runJob(spec) {
239
+ const job = await Job.start(spec);
240
+ if (backgroundHost) {
241
+ backgroundHost.add(job);
242
+ logger.success(`Job ${job.id} started in the background: ${spec.title}`);
243
+ logger.hint('Type /jobs to watch it; you are told here when it finishes.');
244
+ return;
245
+ }
246
+ logger.header(`Job ${job.id}: ${spec.title}`);
247
+ logger.dim(`Logs: ${job.logDirectory}`);
248
+ job.on('step', (run) => logger.plain(run.status === 'running' ? `[${run.label}] ${run.step}` : describeRun(run)));
249
+ await job.done;
250
+ logger.newline();
251
+ for (const line of summarizeJob(job)) {
252
+ logger.plain(line);
253
+ }
254
+ if (!job.succeeded) {
255
+ throw new Error(`Job ${job.id} did not succeed: ${spec.title}`);
256
+ }
257
+ }
258
+ //# sourceMappingURL=job.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job.js","sourceRoot":"","sources":["../../src/jobs/job.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import type { Command, CommandOption } from '../types/index.js';
2
+ import type { WorkflowState } from '../workflow/data/workflow-states.js';
3
+ import { type TargetSummary } from '../workflow/engine/workflow-engine.js';
4
+ import { type RunSpec } from './job.js';
5
+ /**
6
+ * Running a command on its targets. A target is a project item URL, a branch name or a GitHub PR
7
+ * URL; the workflow engine resolves it to a project item, or to a branch with no item. One target
8
+ * runs in this process, exactly as the command always has. Several targets run as a job: each in
9
+ * its own unattended CLI process, in parallel, with everything they will need asked once, up front.
10
+ */
11
+ /** The name of the `--target` option every command that operates on a project item or a branch takes. */
12
+ export declare const TARGET_OPTION_NAME = "target";
13
+ /**
14
+ * The `--target` option of a command that operates on project items, and on branches with no
15
+ * project item when `itemlessBranches` says so. Resolved before the command's other options: with
16
+ * none given, the current branch is the target when it can be - an item's branch, or for a command
17
+ * that takes them any branch other than the base branch - and otherwise the targets are picked
18
+ * (`promptForTargets`). That is what happens on the base branch, where work is approved into and
19
+ * released from.
20
+ */
21
+ export declare function targetOption(itemlessBranches: boolean): CommandOption;
22
+ /** The targets in a `--target` value: comma or whitespace separated, each once. */
23
+ export declare function parseTargets(value: string): string[];
24
+ export interface TargetCommandSpec {
25
+ /** The workflow state the command advances a project item in `currentState` to; null for none. */
26
+ advancesTo: (currentState: WorkflowState | null) => WorkflowState | null;
27
+ /** Whether the command also operates on a branch with no project item. */
28
+ itemlessBranches: boolean;
29
+ /** Run the command on one target in this process; null is the current branch. */
30
+ run: (target: string | null) => Promise<void>;
31
+ }
32
+ /**
33
+ * Run a command on the targets of its resolved `--target` (see `targetOption`): none is the current
34
+ * branch, one runs in this process, several run as a job.
35
+ */
36
+ export declare function runForTargets(command: Command, resolved: Record<string, string>, spec: TargetCommandSpec): Promise<void>;
37
+ /**
38
+ * Pick the targets to operate on: the open PRs into the base branch and the branches this clone
39
+ * knows as project items', any number of them, plus any typed in - project item URLs, branch names
40
+ * or PR URLs. Picking nothing is allowed only when `noneMeans` says what it does (releasing the
41
+ * branch as it is, for instance).
42
+ */
43
+ export declare function promptForTargets(noneMeans: string | null): Promise<string[]>;
44
+ /**
45
+ * The unattended runs of a command, one per target. Everything that can stop a target is checked
46
+ * before any run starts: each target must resolve to work in this repository the command operates
47
+ * on - an item with a live branch here, or a branch with no item for a command that takes those -
48
+ * and on no branch another target already names. Every answer the runs will need is asked here,
49
+ * once: the options of every workflow state any item will enter on its way, then a confirmation of
50
+ * the whole set. Runs work in worktrees, never in the main clone, and launch no Claude session.
51
+ */
52
+ /** The runs of a command on its targets, with what each target was found to be. */
53
+ export interface PreparedTargetRuns {
54
+ runs: RunSpec[];
55
+ summaries: TargetSummary[];
56
+ }
57
+ export declare function prepareTargetRuns(command: Command, targets: readonly string[], resolved: Record<string, string>, spec: Pick<TargetCommandSpec, 'advancesTo' | 'itemlessBranches'>): Promise<PreparedTargetRuns>;
58
+ //# sourceMappingURL=targets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"targets.d.ts","sourceRoot":"","sources":["../../src/jobs/targets.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAQhE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAEzE,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAU,KAAK,OAAO,EAAE,MAAM,UAAU,CAAC;AAEhD;;;;;GAKG;AAEH,yGAAyG;AACzG,eAAO,MAAM,kBAAkB,WAAW,CAAC;AAE3C;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,gBAAgB,EAAE,OAAO,GAAG,aAAa,CASrE;AAED,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAEpD;AAED,MAAM,WAAW,iBAAiB;IAChC,kGAAkG;IAClG,UAAU,EAAE,CAAC,YAAY,EAAE,aAAa,GAAG,IAAI,KAAK,aAAa,GAAG,IAAI,CAAC;IACzE,0EAA0E;IAC1E,gBAAgB,EAAE,OAAO,CAAC;IAC1B,iFAAiF;IACjF,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAa9H;AAaD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAuBlF;AA+BD;;;;;;;GAOG;AACH,mFAAmF;AACnF,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,SAAS,EAAE,aAAa,EAAE,CAAC;CAC5B;AAED,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAChC,IAAI,EAAE,IAAI,CAAC,iBAAiB,EAAE,YAAY,GAAG,kBAAkB,CAAC,GAC/D,OAAO,CAAC,kBAAkB,CAAC,CAsC7B"}
@@ -0,0 +1,215 @@
1
+ import chalk from 'chalk';
2
+ import { claudeEntryPointOption } from '../lib/claude-options.js';
3
+ import { isolationModeOption } from '../lib/isolation.js';
4
+ import { logger } from '../lib/logger.js';
5
+ import { promptConfirm, promptInput, promptMultiSelect } from '../lib/prompt.js';
6
+ import * as git from '../services/git.js';
7
+ import * as github from '../services/github.js';
8
+ import * as worktree from '../services/worktree.js';
9
+ import { mergeConfirmationOption } from '../workflow/engine/approval-flow.js';
10
+ import { getProjectItemUrlForBranch, readTarget, resolveOptionsForAdvancing } from '../workflow/engine/workflow-engine.js';
11
+ import { runJob } from './job.js';
12
+ /**
13
+ * Running a command on its targets. A target is a project item URL, a branch name or a GitHub PR
14
+ * URL; the workflow engine resolves it to a project item, or to a branch with no item. One target
15
+ * runs in this process, exactly as the command always has. Several targets run as a job: each in
16
+ * its own unattended CLI process, in parallel, with everything they will need asked once, up front.
17
+ */
18
+ /** The name of the `--target` option every command that operates on a project item or a branch takes. */
19
+ export const TARGET_OPTION_NAME = 'target';
20
+ /**
21
+ * The `--target` option of a command that operates on project items, and on branches with no
22
+ * project item when `itemlessBranches` says so. Resolved before the command's other options: with
23
+ * none given, the current branch is the target when it can be - an item's branch, or for a command
24
+ * that takes them any branch other than the base branch - and otherwise the targets are picked
25
+ * (`promptForTargets`). That is what happens on the base branch, where work is approved into and
26
+ * released from.
27
+ */
28
+ export function targetOption(itemlessBranches) {
29
+ return {
30
+ longName: TARGET_OPTION_NAME,
31
+ description: itemlessBranches
32
+ ? 'Project item URL, branch name or GitHub PR URL to operate on - comma-separate several to run them in parallel (default: the current branch)'
33
+ : 'Project item URL, or its branch name or PR URL - comma-separate several to run them in parallel (default: the current branch)',
34
+ defaultValue: '',
35
+ resolveValue: async () => await currentBranchIsTarget(itemlessBranches) ? '' : (await promptForTargets(null)).join(',')
36
+ };
37
+ }
38
+ /** The targets in a `--target` value: comma or whitespace separated, each once. */
39
+ export function parseTargets(value) {
40
+ return [...new Set(value.split(/[\s,]+/).map(target => target.trim()).filter(target => target.length > 0))];
41
+ }
42
+ /**
43
+ * Run a command on the targets of its resolved `--target` (see `targetOption`): none is the current
44
+ * branch, one runs in this process, several run as a job.
45
+ */
46
+ export async function runForTargets(command, resolved, spec) {
47
+ const targets = parseTargets(resolved[TARGET_OPTION_NAME] ?? '');
48
+ if (targets.length <= 1) {
49
+ await spec.run(targets[0] ?? null);
50
+ return;
51
+ }
52
+ await runJob({
53
+ title: `${command.name} on ${targets.length} targets`,
54
+ runs: (await prepareTargetRuns(command, targets, resolved, spec)).runs,
55
+ followUp: null,
56
+ failFast: false
57
+ });
58
+ }
59
+ async function currentBranchIsTarget(itemlessBranches) {
60
+ const branchName = await git.getCurrentBranch();
61
+ if (branchName === 'HEAD' || branchName === await worktree.resolveBaseBranch()) {
62
+ return false;
63
+ }
64
+ return itemlessBranches || await getProjectItemUrlForBranch(branchName) !== null;
65
+ }
66
+ /** The picker entry that asks for targets typed in. */
67
+ const ENTER_TARGETS = '\u0000enter-targets';
68
+ /**
69
+ * Pick the targets to operate on: the open PRs into the base branch and the branches this clone
70
+ * knows as project items', any number of them, plus any typed in - project item URLs, branch names
71
+ * or PR URLs. Picking nothing is allowed only when `noneMeans` says what it does (releasing the
72
+ * branch as it is, for instance).
73
+ */
74
+ export async function promptForTargets(noneMeans) {
75
+ const candidates = await listTargetCandidates();
76
+ if (candidates.length === 0) {
77
+ return promptForTypedTargets(noneMeans === null);
78
+ }
79
+ const message = noneMeans
80
+ ? `Pick the targets (space selects, enter confirms; pick none to ${noneMeans}):`
81
+ : 'Pick the targets (space selects, enter confirms):';
82
+ // eslint-disable-next-line no-constant-condition
83
+ while (true) {
84
+ const picked = await promptMultiSelect(message, [
85
+ ...candidates,
86
+ { label: 'Other - type project item URLs, branch names or PR URLs', value: ENTER_TARGETS }
87
+ ]);
88
+ const chosen = picked.filter(value => value !== ENTER_TARGETS);
89
+ const typed = picked.includes(ENTER_TARGETS) ? await promptForTypedTargets(chosen.length === 0 && noneMeans === null) : [];
90
+ const targets = [...new Set([...chosen, ...typed])];
91
+ if (targets.length > 0 || noneMeans !== null) {
92
+ return targets;
93
+ }
94
+ logger.error('Pick at least one target, or pick Other to type one.');
95
+ }
96
+ }
97
+ async function promptForTypedTargets(required) {
98
+ const value = await promptInput('Project item URLs, branch names or PR URLs (comma-separate several to run them in parallel):', {
99
+ validate: input => !required || parseTargets(input).length > 0 ? true : 'Enter at least one project item URL, branch name or PR URL'
100
+ });
101
+ return parseTargets(value);
102
+ }
103
+ /**
104
+ * What can be picked as a target: every open PR into the base branch (by its branch), and every
105
+ * branch this clone knows as a project item's that has no such PR yet.
106
+ */
107
+ async function listTargetCandidates() {
108
+ const baseBranch = await worktree.resolveBaseBranch();
109
+ logger.step(`Finding open PRs into ${baseBranch} and project item branches...`);
110
+ const [prs, itemBranches] = await Promise.all([github.listOpenPrsInto(baseBranch), git.listBranchesWithProjectItemUrl()]);
111
+ const itemUrlByBranch = new Map(itemBranches.map(entry => [entry.branchName, entry.projectItemUrl]));
112
+ const candidates = prs.map(pr => {
113
+ const itemUrl = itemUrlByBranch.get(pr.headRefName);
114
+ return { label: `PR #${pr.number} ${pr.title} (${pr.headRefName}${itemUrl ? `, ${itemUrl}` : ''})`, value: pr.headRefName };
115
+ });
116
+ for (const { branchName, projectItemUrl } of itemBranches) {
117
+ if (branchName !== baseBranch && !prs.some(pr => pr.headRefName === branchName) && await git.localBranchExists(branchName)) {
118
+ candidates.push({ label: `${projectItemUrl} (${branchName}, no PR yet)`, value: branchName });
119
+ }
120
+ }
121
+ return candidates;
122
+ }
123
+ export async function prepareTargetRuns(command, targets, resolved, spec) {
124
+ logger.step(`Resolving ${targets.length} targets...`);
125
+ const summaries = await readTargets(targets, spec);
126
+ const options = {
127
+ ...resolved,
128
+ [isolationModeOption.longName]: 'worktree',
129
+ [claudeEntryPointOption.longName]: 'none'
130
+ };
131
+ for (const summary of summaries.filter(summary => summary.projectItemUrl !== null)) {
132
+ const targetState = spec.advancesTo(summary.currentState);
133
+ if (targetState) {
134
+ await resolveOptionsForAdvancing(summary.currentState, targetState, options);
135
+ }
136
+ }
137
+ logger.newline();
138
+ logger.info(`${command.name} on ${summaries.length} targets, in parallel:`);
139
+ for (const summary of summaries) {
140
+ const where = summary.projectItemUrl ? `${summary.currentState ?? '(not started)'} on ${summary.branchName}` : 'no project item';
141
+ logger.plain(` ${summary.label} ${chalk.dim(`(${where})`)}`);
142
+ }
143
+ logger.newline();
144
+ if (resolved[mergeConfirmationOption.longName] !== 'true'
145
+ && !await promptConfirm(`Run ${command.name} on these ${summaries.length} targets, unattended?`, { default: true })) {
146
+ throw new Error('command cancelled');
147
+ }
148
+ options[mergeConfirmationOption.longName] = 'true';
149
+ const args = serializeOptions(command, options);
150
+ return {
151
+ runs: summaries.map(summary => ({
152
+ label: summary.label,
153
+ args: [command.name, `--${TARGET_OPTION_NAME}`, summary.target, ...args]
154
+ })),
155
+ summaries
156
+ };
157
+ }
158
+ async function readTargets(targets, spec) {
159
+ const results = await Promise.allSettled(targets.map(target => readTarget(target)));
160
+ const problems = [];
161
+ const summaries = [];
162
+ const branches = new Map();
163
+ results.forEach((result, index) => {
164
+ const target = targets[index];
165
+ if (result.status === 'rejected') {
166
+ problems.push(`${target}: ${result.reason.message}`);
167
+ return;
168
+ }
169
+ // Only an item can have no branch: a target that is not an item names its branch.
170
+ const summary = result.value;
171
+ const { branchName } = summary;
172
+ if (!branchName) {
173
+ problems.push(`${target}: ${summary.label} has no live branch in this repository - start it first (idea1 start --target ${summary.projectItemUrl})`);
174
+ }
175
+ else if (!summary.projectItemUrl && !spec.itemlessBranches) {
176
+ problems.push(`${target}: ${branchName} is not a project item's branch`);
177
+ }
178
+ else if (branches.has(branchName)) {
179
+ problems.push(`${target}: ${branchName} is also the branch of ${branches.get(branchName)}`);
180
+ }
181
+ else {
182
+ branches.set(branchName, target);
183
+ summaries.push(summary);
184
+ }
185
+ });
186
+ if (problems.length > 0) {
187
+ throw new Error(`Nothing was started, because not every target can be run:\n${problems.map(problem => ` ${problem}`).join('\n')}`);
188
+ }
189
+ return summaries;
190
+ }
191
+ /**
192
+ * The command line that hands resolved options to a run: every option the command declares and
193
+ * has a value for, so the run is asked nothing.
194
+ */
195
+ function serializeOptions(command, options) {
196
+ const args = [];
197
+ const seen = new Set([TARGET_OPTION_NAME]);
198
+ for (const option of command.options ?? []) {
199
+ const value = options[option.longName];
200
+ if (seen.has(option.longName) || value === undefined) {
201
+ continue;
202
+ }
203
+ seen.add(option.longName);
204
+ if (option.isFlag) {
205
+ if (value === 'true') {
206
+ args.push(`--${option.longName}`);
207
+ }
208
+ }
209
+ else {
210
+ args.push(`--${option.longName}`, value);
211
+ }
212
+ }
213
+ return args;
214
+ }
215
+ //# sourceMappingURL=targets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"targets.js","sourceRoot":"","sources":["../../src/jobs/targets.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,8 @@
1
+ /**
2
+ * The prefix of the line an unattended run writes for each `logger.status`, which the job running
3
+ * it reads as the run's current step (see src/jobs).
4
+ */
5
+ export declare const STATUS_LINE_PREFIX = "::idea1-status:: ";
1
6
  /**
2
7
  * Logger utility for consistent console output with colors
3
8
  */
@@ -7,6 +12,11 @@ export declare const logger: {
7
12
  warning: (message: string) => void;
8
13
  error: (message: string) => void;
9
14
  step: (message: string) => void;
15
+ /**
16
+ * A step that marks where the run is - a workflow state entered, the wait for checks, the merge.
17
+ * Printed like `step`; an unattended run also reports it to the job that runs it.
18
+ */
19
+ status: (message: string) => void;
10
20
  dim: (message: string) => void;
11
21
  plain: (message: string) => void;
12
22
  header: (message: string) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/lib/logger.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,eAAO,MAAM,MAAM;oBACD,MAAM,KAAG,IAAI;uBAIV,MAAM,KAAG,IAAI;uBAIb,MAAM,KAAG,IAAI;qBAIf,MAAM,KAAG,IAAI;oBAId,MAAM,KAAG,IAAI;mBAId,MAAM,KAAG,IAAI;qBAIX,MAAM,KAAG,IAAI;sBAIZ,MAAM,KAAG,IAAI;uBAQZ,MAAM,KAAG,IAAI;mBAOnB,IAAI;IAIjB;;OAEG;oBACa,MAAM,KAAG,IAAI;CAG9B,CAAC"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/lib/logger.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,eAAO,MAAM,kBAAkB,sBAAsB,CAAC;AAEtD;;GAEG;AACH,eAAO,MAAM,MAAM;oBACD,MAAM,KAAG,IAAI;uBAIV,MAAM,KAAG,IAAI;uBAIb,MAAM,KAAG,IAAI;qBAIf,MAAM,KAAG,IAAI;oBAId,MAAM,KAAG,IAAI;IAI7B;;;OAGG;sBACe,MAAM,KAAG,IAAI;mBAOhB,MAAM,KAAG,IAAI;qBAIX,MAAM,KAAG,IAAI;sBAIZ,MAAM,KAAG,IAAI;uBAQZ,MAAM,KAAG,IAAI;mBAOnB,IAAI;IAIjB;;OAEG;oBACa,MAAM,KAAG,IAAI;CAG9B,CAAC"}
@@ -1,4 +1,10 @@
1
1
  import chalk from 'chalk';
2
+ import { isUnattended } from './prompt.js';
3
+ /**
4
+ * The prefix of the line an unattended run writes for each `logger.status`, which the job running
5
+ * it reads as the run's current step (see src/jobs).
6
+ */
7
+ export const STATUS_LINE_PREFIX = '::idea1-status:: ';
2
8
  /**
3
9
  * Logger utility for consistent console output with colors
4
10
  */
@@ -18,6 +24,16 @@ export const logger = {
18
24
  step: (message) => {
19
25
  console.log(chalk.cyan(`→ ${message}`));
20
26
  },
27
+ /**
28
+ * A step that marks where the run is - a workflow state entered, the wait for checks, the merge.
29
+ * Printed like `step`; an unattended run also reports it to the job that runs it.
30
+ */
31
+ status: (message) => {
32
+ console.log(chalk.cyan(`→ ${message}`));
33
+ if (isUnattended()) {
34
+ console.log(`${STATUS_LINE_PREFIX}${message}`);
35
+ }
36
+ },
21
37
  dim: (message) => {
22
38
  console.log(chalk.dim(message));
23
39
  },
@@ -1 +1 @@
1
- {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/lib/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;GAEG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,IAAI,EAAE,CAAC,OAAe,EAAQ,EAAE;QAC9B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IACnC,CAAC;IAED,OAAO,EAAE,CAAC,OAAe,EAAQ,EAAE;QACjC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC,CAAC;IAC3C,CAAC;IAED,OAAO,EAAE,CAAC,OAAe,EAAQ,EAAE;QACjC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,EAAE,CAAC,OAAe,EAAQ,EAAE;QAC/B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC,CAAC;IAC3C,CAAC;IAED,IAAI,EAAE,CAAC,OAAe,EAAQ,EAAE;QAC9B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC,CAAC;IAC1C,CAAC;IAED,GAAG,EAAE,CAAC,OAAe,EAAQ,EAAE;QAC7B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IAClC,CAAC;IAED,KAAK,EAAE,CAAC,OAAe,EAAQ,EAAE;QAC/B,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACvB,CAAC;IAED,MAAM,EAAE,CAAC,OAAe,EAAQ,EAAE;QAChC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,EAAE,CAAC,OAAe,EAAQ,EAAE;QACjC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QACjC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC;IAED,OAAO,EAAE,GAAS,EAAE;QAClB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC;IAED;;OAEG;IACH,IAAI,EAAE,CAAC,OAAe,EAAQ,EAAE;QAC9B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,OAAO,EAAE,CAAC,CAAC,CAAC;IAC9C,CAAC;CACF,CAAC"}
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/lib/logger.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Set on a run that nobody is watching - one target of a batch, run in its own process. Every
3
+ * answer such a run needs is supplied as an option by whoever started it, so a question it would
4
+ * otherwise ask is a failure, reported straight away rather than left waiting for an answer.
5
+ */
6
+ export declare const UNATTENDED_ENV = "IDEA1_UNATTENDED";
7
+ export declare function isUnattended(): boolean;
1
8
  /**
2
9
  * Prompt for text input.
3
10
  * Press Escape to cancel.