@drisp/cli 0.7.4 → 0.7.6

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.
@@ -8,7 +8,7 @@ import {
8
8
  installWorkflowPlugins,
9
9
  resolveWorkflow,
10
10
  writeGlobalConfig
11
- } from "./chunk-TSIMXPJN.js";
11
+ } from "./chunk-W57EQYCM.js";
12
12
  import "./chunk-G3PMV62Z.js";
13
13
 
14
14
  // src/setup/steps/WorkflowInstallWizard.tsx
@@ -93,4 +93,4 @@ function WorkflowInstallWizard({ source, onDone }) {
93
93
  export {
94
94
  WorkflowInstallWizard as default
95
95
  };
96
- //# sourceMappingURL=WorkflowInstallWizard-AJYDKFDL.js.map
96
+ //# sourceMappingURL=WorkflowInstallWizard-YANLNMTP.js.map
@@ -19,7 +19,6 @@ import {
19
19
  BUILD_STRINGS,
20
20
  DEFAULT_PERMISSION_GRACE_MS,
21
21
  LAYOUT_MARKERS,
22
- ORCHESTRATOR_LIMITS,
23
22
  ORCHESTRATOR_LOOP,
24
23
  WAITING_ON_CHILDREN_STOP_REASON,
25
24
  compileWorkflowPlan,
@@ -55,7 +54,7 @@ import {
55
54
  verifyRendered,
56
55
  wakesFreshAfterHandover,
57
56
  workflowRegistryDir
58
- } from "./chunk-TSIMXPJN.js";
57
+ } from "./chunk-W57EQYCM.js";
59
58
  import {
60
59
  __commonJS,
61
60
  __toESM
@@ -13078,12 +13077,12 @@ var SIZE_CLASS_FORECASTS = {
13078
13077
  L: 12e5
13079
13078
  };
13080
13079
  function classOfCap(declaredCap) {
13081
- if (declaredCap <= SIZE_CLASS_CAPS.S) return "S";
13080
+ if (Number.isNaN(declaredCap) || declaredCap <= SIZE_CLASS_CAPS.S) return "S";
13082
13081
  if (declaredCap <= SIZE_CLASS_CAPS.M) return "M";
13083
13082
  return "L";
13084
13083
  }
13085
- function attemptCost(attempt) {
13086
- return attempt.closed ? SIZE_CLASS_FORECASTS[classOfCap(attempt.tokenCap)] : attempt.tokenCap;
13084
+ function forecastOfCap(declaredCap) {
13085
+ return SIZE_CLASS_FORECASTS[classOfCap(declaredCap)];
13087
13086
  }
13088
13087
 
13089
13088
  // ../../packages/protocol/src/v2.ts
@@ -14893,7 +14892,7 @@ async function restoreCheckpoint(store, input) {
14893
14892
 
14894
14893
  // ../../modules/runtime/src/software-version.ts
14895
14894
  import "fs";
14896
- var runnerSoftwareVersion = true ? "0.7.4" : JSON.parse(readFileSync2(new URL("../../../apps/cli/package.json", import.meta.url), "utf8")).version;
14895
+ var runnerSoftwareVersion = true ? "0.7.6" : JSON.parse(readFileSync2(new URL("../../../apps/cli/package.json", import.meta.url), "utf8")).version;
14897
14896
 
14898
14897
  // ../../modules/runtime/src/connection.ts
14899
14898
  var RunnerDisconnectedError = class extends Error {
@@ -20261,7 +20260,8 @@ var issueEntrySchema = external_exports.strictObject({
20261
20260
  workflowName: external_exports.string().max(128)
20262
20261
  });
20263
20262
  var buildPlanSchema = external_exports.strictObject({
20264
- version: external_exports.literal(2),
20263
+ /** 3 carries the forecast; 2 (read, never written) carried the sum of the children's caps. */
20264
+ version: external_exports.union([external_exports.literal(2), external_exports.literal(3)]),
20265
20265
  orchestratorRunId: external_exports.string().min(1),
20266
20266
  planKey: external_exports.string().regex(/^plan:.+$/),
20267
20267
  projectId: external_exports.string().min(1),
@@ -20270,11 +20270,18 @@ var buildPlanSchema = external_exports.strictObject({
20270
20270
  templateVersion: external_exports.string().regex(/^[0-9a-f]{64}$/),
20271
20271
  branch: external_exports.string().regex(/^drisp\/build-[a-z0-9]+$/),
20272
20272
  commit: external_exports.string().regex(/^[0-9a-f]{40}$/),
20273
- budget: external_exports.strictObject({
20274
- tokenBudget: count,
20275
- orchestratorCap: count,
20276
- childCapsSum: count
20277
- }),
20273
+ budget: external_exports.union([
20274
+ external_exports.strictObject({
20275
+ tokenBudget: count,
20276
+ orchestratorCap: count,
20277
+ forecast: count
20278
+ }),
20279
+ external_exports.strictObject({
20280
+ tokenBudget: count,
20281
+ orchestratorCap: count,
20282
+ childCapsSum: count
20283
+ })
20284
+ ]),
20278
20285
  groups: external_exports.array(
20279
20286
  external_exports.strictObject({
20280
20287
  index: external_exports.number().int().positive(),
@@ -20627,11 +20634,12 @@ function planBuild(context) {
20627
20634
  });
20628
20635
  }
20629
20636
  const groups = layers.map((issues, index) => ({ index: index + 1, issues }));
20637
+ const forecast = groups.flatMap((group2) => group2.issues).reduce((sum, entry) => sum + SIZE_CLASS_FORECASTS[entry.sizeClass], 0);
20630
20638
  return {
20631
20639
  status: "planned",
20632
20640
  workflows,
20633
20641
  plan: {
20634
- version: 2,
20642
+ version: 3,
20635
20643
  orchestratorRunId: context.orchestratorRunId,
20636
20644
  planKey: `plan:${input.project.id}`,
20637
20645
  projectId: input.project.id,
@@ -20640,9 +20648,9 @@ function planBuild(context) {
20640
20648
  templateVersion: context.templateVersion,
20641
20649
  branch: buildBranch(input.project.slugId),
20642
20650
  budget: {
20643
- tokenBudget: ORCHESTRATOR_LIMITS.tokenBudget,
20651
+ tokenBudget: defaultBudget(forecast),
20644
20652
  orchestratorCap: ORCHESTRATOR_LOOP.maxRunTokens,
20645
- childCapsSum: groups.flatMap((group2) => group2.issues).reduce((sum, entry) => sum + entry.tokenCap, 0)
20653
+ forecast
20646
20654
  },
20647
20655
  groups,
20648
20656
  skipped,
@@ -20667,6 +20675,9 @@ function finalizePlan(draft, commit) {
20667
20675
  ...needsPerson ? { needsPerson } : {}
20668
20676
  };
20669
20677
  }
20678
+ function defaultBudget(forecast) {
20679
+ return Math.ceil(forecast * 1.5 / 1e5) * 1e5;
20680
+ }
20670
20681
 
20671
20682
  // src/core/build/childWorktree.ts
20672
20683
  import fs23 from "fs";
@@ -21899,7 +21910,7 @@ export {
21899
21910
  RUN_EXIT_CODE,
21900
21911
  localAnswerDecision,
21901
21912
  runExec,
21902
- attemptCost,
21913
+ forecastOfCap,
21903
21914
  repositoryBindingSchema,
21904
21915
  commandSchema,
21905
21916
  historyRecordSchema,
@@ -21956,4 +21967,4 @@ export {
21956
21967
  runMachineRunners,
21957
21968
  writeIdentityOnce
21958
21969
  };
21959
- //# sourceMappingURL=chunk-XG7B4OOC.js.map
21970
+ //# sourceMappingURL=chunk-2N7IBKJF.js.map
@@ -21287,7 +21287,6 @@ var workflow_default = '# Orchestrator: plan and run a Build\n\nYou plan and run
21287
21287
  var ORCHESTRATOR_WORKFLOW_NAME = "orchestrator";
21288
21288
  var ORCHESTRATOR_LIMITS = {
21289
21289
  maxChildren: 2,
21290
- tokenBudget: 6e7,
21291
21290
  tickAllowance: 300
21292
21291
  };
21293
21292
  var ORCHESTRATOR_LOOP = {
@@ -21469,6 +21468,10 @@ Merge with \`gh pr merge --squash --delete-branch --match-head-commit <sha>\`, w
21469
21468
  push. When it exits non-zero, \`gh pr view --json state\` decides: \`MERGED\` means the merge happened (a worktree
21470
21469
  cannot check out main afterwards); anything else means it did not.
21471
21470
 
21471
+ After a merge, and only then, run \`drisp build merged <pr url>\` in this worktree: it records the merged pull request as the
21472
+ \`pull_request\` run artifact and exits non-zero if the pull request is not merged. Never run it before the merge or
21473
+ after a failed one; if it fails only because GitHub has not caught up, wait a few seconds and run it again.
21474
+
21472
21475
  ## Evidence comment
21473
21476
 
21474
21477
  Post exactly this on the Linear issue, filling the angle brackets:
@@ -24251,4 +24254,4 @@ export {
24251
24254
  compileWorkflowPlan,
24252
24255
  collectMcpServersWithOptions
24253
24256
  };
24254
- //# sourceMappingURL=chunk-TSIMXPJN.js.map
24257
+ //# sourceMappingURL=chunk-W57EQYCM.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  runMachineRunners
3
- } from "./chunk-XG7B4OOC.js";
3
+ } from "./chunk-2N7IBKJF.js";
4
4
 
5
5
  // src/app/entry/runnerDaemon.ts
6
6
  if (process.argv.includes("--help")) {
@@ -13,4 +13,4 @@ if (process.argv.includes("--help")) {
13
13
  process.exitCode = 1;
14
14
  });
15
15
  }
16
- //# sourceMappingURL=chunk-F6XUMTMC.js.map
16
+ //# sourceMappingURL=chunk-Y6XJPUR2.js.map
package/dist/cli.js CHANGED
@@ -10,7 +10,6 @@ import {
10
10
  ServiceNotEnabledError,
11
11
  approvalAnswer,
12
12
  attachRuntimeEventLoop,
13
- attemptCost,
14
13
  behindMain,
15
14
  bootstrapRuntimeConfig,
16
15
  buildApiKeyHelperSettings,
@@ -48,6 +47,7 @@ import {
48
47
  finalizePlan,
49
48
  fit,
50
49
  fitAnsi,
50
+ forecastOfCap,
51
51
  forgetRunner,
52
52
  formatClock,
53
53
  formatProbeCommand,
@@ -140,7 +140,7 @@ import {
140
140
  visualPositionToOffset,
141
141
  wrapText,
142
142
  writeIdentityOnce
143
- } from "./chunk-XG7B4OOC.js";
143
+ } from "./chunk-2N7IBKJF.js";
144
144
  import {
145
145
  generateId as generateId2
146
146
  } from "./chunk-PQIB66SG.js";
@@ -198,7 +198,7 @@ import {
198
198
  workflowRegistryDir,
199
199
  writeGlobalConfig,
200
200
  writeProjectConfig
201
- } from "./chunk-TSIMXPJN.js";
201
+ } from "./chunk-W57EQYCM.js";
202
202
  import {
203
203
  __toESM
204
204
  } from "./chunk-G3PMV62Z.js";
@@ -206,10 +206,10 @@ import {
206
206
  // src/app/entry/cli.tsx
207
207
  import { render } from "ink";
208
208
  import meow from "meow";
209
- import fs10 from "fs";
209
+ import fs11 from "fs";
210
210
  import { createRequire } from "module";
211
211
  import os5 from "os";
212
- import path10 from "path";
212
+ import path11 from "path";
213
213
  import { fileURLToPath } from "url";
214
214
 
215
215
  // src/app/shell/sessionUiState.ts
@@ -5328,14 +5328,14 @@ function extractWebSearch(_input, response) {
5328
5328
  return { type: "text", content: extractTextContent(response), maxLines: 10 };
5329
5329
  }
5330
5330
  function extractNotebookEdit(input, _response) {
5331
- const path11 = typeof input["notebook_path"] === "string" ? input["notebook_path"] : "";
5331
+ const path12 = typeof input["notebook_path"] === "string" ? input["notebook_path"] : "";
5332
5332
  const mode = typeof input["edit_mode"] === "string" ? input["edit_mode"] : "replace";
5333
5333
  const source = typeof input["new_source"] === "string" ? input["new_source"] : "";
5334
- if (!source) return { type: "text", content: `${mode} cell in ${path11}` };
5334
+ if (!source) return { type: "text", content: `${mode} cell in ${path12}` };
5335
5335
  return {
5336
5336
  type: "code",
5337
5337
  content: source,
5338
- language: detectLanguage(path11),
5338
+ language: detectLanguage(path12),
5339
5339
  maxLines: 10
5340
5340
  };
5341
5341
  }
@@ -5861,10 +5861,10 @@ function extractToolSubject(toolName, toolInput) {
5861
5861
  const parts = [];
5862
5862
  const pattern = str(input, "pattern");
5863
5863
  const glob = str(input, "glob");
5864
- const path11 = str(input, "path");
5864
+ const path12 = str(input, "path");
5865
5865
  if (pattern) parts.push(`"${pattern}"`);
5866
5866
  if (glob) parts.push(glob);
5867
- if (path11) parts.push(`in ${path11}`);
5867
+ if (path12) parts.push(`in ${path12}`);
5868
5868
  return parts.length > 0 ? parts.join(" ") : void 0;
5869
5869
  }
5870
5870
  case "Skill":
@@ -13095,7 +13095,7 @@ var thisMachine = (installationId) => ({
13095
13095
  os: `${platform()} ${release()}`.slice(0, 64),
13096
13096
  softwareVersion: runnerSoftwareVersion
13097
13097
  });
13098
- var post = (origin, path11, body) => fetch(new URL(path11, origin), {
13098
+ var post = (origin, path12, body) => fetch(new URL(path12, origin), {
13099
13099
  method: "POST",
13100
13100
  headers: { "Content-Type": "application/json" },
13101
13101
  body: JSON.stringify(body)
@@ -13114,8 +13114,8 @@ async function alreadyConnected(existing, { forTeam, ownIdentity }) {
13114
13114
  const problem = own ? await credentialAccepted(own.config) ? void 0 : "lapsed" : forTeam(existing.orgId).length ? "other_runner" : "missing";
13115
13115
  const runner = { orgId: existing.orgId, runnerId: existing.runnerId, name: existing.name };
13116
13116
  if (own && problem === void 0) return { status: "already_connected", ...runner, path: own.path };
13117
- const path11 = (own ?? forTeam(existing.orgId)[0])?.path;
13118
- return { status: "identity_unusable", ...runner, problem, ...path11 ? { path: path11 } : {} };
13117
+ const path12 = (own ?? forTeam(existing.orgId)[0])?.path;
13118
+ return { status: "identity_unusable", ...runner, problem, ...path12 ? { path: path12 } : {} };
13119
13119
  }
13120
13120
  async function connectWithCode({
13121
13121
  code,
@@ -13187,20 +13187,20 @@ async function saveIdentity(origin, credential, { single, forTeam }, directory)
13187
13187
  name: credential.name
13188
13188
  });
13189
13189
  const replaced = [];
13190
- for (const { path: path12 } of forTeam(credential.orgId)) {
13191
- const aside = `${path12}.replaced-${Date.now()}`;
13192
- await rename(path12, aside);
13190
+ for (const { path: path13 } of forTeam(credential.orgId)) {
13191
+ const aside = `${path13}.replaced-${Date.now()}`;
13192
+ await rename(path13, aside);
13193
13193
  replaced.push(aside);
13194
13194
  }
13195
- const path11 = single ?? teamIdentityPath(origin, credential.orgId, directory);
13195
+ const path12 = single ?? teamIdentityPath(origin, credential.orgId, directory);
13196
13196
  try {
13197
- await writeIdentityOnce(path11, JSON.stringify(config, null, 2) + "\n");
13197
+ await writeIdentityOnce(path12, JSON.stringify(config, null, 2) + "\n");
13198
13198
  } catch (error) {
13199
13199
  if (error.code === "EEXIST")
13200
- throw new Error(`Another Connect wrote a Runner identity for this Team at ${path11} meanwhile; it was left unchanged.`);
13200
+ throw new Error(`Another Connect wrote a Runner identity for this Team at ${path12} meanwhile; it was left unchanged.`);
13201
13201
  throw error;
13202
13202
  }
13203
- return { status: "connected", config, path: path11, replaced };
13203
+ return { status: "connected", config, path: path12, replaced };
13204
13204
  }
13205
13205
  function pathSegment(value) {
13206
13206
  const segment = encodeURIComponent(value);
@@ -13240,7 +13240,7 @@ async function refuseExisting(target) {
13240
13240
  throw new Error(`This machine already has a Runner${name ? ` (${name})` : ""} configured at ${target}.`);
13241
13241
  }
13242
13242
  async function disconnectRunner({
13243
- identity: { path: path11, config },
13243
+ identity: { path: path12, config },
13244
13244
  serviceManager,
13245
13245
  othersRemain
13246
13246
  }) {
@@ -13273,7 +13273,7 @@ async function disconnectRunner({
13273
13273
  await restore();
13274
13274
  throw new Error(`The Hub refused to disconnect ${name} (${body.error ?? response.status}); it is still connected.`);
13275
13275
  }
13276
- await forgetRunner(path11);
13276
+ await forgetRunner(path12);
13277
13277
  if (othersRemain) await restore();
13278
13278
  else await serviceManager?.remove();
13279
13279
  return result;
@@ -13426,18 +13426,18 @@ async function runRunnerCommandV2(input, options = {}) {
13426
13426
  `This machine is already connected to this Team as ${outcome.name}, but ${why}. ` + (code ? `The code was not used: connect a new Runner in its place with ${retry}. ` : `Connect a new Runner in its place with a Connect code from Settings \u2192 Runners: ${retry}. `) + `The old ${outcome.name} stays listed in Settings \u2192 Runners, offline.`
13427
13427
  );
13428
13428
  }
13429
- const { config, path: path11, replaced } = outcome;
13429
+ const { config, path: path12, replaced } = outcome;
13430
13430
  for (const aside of replaced)
13431
13431
  process.stdout.write(
13432
13432
  `The Hub no longer recognised this machine's earlier identity for this Team; it was moved aside to ${aside}.
13433
13433
  `
13434
13434
  );
13435
13435
  process.stdout.write(
13436
- `Connected as ${config.name ?? config.runnerId}. Identity saved to ${path11}.
13436
+ `Connected as ${config.name ?? config.runnerId}. Identity saved to ${path12}.
13437
13437
  `
13438
13438
  );
13439
13439
  if (services) {
13440
- const service = await ensureService(services, config, path11);
13440
+ const service = await ensureService(services, config, path12);
13441
13441
  process.stdout.write(`${serviceStarted(service)}
13442
13442
  `);
13443
13443
  return 0;
@@ -13446,7 +13446,7 @@ async function runRunnerCommandV2(input, options = {}) {
13446
13446
  process.stdout.write(
13447
13447
  "No launchd or systemd here to run the Runner as a background service; running it in the foreground instead.\n"
13448
13448
  );
13449
- await runConfiguredRunner(path11, options.signal);
13449
+ await runConfiguredRunner(path12, options.signal);
13450
13450
  return 0;
13451
13451
  }
13452
13452
  case "disconnect": {
@@ -13517,9 +13517,9 @@ async function runRunnerCommandV2(input, options = {}) {
13517
13517
  configured: true,
13518
13518
  // One entry per Team this machine serves; credentials are never printed.
13519
13519
  teams: identities.map(
13520
- ({ path: path11, config: { token: _token, ...config } }) => ({
13520
+ ({ path: path12, config: { token: _token, ...config } }) => ({
13521
13521
  ...config,
13522
- path: path11
13522
+ path: path12
13523
13523
  })
13524
13524
  ),
13525
13525
  service: service ? {
@@ -13864,9 +13864,9 @@ var DrispClient = class _DrispClient {
13864
13864
  if (!match) throw new Error("invalid_hub_url");
13865
13865
  return new _DrispClient(url.origin, decodeURIComponent(match[1]), async () => token);
13866
13866
  }
13867
- async request(path11, body) {
13867
+ async request(path12, body) {
13868
13868
  const response = await fetch(
13869
- `${this.baseUrl}/v2/orgs/${encodeURIComponent(this.orgId)}${path11}`,
13869
+ `${this.baseUrl}/v2/orgs/${encodeURIComponent(this.orgId)}${path12}`,
13870
13870
  {
13871
13871
  method: body === void 0 ? "GET" : "POST",
13872
13872
  headers: {
@@ -14362,21 +14362,15 @@ function assessTick(facts) {
14362
14362
  }).length;
14363
14363
  const queue = [];
14364
14364
  if (!parkReason) {
14365
- let capped = Object.values(state.attempts).flat().reduce(
14366
- (sum, attempt) => sum + attemptCost({
14367
- tokenCap: attempt.tokenCap,
14368
- closed: views.get(attempt.runId)?.closed === true
14369
- }),
14370
- 0
14371
- );
14365
+ let committed = Object.values(state.attempts).flat().reduce((sum, attempt) => sum + forecastOfCap(attempt.tokenCap), 0);
14372
14366
  for (const entry of entries) {
14373
14367
  if (status.get(entry.id) !== "ready") continue;
14374
- if (capped + entry.tokenCap > facts.limits.tokenBudget) {
14368
+ if (committed + forecastOfCap(entry.tokenCap) > facts.limits.tokenBudget) {
14375
14369
  parkReason = "budget";
14376
14370
  break;
14377
14371
  }
14378
14372
  queue.push(entry);
14379
- capped += entry.tokenCap;
14373
+ committed += forecastOfCap(entry.tokenCap);
14380
14374
  }
14381
14375
  }
14382
14376
  return {
@@ -14535,7 +14529,11 @@ async function runBuildTick(deps) {
14535
14529
  state: stored,
14536
14530
  children: children.runs,
14537
14531
  templateVersion,
14538
- limits: buildLimits(ORCHESTRATOR_LIMITS, parent.delegation),
14532
+ // The approved plan's budget (the member's, once it is editable) narrowed by what the Hub enforces.
14533
+ limits: buildLimits(
14534
+ { ...ORCHESTRATOR_LIMITS, tokenBudget: plan.budget.tokenBudget },
14535
+ parent.delegation
14536
+ ),
14539
14537
  pullRequests: (branch) => deps.pullRequests(deps.folder, branch),
14540
14538
  locate: (entry) => locate(deps, entry, issues.get(entry.id)?.branchName),
14541
14539
  rebaseFailed: deps.rebaseFailed ?? [],
@@ -14760,16 +14758,73 @@ function runBuildStep(input) {
14760
14758
  return artifact;
14761
14759
  }
14762
14760
 
14761
+ // src/core/build/merged.ts
14762
+ import fs9 from "fs";
14763
+ import path9 from "path";
14764
+ var pullRequestArtifactSchema = external_exports.strictObject({
14765
+ url: external_exports.url(),
14766
+ number: external_exports.number().int().positive(),
14767
+ sha: external_exports.string().regex(/^[0-9a-f]{40}$/),
14768
+ mergedAt: external_exports.iso.datetime()
14769
+ });
14770
+ function runBuildMerged(input) {
14771
+ const directory = requireEnv(input.env, "DRISP_RUN_ARTIFACTS");
14772
+ if (!fs9.statSync(directory, { throwIfNoEntry: false })?.isDirectory())
14773
+ throw new BuildUsageError(
14774
+ `DRISP_RUN_ARTIFACTS (${directory}) is not a directory.`
14775
+ );
14776
+ let view;
14777
+ try {
14778
+ view = JSON.parse(
14779
+ input.gh(
14780
+ [
14781
+ "pr",
14782
+ "view",
14783
+ ...input.pullRequest ? [input.pullRequest] : [],
14784
+ "--json",
14785
+ "state,url,number,mergeCommit,mergedAt"
14786
+ ],
14787
+ input.cwd
14788
+ )
14789
+ );
14790
+ } catch {
14791
+ throw new BuildUsageError("gh pr view did not report this pull request.");
14792
+ }
14793
+ if (view.state !== "MERGED")
14794
+ throw new BuildUsageError(
14795
+ `This pull request is not merged (state ${String(view.state)}).`
14796
+ );
14797
+ const parsed = pullRequestArtifactSchema.safeParse({
14798
+ url: view.url,
14799
+ number: view.number,
14800
+ sha: view.mergeCommit?.oid,
14801
+ mergedAt: view.mergedAt
14802
+ });
14803
+ if (!parsed.success)
14804
+ throw new BuildUsageError(
14805
+ `The merged pull request has a bad shape: ${parsed.error.issues.map((issue) => issue.path.join(".")).join(", ")}.`
14806
+ );
14807
+ fs9.writeFileSync(
14808
+ path9.join(directory, "pull_request.json"),
14809
+ `${JSON.stringify(parsed.data)}
14810
+ `
14811
+ );
14812
+ return parsed.data;
14813
+ }
14814
+
14763
14815
  // src/app/entry/buildCommand.ts
14764
14816
  var USAGE3 = `Usage: drisp build plan --input <path>
14765
14817
  drisp build tick --input <path> [--rebase-failed <IDENTIFIER>]...
14766
14818
  drisp build checks
14767
14819
  drisp build step <n> [--qa none|web|macos]
14820
+ drisp build merged [<pr url or number>]
14768
14821
  plan and tick run inside an Orchestrator Run (DRISP_RUN_ID, DRISP_RUNNER_ID and DRISP_RUN_ARTIFACTS set; tick also
14769
14822
  DRISP_RUN_TOKEN and DRISP_HUB_URL). DRISP_BUILD_PLAN_INPUT=<path> stands in for plan's --input, with
14770
14823
  fills/<IDENTIFIER>.json beside it. checks runs in a child's worktree: the merge gate's verdict on HEAD's GitHub runs.
14771
14824
  step runs in any Run with DRISP_RUN_ARTIFACTS set: it writes the step artifact {index, title, total} for gate <n> of the
14772
- build-child template (QA is a gate unless --qa none) and refuses an index outside the list.`;
14825
+ build-child template (QA is a gate unless --qa none) and refuses an index outside the list.
14826
+ merged runs in a child's worktree after its pull request merged: it writes the pull_request artifact
14827
+ {url, number, sha, mergedAt} and refuses a pull request that is not merged.`;
14773
14828
  function githubPullRequests(folder, branch) {
14774
14829
  const output = execFileSync(
14775
14830
  "gh",
@@ -14887,6 +14942,14 @@ async function runBuildCommand(input) {
14887
14942
  case "checks":
14888
14943
  output = runBuildChecks(input.cwd, input.checks ?? defaultChecks);
14889
14944
  break;
14945
+ case "merged":
14946
+ output = runBuildMerged({
14947
+ env: env2,
14948
+ cwd: input.cwd,
14949
+ ...input.positional?.[0] ? { pullRequest: input.positional[0] } : {},
14950
+ gh: (input.checks ?? defaultChecks).gh
14951
+ });
14952
+ break;
14890
14953
  case "step":
14891
14954
  output = runBuildStep({
14892
14955
  env: env2,
@@ -14916,9 +14979,9 @@ import process7 from "process";
14916
14979
 
14917
14980
  // src/harnesses/claude/system/doctorEnvironment.ts
14918
14981
  import { execFileSync as execFileSync2 } from "child_process";
14919
- import * as fs9 from "fs";
14982
+ import * as fs10 from "fs";
14920
14983
  import * as os4 from "os";
14921
- import * as path9 from "path";
14984
+ import * as path10 from "path";
14922
14985
  var MANAGED_POLICY_KEYS = [
14923
14986
  "forceLoginMethod",
14924
14987
  "forceLoginOrgUUID",
@@ -15022,8 +15085,8 @@ function collectEnvironment(options = {}) {
15022
15085
  const detectVersion = options.detectClaudeVersionFn ?? detectClaudeVersion;
15023
15086
  const runAuthStatus = options.runClaudeAuthStatusFn ?? runClaudeAuthStatus;
15024
15087
  const resolveForwarder = options.resolveHookForwarderCommandFn ?? resolveHookForwarderCommand;
15025
- const statFn = options.statFn ?? ((p) => fs9.statSync(p));
15026
- const readFileFn = options.readFileFn ?? ((p) => fs9.readFileSync(p, "utf8"));
15088
+ const statFn = options.statFn ?? ((p) => fs10.statSync(p));
15089
+ const readFileFn = options.readFileFn ?? ((p) => fs10.readFileSync(p, "utf8"));
15027
15090
  const settingsPaths = resolveClaudeSettingsSurfacePaths(
15028
15091
  homeDir,
15029
15092
  cwd,
@@ -15068,7 +15131,7 @@ function collectEnvironment(options = {}) {
15068
15131
  });
15069
15132
  let globalConfigPresent = false;
15070
15133
  try {
15071
- statFn(path9.join(homeDir, ".claude.json"));
15134
+ statFn(path10.join(homeDir, ".claude.json"));
15072
15135
  globalConfigPresent = true;
15073
15136
  } catch {
15074
15137
  globalConfigPresent = false;
@@ -15548,13 +15611,13 @@ function runRunsCommand(input) {
15548
15611
  // src/app/entry/cli.tsx
15549
15612
  import { jsx as jsx24 } from "react/jsx-runtime";
15550
15613
  function resolvePackageJsonPath(entryUrl) {
15551
- let currentDir = path10.dirname(fileURLToPath(entryUrl));
15614
+ let currentDir = path11.dirname(fileURLToPath(entryUrl));
15552
15615
  for (; ; ) {
15553
- const candidatePath = path10.join(currentDir, "package.json");
15554
- if (fs10.existsSync(candidatePath)) {
15616
+ const candidatePath = path11.join(currentDir, "package.json");
15617
+ if (fs11.existsSync(candidatePath)) {
15555
15618
  return candidatePath;
15556
15619
  }
15557
- const parentDir = path10.dirname(currentDir);
15620
+ const parentDir = path11.dirname(currentDir);
15558
15621
  if (parentDir === currentDir) {
15559
15622
  throw new Error("Could not locate package.json for CLI metadata.");
15560
15623
  }
@@ -15727,6 +15790,7 @@ var cli = meow(
15727
15790
  build tick --input <path> Run one step of a started Build (prints the next action; [--rebase-failed <ID>]...)
15728
15791
  build checks The merge gate's verdict on HEAD's GitHub runs (in a child's worktree)
15729
15792
  build step <n> Report the Run's current step: writes the step run artifact ([--qa none|web|macos])
15793
+ build merged Record the merged pull request: writes the pull_request run artifact
15730
15794
  telemetry [action] Manage anonymous telemetry (enable/disable/status)
15731
15795
  doctor Diagnose Claude headless setup (use with --harness=claude)
15732
15796
 
@@ -15906,7 +15970,7 @@ var cli = meow(
15906
15970
  }
15907
15971
  );
15908
15972
  async function main() {
15909
- const projectDir = path10.resolve(cli.flags.projectDir);
15973
+ const projectDir = path11.resolve(cli.flags.projectDir);
15910
15974
  const [command, ...commandArgs] = cli.input;
15911
15975
  const isRunCommand = command === "run" || command === "exec";
15912
15976
  if (command && !KNOWN_COMMANDS.has(command)) {
@@ -15960,7 +16024,7 @@ Available commands: ${[...KNOWN_COMMANDS].join(", ")}`
15960
16024
  await exitWith(1);
15961
16025
  return;
15962
16026
  }
15963
- const { default: WorkflowInstallWizard } = await import("./WorkflowInstallWizard-AJYDKFDL.js");
16027
+ const { default: WorkflowInstallWizard } = await import("./WorkflowInstallWizard-YANLNMTP.js");
15964
16028
  const { waitUntilExit } = render(
15965
16029
  /* @__PURE__ */ jsx24(
15966
16030
  WorkflowInstallWizard,
@@ -16127,8 +16191,8 @@ Available commands: ${[...KNOWN_COMMANDS].join(", ")}`
16127
16191
  const showSetup = isRunCommand ? false : shouldShowSetup({
16128
16192
  cliInput: cli.input,
16129
16193
  setupComplete: globalConfig.setupComplete,
16130
- globalConfigExists: fs10.existsSync(
16131
- path10.join(os5.homedir(), ".config", "athena", "config.json")
16194
+ globalConfigExists: fs11.existsSync(
16195
+ path11.join(os5.homedir(), ".config", "athena", "config.json")
16132
16196
  )
16133
16197
  });
16134
16198
  let runtimeConfig;
@@ -1,6 +1,6 @@
1
- import "./chunk-F6XUMTMC.js";
2
- import "./chunk-XG7B4OOC.js";
1
+ import "./chunk-Y6XJPUR2.js";
2
+ import "./chunk-2N7IBKJF.js";
3
3
  import "./chunk-PQIB66SG.js";
4
- import "./chunk-TSIMXPJN.js";
4
+ import "./chunk-W57EQYCM.js";
5
5
  import "./chunk-G3PMV62Z.js";
6
6
  //# sourceMappingURL=dashboard-daemon.js.map
package/dist/runner.js CHANGED
@@ -1,6 +1,6 @@
1
- import "./chunk-F6XUMTMC.js";
2
- import "./chunk-XG7B4OOC.js";
1
+ import "./chunk-Y6XJPUR2.js";
2
+ import "./chunk-2N7IBKJF.js";
3
3
  import "./chunk-PQIB66SG.js";
4
- import "./chunk-TSIMXPJN.js";
4
+ import "./chunk-W57EQYCM.js";
5
5
  import "./chunk-G3PMV62Z.js";
6
6
  //# sourceMappingURL=runner.js.map
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "hooks",
18
18
  "dashboard"
19
19
  ],
20
- "version": "0.7.4",
20
+ "version": "0.7.6",
21
21
  "license": "MIT",
22
22
  "bin": {
23
23
  "athena": "dist/cli.js",