@codions/portta 0.0.0-develop.149.sha-240655c → 0.0.0-develop.150.sha-ed65081

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/host.js CHANGED
@@ -23429,17 +23429,17 @@ var init_json_schema_processors = __esm({
23429
23429
  minItems--;
23430
23430
  }
23431
23431
  const maxItems = def.items.length;
23432
- const isClosed = !def.rest;
23432
+ const isClosed2 = !def.rest;
23433
23433
  if (ctx.target === "draft-2020-12") {
23434
23434
  json3.prefixItems = prefixItems;
23435
- if (isClosed) {
23435
+ if (isClosed2) {
23436
23436
  json3.items = false;
23437
23437
  } else if (rest) {
23438
23438
  json3.items = rest;
23439
23439
  }
23440
23440
  if (minItems > 0)
23441
23441
  json3.minItems = minItems;
23442
- if (isClosed)
23442
+ if (isClosed2)
23443
23443
  json3.maxItems = maxItems;
23444
23444
  } else if (ctx.target === "openapi-3.0") {
23445
23445
  json3.items = {
@@ -23450,18 +23450,18 @@ var init_json_schema_processors = __esm({
23450
23450
  }
23451
23451
  if (minItems > 0)
23452
23452
  json3.minItems = minItems;
23453
- if (isClosed)
23453
+ if (isClosed2)
23454
23454
  json3.maxItems = maxItems;
23455
23455
  } else {
23456
23456
  json3.items = prefixItems;
23457
- if (isClosed) {
23457
+ if (isClosed2) {
23458
23458
  json3.additionalItems = false;
23459
23459
  } else if (rest) {
23460
23460
  json3.additionalItems = rest;
23461
23461
  }
23462
23462
  if (minItems > 0)
23463
23463
  json3.minItems = minItems;
23464
- if (isClosed)
23464
+ if (isClosed2)
23465
23465
  json3.maxItems = maxItems;
23466
23466
  }
23467
23467
  const { minimum, maximum } = schema._zod.bag;
@@ -34015,17 +34015,17 @@ var require_fast_uri = __commonJS({
34015
34015
  if (baseMalformed || relativeMalformed || baseMalformedPercentEncoding || relativeMalformedPercentEncoding || baseMalformedSchemeSpecific || relativeMalformedSchemeSpecific || baseMalformedHost || relativeMalformedHost || baseMalformedScheme || relativeMalformedScheme) {
34016
34016
  throw new Error(baseParsed.error || relativeParsed.error || "URI is malformed.");
34017
34017
  }
34018
- const resolved = resolveComponent(baseParsed, relativeParsed, schemelessOptions, true);
34019
- const resolvedSchemeHandler = getSchemeHandler(options && options.scheme || resolved.scheme);
34020
- const resolvedHost = resolved.host;
34018
+ const resolved2 = resolveComponent(baseParsed, relativeParsed, schemelessOptions, true);
34019
+ const resolvedSchemeHandler = getSchemeHandler(options && options.scheme || resolved2.scheme);
34020
+ const resolvedHost = resolved2.host;
34021
34021
  const resolvedHostIsIP = resolvedHost !== void 0 && resolvedHost !== "" && (isIPv4(resolvedHost) || normalizeIPv6(resolvedHost).isIPV6);
34022
- canonicalizeHost(resolved, options || {}, resolvedSchemeHandler, resolvedHostIsIP);
34022
+ canonicalizeHost(resolved2, options || {}, resolvedSchemeHandler, resolvedHostIsIP);
34023
34023
  const encodedASCIIHost = resolvedHost && resolvedHost.indexOf("%") !== -1 && !new RegExp("\\P{ASCII}", "u").test(resolvedHost);
34024
- if (resolved.error && !encodedASCIIHost) {
34025
- throw new Error(resolved.error);
34024
+ if (resolved2.error && !encodedASCIIHost) {
34025
+ throw new Error(resolved2.error);
34026
34026
  }
34027
34027
  schemelessOptions.skipEscape = true;
34028
- return serialize2(resolved, schemelessOptions);
34028
+ return serialize2(resolved2, schemelessOptions);
34029
34029
  }
34030
34030
  function resolveComponent(base, relative5, options, skipNormalization) {
34031
34031
  const target = {};
@@ -43704,8 +43704,8 @@ function convertBaseSchema(schema, ctx) {
43704
43704
  });
43705
43705
  }
43706
43706
  ctx.processing.add(refPath);
43707
- const resolved = resolveRef(refPath, ctx);
43708
- const zodSchema2 = convertSchema(resolved, ctx);
43707
+ const resolved2 = resolveRef(refPath, ctx);
43708
+ const zodSchema2 = convertSchema(resolved2, ctx);
43709
43709
  ctx.refs.set(refPath, zodSchema2);
43710
43710
  ctx.processing.delete(refPath);
43711
43711
  return zodSchema2;
@@ -44576,8 +44576,8 @@ function createHostShellPathRefresher(options = {}) {
44576
44576
  if (pending) return pending;
44577
44577
  if (expiresAt > now()) return Promise.resolve({ changed: false, path });
44578
44578
  pending = (async () => {
44579
- const resolved = await resolvePath();
44580
- const next = resolved ? mergePaths(path, resolved) : path;
44579
+ const resolved2 = await resolvePath();
44580
+ const next = resolved2 ? mergePaths(path, resolved2) : path;
44581
44581
  const changed = next !== path;
44582
44582
  path = next;
44583
44583
  if (path) env2.PATH = path;
@@ -44771,8 +44771,8 @@ function resolveHostTool(tool, options) {
44771
44771
  return defaultHostToolResolver()(tool);
44772
44772
  }
44773
44773
  function hostToolInvocation(tool, options) {
44774
- const resolved = resolveHostTool(tool, options) ?? tool;
44775
- return /[\s'"\\]/.test(resolved) ? `'${resolved.replaceAll("'", "'\\''")}'` : resolved;
44774
+ const resolved2 = resolveHostTool(tool, options) ?? tool;
44775
+ return /[\s'"\\]/.test(resolved2) ? `'${resolved2.replaceAll("'", "'\\''")}'` : resolved2;
44776
44776
  }
44777
44777
  function resolveWorkerBins(env2 = process.env) {
44778
44778
  const resolve21 = (name, override) => {
@@ -48278,9 +48278,9 @@ function sanitizeNameSegment(value, maxLength = 24) {
48278
48278
  return trimmed || "x";
48279
48279
  }
48280
48280
  function buildProjectSessionName(projectRoot2) {
48281
- const resolved = resolve4(projectRoot2);
48282
- const base = sanitizeNameSegment(basename2(resolved), 18);
48283
- const hash4 = createHash5("sha1").update(resolved).digest("hex").slice(0, 8);
48281
+ const resolved2 = resolve4(projectRoot2);
48282
+ const base = sanitizeNameSegment(basename2(resolved2), 18);
48283
+ const hash4 = createHash5("sha1").update(resolved2).digest("hex").slice(0, 8);
48284
48284
  return `${RUNTIME_IDENTITY.tmuxPrefix}-${base}-${hash4}`;
48285
48285
  }
48286
48286
  function buildWorktreeWindowName(branch) {
@@ -48768,12 +48768,12 @@ import { spawnSync as spawnSync4 } from "node:child_process";
48768
48768
  import { readdirSync, realpathSync, rmSync, statSync as statSync3 } from "node:fs";
48769
48769
  import { basename as basename3, dirname as dirname7, join as join6, resolve as resolve6 } from "node:path";
48770
48770
  function canonicalizeFsPath(input2) {
48771
- const resolved = resolve6(input2);
48771
+ const resolved2 = resolve6(input2);
48772
48772
  try {
48773
- return realpathSync(resolved);
48773
+ return realpathSync(resolved2);
48774
48774
  } catch {
48775
48775
  const missing = [];
48776
- let current = resolved;
48776
+ let current = resolved2;
48777
48777
  while (current !== dirname7(current)) {
48778
48778
  missing.unshift(basename3(current));
48779
48779
  current = dirname7(current);
@@ -48782,7 +48782,7 @@ function canonicalizeFsPath(input2) {
48782
48782
  } catch {
48783
48783
  }
48784
48784
  }
48785
- return resolved;
48785
+ return resolved2;
48786
48786
  }
48787
48787
  }
48788
48788
  function sameFsPath(left, right) {
@@ -49124,20 +49124,20 @@ function loadProjectAllowlist(options = {}) {
49124
49124
  return [...new Set(roots.map((root) => canonicalizeFsPath(root)))];
49125
49125
  }
49126
49126
  function isPathInsideAllowlist(candidate, allowlist) {
49127
- const resolved = canonicalizeFsPath(candidate);
49127
+ const resolved2 = canonicalizeFsPath(candidate);
49128
49128
  return allowlist.some((root) => {
49129
49129
  const canonicalRoot = canonicalizeFsPath(root);
49130
- if (resolved === canonicalRoot) return true;
49130
+ if (resolved2 === canonicalRoot) return true;
49131
49131
  const prefix = canonicalRoot.endsWith("/") ? canonicalRoot : `${canonicalRoot}/`;
49132
- return resolved.startsWith(prefix);
49132
+ return resolved2.startsWith(prefix);
49133
49133
  });
49134
49134
  }
49135
49135
  function assertProjectRootAllowed(candidate, allowlist) {
49136
- const resolved = canonicalizeFsPath(candidate);
49137
- if (!isPathInsideAllowlist(resolved, allowlist)) {
49138
- throw new ProjectAllowlistError(`Project root is outside the configured allowlist: ${resolved}`);
49136
+ const resolved2 = canonicalizeFsPath(candidate);
49137
+ if (!isPathInsideAllowlist(resolved2, allowlist)) {
49138
+ throw new ProjectAllowlistError(`Project root is outside the configured allowlist: ${resolved2}`);
49139
49139
  }
49140
- return resolved;
49140
+ return resolved2;
49141
49141
  }
49142
49142
  function registerableProjectRoot(inputPath, deps) {
49143
49143
  const trimmed = inputPath.trim();
@@ -52328,8 +52328,8 @@ var LifecycleService = class {
52328
52328
  }
52329
52329
  async openWorktree(branch, options = {}) {
52330
52330
  try {
52331
- const resolved = await this.resolveExistingWorktree(branch);
52332
- let initialized = resolved.meta ? await this.refreshManagedArtifacts(resolved) : await this.initializeUnmanagedWorktree(resolved);
52331
+ const resolved2 = await this.resolveExistingWorktree(branch);
52332
+ let initialized = resolved2.meta ? await this.refreshManagedArtifacts(resolved2) : await this.initializeUnmanagedWorktree(resolved2);
52333
52333
  const { profileName, profile } = this.resolveProfile(initialized.meta.profile);
52334
52334
  const agent = this.resolveAgentDefinition(initialized.meta.agent);
52335
52335
  const interfaceMode = this.resolveInterfaceMode(
@@ -52346,11 +52346,11 @@ var LifecycleService = class {
52346
52346
  await writeWorktreeMeta(initialized.paths.gitDir, nextMeta);
52347
52347
  initialized = { ...initialized, meta: nextMeta };
52348
52348
  }
52349
- const launchMode = resolved.meta && agent.capabilities.resume ? "resume" : "fresh";
52349
+ const launchMode = resolved2.meta && agent.capabilities.resume ? "resume" : "fresh";
52350
52350
  const resumeConversationId = resolveCodexResumeConversationId(initialized.meta, agent, launchMode);
52351
52351
  await ensureAgentRuntimeArtifacts({
52352
52352
  gitDir: initialized.paths.gitDir,
52353
- worktreePath: resolved.entry.path
52353
+ worktreePath: resolved2.entry.path
52354
52354
  });
52355
52355
  await this.materializeRuntimeSession({
52356
52356
  branch,
@@ -52358,7 +52358,7 @@ var LifecycleService = class {
52358
52358
  profile,
52359
52359
  agent,
52360
52360
  initialized,
52361
- worktreePath: resolved.entry.path,
52361
+ worktreePath: resolved2.entry.path,
52362
52362
  launchMode,
52363
52363
  followUpPrompt: options.prompt,
52364
52364
  source: options.oneshot ? "oneshot" : initialized.meta.source,
@@ -52366,7 +52366,7 @@ var LifecycleService = class {
52366
52366
  interfaceMode
52367
52367
  });
52368
52368
  if (initialized.meta.agentTerminalStale === true) {
52369
- await writeWorktreeMeta(resolved.gitDir, {
52369
+ await writeWorktreeMeta(resolved2.gitDir, {
52370
52370
  ...initialized.meta,
52371
52371
  agentTerminalStale: false
52372
52372
  });
@@ -52374,8 +52374,8 @@ var LifecycleService = class {
52374
52374
  if (interfaceMode === "terminal") {
52375
52375
  await this.restoreWorktreeTabs({
52376
52376
  branch,
52377
- gitDir: resolved.gitDir,
52378
- worktreePath: resolved.entry.path,
52377
+ gitDir: resolved2.gitDir,
52378
+ worktreePath: resolved2.entry.path,
52379
52379
  profile,
52380
52380
  profileName,
52381
52381
  agent,
@@ -52393,11 +52393,11 @@ var LifecycleService = class {
52393
52393
  }
52394
52394
  async refreshAgentTerminal(branch) {
52395
52395
  try {
52396
- const resolved = await this.resolveExistingWorktree(branch);
52397
- if (!resolved.meta) {
52396
+ const resolved2 = await this.resolveExistingWorktree(branch);
52397
+ if (!resolved2.meta) {
52398
52398
  throw new LifecycleError(`Worktree ${branch} has no managed metadata to refresh`, 409);
52399
52399
  }
52400
- const initialized = await this.refreshManagedArtifacts(resolved);
52400
+ const initialized = await this.refreshManagedArtifacts(resolved2);
52401
52401
  const { profileName, profile } = this.resolveProfile(initialized.meta.profile);
52402
52402
  const agent = this.resolveAgentDefinition(initialized.meta.agent);
52403
52403
  if (agent.kind !== "builtin" || agent.implementation.agent !== "codex" && agent.implementation.agent !== "claude") {
@@ -52416,8 +52416,8 @@ var LifecycleService = class {
52416
52416
  resumeConversationId = await this.ensureRootSessionId({
52417
52417
  meta: initialized.meta,
52418
52418
  agentKind: agent.implementation.agent,
52419
- worktreePath: resolved.entry.path,
52420
- resolved
52419
+ worktreePath: resolved2.entry.path,
52420
+ resolved: resolved2
52421
52421
  });
52422
52422
  if (!resumeConversationId) {
52423
52423
  throw new LifecycleError(`No ${agent.label} conversation is available to refresh`, 409);
@@ -52425,7 +52425,7 @@ var LifecycleService = class {
52425
52425
  }
52426
52426
  await ensureAgentRuntimeArtifacts({
52427
52427
  gitDir: initialized.paths.gitDir,
52428
- worktreePath: resolved.entry.path
52428
+ worktreePath: resolved2.entry.path
52429
52429
  });
52430
52430
  await this.materializeRuntimeSession({
52431
52431
  branch,
@@ -52433,19 +52433,19 @@ var LifecycleService = class {
52433
52433
  profile,
52434
52434
  agent,
52435
52435
  initialized,
52436
- worktreePath: resolved.entry.path,
52436
+ worktreePath: resolved2.entry.path,
52437
52437
  launchMode: "resume",
52438
52438
  resumeConversationId
52439
52439
  });
52440
- const refreshedMeta = await this.readMetaOrThrow(resolved.gitDir);
52441
- await writeWorktreeMeta(resolved.gitDir, {
52440
+ const refreshedMeta = await this.readMetaOrThrow(resolved2.gitDir);
52441
+ await writeWorktreeMeta(resolved2.gitDir, {
52442
52442
  ...refreshedMeta,
52443
52443
  agentTerminalStale: false
52444
52444
  });
52445
52445
  await this.restoreWorktreeTabs({
52446
52446
  branch,
52447
- gitDir: resolved.gitDir,
52448
- worktreePath: resolved.entry.path,
52447
+ gitDir: resolved2.gitDir,
52448
+ worktreePath: resolved2.entry.path,
52449
52449
  profile,
52450
52450
  profileName,
52451
52451
  agent,
@@ -52550,27 +52550,27 @@ var LifecycleService = class {
52550
52550
  return meta3;
52551
52551
  }
52552
52552
  async prepareTabContext(branch) {
52553
- const resolved = await this.resolveExistingWorktree(branch);
52554
- if (!resolved.meta) throw new LifecycleError(`Worktree ${branch} has no managed metadata`, 409);
52553
+ const resolved2 = await this.resolveExistingWorktree(branch);
52554
+ if (!resolved2.meta) throw new LifecycleError(`Worktree ${branch} has no managed metadata`, 409);
52555
52555
  const sessionName = buildProjectSessionName(this.deps.projectRoot);
52556
52556
  const windowName = buildWorktreeWindowName(branch);
52557
52557
  if (!await this.deps.sessions.hasWindow(sessionName, windowName)) {
52558
52558
  throw new LifecycleError(`Worktree ${branch} is not open`, 409);
52559
52559
  }
52560
- const { profileName, profile } = this.resolveProfile(resolved.meta.profile);
52560
+ const { profileName, profile } = this.resolveProfile(resolved2.meta.profile);
52561
52561
  if (profile.runtime === "docker") {
52562
52562
  throw new LifecycleError("Tabs are not supported for Docker worktrees", 409);
52563
52563
  }
52564
- const agent = this.resolveAgentDefinition(resolved.meta.agent);
52564
+ const agent = this.resolveAgentDefinition(resolved2.meta.agent);
52565
52565
  if (agent.kind !== "builtin") {
52566
52566
  throw new LifecycleError("Tabs are only available for the built-in Claude and Codex agents", 409);
52567
52567
  }
52568
- const initialized = await this.refreshManagedArtifacts(resolved);
52568
+ const initialized = await this.refreshManagedArtifacts(resolved2);
52569
52569
  return {
52570
- resolved,
52570
+ resolved: resolved2,
52571
52571
  initialized,
52572
52572
  meta: initialized.meta,
52573
- worktreePath: resolved.entry.path,
52573
+ worktreePath: resolved2.entry.path,
52574
52574
  agent,
52575
52575
  agentKind: agent.implementation.agent,
52576
52576
  profile,
@@ -52644,16 +52644,16 @@ var LifecycleService = class {
52644
52644
  * Idempotent: returns true when armed state was cleared, false otherwise.
52645
52645
  * The server-side oneshot watcher calls this on any browser-originated interaction. */
52646
52646
  async disarmOneshot(branch) {
52647
- let resolved;
52647
+ let resolved2;
52648
52648
  try {
52649
- resolved = await this.resolveExistingWorktree(branch);
52649
+ resolved2 = await this.resolveExistingWorktree(branch);
52650
52650
  } catch {
52651
52651
  return false;
52652
52652
  }
52653
- if (!resolved.meta?.oneshot) return false;
52654
- const nextMeta = { ...resolved.meta };
52653
+ if (!resolved2.meta?.oneshot) return false;
52654
+ const nextMeta = { ...resolved2.meta };
52655
52655
  delete nextMeta.oneshot;
52656
- await writeWorktreeMeta(resolved.gitDir, nextMeta);
52656
+ await writeWorktreeMeta(resolved2.gitDir, nextMeta);
52657
52657
  return true;
52658
52658
  }
52659
52659
  async closeWorktree(branch) {
@@ -52666,8 +52666,8 @@ var LifecycleService = class {
52666
52666
  }
52667
52667
  async removeWorktree(branch) {
52668
52668
  try {
52669
- const resolved = await this.resolveExistingWorktree(branch);
52670
- await this.removeResolvedWorktree(resolved);
52669
+ const resolved2 = await this.resolveExistingWorktree(branch);
52670
+ await this.removeResolvedWorktree(resolved2);
52671
52671
  } catch (error61) {
52672
52672
  throw this.wrapOperationError(error61);
52673
52673
  }
@@ -52677,12 +52677,12 @@ var LifecycleService = class {
52677
52677
  const resolvedWorktrees = await this.resolveAllWorktrees();
52678
52678
  const sessionName = buildProjectSessionName(this.deps.projectRoot);
52679
52679
  const removedBranches = [];
52680
- for (const resolved of resolvedWorktrees) {
52681
- const branch = resolved.entry.branch ?? resolved.entry.path;
52680
+ for (const resolved2 of resolvedWorktrees) {
52681
+ const branch = resolved2.entry.branch ?? resolved2.entry.path;
52682
52682
  if (await this.deps.sessions.hasWindow(sessionName, buildWorktreeWindowName(branch))) {
52683
52683
  continue;
52684
52684
  }
52685
- await this.removeResolvedWorktree(resolved);
52685
+ await this.removeResolvedWorktree(resolved2);
52686
52686
  removedBranches.push(branch);
52687
52687
  }
52688
52688
  return { removedBranches };
@@ -52692,8 +52692,8 @@ var LifecycleService = class {
52692
52692
  }
52693
52693
  async mergeWorktree(branch) {
52694
52694
  try {
52695
- const resolved = await this.resolveExistingWorktree(branch);
52696
- this.ensureNoUncommittedChanges(resolved.entry);
52695
+ const resolved2 = await this.resolveExistingWorktree(branch);
52696
+ this.ensureNoUncommittedChanges(resolved2.entry);
52697
52697
  mergeManagedWorktree(
52698
52698
  {
52699
52699
  repoRoot: this.deps.projectRoot,
@@ -52703,7 +52703,7 @@ var LifecycleService = class {
52703
52703
  this.deps.git
52704
52704
  );
52705
52705
  try {
52706
- await this.removeResolvedWorktree(resolved);
52706
+ await this.removeResolvedWorktree(resolved2);
52707
52707
  } catch (error61) {
52708
52708
  throw new LifecycleError(
52709
52709
  `Merged ${branch} into ${this.deps.config.workspace.mainBranch} but cleanup failed: ${toErrorMessage2(error61)}`,
@@ -52716,11 +52716,11 @@ var LifecycleService = class {
52716
52716
  }
52717
52717
  async setWorktreeArchived(branch, archived) {
52718
52718
  try {
52719
- const resolved = await this.resolveExistingWorktree(branch);
52719
+ const resolved2 = await this.resolveExistingWorktree(branch);
52720
52720
  if (archived) {
52721
52721
  await this.closeBranchWindow(branch);
52722
52722
  }
52723
- await this.updateWorktreeArchivedState(resolved.entry.path, archived);
52723
+ await this.updateWorktreeArchivedState(resolved2.entry.path, archived);
52724
52724
  } catch (error61) {
52725
52725
  throw this.wrapOperationError(error61);
52726
52726
  }
@@ -52728,12 +52728,12 @@ var LifecycleService = class {
52728
52728
  async setWorktreeLabel(branch, label) {
52729
52729
  try {
52730
52730
  const normalizedLabel = normalizeWorktreeLabel(label);
52731
- const resolved = await this.resolveExistingWorktree(branch);
52732
- if (!resolved.meta) {
52731
+ const resolved2 = await this.resolveExistingWorktree(branch);
52732
+ if (!resolved2.meta) {
52733
52733
  throw new LifecycleError(`Worktree ${branch} has no managed metadata to label`, 409);
52734
52734
  }
52735
- const nextMeta = this.withUpdatedLabel(resolved.meta, normalizedLabel);
52736
- await writeWorktreeMeta(resolved.gitDir, nextMeta);
52735
+ const nextMeta = this.withUpdatedLabel(resolved2.meta, normalizedLabel);
52736
+ await writeWorktreeMeta(resolved2.gitDir, nextMeta);
52737
52737
  await this.deps.reconciliation.reconcile(this.deps.projectRoot, { force: true });
52738
52738
  return { label: normalizedLabel };
52739
52739
  } catch (error61) {
@@ -52745,20 +52745,20 @@ var LifecycleService = class {
52745
52745
  * conversation); when it is closed the new profile applies on the next open. */
52746
52746
  async setWorktreeProfile(branch, profileName) {
52747
52747
  try {
52748
- const resolved = await this.resolveExistingWorktree(branch);
52749
- if (!resolved.meta) {
52748
+ const resolved2 = await this.resolveExistingWorktree(branch);
52749
+ if (!resolved2.meta) {
52750
52750
  throw new LifecycleError(`Worktree ${branch} has no managed metadata to reprofile`, 409);
52751
52751
  }
52752
52752
  const { profileName: nextProfileName, profile } = this.resolveProfile(profileName);
52753
52753
  const wasOpen = await isWorktreeOpen(this.deps.sessions, this.deps.projectRoot, branch);
52754
- if (resolved.meta.profile === nextProfileName) {
52754
+ if (resolved2.meta.profile === nextProfileName) {
52755
52755
  return { profile: nextProfileName, restarted: false };
52756
52756
  }
52757
- if (resolved.meta.runtime === "docker") {
52757
+ if (resolved2.meta.runtime === "docker") {
52758
52758
  await this.deps.docker.removeContainer(branch);
52759
52759
  }
52760
- await writeWorktreeMeta(resolved.gitDir, {
52761
- ...resolved.meta,
52760
+ await writeWorktreeMeta(resolved2.gitDir, {
52761
+ ...resolved2.meta,
52762
52762
  profile: nextProfileName,
52763
52763
  runtime: profile.runtime
52764
52764
  });
@@ -52942,30 +52942,30 @@ var LifecycleService = class {
52942
52942
  })
52943
52943
  );
52944
52944
  }
52945
- async initializeUnmanagedWorktree(resolved) {
52945
+ async initializeUnmanagedWorktree(resolved2) {
52946
52946
  const { profileName, profile } = this.resolveProfile(void 0);
52947
- const dotenvValues = await loadDotenvLocal(resolved.entry.path);
52947
+ const dotenvValues = await loadDotenvLocal(resolved2.entry.path);
52948
52948
  return initializeManagedWorktree({
52949
- gitDir: resolved.gitDir,
52950
- branch: resolved.entry.branch ?? resolved.entry.path,
52949
+ gitDir: resolved2.gitDir,
52950
+ branch: resolved2.entry.branch ?? resolved2.entry.path,
52951
52951
  profile: profileName,
52952
52952
  agent: this.deps.config.workspace.defaultAgent,
52953
52953
  runtime: profile.runtime,
52954
52954
  startupEnvValues: await this.buildStartupEnvValues(void 0),
52955
52955
  allocatedPorts: await this.allocatePorts(),
52956
- runtimeEnvExtras: { [ENV_NAMES.worktreePath]: resolved.entry.path },
52956
+ runtimeEnvExtras: { [ENV_NAMES.worktreePath]: resolved2.entry.path },
52957
52957
  dotenvValues,
52958
52958
  ...await this.controlEnvFields(profile.runtime)
52959
52959
  });
52960
52960
  }
52961
- async refreshManagedArtifacts(resolved) {
52962
- if (!resolved.meta) {
52961
+ async refreshManagedArtifacts(resolved2) {
52962
+ if (!resolved2.meta) {
52963
52963
  throw new Error("Missing managed metadata");
52964
52964
  }
52965
52965
  return await this.refreshManagedArtifactsFromMeta({
52966
- gitDir: resolved.gitDir,
52967
- meta: resolved.meta,
52968
- worktreePath: resolved.entry.path
52966
+ gitDir: resolved2.gitDir,
52967
+ meta: resolved2.meta,
52968
+ worktreePath: resolved2.entry.path
52969
52969
  });
52970
52970
  }
52971
52971
  async refreshManagedArtifactsFromMeta(input2) {
@@ -53200,22 +53200,22 @@ ${oneshotPrompt}` : oneshotPrompt ?? baseSystemPrompt;
53200
53200
  if (!controlUrl) return {};
53201
53201
  return { controlUrl, controlToken: await this.deps.getControlToken() };
53202
53202
  }
53203
- async removeResolvedWorktree(resolved) {
53203
+ async removeResolvedWorktree(resolved2) {
53204
53204
  await this.runLifecycleHook({
53205
53205
  name: "preRemove",
53206
53206
  command: this.deps.config.lifecycleHooks.preRemove,
53207
- meta: resolved.meta,
53208
- worktreePath: resolved.entry.path
53207
+ meta: resolved2.meta,
53208
+ worktreePath: resolved2.entry.path
53209
53209
  });
53210
- const branch = resolved.entry.branch ?? resolved.entry.path;
53211
- if (resolved.meta?.runtime === "docker") {
53210
+ const branch = resolved2.entry.branch ?? resolved2.entry.path;
53211
+ if (resolved2.meta?.runtime === "docker") {
53212
53212
  await this.deps.docker.removeContainer(branch);
53213
53213
  }
53214
53214
  await this.killWorktreeWindows(branch);
53215
53215
  removeManagedWorktree(
53216
53216
  {
53217
53217
  repoRoot: this.deps.projectRoot,
53218
- worktreePath: resolved.entry.path,
53218
+ worktreePath: resolved2.entry.path,
53219
53219
  branch,
53220
53220
  force: true,
53221
53221
  deleteBranch: true,
@@ -53223,7 +53223,7 @@ ${oneshotPrompt}` : oneshotPrompt ?? baseSystemPrompt;
53223
53223
  },
53224
53224
  this.deps.git
53225
53225
  );
53226
- await this.updateWorktreeArchivedState(resolved.entry.path, false);
53226
+ await this.updateWorktreeArchivedState(resolved2.entry.path, false);
53227
53227
  await this.deps.reconciliation.reconcile(this.deps.projectRoot, { force: true });
53228
53228
  }
53229
53229
  async runLifecycleHook(input2) {
@@ -55601,7 +55601,7 @@ var Hono = class _Hono {
55601
55601
  return this.#handleError(err2, c);
55602
55602
  }
55603
55603
  return res instanceof Promise ? res.then(
55604
- (resolved) => resolved || (c.finalized ? c.res : this.#notFoundHandler(c))
55604
+ (resolved2) => resolved2 || (c.finalized ? c.res : this.#notFoundHandler(c))
55605
55605
  ).catch((err2) => this.#handleError(err2, c)) : res ?? this.#notFoundHandler(c);
55606
55606
  }
55607
55607
  const composed = compose(matchResult[0], this.errorHandler, this.#notFoundHandler);
@@ -56465,11 +56465,11 @@ function contractRoute(app, key, tag, handler) {
56465
56465
  app.on(route.method, route.path, describeContractRoute(key, tag), async (c, next) => {
56466
56466
  const params = route.pathParams ? parseValue(route.pathParams, c.req.param(), "Invalid path parameters") : { ok: true, data: void 0 };
56467
56467
  if (!params.ok) return params.response;
56468
- const query = route.query ? parseValue(route.query, readSearchParams(new URL(c.req.url)), "Invalid query") : { ok: true, data: void 0 };
56469
- if (!query.ok) return query.response;
56468
+ const query2 = route.query ? parseValue(route.query, readSearchParams(new URL(c.req.url)), "Invalid query") : { ok: true, data: void 0 };
56469
+ if (!query2.ok) return query2.response;
56470
56470
  const body = route.body ? parseJsonValue(route.body, await c.req.text()) : { ok: true, data: void 0 };
56471
56471
  if (!body.ok) return body.response;
56472
- const input2 = { params: params.data, query: query.data, body: body.data };
56472
+ const input2 = { params: params.data, query: query2.data, body: body.data };
56473
56473
  return handler(c, input2, next);
56474
56474
  });
56475
56475
  }
@@ -56515,55 +56515,55 @@ function agentId(id) {
56515
56515
  }
56516
56516
  async function apiAttachAgentsWorktree(project, branch) {
56517
56517
  touchDashboardActivity();
56518
- const resolved = await project.resolveAgentsWorktree(branch);
56519
- if (!resolved.ok) return resolved.response;
56520
- const chatSupport = project.resolveWorktreeAgentChatSupport(resolved.worktree, "chat");
56518
+ const resolved2 = await project.resolveAgentsWorktree(branch);
56519
+ if (!resolved2.ok) return resolved2.response;
56520
+ const chatSupport = project.resolveWorktreeAgentChatSupport(resolved2.worktree, "chat");
56521
56521
  if (!chatSupport.ok) {
56522
56522
  return errorResponse(chatSupport.error, chatSupport.status);
56523
56523
  }
56524
- const result = chatSupport.data.provider === "claude" ? await project.claudeConversationService.attachWorktreeConversation(resolved.worktree) : await project.worktreeConversationService.attachWorktreeConversation(resolved.worktree);
56524
+ const result = chatSupport.data.provider === "claude" ? await project.claudeConversationService.attachWorktreeConversation(resolved2.worktree) : await project.worktreeConversationService.attachWorktreeConversation(resolved2.worktree);
56525
56525
  return result.ok ? jsonResponse(project.withClaudeLiveConversation(result.data)) : errorResponse(result.error, result.status);
56526
56526
  }
56527
56527
  async function apiGetAgentsWorktreeHistory(project, branch) {
56528
56528
  touchDashboardActivity();
56529
- const resolved = await project.resolveAgentsWorktree(branch);
56530
- if (!resolved.ok) return resolved.response;
56531
- const chatSupport = project.resolveWorktreeAgentChatSupport(resolved.worktree, "chat");
56529
+ const resolved2 = await project.resolveAgentsWorktree(branch);
56530
+ if (!resolved2.ok) return resolved2.response;
56531
+ const chatSupport = project.resolveWorktreeAgentChatSupport(resolved2.worktree, "chat");
56532
56532
  if (!chatSupport.ok) {
56533
56533
  return errorResponse(chatSupport.error, chatSupport.status);
56534
56534
  }
56535
- const result = chatSupport.data.provider === "claude" ? await project.claudeConversationService.readWorktreeConversation(resolved.worktree) : await project.worktreeConversationService.readWorktreeConversation(resolved.worktree);
56535
+ const result = chatSupport.data.provider === "claude" ? await project.claudeConversationService.readWorktreeConversation(resolved2.worktree) : await project.worktreeConversationService.readWorktreeConversation(resolved2.worktree);
56536
56536
  return result.ok ? jsonResponse(project.withClaudeLiveConversation(result.data)) : errorResponse(result.error, result.status);
56537
56537
  }
56538
56538
  async function apiSendAgentsWorktreeMessage(project, branch, text) {
56539
56539
  touchDashboardActivity();
56540
56540
  await project.disarmOneshotIfArmed(branch, "agents-send-message");
56541
- const resolved = await project.resolveAgentsWorktree(branch);
56542
- if (!resolved.ok) return resolved.response;
56543
- if (!resolved.worktree.mux) {
56541
+ const resolved2 = await project.resolveAgentsWorktree(branch);
56542
+ if (!resolved2.ok) return resolved2.response;
56543
+ if (!resolved2.worktree.mux) {
56544
56544
  return errorResponse("Open this worktree in the main dashboard before sending messages here", 409);
56545
56545
  }
56546
- const chatSupport = project.resolveWorktreeAgentChatSupport(resolved.worktree, "chat");
56546
+ const chatSupport = project.resolveWorktreeAgentChatSupport(resolved2.worktree, "chat");
56547
56547
  if (!chatSupport.ok) {
56548
56548
  return errorResponse(chatSupport.error, chatSupport.status);
56549
56549
  }
56550
56550
  if (chatSupport.data.provider === "codex") {
56551
56551
  const sendResult2 = await project.worktreeConversationService.sendWorktreeConversationMessage(
56552
- resolved.worktree,
56552
+ resolved2.worktree,
56553
56553
  text
56554
56554
  );
56555
56555
  if (!sendResult2.ok) {
56556
56556
  return errorResponse(sendResult2.error, sendResult2.status);
56557
56557
  }
56558
- await project.setAgentTerminalStale(resolved.worktree, true);
56558
+ await project.setAgentTerminalStale(resolved2.worktree, true);
56559
56559
  return jsonResponse(sendResult2.data);
56560
56560
  }
56561
- const conversationResult = await project.claudeConversationService.readWorktreeConversation(resolved.worktree);
56561
+ const conversationResult = await project.claudeConversationService.readWorktreeConversation(resolved2.worktree);
56562
56562
  if (!conversationResult.ok) {
56563
56563
  return errorResponse(conversationResult.error, conversationResult.status);
56564
56564
  }
56565
56565
  const streamingResponse = await project.sendClaudeStreamingMessage({
56566
- worktree: resolved.worktree,
56566
+ worktree: resolved2.worktree,
56567
56567
  text,
56568
56568
  conversationId: conversationResult.data.conversation.conversationId
56569
56569
  });
@@ -56591,24 +56591,24 @@ async function apiSendAgentsWorktreeMessage(project, branch, text) {
56591
56591
  async function apiInterruptAgentsWorktree(project, branch) {
56592
56592
  touchDashboardActivity();
56593
56593
  await project.disarmOneshotIfArmed(branch, "agents-interrupt");
56594
- const resolved = await project.resolveAgentsWorktree(branch);
56595
- if (!resolved.ok) return resolved.response;
56596
- if (!resolved.worktree.mux) {
56594
+ const resolved2 = await project.resolveAgentsWorktree(branch);
56595
+ if (!resolved2.ok) return resolved2.response;
56596
+ if (!resolved2.worktree.mux) {
56597
56597
  return errorResponse("Open this worktree in the main dashboard before interrupting it here", 409);
56598
56598
  }
56599
- const chatSupport = project.resolveWorktreeAgentChatSupport(resolved.worktree, "interrupt");
56599
+ const chatSupport = project.resolveWorktreeAgentChatSupport(resolved2.worktree, "interrupt");
56600
56600
  if (!chatSupport.ok) {
56601
56601
  return errorResponse(chatSupport.error, chatSupport.status);
56602
56602
  }
56603
56603
  if (chatSupport.data.provider === "codex") {
56604
- const interruptResult2 = await project.worktreeConversationService.interruptWorktreeConversation(resolved.worktree);
56604
+ const interruptResult2 = await project.worktreeConversationService.interruptWorktreeConversation(resolved2.worktree);
56605
56605
  if (!interruptResult2.ok) {
56606
56606
  return errorResponse(interruptResult2.error, interruptResult2.status);
56607
56607
  }
56608
- await project.setAgentTerminalStale(resolved.worktree, true);
56608
+ await project.setAgentTerminalStale(resolved2.worktree, true);
56609
56609
  return jsonResponse(interruptResult2.data);
56610
56610
  }
56611
- const conversationResult = await project.claudeConversationService.readWorktreeConversation(resolved.worktree);
56611
+ const conversationResult = await project.claudeConversationService.readWorktreeConversation(resolved2.worktree);
56612
56612
  if (!conversationResult.ok) {
56613
56613
  return errorResponse(conversationResult.error, conversationResult.status);
56614
56614
  }
@@ -56616,7 +56616,7 @@ async function apiInterruptAgentsWorktree(project, branch) {
56616
56616
  conversationResult.data.conversation.conversationId
56617
56617
  );
56618
56618
  if (activeClaudeInterrupt.ok) {
56619
- await project.setAgentTerminalStale(resolved.worktree, true);
56619
+ await project.setAgentTerminalStale(resolved2.worktree, true);
56620
56620
  return jsonResponse({
56621
56621
  conversationId: conversationResult.data.conversation.conversationId,
56622
56622
  turnId: activeClaudeInterrupt.turnId,
@@ -56733,8 +56733,8 @@ function branchRoutes(deps) {
56733
56733
  deps,
56734
56734
  "fetchAvailableBranches",
56735
56735
  "Branches",
56736
- ({ runtime }, { query }) => jsonResponse({
56737
- branches: runtime.lifecycleService.listAvailableBranches({ includeRemote: query.includeRemote === true })
56736
+ ({ runtime }, { query: query2 }) => jsonResponse({
56737
+ branches: runtime.lifecycleService.listAvailableBranches({ includeRemote: query2.includeRemote === true })
56738
56738
  })
56739
56739
  );
56740
56740
  projectRoute(
@@ -57601,7 +57601,7 @@ var CACHE_TTL_MS = 3e5;
57601
57601
  var issueCache = null;
57602
57602
  var viewerIdCache = null;
57603
57603
  var inProgressStateIdCache = /* @__PURE__ */ new Map();
57604
- async function postLinearGraphql(query, variables) {
57604
+ async function postLinearGraphql(query2, variables) {
57605
57605
  const apiKey = process.env.LINEAR_API_KEY;
57606
57606
  if (!apiKey) {
57607
57607
  return { ok: false, error: "LINEAR_API_KEY not set" };
@@ -57613,7 +57613,7 @@ async function postLinearGraphql(query, variables) {
57613
57613
  "Content-Type": "application/json",
57614
57614
  Authorization: apiKey
57615
57615
  },
57616
- body: JSON.stringify(variables ? { query, variables } : { query })
57616
+ body: JSON.stringify(variables ? { query: query2, variables } : { query: query2 })
57617
57617
  });
57618
57618
  if (!res.ok) {
57619
57619
  const text = await res.text();
@@ -58350,9 +58350,9 @@ function runRoutes(deps) {
58350
58350
  if (detail === null || detail.run.projectId !== project.prefix) return errorResponse("Run not found", 404);
58351
58351
  return jsonResponse(detail);
58352
58352
  });
58353
- projectRoute(app, deps, "fetchRunEvents", "Runs", (project, { params, query }) => {
58353
+ projectRoute(app, deps, "fetchRunEvents", "Runs", (project, { params, query: query2 }) => {
58354
58354
  if (!projectRun(project, params.runId)) return errorResponse("Run not found", 404);
58355
- return jsonResponse(project.runs.presentation.events(params.runId, query.after));
58355
+ return jsonResponse(project.runs.presentation.events(params.runId, query2.after));
58356
58356
  });
58357
58357
  projectRoute(app, deps, "cancelRun", "Runs", async (project, { params: { runId } }) => {
58358
58358
  const detail = project.runs.presentation.detail(runId);
@@ -58376,9 +58376,9 @@ function runRoutes(deps) {
58376
58376
  if (!result.ok) return errorResponse(result.reason, result.reason === "not_found" ? 404 : 409);
58377
58377
  return jsonResponse(project.runs.presentation.detail(runId));
58378
58378
  });
58379
- projectRoute(app, deps, "fetchExecutionTranscript", "Runs", async (project, { params, query }) => {
58379
+ projectRoute(app, deps, "fetchExecutionTranscript", "Runs", async (project, { params, query: query2 }) => {
58380
58380
  if (!projectExecution(project, params.executionId)) return errorResponse("Execution not found", 404);
58381
- const result = await project.runs.transcripts.read(params.executionId, query.after);
58381
+ const result = await project.runs.transcripts.read(params.executionId, query2.after);
58382
58382
  if (!result.ok)
58383
58383
  return errorResponse(
58384
58384
  result.reason === "not_found" ? "Execution not found" : "Transcript unavailable",
@@ -65202,13 +65202,13 @@ var ClaudeConversationService = class {
65202
65202
  async attachWorktreeConversation(worktree) {
65203
65203
  return await this.withResolvedConversation(
65204
65204
  worktree,
65205
- async (resolved) => ok(toWorktreeConversationResponse(worktree, resolved.conversationMeta, resolved.session))
65205
+ async (resolved2) => ok(toWorktreeConversationResponse(worktree, resolved2.conversationMeta, resolved2.session))
65206
65206
  );
65207
65207
  }
65208
65208
  async readWorktreeConversation(worktree) {
65209
65209
  return await this.withResolvedConversation(
65210
65210
  worktree,
65211
- async (resolved) => ok(toWorktreeConversationResponse(worktree, resolved.conversationMeta, resolved.session))
65211
+ async (resolved2) => ok(toWorktreeConversationResponse(worktree, resolved2.conversationMeta, resolved2.session))
65212
65212
  );
65213
65213
  }
65214
65214
  async setWorktreeConversationSession(worktree, sessionId) {
@@ -65232,9 +65232,9 @@ var ClaudeConversationService = class {
65232
65232
  return err(409, "Worktree chat is only available for Claude worktrees");
65233
65233
  }
65234
65234
  try {
65235
- const resolved = await this.resolveConversation(worktree);
65236
- if (!resolved.ok) return resolved;
65237
- return await fn(resolved.data);
65235
+ const resolved2 = await this.resolveConversation(worktree);
65236
+ if (!resolved2.ok) return resolved2;
65237
+ return await fn(resolved2.data);
65238
65238
  } catch (error61) {
65239
65239
  const message = error61 instanceof Error ? error61.message : String(error61);
65240
65240
  return err(502, message);
@@ -65596,11 +65596,11 @@ var EnvironmentDiagnosticsService = class {
65596
65596
  };
65597
65597
  }
65598
65598
  async commandCheck(id, label, required2, command, args, remediation) {
65599
- const resolved = this.resolveCommand(command);
65600
- if (!resolved) {
65599
+ const resolved2 = this.resolveCommand(command);
65600
+ if (!resolved2) {
65601
65601
  return check2(id, label, "error", required2, `${command} is unavailable`, remediation);
65602
65602
  }
65603
- const result = await this.runCommand(resolved, args);
65603
+ const result = await this.runCommand(resolved2, args);
65604
65604
  const summary = result.output.split("\n")[0] ?? "";
65605
65605
  if (result.ok) return check2(id, label, "ok", required2, summary || `${command} is available`);
65606
65606
  return check2(
@@ -65628,8 +65628,8 @@ var EnvironmentDiagnosticsService = class {
65628
65628
  }
65629
65629
  async codexAutoReviewCheck() {
65630
65630
  const required2 = this.deps.config.workspace.defaultAgent === "codex";
65631
- const resolved = this.resolveCommand("codex");
65632
- if (!resolved) {
65631
+ const resolved2 = this.resolveCommand("codex");
65632
+ if (!resolved2) {
65633
65633
  return check2(
65634
65634
  "codex-auto-review",
65635
65635
  "Codex oneshot",
@@ -65639,7 +65639,7 @@ var EnvironmentDiagnosticsService = class {
65639
65639
  "Install Codex CLI and ensure it is on PATH"
65640
65640
  );
65641
65641
  }
65642
- const result = await this.runCommand(resolved, ["--help"]);
65642
+ const result = await this.runCommand(resolved2, ["--help"]);
65643
65643
  if (result.ok && codexHelpSupportsAutoReview(result.output)) {
65644
65644
  return check2("codex-auto-review", "Codex oneshot", "ok", required2, "Automatic approval review is supported");
65645
65645
  }
@@ -68432,9 +68432,9 @@ var WorkflowCatalogService = class {
68432
68432
  };
68433
68433
  }
68434
68434
  async createSnapshot(input2) {
68435
- const resolved = await this.resolve(input2.name);
68436
- if (!resolved.ok) return resolved;
68437
- const definition = resolved.definition;
68435
+ const resolved2 = await this.resolve(input2.name);
68436
+ if (!resolved2.ok) return resolved2;
68437
+ const definition = resolved2.definition;
68438
68438
  return {
68439
68439
  ok: true,
68440
68440
  snapshot: {
@@ -69269,9 +69269,9 @@ var WorktreeConversationService = class {
69269
69269
  return err(409, "Worktree chat is only available for Codex worktrees");
69270
69270
  }
69271
69271
  try {
69272
- const resolved = await this.resolveConversation(worktree, allowCreate);
69273
- if (!resolved.ok) return resolved;
69274
- return await fn(resolved.data);
69272
+ const resolved2 = await this.resolveConversation(worktree, allowCreate);
69273
+ if (!resolved2.ok) return resolved2;
69274
+ return await fn(resolved2.data);
69275
69275
  } catch (error61) {
69276
69276
  const message = error61 instanceof Error ? error61.message : String(error61);
69277
69277
  return err(502, message);
@@ -69529,7 +69529,7 @@ var DockerComposeEnvironmentProvider = class {
69529
69529
  if (result.exit.code !== 0) throw new Error(result.stderr.trim());
69530
69530
  }
69531
69531
  async resume(handle) {
69532
- const resolved = {
69532
+ const resolved2 = {
69533
69533
  provider: this.id,
69534
69534
  configRef: typeof handle.providerRef.value.composeFile === "string" ? handle.providerRef.value.composeFile : null,
69535
69535
  configHash: "",
@@ -69560,7 +69560,7 @@ var DockerComposeEnvironmentProvider = class {
69560
69560
  isolationRisks: []
69561
69561
  }
69562
69562
  };
69563
- return this.start(resolved, handle.scope);
69563
+ return this.start(resolved2, handle.scope);
69564
69564
  }
69565
69565
  async rebuild(environment, scope, previous) {
69566
69566
  if (previous) await this.destroy(previous);
@@ -70219,34 +70219,34 @@ function createProjectEnvironments(deps) {
70219
70219
  return { ok: false, reason: "selection_required", diagnostics: probe.configRefs };
70220
70220
  }
70221
70221
  const provider = selected === "devcontainer" ? devContainerProvider : selected === "docker" ? dockerEnvironmentProvider : selected === "compose" ? composeEnvironmentProvider : selected === "dockerfile" ? dockerfileEnvironmentProvider : hostEnvironmentProvider;
70222
- const resolved = await provider.resolve({
70222
+ const resolved2 = await provider.resolve({
70223
70223
  ...context,
70224
70224
  configRef: selected === "docker" ? input2.profileName ?? void 0 : profile?.environment?.config
70225
70225
  });
70226
- const id = environmentIdFor(scope, resolved.provider, resolved.configRef);
70226
+ const id = environmentIdFor(scope, resolved2.provider, resolved2.configRef);
70227
70227
  const existing = environmentStore.get(id);
70228
70228
  const now = (/* @__PURE__ */ new Date()).toISOString();
70229
- const trusted = resolved.provider !== "devcontainer" || resolved.configRef === null || environmentStore.isTrusted(scope.projectId, resolved.configRef, resolved.configHash);
70229
+ const trusted = resolved2.provider !== "devcontainer" || resolved2.configRef === null || environmentStore.isTrusted(scope.projectId, resolved2.configRef, resolved2.configHash);
70230
70230
  if (!trusted) {
70231
70231
  environmentStore.save({
70232
70232
  id,
70233
- provider: resolved.provider,
70233
+ provider: resolved2.provider,
70234
70234
  scope,
70235
70235
  status: "awaiting_trust",
70236
70236
  desiredStatus: input2.start ? "ready" : "stopped",
70237
- workspace: resolved.workspace,
70237
+ workspace: resolved2.workspace,
70238
70238
  providerRef: { schemaVersion: 1, value: {} },
70239
- configRef: resolved.configRef,
70240
- configHash: resolved.configHash,
70241
- capabilities: resolved.capabilities,
70242
- security: { ...resolved.security, trusted: false },
70239
+ configRef: resolved2.configRef,
70240
+ configHash: resolved2.configHash,
70241
+ capabilities: resolved2.capabilities,
70242
+ security: { ...resolved2.security, trusted: false },
70243
70243
  error: null,
70244
70244
  createdAt: existing?.createdAt ?? now,
70245
70245
  updatedAt: now
70246
70246
  });
70247
- return { ok: false, reason: "trust_required", diagnostics: resolved.security.reasons, environmentId: id };
70247
+ return { ok: false, reason: "trust_required", diagnostics: resolved2.security.reasons, environmentId: id };
70248
70248
  }
70249
- if (input2.start && resolved.provider !== "host" && !hasEnvironmentCapacity(projectEnvironments(), id, MAX_CONCURRENT_PROJECT_ENVIRONMENTS)) {
70249
+ if (input2.start && resolved2.provider !== "host" && !hasEnvironmentCapacity(projectEnvironments(), id, MAX_CONCURRENT_PROJECT_ENVIRONMENTS)) {
70250
70250
  return {
70251
70251
  ok: false,
70252
70252
  reason: "unavailable",
@@ -70254,26 +70254,26 @@ function createProjectEnvironments(deps) {
70254
70254
  };
70255
70255
  }
70256
70256
  let handle;
70257
- const reusable = existing && existing.configHash === resolved.configHash && (existing.provider === "host" || existing.providerRef.value.containerId || existing.providerRef.value.containerName);
70258
- if (!input2.start && resolved.provider !== "host") {
70257
+ const reusable = existing && existing.configHash === resolved2.configHash && (existing.provider === "host" || existing.providerRef.value.containerId || existing.providerRef.value.containerName);
70258
+ if (!input2.start && resolved2.provider !== "host") {
70259
70259
  if (reusable) {
70260
70260
  const observed = await provider.inspect(existing);
70261
70261
  handle = { ...existing, scope, status: observed.status };
70262
70262
  } else {
70263
70263
  handle = {
70264
70264
  id,
70265
- provider: resolved.provider,
70265
+ provider: resolved2.provider,
70266
70266
  scope,
70267
70267
  status: "detected",
70268
- workspace: resolved.workspace,
70268
+ workspace: resolved2.workspace,
70269
70269
  providerRef: { schemaVersion: 1, value: {} }
70270
70270
  };
70271
70271
  }
70272
70272
  } else if (reusable) {
70273
70273
  const observed = await provider.inspect(existing);
70274
- handle = observed.status === "ready" ? { ...existing, scope, status: "ready" } : observed.status === "stopped" ? await provider.resume(existing) : await provider.start(resolved, scope);
70274
+ handle = observed.status === "ready" ? { ...existing, scope, status: "ready" } : observed.status === "stopped" ? await provider.resume(existing) : await provider.start(resolved2, scope);
70275
70275
  } else {
70276
- handle = await provider.start(resolved, scope);
70276
+ handle = await provider.start(resolved2, scope);
70277
70277
  }
70278
70278
  if (handle.provider !== "host" && handle.status === "ready") {
70279
70279
  try {
@@ -70285,11 +70285,11 @@ function createProjectEnvironments(deps) {
70285
70285
  }
70286
70286
  environmentStore.save({
70287
70287
  ...handle,
70288
- desiredStatus: input2.start || resolved.provider === "host" ? "ready" : "stopped",
70289
- configRef: resolved.configRef,
70290
- configHash: resolved.configHash,
70291
- capabilities: resolved.capabilities,
70292
- security: { ...resolved.security, trusted: true },
70288
+ desiredStatus: input2.start || resolved2.provider === "host" ? "ready" : "stopped",
70289
+ configRef: resolved2.configRef,
70290
+ configHash: resolved2.configHash,
70291
+ capabilities: resolved2.capabilities,
70292
+ security: { ...resolved2.security, trusted: true },
70293
70293
  error: null,
70294
70294
  createdAt: existing?.createdAt ?? now,
70295
70295
  updatedAt: now
@@ -70597,22 +70597,22 @@ function createProjectEnvironments(deps) {
70597
70597
  };
70598
70598
  }
70599
70599
  try {
70600
- let resolved = resolvedFromRecord(record5);
70600
+ let resolved2 = resolvedFromRecord(record5);
70601
70601
  if (action !== "stop") {
70602
- resolved = await provider.resolve({
70602
+ resolved2 = await provider.resolve({
70603
70603
  workspacePath: record5.workspace.hostPath,
70604
70604
  projectPath: PROJECT_DIR,
70605
70605
  scope: record5.scope,
70606
70606
  configRef: record5.configRef ?? void 0
70607
70607
  });
70608
- if (resolved.configHash !== record5.configHash && resolved.provider === "devcontainer") {
70609
- const trusted = resolved.configRef !== null && environmentStore.isTrusted(record5.scope.projectId, resolved.configRef, resolved.configHash);
70608
+ if (resolved2.configHash !== record5.configHash && resolved2.provider === "devcontainer") {
70609
+ const trusted = resolved2.configRef !== null && environmentStore.isTrusted(record5.scope.projectId, resolved2.configRef, resolved2.configHash);
70610
70610
  if (!trusted) {
70611
70611
  saveEnvironment(record5, {
70612
70612
  status: "awaiting_trust",
70613
70613
  desiredStatus: "ready",
70614
- configHash: resolved.configHash,
70615
- security: { ...resolved.security, trusted: false }
70614
+ configHash: resolved2.configHash,
70615
+ security: { ...resolved2.security, trusted: false }
70616
70616
  });
70617
70617
  return { ok: false, error: "Environment configuration changed and requires trust", status: 409 };
70618
70618
  }
@@ -70637,13 +70637,13 @@ function createProjectEnvironments(deps) {
70637
70637
  } else if (action === "rebuild") {
70638
70638
  const rebuilding = saveEnvironment(record5, { status: "building", desiredStatus: "ready", error: null });
70639
70639
  await deactivateEnvironmentAccess(rebuilding, false);
70640
- handle = await provider.rebuild(resolved, rebuilding.scope, rebuilding);
70640
+ handle = await provider.rebuild(resolved2, rebuilding.scope, rebuilding);
70641
70641
  } else {
70642
70642
  const observed = record5.status === "ready" ? await provider.inspect(record5) : { status: "missing" };
70643
70643
  if (observed.status === "ready") handle = { ...record5, status: "ready" };
70644
70644
  else {
70645
70645
  const starting = saveEnvironment(record5, { status: "starting", desiredStatus: "ready", error: null });
70646
- handle = observed.status === "stopped" ? await provider.resume(starting) : await provider.start(resolved, starting.scope);
70646
+ handle = observed.status === "stopped" ? await provider.resume(starting) : await provider.start(resolved2, starting.scope);
70647
70647
  }
70648
70648
  }
70649
70649
  if (handle.provider !== "host") handle = await applyEnvironmentResourcePolicy(serverProcessRunner, handle);
@@ -71391,20 +71391,20 @@ function createProjectApp(runtime, instancePrefix, host) {
71391
71391
  await reconciliationService.reconcile(PROJECT_DIR);
71392
71392
  const state = projectRuntime.getWorktreeByBranch(branch);
71393
71393
  if (!state) return { ok: false, error: `Worktree not found: ${branch}`, status: 404 };
71394
- const resolved = await resolveAgentsWorktree(branch);
71395
- if (!resolved.ok) {
71394
+ const resolved2 = await resolveAgentsWorktree(branch);
71395
+ if (!resolved2.ok) {
71396
71396
  return { ok: false, error: `Worktree not found: ${branch}`, status: 404 };
71397
71397
  }
71398
- const chatSupport = resolveWorktreeAgentChatSupport(resolved.worktree, "chat");
71398
+ const chatSupport = resolveWorktreeAgentChatSupport(resolved2.worktree, "chat");
71399
71399
  if (!chatSupport.ok) return { ok: false, error: chatSupport.error, status: chatSupport.status };
71400
- const conversationResult = chatSupport.data.provider === "claude" ? await claudeConversationService.readWorktreeConversation(resolved.worktree) : await worktreeConversationService.readWorktreeConversation(resolved.worktree);
71400
+ const conversationResult = chatSupport.data.provider === "claude" ? await claudeConversationService.readWorktreeConversation(resolved2.worktree) : await worktreeConversationService.readWorktreeConversation(resolved2.worktree);
71401
71401
  if (!conversationResult.ok) return { ok: false, error: conversationResult.error, status: conversationResult.status };
71402
71402
  const prUrl = (state.prs ?? []).find((pr) => pr.state === "open" || pr.state === "merged")?.url ?? null;
71403
71403
  const exportInput = {
71404
71404
  target,
71405
71405
  branch,
71406
71406
  baseBranch: state.baseBranch ?? null,
71407
- agent: resolved.worktree.agentName ?? null,
71407
+ agent: resolved2.worktree.agentName ?? null,
71408
71408
  prUrl,
71409
71409
  conversation: conversationResult.data.conversation,
71410
71410
  taskflowVersion: PORTTA_FLOW_VERSION
@@ -71799,21 +71799,21 @@ function nextConversationMessageOrder(messages) {
71799
71799
  return messages.reduce((order2, message) => Math.max(order2, message.order + 1), 0);
71800
71800
  }
71801
71801
  async function loadAgentsConversationInitialState(project, branch) {
71802
- const resolved = await project.resolveAgentsWorktree(branch);
71803
- if (!resolved.ok) {
71802
+ const resolved2 = await project.resolveAgentsWorktree(branch);
71803
+ if (!resolved2.ok) {
71804
71804
  return {
71805
71805
  ok: false,
71806
- message: await readErrorMessage(resolved.response)
71806
+ message: await readErrorMessage(resolved2.response)
71807
71807
  };
71808
71808
  }
71809
- const chatSupport = project.resolveWorktreeAgentChatSupport(resolved.worktree, "chat");
71809
+ const chatSupport = project.resolveWorktreeAgentChatSupport(resolved2.worktree, "chat");
71810
71810
  if (!chatSupport.ok) {
71811
71811
  return {
71812
71812
  ok: false,
71813
71813
  message: chatSupport.error
71814
71814
  };
71815
71815
  }
71816
- const result = chatSupport.data.provider === "claude" ? await project.claudeConversationService.readWorktreeConversation(resolved.worktree) : await project.worktreeConversationService.readWorktreeConversation(resolved.worktree);
71816
+ const result = chatSupport.data.provider === "claude" ? await project.claudeConversationService.readWorktreeConversation(resolved2.worktree) : await project.worktreeConversationService.readWorktreeConversation(resolved2.worktree);
71817
71817
  return result.ok ? { ok: true, data: project.withClaudeLiveConversation(result.data) } : { ok: false, message: result.error };
71818
71818
  }
71819
71819
  var agentsSocketRoute = {
@@ -72223,7 +72223,7 @@ function createDaemonTaskflowHost(context) {
72223
72223
  port: hostListen(env2).port,
72224
72224
  workflowBuiltinsDir: taskflowAssets(env2).workflowBuiltinsDir,
72225
72225
  version: env2.PORTTA_VERSION || "0.0.0-local",
72226
- buildDate: true ? "2026-09-16T03:00:29Z" : (/* @__PURE__ */ new Date()).toISOString(),
72226
+ buildDate: true ? "2026-09-16T05:05:26Z" : (/* @__PURE__ */ new Date()).toISOString(),
72227
72227
  environmentStore: createEnvironmentStore(paths.database),
72228
72228
  hostEnvironmentProvider: new HostEnvironmentProvider(),
72229
72229
  devContainerProvider: new DevContainerProvider(),
@@ -73521,16 +73521,12 @@ function matchPath(pattern, path) {
73521
73521
 
73522
73522
  // ../core/src/activity.ts
73523
73523
  var BASE_ACTIVITY_KINDS = [
73524
- "task.created",
73525
- "task.updated",
73526
- "task.status",
73527
- "task.assigned",
73528
- "task.note",
73529
- "task.comment",
73530
- "task.linked",
73531
- "task.synced",
73532
- "task.conflict",
73533
- "task.deleted",
73524
+ "issue.created",
73525
+ "issue.updated",
73526
+ "issue.state",
73527
+ "issue.assigned",
73528
+ "issue.comment",
73529
+ "issue.linked",
73534
73530
  "session.started",
73535
73531
  "session.ended",
73536
73532
  "session.abandoned",
@@ -73557,70 +73553,9 @@ var SESSION_ABANDON_AFTER_SECONDS = 6 * 60 * 60;
73557
73553
  // ../core/src/repos-scan.ts
73558
73554
  var INSTRUCTION_MAX_BYTES = 64 * 1024;
73559
73555
 
73560
- // ../core/src/tasks.ts
73561
- var TASK_STATUSES = ["backlog", "ready", "in_progress", "review", "blocked", "done"];
73562
- var DEFAULT_TASK_WORKFLOW = {
73563
- statuses: TASK_STATUSES.map((id) => ({ id, label: null })),
73564
- defaultStatus: "backlog"
73565
- };
73566
- var TASK_PRIORITIES = ["low", "medium", "high", "urgent"];
73567
- var TASK_DRAFT_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
73568
- var TASK_TYPE_CATALOG = [
73569
- { id: "feature", tone: "accent", aliases: ["feat", "features", "enhancement-request", "story"] },
73570
- { id: "bug", tone: "danger", aliases: ["fix", "bugfix", "defect", "regression"] },
73571
- { id: "improvement", tone: "info", aliases: ["enhancement", "refactor", "perf", "performance"] },
73572
- { id: "chore", tone: "neutral", aliases: ["task", "maintenance", "build", "ci", "deps"] },
73573
- { id: "research", tone: "agent", aliases: ["spike", "investigation", "discovery"] },
73574
- { id: "documentation", tone: "outline", aliases: ["docs", "doc"] }
73575
- ];
73576
- var TASK_TYPES = TASK_TYPE_CATALOG.map((entry) => entry.id);
73577
-
73578
- // ../core/src/task-example.ts
73579
- var PortableKey = external_exports.string().min(1).max(80).regex(/^[a-z0-9][a-z0-9._-]*$/i);
73580
- var ProjectRelativePath = external_exports.string().min(1).max(255).regex(/^[A-Za-z0-9][A-Za-z0-9._-]*$/).refine((value) => !value.includes(".."));
73581
- var RepositoryRelativePath = external_exports.string().min(1).max(255).regex(/^[A-Za-z0-9][A-Za-z0-9._-]*(\/[A-Za-z0-9][A-Za-z0-9._-]*)?$/).refine((value) => !value.includes(".."));
73582
- var ExampleComment = external_exports.object({
73583
- key: PortableKey,
73584
- actor: external_exports.string().min(1).max(64),
73585
- actorKind: external_exports.enum(["human", "agent", "system"]).optional(),
73586
- body: external_exports.string().min(1).max(65536)
73587
- }).strict();
73588
- var ExampleTask = external_exports.lazy(() => external_exports.object({
73589
- key: PortableKey,
73590
- title: external_exports.string().min(1).max(200),
73591
- description: external_exports.string().max(65536).nullable().optional(),
73592
- status: external_exports.enum(TASK_STATUSES).optional(),
73593
- priority: external_exports.enum(TASK_PRIORITIES).nullable().optional(),
73594
- type: external_exports.string().max(32).nullable().optional(),
73595
- labels: external_exports.array(external_exports.string().min(1).max(64)).max(32).optional(),
73596
- assignee: external_exports.string().max(64).nullable().optional(),
73597
- agent: external_exports.string().max(64).nullable().optional(),
73598
- repository: external_exports.string().min(1).max(128).nullable().optional(),
73599
- environment: external_exports.string().min(1).max(255).nullable().optional(),
73600
- service: external_exports.string().max(64).nullable().optional(),
73601
- dueAt: external_exports.string().regex(/^\d{4}-\d{2}-\d{2}(T[\d:.+-Z]+)?$/).nullable().optional(),
73602
- parent: PortableKey.nullable().optional(),
73603
- comments: external_exports.array(ExampleComment).max(32).optional(),
73604
- subtasks: external_exports.array(ExampleTask).max(32).optional()
73605
- }).strict());
73606
- var ExampleRepository = external_exports.object({
73607
- key: PortableKey,
73608
- name: external_exports.string().min(1).max(128),
73609
- role: external_exports.string().max(32).nullable().optional(),
73610
- relativePath: RepositoryRelativePath.optional(),
73611
- remoteUrl: external_exports.string().min(1).max(512).optional()
73612
- }).strict();
73613
- var ExampleDocument = external_exports.object({
73614
- schemaVersion: external_exports.literal(1),
73615
- project: external_exports.object({
73616
- slug: external_exports.string().min(1).max(64).regex(/^[a-z0-9][a-z0-9-]*$/),
73617
- name: external_exports.string().min(1).max(120),
73618
- description: external_exports.string().max(2e3).nullable().optional(),
73619
- relativePath: ProjectRelativePath.optional()
73620
- }).strict(),
73621
- repositories: external_exports.array(ExampleRepository).max(32).optional(),
73622
- tasks: external_exports.array(ExampleTask).max(64)
73623
- }).strict();
73556
+ // ../core/src/database-config.ts
73557
+ import { join as join29 } from "node:path";
73558
+ var DATABASE_RELATIVE_PATH = join29("state", "panel", "portta.db");
73624
73559
 
73625
73560
  // ../../node_modules/ws/wrapper.mjs
73626
73561
  var import_stream = __toESM(require_stream(), 1);
@@ -73629,6 +73564,462 @@ var import_sender = __toESM(require_sender(), 1);
73629
73564
  var import_websocket = __toESM(require_websocket(), 1);
73630
73565
  var import_websocket_server = __toESM(require_websocket_server(), 1);
73631
73566
 
73567
+ // ../host/src/forge/gh.ts
73568
+ import { execFile as execFile2 } from "node:child_process";
73569
+ var TIMEOUT_MS = 2e4;
73570
+ var ISSUE_PAGE_LIMIT = 100;
73571
+ var ForgeError = class extends Error {
73572
+ kind;
73573
+ hint;
73574
+ constructor(kind, message, hint) {
73575
+ super(message);
73576
+ this.name = "ForgeError";
73577
+ this.kind = kind;
73578
+ this.hint = hint;
73579
+ }
73580
+ };
73581
+ var FORGE_STATUS = {
73582
+ unavailable: 503,
73583
+ unauthenticated: 401,
73584
+ forbidden: 403,
73585
+ "not-found": 404,
73586
+ "rate-limited": 429,
73587
+ timeout: 504,
73588
+ failed: 502
73589
+ };
73590
+ function classify(stderr) {
73591
+ const text = stderr.toLowerCase();
73592
+ if (text.includes("gh auth login") || text.includes("not logged") || text.includes("authentication token")) {
73593
+ return "unauthenticated";
73594
+ }
73595
+ if (text.includes("rate limit") || text.includes("secondary rate")) return "rate-limited";
73596
+ if (text.includes("could not resolve to") || text.includes("not found") || text.includes("404")) return "not-found";
73597
+ if (text.includes("forbidden") || text.includes("403") || text.includes("must have admin")) return "forbidden";
73598
+ return "failed";
73599
+ }
73600
+ var resolved;
73601
+ function ghPath() {
73602
+ if (resolved === void 0) resolved = resolveHostToolThoroughly("gh");
73603
+ if (!resolved) {
73604
+ throw new ForgeError(
73605
+ "unavailable",
73606
+ "the GitHub CLI is not installed on this host",
73607
+ "install gh (https://cli.github.com) and run gh auth login, then reload"
73608
+ );
73609
+ }
73610
+ return resolved;
73611
+ }
73612
+ function runGh2(args, options = {}) {
73613
+ const binary = ghPath();
73614
+ return new Promise((resolve21, reject2) => {
73615
+ const child = execFile2(
73616
+ binary,
73617
+ args,
73618
+ {
73619
+ cwd: options.cwd,
73620
+ timeout: TIMEOUT_MS,
73621
+ maxBuffer: 16 * 1024 * 1024,
73622
+ // `gh` colours and paginates when it thinks it is talking to a person.
73623
+ // Both would end up in the JSON the panel parses.
73624
+ env: { ...process.env, GH_PAGER: "cat", NO_COLOR: "1", GH_PROMPT_DISABLED: "1" }
73625
+ },
73626
+ (error61, stdout, stderr) => {
73627
+ if (!error61) return resolve21(stdout);
73628
+ if (error61.killed) {
73629
+ return reject2(new ForgeError("timeout", `gh ${args[0]} ${args[1] ?? ""} took longer than ${TIMEOUT_MS / 1e3}s`));
73630
+ }
73631
+ const detail = (stderr || error61.message).trim();
73632
+ reject2(new ForgeError(classify(detail), detail.split("\n")[0] ?? "gh failed", hintFor(classify(detail))));
73633
+ }
73634
+ );
73635
+ if (options.stdin !== void 0) {
73636
+ child.stdin?.end(options.stdin);
73637
+ }
73638
+ });
73639
+ }
73640
+ function hintFor(kind) {
73641
+ if (kind === "unauthenticated") return "run gh auth login on this host";
73642
+ if (kind === "rate-limited") return "GitHub is rate-limiting this account; try again shortly";
73643
+ if (kind === "forbidden") return "this account cannot see or write that repository";
73644
+ return void 0;
73645
+ }
73646
+ async function runGhJson(args, options) {
73647
+ const stdout = await runGh2(args, options);
73648
+ const text = stdout.trim();
73649
+ if (text === "") return [];
73650
+ try {
73651
+ return JSON.parse(text);
73652
+ } catch {
73653
+ throw new ForgeError("failed", `gh answered something that is not JSON: ${text.slice(0, 200)}`);
73654
+ }
73655
+ }
73656
+ async function ghStatus() {
73657
+ let binary;
73658
+ try {
73659
+ binary = ghPath();
73660
+ } catch (error61) {
73661
+ return { available: false, authenticated: false, account: null, detail: error61.message };
73662
+ }
73663
+ try {
73664
+ const user = await runGhJson(["api", "user", "--jq", "{login: .login}"]);
73665
+ return { available: true, authenticated: true, account: user.login, detail: null };
73666
+ } catch (error61) {
73667
+ const failure = error61 instanceof ForgeError ? error61 : null;
73668
+ return {
73669
+ available: true,
73670
+ authenticated: false,
73671
+ account: null,
73672
+ detail: failure?.message ?? `gh at ${binary} could not be asked who it is`
73673
+ };
73674
+ }
73675
+ }
73676
+
73677
+ // ../host/src/forge/issues.ts
73678
+ var LIST_FIELDS = [
73679
+ "number",
73680
+ "title",
73681
+ "state",
73682
+ "stateReason",
73683
+ "labels",
73684
+ "assignees",
73685
+ "milestone",
73686
+ "author",
73687
+ "comments",
73688
+ "createdAt",
73689
+ "updatedAt",
73690
+ "url"
73691
+ ].join(",");
73692
+ var VIEW_FIELDS = `${LIST_FIELDS},body`;
73693
+ function listIssues(repo, query2 = {}) {
73694
+ const args = ["issue", "list", "--repo", repo, "--json", LIST_FIELDS, "--limit", String(query2.limit ?? ISSUE_PAGE_LIMIT)];
73695
+ args.push("--state", query2.state ?? "open");
73696
+ if (query2.assignee) args.push("--assignee", query2.assignee);
73697
+ if (query2.label) args.push("--label", query2.label);
73698
+ if (query2.milestone) args.push("--milestone", query2.milestone);
73699
+ if (query2.search) args.push("--search", query2.search);
73700
+ return runGhJson(args);
73701
+ }
73702
+ async function viewIssue(repo, number4) {
73703
+ const [issue2, comments] = await Promise.all([
73704
+ runGhJson(["issue", "view", String(number4), "--repo", repo, "--json", VIEW_FIELDS]),
73705
+ runGhJson([
73706
+ "api",
73707
+ `repos/${repo}/issues/${number4}/comments`,
73708
+ "--paginate",
73709
+ "--jq",
73710
+ "[.[] | {id: (.id|tostring), body: .body, createdAt: .created_at, updatedAt: .updated_at, url: .html_url, author: {login: .user.login, avatarUrl: .user.avatar_url}}]"
73711
+ ]).catch(() => [])
73712
+ ]);
73713
+ return { ...issue2, comments };
73714
+ }
73715
+ async function createIssue(repo, draft) {
73716
+ const args = ["issue", "create", "--repo", repo, "--title", draft.title, "--body", draft.body ?? ""];
73717
+ for (const label of draft.labels ?? []) args.push("--label", label);
73718
+ for (const assignee of draft.assignees ?? []) args.push("--assignee", assignee);
73719
+ if (draft.milestone) args.push("--milestone", draft.milestone);
73720
+ const url2 = (await runGh2(args)).trim().split("\n").pop() ?? "";
73721
+ const number4 = Number(/\/(\d+)\s*$/.exec(url2)?.[1]);
73722
+ if (!Number.isInteger(number4)) {
73723
+ throw new Error(`gh issue create did not answer with an issue URL: ${url2.slice(0, 200)}`);
73724
+ }
73725
+ return viewIssue(repo, number4);
73726
+ }
73727
+ async function editIssue(repo, number4, patch) {
73728
+ const fields = [];
73729
+ if (patch.title !== void 0) fields.push("--title", patch.title);
73730
+ if (patch.body !== void 0) fields.push("--body", patch.body);
73731
+ for (const label of patch.addLabels ?? []) fields.push("--add-label", label);
73732
+ for (const label of patch.removeLabels ?? []) fields.push("--remove-label", label);
73733
+ for (const login of patch.addAssignees ?? []) fields.push("--add-assignee", login);
73734
+ for (const login of patch.removeAssignees ?? []) fields.push("--remove-assignee", login);
73735
+ if (patch.milestone !== void 0) fields.push("--milestone", patch.milestone);
73736
+ if (fields.length === 0) return;
73737
+ await runGh2(["issue", "edit", String(number4), "--repo", repo, ...fields]);
73738
+ }
73739
+ async function setIssueState(repo, number4, state, reason) {
73740
+ const verb = state === "closed" ? "close" : "reopen";
73741
+ const why = state === "closed" && reason ? ["--reason", reason] : [];
73742
+ await runGh2(["issue", verb, String(number4), "--repo", repo, ...why]);
73743
+ }
73744
+ async function commentOnIssue(repo, number4, body) {
73745
+ await runGh2(["issue", "comment", String(number4), "--repo", repo, "--body-file", "-"], { stdin: body });
73746
+ }
73747
+ async function issueVocabulary(repo) {
73748
+ const [labels, assignees, milestones] = await Promise.all([
73749
+ runGhJson(["label", "list", "--repo", repo, "--json", "name,color,description", "--limit", "200"]).catch(() => []),
73750
+ runGhJson([
73751
+ "api",
73752
+ `repos/${repo}/assignees`,
73753
+ "--paginate",
73754
+ "--jq",
73755
+ "[.[] | {login: .login, avatarUrl: .avatar_url}]"
73756
+ ]).catch(() => []),
73757
+ runGhJson([
73758
+ "api",
73759
+ `repos/${repo}/milestones?state=all`,
73760
+ "--paginate",
73761
+ "--jq",
73762
+ "[.[] | {number: .number, title: .title, state: .state, dueOn: .due_on}]"
73763
+ ]).catch(() => [])
73764
+ ]);
73765
+ return { labels, assignees, milestones };
73766
+ }
73767
+ function assignedIssues(limit = 50) {
73768
+ return runGhJson([
73769
+ "search",
73770
+ "issues",
73771
+ "--assignee",
73772
+ "@me",
73773
+ "--state",
73774
+ "open",
73775
+ "--limit",
73776
+ String(limit),
73777
+ "--json",
73778
+ "number,title,state,labels,assignees,author,createdAt,updatedAt,url,repository"
73779
+ ]);
73780
+ }
73781
+
73782
+ // ../host/src/forge/linear.ts
73783
+ var CLOSED_TYPES = /* @__PURE__ */ new Set(["completed", "canceled"]);
73784
+ function isClosed(issue2) {
73785
+ return CLOSED_TYPES.has(issue2.state?.type ?? "");
73786
+ }
73787
+ var ISSUE_FIELDS = `
73788
+ id identifier title url createdAt updatedAt
73789
+ state { name type }
73790
+ assignee { name displayName avatarUrl }
73791
+ creator { name displayName avatarUrl }
73792
+ labels { nodes { name color } }
73793
+ project { name }
73794
+ `;
73795
+ var TEAM_ISSUES_QUERY = `
73796
+ query TeamIssues($key: String!, $first: Int!, $closed: Boolean!) {
73797
+ issues(
73798
+ filter: { team: { key: { eq: $key } }, state: { type: { nin: ["completed", "canceled"] } } }
73799
+ orderBy: updatedAt
73800
+ first: $first
73801
+ ) @skip(if: $closed) { nodes { ${ISSUE_FIELDS} } }
73802
+ all: issues(filter: { team: { key: { eq: $key } } }, orderBy: updatedAt, first: $first)
73803
+ @include(if: $closed) { nodes { ${ISSUE_FIELDS} } }
73804
+ }
73805
+ `;
73806
+ var ISSUE_QUERY = `
73807
+ query Issue($id: String!) {
73808
+ issue(id: $id) {
73809
+ ${ISSUE_FIELDS}
73810
+ description
73811
+ comments(first: 100) { nodes { id body createdAt updatedAt url user { name avatarUrl } } }
73812
+ }
73813
+ }
73814
+ `;
73815
+ async function query(document, variables) {
73816
+ const response = await postLinearGraphql(document, variables);
73817
+ if (!response.ok) {
73818
+ const kind = response.error.includes("LINEAR_API_KEY") ? "unauthenticated" : "failed";
73819
+ throw new ForgeError(kind, response.error, kind === "unauthenticated" ? "set LINEAR_API_KEY on this host" : void 0);
73820
+ }
73821
+ const body = response.data;
73822
+ if (body.errors?.length) throw new ForgeError("failed", body.errors.map((e) => e.message).join("; "));
73823
+ if (!body.data) throw new ForgeError("failed", "Linear answered with no data");
73824
+ return body.data;
73825
+ }
73826
+ var TEAM_KEY = /^[A-Z][A-Z0-9]{0,9}$/;
73827
+ function teamKeyOf(raw2) {
73828
+ const key = (raw2 ?? "").trim().toUpperCase();
73829
+ if (!TEAM_KEY.test(key)) throw new ForgeError("failed", `not a Linear team key: ${raw2 ?? "(none)"}`, "expected something like ENG");
73830
+ return key;
73831
+ }
73832
+ async function listTeamIssues(teamKey, options = {}) {
73833
+ const closed = options.state === "closed" || options.state === "all";
73834
+ const data = await query(
73835
+ TEAM_ISSUES_QUERY,
73836
+ { key: teamKey, first: options.limit ?? 100, closed }
73837
+ );
73838
+ const nodes = (closed ? data.all?.nodes : data.issues?.nodes) ?? [];
73839
+ return options.state === "closed" ? nodes.filter(isClosed) : nodes;
73840
+ }
73841
+ function viewIssue2(identifier) {
73842
+ return query(ISSUE_QUERY, { id: identifier }).then((data) => {
73843
+ if (!data.issue) throw new ForgeError("not-found", `no Linear issue ${identifier}`);
73844
+ return data.issue;
73845
+ });
73846
+ }
73847
+ var CREATE_MUTATION = `
73848
+ mutation Create($input: IssueCreateInput!) {
73849
+ issueCreate(input: $input) { success issue { identifier } }
73850
+ }
73851
+ `;
73852
+ async function createIssue2(teamKey, draft) {
73853
+ const team = await query(
73854
+ "query Team($key: String!) { teams(filter: { key: { eq: $key } }, first: 1) { nodes { id } } }",
73855
+ { key: teamKey }
73856
+ );
73857
+ const teamId = team.teams.nodes[0]?.id;
73858
+ if (!teamId) throw new ForgeError("not-found", `no Linear team ${teamKey}`);
73859
+ const created = await query(
73860
+ CREATE_MUTATION,
73861
+ { input: { teamId, title: draft.title, description: draft.body ?? "" } }
73862
+ );
73863
+ const identifier = created.issueCreate.issue?.identifier;
73864
+ if (!created.issueCreate.success || !identifier) throw new ForgeError("failed", "Linear refused to create the issue");
73865
+ return viewIssue2(identifier);
73866
+ }
73867
+ var UPDATE_MUTATION = `
73868
+ mutation Update($id: String!, $input: IssueUpdateInput!) {
73869
+ issueUpdate(id: $id, input: $input) { success }
73870
+ }
73871
+ `;
73872
+ async function editIssue2(identifier, patch) {
73873
+ const issue2 = await viewIssue2(identifier);
73874
+ const input2 = {};
73875
+ if (patch.title !== void 0) input2["title"] = patch.title;
73876
+ if (patch.body !== void 0) input2["description"] = patch.body;
73877
+ if (patch.state && patch.state === "closed" !== isClosed(issue2)) {
73878
+ input2["stateId"] = await stateIdFor(identifier, patch.state);
73879
+ }
73880
+ if (Object.keys(input2).length > 0) {
73881
+ const result = await query(UPDATE_MUTATION, { id: issue2.id, input: input2 });
73882
+ if (!result.issueUpdate.success) throw new ForgeError("failed", "Linear refused the change");
73883
+ }
73884
+ return viewIssue2(identifier);
73885
+ }
73886
+ async function stateIdFor(identifier, state) {
73887
+ const wanted = state === "closed" ? ["completed"] : ["unstarted", "backlog", "started"];
73888
+ const data = await query(
73889
+ "query States($id: String!) { issue(id: $id) { team { states { nodes { id type position } } } } }",
73890
+ { id: identifier }
73891
+ );
73892
+ const states2 = data.issue?.team.states.nodes ?? [];
73893
+ const match2 = wanted.flatMap((type) => states2.filter((s) => s.type === type)).sort((a, b) => a.position - b.position)[0];
73894
+ if (!match2) throw new ForgeError("failed", `this Linear team has no ${state === "closed" ? "completed" : "open"} state`);
73895
+ return match2.id;
73896
+ }
73897
+ var COMMENT_MUTATION = `
73898
+ mutation Comment($input: CommentCreateInput!) { commentCreate(input: $input) { success } }
73899
+ `;
73900
+ async function commentOnIssue2(identifier, body) {
73901
+ const issue2 = await viewIssue2(identifier);
73902
+ const result = await query(COMMENT_MUTATION, {
73903
+ input: { issueId: issue2.id, body }
73904
+ });
73905
+ if (!result.commentCreate.success) throw new ForgeError("failed", "Linear refused the comment");
73906
+ return viewIssue2(identifier);
73907
+ }
73908
+ async function linearStatus() {
73909
+ if (!process.env["LINEAR_API_KEY"]?.trim()) {
73910
+ return { available: false, authenticated: false, account: null, detail: "LINEAR_API_KEY is not set on this host" };
73911
+ }
73912
+ try {
73913
+ const data = await query("query { viewer { name } }", {});
73914
+ return { available: true, authenticated: true, account: data.viewer.name, detail: null };
73915
+ } catch (error61) {
73916
+ return { available: true, authenticated: false, account: null, detail: error61.message };
73917
+ }
73918
+ }
73919
+
73920
+ // ../host/src/forge/routes.ts
73921
+ var REPO = /^[A-Za-z0-9][A-Za-z0-9._-]*\/[A-Za-z0-9][A-Za-z0-9._-]*$/;
73922
+ function repositoryOf(raw2) {
73923
+ const repo = raw2?.trim() ?? "";
73924
+ if (!REPO.test(repo)) throw new ForgeError("failed", `not a repository: ${repo || "(none)"}`, "expected owner/name");
73925
+ return repo;
73926
+ }
73927
+ var IDENTIFIER = /^[A-Z][A-Z0-9]{0,9}-\d{1,9}$/;
73928
+ function identifierOf(raw2) {
73929
+ const identifier = (raw2 ?? "").trim().toUpperCase();
73930
+ if (!IDENTIFIER.test(identifier)) throw new ForgeError("not-found", `not a Linear issue: ${raw2 ?? "(none)"}`);
73931
+ return identifier;
73932
+ }
73933
+ function numberOf(raw2) {
73934
+ const value = Number(raw2);
73935
+ if (!Number.isInteger(value) || value <= 0) throw new ForgeError("not-found", `not an issue number: ${raw2}`);
73936
+ return value;
73937
+ }
73938
+ function createForgeRoutes() {
73939
+ const api = new Hono2();
73940
+ api.onError((error61, c) => {
73941
+ if (error61 instanceof ForgeError) {
73942
+ return c.json({ error: error61.message, kind: error61.kind, hint: error61.hint ?? null }, { status: FORGE_STATUS[error61.kind] });
73943
+ }
73944
+ return c.json({ error: String(error61), kind: "failed", hint: null }, { status: 502 });
73945
+ });
73946
+ api.get("/status", async (c) => {
73947
+ const [github, linear] = await Promise.all([ghStatus(), linearStatus()]);
73948
+ return c.json({ github, linear });
73949
+ });
73950
+ api.get("/linear/issues", async (c) => {
73951
+ const state = c.req.query("state");
73952
+ const limit = Number(c.req.query("limit"));
73953
+ return c.json(
73954
+ await listTeamIssues(teamKeyOf(c.req.query("team")), {
73955
+ state: state === "closed" || state === "all" ? state : "open",
73956
+ limit: Number.isInteger(limit) && limit > 0 ? limit : void 0
73957
+ })
73958
+ );
73959
+ });
73960
+ api.get("/linear/issues/:identifier", async (c) => c.json(await viewIssue2(identifierOf(c.req.param("identifier")))));
73961
+ api.post("/linear/issues", async (c) => {
73962
+ const draft = await c.req.json();
73963
+ if (!draft?.title?.trim()) throw new ForgeError("failed", "an issue needs a title");
73964
+ return c.json(await createIssue2(teamKeyOf(c.req.query("team")), { title: draft.title, body: draft.body }), { status: 201 });
73965
+ });
73966
+ api.patch(
73967
+ "/linear/issues/:identifier",
73968
+ async (c) => c.json(await editIssue2(identifierOf(c.req.param("identifier")), await c.req.json()))
73969
+ );
73970
+ api.post("/linear/issues/:identifier/comments", async (c) => {
73971
+ const { body } = await c.req.json();
73972
+ if (!body?.trim()) throw new ForgeError("failed", "a comment needs a body");
73973
+ return c.json(await commentOnIssue2(identifierOf(c.req.param("identifier")), body));
73974
+ });
73975
+ api.get("/issues", async (c) => {
73976
+ const query2 = c.req.query();
73977
+ const state = query2["state"];
73978
+ return c.json(
73979
+ await listIssues(repositoryOf(query2["repo"]), {
73980
+ state: state === "closed" || state === "all" ? state : "open",
73981
+ assignee: query2["assignee"],
73982
+ label: query2["label"],
73983
+ milestone: query2["milestone"],
73984
+ search: query2["q"],
73985
+ limit: query2["limit"] ? Number(query2["limit"]) : void 0
73986
+ })
73987
+ );
73988
+ });
73989
+ api.get(
73990
+ "/issues/:number",
73991
+ async (c) => c.json(await viewIssue(repositoryOf(c.req.query("repo")), numberOf(c.req.param("number"))))
73992
+ );
73993
+ api.post("/issues", async (c) => {
73994
+ const draft = await c.req.json();
73995
+ if (!draft?.title?.trim()) throw new ForgeError("failed", "an issue needs a title");
73996
+ return c.json(await createIssue(repositoryOf(c.req.query("repo")), draft), { status: 201 });
73997
+ });
73998
+ api.patch("/issues/:number", async (c) => {
73999
+ const repo = repositoryOf(c.req.query("repo"));
74000
+ const number4 = numberOf(c.req.param("number"));
74001
+ const patch = await c.req.json();
74002
+ const { state, stateReason, ...fields } = patch;
74003
+ await editIssue(repo, number4, fields);
74004
+ if (state) await setIssueState(repo, number4, state, stateReason);
74005
+ return c.json(await viewIssue(repo, number4));
74006
+ });
74007
+ api.post("/issues/:number/comments", async (c) => {
74008
+ const repo = repositoryOf(c.req.query("repo"));
74009
+ const number4 = numberOf(c.req.param("number"));
74010
+ const { body } = await c.req.json();
74011
+ if (!body?.trim()) throw new ForgeError("failed", "a comment needs a body");
74012
+ await commentOnIssue(repo, number4, body);
74013
+ return c.json(await viewIssue(repo, number4));
74014
+ });
74015
+ api.get("/vocabulary", async (c) => c.json(await issueVocabulary(repositoryOf(c.req.query("repo")))));
74016
+ api.get("/assigned", async (c) => {
74017
+ const limit = Number(c.req.query("limit"));
74018
+ return c.json(await assignedIssues(Number.isInteger(limit) && limit > 0 ? limit : void 0));
74019
+ });
74020
+ return api;
74021
+ }
74022
+
73632
74023
  // ../host/src/app.ts
73633
74024
  var HOST_PUBLIC_ROUTES = /* @__PURE__ */ new Set(["GET /api/health"]);
73634
74025
  function createHostApp(options) {
@@ -73644,6 +74035,7 @@ function createHostApp(options) {
73644
74035
  return next();
73645
74036
  });
73646
74037
  app.get("/api/health", (c) => c.json({ ok: true }));
74038
+ app.route("/api/forge", createForgeRoutes());
73647
74039
  for (const module of options.modules) {
73648
74040
  if (module.routes) app.route(`/api/modules/${module.manifest.id}`, module.routes(options.context));
73649
74041
  }