@amistio/cli 0.1.23 → 0.1.24

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/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { createHash as createHash7, randomUUID } from "node:crypto";
5
- import { writeFile as writeFile9 } from "node:fs/promises";
6
- import os7 from "node:os";
7
- import path15 from "node:path";
4
+ import { createHash as createHash8, randomUUID } from "node:crypto";
5
+ import { writeFile as writeFile10 } from "node:fs/promises";
6
+ import os8 from "node:os";
7
+ import path16 from "node:path";
8
8
  import { Command } from "commander";
9
9
 
10
10
  // ../shared/src/schemas.ts
@@ -2178,6 +2178,24 @@ async function readGitTopLevel(rootDir) {
2178
2178
 
2179
2179
  // src/api-client.ts
2180
2180
  import { z as z3 } from "zod";
2181
+ var AmistioApiError = class extends Error {
2182
+ constructor(status, statusText, detail) {
2183
+ super(`Amistio API request failed: ${status} ${statusText}${detail ? ` - ${detail}` : ""}`);
2184
+ this.status = status;
2185
+ this.statusText = statusText;
2186
+ this.detail = detail;
2187
+ this.name = "AmistioApiError";
2188
+ }
2189
+ status;
2190
+ statusText;
2191
+ detail;
2192
+ };
2193
+ function isRetryableApiError(error) {
2194
+ if (error instanceof AmistioApiError) {
2195
+ return error.status === 408 || error.status === 429 || error.status >= 500;
2196
+ }
2197
+ return error instanceof TypeError;
2198
+ }
2181
2199
  var ApiClient = class {
2182
2200
  constructor(options) {
2183
2201
  this.options = options;
@@ -2519,7 +2537,7 @@ var ApiClient = class {
2519
2537
  });
2520
2538
  if (!response.ok) {
2521
2539
  const detail = await response.text().catch(() => "");
2522
- throw new Error(`Amistio API request failed: ${response.status} ${response.statusText}${detail ? ` - ${detail}` : ""}`);
2540
+ throw new AmistioApiError(response.status, response.statusText, detail);
2523
2541
  }
2524
2542
  return schema.parse(await response.json());
2525
2543
  }
@@ -2554,8 +2572,8 @@ var toolSessionMutationSchema = z3.object({
2554
2572
  });
2555
2573
  function resolveApiUrl(apiUrl, urlPath) {
2556
2574
  const base = apiUrl.endsWith("/") ? apiUrl.slice(0, -1) : apiUrl;
2557
- const path16 = urlPath.startsWith("/") ? urlPath : `/${urlPath}`;
2558
- return new URL(`${base}${path16}`);
2575
+ const path17 = urlPath.startsWith("/") ? urlPath : `/${urlPath}`;
2576
+ return new URL(`${base}${path17}`);
2559
2577
  }
2560
2578
 
2561
2579
  // src/orchestrator.ts
@@ -2619,11 +2637,155 @@ async function writePromptFile(filePath, prompt) {
2619
2637
  return filePath;
2620
2638
  }
2621
2639
 
2622
- // src/local-tool-runner.ts
2623
- import { spawn } from "node:child_process";
2624
- import { mkdtemp, readFile as readFile3, rm, writeFile as writeFile4 } from "node:fs/promises";
2640
+ // src/result-finalization-outbox.ts
2641
+ import { createHash as createHash2 } from "node:crypto";
2642
+ import { mkdir as mkdir5, readdir as readdir2, readFile as readFile3, rename, rm, writeFile as writeFile4 } from "node:fs/promises";
2625
2643
  import os2 from "node:os";
2626
2644
  import path5 from "node:path";
2645
+ import { z as z4 } from "zod";
2646
+ var brainGenerationResultMutationSchema = z4.discriminatedUnion("status", [
2647
+ z4.object({
2648
+ status: z4.literal("completed"),
2649
+ runnerId: z4.string().min(1),
2650
+ idempotencyKey: z4.string().min(1),
2651
+ artifacts: z4.array(generatedBrainArtifactSchema).min(1),
2652
+ tool: z4.string().min(1).optional(),
2653
+ durationMs: z4.number().int().nonnegative().optional(),
2654
+ sessionPolicy: sessionPolicySchema.optional(),
2655
+ sessionGroupKey: z4.string().min(1).optional(),
2656
+ toolSessionId: z4.string().min(1).optional(),
2657
+ sessionDecision: sessionDecisionSchema.optional(),
2658
+ sessionDecisionReason: z4.string().min(1).optional(),
2659
+ message: z4.string().optional()
2660
+ }),
2661
+ z4.object({
2662
+ status: z4.literal("failed"),
2663
+ runnerId: z4.string().min(1),
2664
+ idempotencyKey: z4.string().min(1),
2665
+ tool: z4.string().min(1).optional(),
2666
+ durationMs: z4.number().int().nonnegative().optional(),
2667
+ sessionPolicy: sessionPolicySchema.optional(),
2668
+ sessionGroupKey: z4.string().min(1).optional(),
2669
+ toolSessionId: z4.string().min(1).optional(),
2670
+ sessionDecision: sessionDecisionSchema.optional(),
2671
+ sessionDecisionReason: z4.string().min(1).optional(),
2672
+ message: z4.string().optional(),
2673
+ error: z4.string().optional()
2674
+ })
2675
+ ]);
2676
+ var brainGenerationFinalizationEntrySchema = z4.object({
2677
+ schemaVersion: z4.literal(1),
2678
+ kind: z4.literal("brainGenerationResult"),
2679
+ status: z4.enum(["pending", "terminal"]),
2680
+ accountId: z4.string().min(1),
2681
+ projectId: z4.string().min(1),
2682
+ repositoryLinkId: z4.string().min(1),
2683
+ runnerId: z4.string().min(1),
2684
+ workItemId: z4.string().min(1),
2685
+ workKind: z4.enum(["brainGeneration", "planRevision"]),
2686
+ attempt: z4.number().int().nonnegative(),
2687
+ idempotencyKey: z4.string().min(1),
2688
+ result: brainGenerationResultMutationSchema,
2689
+ retryCount: z4.number().int().nonnegative(),
2690
+ createdAt: z4.string().min(1),
2691
+ updatedAt: z4.string().min(1),
2692
+ lastError: z4.string().optional()
2693
+ });
2694
+ function defaultResultFinalizationOutboxDir() {
2695
+ return path5.join(os2.homedir(), ".config", "amistio", "result-finalizations");
2696
+ }
2697
+ function createBrainGenerationFinalizationEntry(input, now = (/* @__PURE__ */ new Date()).toISOString()) {
2698
+ return brainGenerationFinalizationEntrySchema.parse({
2699
+ schemaVersion: 1,
2700
+ kind: "brainGenerationResult",
2701
+ status: "pending",
2702
+ accountId: input.accountId,
2703
+ projectId: input.projectId,
2704
+ repositoryLinkId: input.repositoryLinkId,
2705
+ runnerId: input.runnerId,
2706
+ workItemId: input.workItemId,
2707
+ workKind: input.workKind,
2708
+ attempt: input.attempt,
2709
+ idempotencyKey: input.idempotencyKey,
2710
+ result: input.result,
2711
+ retryCount: 0,
2712
+ createdAt: now,
2713
+ updatedAt: now
2714
+ });
2715
+ }
2716
+ async function upsertBrainGenerationFinalizationEntry(entry, outboxDir = defaultResultFinalizationOutboxDir()) {
2717
+ await mkdir5(outboxDir, { recursive: true });
2718
+ const filePath = brainGenerationFinalizationEntryPath(entry, outboxDir);
2719
+ const tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
2720
+ await writeFile4(tempPath, `${JSON.stringify(entry, null, 2)}
2721
+ `, "utf8");
2722
+ await rename(tempPath, filePath);
2723
+ }
2724
+ async function listPendingBrainGenerationFinalizations(scope, outboxDir = defaultResultFinalizationOutboxDir()) {
2725
+ const entries = await readdir2(outboxDir, { withFileTypes: true }).catch((error) => {
2726
+ if (error.code === "ENOENT") return [];
2727
+ throw error;
2728
+ });
2729
+ const pending = [];
2730
+ for (const entry of entries) {
2731
+ if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
2732
+ const filePath = path5.join(outboxDir, entry.name);
2733
+ let raw;
2734
+ try {
2735
+ raw = JSON.parse(await readFile3(filePath, "utf8"));
2736
+ } catch {
2737
+ continue;
2738
+ }
2739
+ const parsed = brainGenerationFinalizationEntrySchema.safeParse(raw);
2740
+ if (!parsed.success) continue;
2741
+ const value = parsed.data;
2742
+ if (value.status !== "pending") continue;
2743
+ if (value.accountId !== scope.accountId || value.projectId !== scope.projectId || value.repositoryLinkId !== scope.repositoryLinkId || value.runnerId !== scope.runnerId) continue;
2744
+ pending.push(value);
2745
+ }
2746
+ return pending.sort((first, second) => Date.parse(first.createdAt) - Date.parse(second.createdAt));
2747
+ }
2748
+ async function markBrainGenerationFinalizationRetry(entry, error, outboxDir = defaultResultFinalizationOutboxDir()) {
2749
+ const updated = brainGenerationFinalizationEntrySchema.parse({
2750
+ ...entry,
2751
+ status: "pending",
2752
+ retryCount: entry.retryCount + 1,
2753
+ lastError: truncateLocalError(error),
2754
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
2755
+ });
2756
+ await upsertBrainGenerationFinalizationEntry(updated, outboxDir);
2757
+ return updated;
2758
+ }
2759
+ async function markBrainGenerationFinalizationTerminal(entry, error, outboxDir = defaultResultFinalizationOutboxDir()) {
2760
+ const updated = brainGenerationFinalizationEntrySchema.parse({
2761
+ ...entry,
2762
+ status: "terminal",
2763
+ lastError: truncateLocalError(error),
2764
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
2765
+ });
2766
+ await upsertBrainGenerationFinalizationEntry(updated, outboxDir);
2767
+ return updated;
2768
+ }
2769
+ async function deleteBrainGenerationFinalizationEntry(entry, outboxDir = defaultResultFinalizationOutboxDir()) {
2770
+ await rm(brainGenerationFinalizationEntryPath(entry, outboxDir), { force: true });
2771
+ }
2772
+ function brainGenerationFinalizationEntryPath(entry, outboxDir) {
2773
+ return path5.join(outboxDir, `${brainGenerationFinalizationEntryKey(entry)}.json`);
2774
+ }
2775
+ function brainGenerationFinalizationEntryKey(entry) {
2776
+ const hash = createHash2("sha256").update([entry.accountId, entry.projectId, entry.repositoryLinkId, entry.runnerId, entry.workItemId, String(entry.attempt), entry.idempotencyKey].join("\0")).digest("hex").slice(0, 32);
2777
+ return `brain-generation-${hash}`;
2778
+ }
2779
+ function truncateLocalError(error) {
2780
+ const trimmed = error.trim();
2781
+ return trimmed.length > 600 ? `${trimmed.slice(0, 600)}...` : trimmed;
2782
+ }
2783
+
2784
+ // src/local-tool-runner.ts
2785
+ import { spawn } from "node:child_process";
2786
+ import { mkdtemp, readFile as readFile4, rm as rm2, writeFile as writeFile5 } from "node:fs/promises";
2787
+ import os3 from "node:os";
2788
+ import path6 from "node:path";
2627
2789
  var localToolNames = runnerToolNames;
2628
2790
  var allReasoningEfforts = ["auto", "low", "medium", "high", "xhigh"];
2629
2791
  var highReasoningEfforts = ["auto", "high", "xhigh"];
@@ -2830,9 +2992,9 @@ async function detectLocalTools() {
2830
2992
  );
2831
2993
  }
2832
2994
  async function runLocalTool(options) {
2833
- const promptTempDir = await mkdtemp(path5.join(os2.tmpdir(), "amistio-prompt-"));
2834
- const promptFilePath = path5.join(promptTempDir, "prompt.md");
2835
- await writeFile4(promptFilePath, options.prompt, "utf8");
2995
+ const promptTempDir = await mkdtemp(path6.join(os3.tmpdir(), "amistio-prompt-"));
2996
+ const promptFilePath = path6.join(promptTempDir, "prompt.md");
2997
+ await writeFile5(promptFilePath, options.prompt, "utf8");
2836
2998
  const modelConfig = normalizeModelOptions(options);
2837
2999
  try {
2838
3000
  const runnerOptions = {
@@ -2864,11 +3026,11 @@ async function runLocalTool(options) {
2864
3026
  ...result
2865
3027
  };
2866
3028
  } finally {
2867
- await rm(promptTempDir, { recursive: true, force: true });
3029
+ await rm2(promptTempDir, { recursive: true, force: true });
2868
3030
  }
2869
3031
  }
2870
3032
  async function createToolRunPreview(options) {
2871
- const promptFilePath = path5.join(os2.tmpdir(), "amistio-generated-prompt.md");
3033
+ const promptFilePath = path6.join(os3.tmpdir(), "amistio-generated-prompt.md");
2872
3034
  const modelConfig = normalizeModelOptions(options);
2873
3035
  const runnerOptions = {
2874
3036
  rootDir: options.rootDir,
@@ -3061,13 +3223,13 @@ async function detectProviderCatalog(adapter) {
3061
3223
  }
3062
3224
  async function loadOpencodeProviderCatalog() {
3063
3225
  const configPaths = [
3064
- path5.join(os2.homedir(), ".config", "opencode", "opencode.json"),
3065
- path5.join(os2.homedir(), ".config", "opencode", "config.json"),
3066
- path5.join(process.cwd(), "opencode.json")
3226
+ path6.join(os3.homedir(), ".config", "opencode", "opencode.json"),
3227
+ path6.join(os3.homedir(), ".config", "opencode", "config.json"),
3228
+ path6.join(process.cwd(), "opencode.json")
3067
3229
  ];
3068
3230
  for (const configPath of configPaths) {
3069
3231
  try {
3070
- const parsed = JSON.parse(await readFile3(configPath, "utf8"));
3232
+ const parsed = JSON.parse(await readFile4(configPath, "utf8"));
3071
3233
  const providerValue = isRecord(parsed) ? parsed.provider : void 0;
3072
3234
  const catalog = sanitizeProviderCatalog(providerValue);
3073
3235
  if (catalog) return catalog;
@@ -3439,16 +3601,16 @@ function shellQuote(value) {
3439
3601
 
3440
3602
  // src/runner-daemon.ts
3441
3603
  import { spawn as spawn2 } from "node:child_process";
3442
- import { createHash as createHash2 } from "node:crypto";
3604
+ import { createHash as createHash3 } from "node:crypto";
3443
3605
  import { openSync } from "node:fs";
3444
- import { mkdir as mkdir5, readdir as readdir2, readFile as readFile4, writeFile as writeFile5 } from "node:fs/promises";
3445
- import os3 from "node:os";
3446
- import path6 from "node:path";
3606
+ import { mkdir as mkdir6, readdir as readdir3, readFile as readFile5, writeFile as writeFile6 } from "node:fs/promises";
3607
+ import os4 from "node:os";
3608
+ import path7 from "node:path";
3447
3609
  function currentRunnerMode() {
3448
3610
  return process.env.AMISTIO_RUNNER_MODE === "background" ? "background" : "foreground";
3449
3611
  }
3450
3612
  function defaultRunnerMetadataDir() {
3451
- return path6.join(os3.homedir(), ".config", "amistio", "runners");
3613
+ return path7.join(os4.homedir(), ".config", "amistio", "runners");
3452
3614
  }
3453
3615
  function updatedCliRunnerLaunchOptions() {
3454
3616
  return { executablePath: "amistio", directExecutable: true };
@@ -3465,8 +3627,8 @@ async function startRunnerDaemon(input) {
3465
3627
  if (existing?.status === "running" && isProcessRunning(existing.pid)) {
3466
3628
  throw new Error(`Background runner ${existing.runnerId} is already running with PID ${existing.pid}.`);
3467
3629
  }
3468
- await mkdir5(metadataDir, { recursive: true });
3469
- const logPath = path6.join(metadataDir, `${runnerDaemonKey(input)}.log`);
3630
+ await mkdir6(metadataDir, { recursive: true });
3631
+ const logPath = path7.join(metadataDir, `${runnerDaemonKey(input)}.log`);
3470
3632
  const logFd = openSync(logPath, "a");
3471
3633
  const launch = resolveRunnerDaemonLaunch({
3472
3634
  args: input.args,
@@ -3493,13 +3655,13 @@ async function startRunnerDaemon(input) {
3493
3655
  projectId: input.projectId,
3494
3656
  repositoryLinkId: input.repositoryLinkId,
3495
3657
  runnerId: input.runnerId,
3496
- rootDir: path6.resolve(input.rootDir),
3658
+ rootDir: path7.resolve(input.rootDir),
3497
3659
  apiUrl: input.apiUrl,
3498
3660
  pid: child.pid,
3499
3661
  status: "running",
3500
3662
  startedAt: now,
3501
3663
  updatedAt: now,
3502
- hostname: os3.hostname(),
3664
+ hostname: os4.hostname(),
3503
3665
  logPath
3504
3666
  };
3505
3667
  await writeRunnerDaemonMetadata(metadata, metadataDir);
@@ -3507,8 +3669,8 @@ async function startRunnerDaemon(input) {
3507
3669
  }
3508
3670
  async function restartRunnerDaemonProcess(metadata, args, input = {}) {
3509
3671
  const metadataDir = input.metadataDir ?? defaultRunnerMetadataDir();
3510
- await mkdir5(metadataDir, { recursive: true });
3511
- const logPath = metadata.logPath ?? path6.join(metadataDir, `${runnerDaemonKey(metadata)}.log`);
3672
+ await mkdir6(metadataDir, { recursive: true });
3673
+ const logPath = metadata.logPath ?? path7.join(metadataDir, `${runnerDaemonKey(metadata)}.log`);
3512
3674
  const logFd = openSync(logPath, "a");
3513
3675
  const launch = resolveRunnerDaemonLaunch({
3514
3676
  args,
@@ -3536,7 +3698,7 @@ async function restartRunnerDaemonProcess(metadata, args, input = {}) {
3536
3698
  status: "running",
3537
3699
  startedAt: now,
3538
3700
  updatedAt: now,
3539
- hostname: os3.hostname(),
3701
+ hostname: os4.hostname(),
3540
3702
  logPath
3541
3703
  };
3542
3704
  await writeRunnerDaemonMetadata(replacement, metadataDir);
@@ -3545,12 +3707,12 @@ async function restartRunnerDaemonProcess(metadata, args, input = {}) {
3545
3707
  async function listRunnerDaemonMetadata(input, metadataDir = defaultRunnerMetadataDir()) {
3546
3708
  let entries;
3547
3709
  try {
3548
- entries = await readdir2(metadataDir);
3710
+ entries = await readdir3(metadataDir);
3549
3711
  } catch {
3550
3712
  return [];
3551
3713
  }
3552
3714
  const records = await Promise.all(
3553
- entries.filter((entry) => entry.endsWith(".json")).map(async (entry) => readRunnerDaemonMetadataFile(path6.join(metadataDir, entry)))
3715
+ entries.filter((entry) => entry.endsWith(".json")).map(async (entry) => readRunnerDaemonMetadataFile(path7.join(metadataDir, entry)))
3554
3716
  );
3555
3717
  return records.filter((record) => Boolean(record)).filter((record) => record.accountId === input.accountId && record.projectId === input.projectId && record.repositoryLinkId === input.repositoryLinkId).filter((record) => !input.runnerId || record.runnerId === input.runnerId).sort((a, b) => Date.parse(b.updatedAt) - Date.parse(a.updatedAt));
3556
3718
  }
@@ -3558,8 +3720,8 @@ async function readRunnerDaemonMetadata(input, metadataDir = defaultRunnerMetada
3558
3720
  return readRunnerDaemonMetadataFile(runnerDaemonMetadataPath(input, metadataDir));
3559
3721
  }
3560
3722
  async function writeRunnerDaemonMetadata(metadata, metadataDir = defaultRunnerMetadataDir()) {
3561
- await mkdir5(metadataDir, { recursive: true });
3562
- await writeFile5(runnerDaemonMetadataPath(metadata, metadataDir), JSON.stringify(metadata, null, 2), { encoding: "utf8", mode: 384 });
3723
+ await mkdir6(metadataDir, { recursive: true });
3724
+ await writeFile6(runnerDaemonMetadataPath(metadata, metadataDir), JSON.stringify(metadata, null, 2), { encoding: "utf8", mode: 384 });
3563
3725
  }
3564
3726
  async function markRunnerDaemonStopped(metadata, metadataDir = defaultRunnerMetadataDir()) {
3565
3727
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -3621,14 +3783,14 @@ function runnerDaemonUptime(metadata, now = Date.now()) {
3621
3783
  return `${seconds}s`;
3622
3784
  }
3623
3785
  function runnerDaemonMetadataPath(input, metadataDir) {
3624
- return path6.join(metadataDir, `${runnerDaemonKey(input)}.json`);
3786
+ return path7.join(metadataDir, `${runnerDaemonKey(input)}.json`);
3625
3787
  }
3626
3788
  function runnerDaemonKey(input) {
3627
- return createHash2("sha256").update(`${input.accountId}:${input.projectId}:${input.repositoryLinkId}:${input.runnerId}`).digest("hex");
3789
+ return createHash3("sha256").update(`${input.accountId}:${input.projectId}:${input.repositoryLinkId}:${input.runnerId}`).digest("hex");
3628
3790
  }
3629
3791
  async function readRunnerDaemonMetadataFile(filePath) {
3630
3792
  try {
3631
- const parsed = JSON.parse(await readFile4(filePath, "utf8"));
3793
+ const parsed = JSON.parse(await readFile5(filePath, "utf8"));
3632
3794
  if (parsed.schemaVersion !== 1 || !parsed.runnerId || !parsed.projectId || !parsed.repositoryLinkId) {
3633
3795
  return void 0;
3634
3796
  }
@@ -3640,10 +3802,10 @@ async function readRunnerDaemonMetadataFile(filePath) {
3640
3802
 
3641
3803
  // src/runner-service.ts
3642
3804
  import { spawn as spawn3 } from "node:child_process";
3643
- import { createHash as createHash3 } from "node:crypto";
3644
- import { mkdir as mkdir6, readFile as readFile5, rm as rm2, writeFile as writeFile6 } from "node:fs/promises";
3645
- import os4 from "node:os";
3646
- import path7 from "node:path";
3805
+ import { createHash as createHash4 } from "node:crypto";
3806
+ import { mkdir as mkdir7, readFile as readFile6, rm as rm3, writeFile as writeFile7 } from "node:fs/promises";
3807
+ import os5 from "node:os";
3808
+ import path8 from "node:path";
3647
3809
  function detectRunnerServicePlatform(platform = process.platform) {
3648
3810
  if (platform === "darwin") return "launchd";
3649
3811
  if (platform === "linux") return "systemd";
@@ -3654,19 +3816,19 @@ function createRunnerServiceDescriptor(input) {
3654
3816
  if (platform === "unsupported") {
3655
3817
  throw new Error("Startup services are supported for user-level launchd on macOS and systemd user services on Linux.");
3656
3818
  }
3657
- const homeDir = input.homeDir ?? os4.homedir();
3819
+ const homeDir = input.homeDir ?? os5.homedir();
3658
3820
  const serviceName = runnerServiceName(input);
3659
3821
  const serviceFilePath = runnerServiceFilePath(platform, serviceName, homeDir);
3660
3822
  const now = (/* @__PURE__ */ new Date()).toISOString();
3661
3823
  const command = [input.executablePath ?? process.execPath, input.scriptPath ?? process.argv[1], ...input.args];
3662
- const logPath = path7.join(input.metadataDir ?? defaultRunnerMetadataDir(), `${runnerServiceKey(input)}.service.log`);
3824
+ const logPath = path8.join(input.metadataDir ?? defaultRunnerMetadataDir(), `${runnerServiceKey(input)}.service.log`);
3663
3825
  const metadata = {
3664
3826
  schemaVersion: 1,
3665
3827
  accountId: input.accountId,
3666
3828
  projectId: input.projectId,
3667
3829
  repositoryLinkId: input.repositoryLinkId,
3668
3830
  runnerId: input.runnerId,
3669
- rootDir: path7.resolve(input.rootDir),
3831
+ rootDir: path8.resolve(input.rootDir),
3670
3832
  apiUrl: input.apiUrl,
3671
3833
  serviceName,
3672
3834
  serviceFilePath,
@@ -3683,9 +3845,9 @@ function createRunnerServiceDescriptor(input) {
3683
3845
  }
3684
3846
  async function installRunnerService(input, options = {}) {
3685
3847
  const descriptor = createRunnerServiceDescriptor(input);
3686
- await mkdir6(path7.dirname(descriptor.metadata.serviceFilePath), { recursive: true });
3687
- await mkdir6(input.metadataDir ?? defaultRunnerMetadataDir(), { recursive: true });
3688
- await writeFile6(descriptor.metadata.serviceFilePath, descriptor.content, { encoding: "utf8", mode: 384 });
3848
+ await mkdir7(path8.dirname(descriptor.metadata.serviceFilePath), { recursive: true });
3849
+ await mkdir7(input.metadataDir ?? defaultRunnerMetadataDir(), { recursive: true });
3850
+ await writeFile7(descriptor.metadata.serviceFilePath, descriptor.content, { encoding: "utf8", mode: 384 });
3689
3851
  await writeRunnerServiceMetadata(descriptor.metadata, input.metadataDir);
3690
3852
  if (options.activate !== false) {
3691
3853
  const activation = await activateRunnerService(descriptor.metadata);
@@ -3701,13 +3863,13 @@ async function removeRunnerService(input) {
3701
3863
  return void 0;
3702
3864
  }
3703
3865
  await deactivateRunnerService(metadata).catch(() => void 0);
3704
- await rm2(metadata.serviceFilePath, { force: true });
3705
- await rm2(runnerServiceMetadataPath(input, input.metadataDir ?? defaultRunnerMetadataDir()), { force: true });
3866
+ await rm3(metadata.serviceFilePath, { force: true });
3867
+ await rm3(runnerServiceMetadataPath(input, input.metadataDir ?? defaultRunnerMetadataDir()), { force: true });
3706
3868
  return { ...metadata, status: "removed", updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
3707
3869
  }
3708
3870
  async function readRunnerServiceMetadata(input, metadataDir = defaultRunnerMetadataDir()) {
3709
3871
  try {
3710
- const parsed = JSON.parse(await readFile5(runnerServiceMetadataPath(input, metadataDir), "utf8"));
3872
+ const parsed = JSON.parse(await readFile6(runnerServiceMetadataPath(input, metadataDir), "utf8"));
3711
3873
  if (parsed.schemaVersion !== 1 || !parsed.serviceName || !parsed.serviceFilePath) {
3712
3874
  return void 0;
3713
3875
  }
@@ -3717,8 +3879,8 @@ async function readRunnerServiceMetadata(input, metadataDir = defaultRunnerMetad
3717
3879
  }
3718
3880
  }
3719
3881
  async function writeRunnerServiceMetadata(metadata, metadataDir = defaultRunnerMetadataDir()) {
3720
- await mkdir6(metadataDir, { recursive: true });
3721
- await writeFile6(runnerServiceMetadataPath(metadata, metadataDir), JSON.stringify(metadata, null, 2), { encoding: "utf8", mode: 384 });
3882
+ await mkdir7(metadataDir, { recursive: true });
3883
+ await writeFile7(runnerServiceMetadataPath(metadata, metadataDir), JSON.stringify(metadata, null, 2), { encoding: "utf8", mode: 384 });
3722
3884
  }
3723
3885
  async function runnerServiceRuntimeStatus(metadata) {
3724
3886
  if (metadata.platform === "launchd") {
@@ -3801,18 +3963,18 @@ WantedBy=default.target
3801
3963
  }
3802
3964
  function runnerServiceFilePath(platform, serviceName, homeDir) {
3803
3965
  if (platform === "launchd") {
3804
- return path7.join(homeDir, "Library", "LaunchAgents", `${serviceName}.plist`);
3966
+ return path8.join(homeDir, "Library", "LaunchAgents", `${serviceName}.plist`);
3805
3967
  }
3806
- return path7.join(homeDir, ".config", "systemd", "user", `${serviceName}.service`);
3968
+ return path8.join(homeDir, ".config", "systemd", "user", `${serviceName}.service`);
3807
3969
  }
3808
3970
  function runnerServiceMetadataPath(input, metadataDir) {
3809
- return path7.join(metadataDir, `${runnerServiceKey(input)}.service.json`);
3971
+ return path8.join(metadataDir, `${runnerServiceKey(input)}.service.json`);
3810
3972
  }
3811
3973
  function runnerServiceName(input) {
3812
3974
  return `com.amistio.runner.${runnerServiceKey(input).slice(0, 20)}`;
3813
3975
  }
3814
3976
  function runnerServiceKey(input) {
3815
- return createHash3("sha256").update(`${input.accountId}:${input.projectId}:${input.repositoryLinkId}:${input.runnerId}`).digest("hex");
3977
+ return createHash4("sha256").update(`${input.accountId}:${input.projectId}:${input.repositoryLinkId}:${input.runnerId}`).digest("hex");
3816
3978
  }
3817
3979
  function launchdDomain() {
3818
3980
  const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
@@ -3988,9 +4150,9 @@ function tokens(value) {
3988
4150
 
3989
4151
  // src/sync.ts
3990
4152
  import { execFile as execFile3 } from "node:child_process";
3991
- import { createHash as createHash4 } from "node:crypto";
3992
- import { mkdir as mkdir7, readdir as readdir3, readFile as readFile6, stat as stat3, writeFile as writeFile7 } from "node:fs/promises";
3993
- import path8 from "node:path";
4153
+ import { createHash as createHash5 } from "node:crypto";
4154
+ import { mkdir as mkdir8, readdir as readdir4, readFile as readFile7, stat as stat3, writeFile as writeFile8 } from "node:fs/promises";
4155
+ import path9 from "node:path";
3994
4156
  import { promisify as promisify3 } from "node:util";
3995
4157
  var execFileAsync3 = promisify3(execFile3);
3996
4158
  var legacySyncRoots = ["architecture", "context", "decisions", "features", "memory", "plans", "prompts", "workflows"];
@@ -4086,7 +4248,7 @@ async function readLocalSyncedDocuments(rootDir) {
4086
4248
  const documentFiles = await findBrainDocumentFiles(rootDir);
4087
4249
  const documents = [];
4088
4250
  for (const fullPath of documentFiles) {
4089
- const raw = await readFile6(fullPath, "utf8");
4251
+ const raw = await readFile7(fullPath, "utf8");
4090
4252
  const repoPath = toRepoPath(rootDir, fullPath);
4091
4253
  const parsed = parseSyncedDocument(raw, repoPath);
4092
4254
  if (!parsed) {
@@ -4136,8 +4298,8 @@ async function materializeBrainDocuments(rootDir, documents, options = {}) {
4136
4298
  result.skipped.push(document.repoPath);
4137
4299
  continue;
4138
4300
  }
4139
- await mkdir7(path8.dirname(fullPath), { recursive: true });
4140
- await writeFile7(fullPath, createSyncedDocumentContent(document), "utf8");
4301
+ await mkdir8(path9.dirname(fullPath), { recursive: true });
4302
+ await writeFile8(fullPath, createSyncedDocumentContent(document), "utf8");
4141
4303
  result.written.push(document.repoPath);
4142
4304
  }
4143
4305
  return result;
@@ -4266,7 +4428,7 @@ function parseSyncedHtml(content) {
4266
4428
  }
4267
4429
  async function readExistingSyncedDocument(fullPath) {
4268
4430
  try {
4269
- const raw = await readFile6(fullPath, "utf8");
4431
+ const raw = await readFile7(fullPath, "utf8");
4270
4432
  const parsed = parseSyncedDocument(raw, fullPath);
4271
4433
  if (!parsed) {
4272
4434
  return { exists: true };
@@ -4291,7 +4453,7 @@ async function readExistingSyncedDocument(fullPath) {
4291
4453
  async function findBrainDocumentFiles(rootDir) {
4292
4454
  const files = [];
4293
4455
  for (const syncRoot of [...syncRoots, htmlSyncRoot]) {
4294
- const fullRoot = path8.join(rootDir, syncRoot);
4456
+ const fullRoot = path9.join(rootDir, syncRoot);
4295
4457
  if (!await exists2(fullRoot)) {
4296
4458
  continue;
4297
4459
  }
@@ -4300,8 +4462,8 @@ async function findBrainDocumentFiles(rootDir) {
4300
4462
  return files;
4301
4463
  }
4302
4464
  async function walkBrainDocumentFiles(directory, files) {
4303
- for (const entry of await readdir3(directory, { withFileTypes: true })) {
4304
- const fullPath = path8.join(directory, entry.name);
4465
+ for (const entry of await readdir4(directory, { withFileTypes: true })) {
4466
+ const fullPath = path9.join(directory, entry.name);
4305
4467
  if (entry.isDirectory()) {
4306
4468
  await walkBrainDocumentFiles(fullPath, files);
4307
4469
  } else if (entry.isFile() && /\.(md|mdx|html?)$/i.test(entry.name)) {
@@ -4310,23 +4472,23 @@ async function walkBrainDocumentFiles(directory, files) {
4310
4472
  }
4311
4473
  }
4312
4474
  function safeRepoPath(rootDir, repoPath) {
4313
- if (path8.isAbsolute(repoPath)) {
4475
+ if (path9.isAbsolute(repoPath)) {
4314
4476
  throw new Error(`Refusing to use absolute repo path: ${repoPath}`);
4315
4477
  }
4316
- const normalized = path8.normalize(repoPath);
4317
- if (normalized === ".." || normalized.startsWith(`..${path8.sep}`)) {
4478
+ const normalized = path9.normalize(repoPath);
4479
+ if (normalized === ".." || normalized.startsWith(`..${path9.sep}`)) {
4318
4480
  throw new Error(`Refusing to use path outside the repository: ${repoPath}`);
4319
4481
  }
4320
- const root = path8.resolve(rootDir);
4321
- const fullPath = path8.resolve(root, normalized);
4322
- if (!fullPath.startsWith(`${root}${path8.sep}`)) {
4482
+ const root = path9.resolve(rootDir);
4483
+ const fullPath = path9.resolve(root, normalized);
4484
+ if (!fullPath.startsWith(`${root}${path9.sep}`)) {
4323
4485
  throw new Error(`Refusing to use path outside the repository: ${repoPath}`);
4324
4486
  }
4325
4487
  return fullPath;
4326
4488
  }
4327
4489
  function isControlPlanePath(repoPath) {
4328
- const normalized = path8.normalize(repoPath);
4329
- return syncRoots.some((syncRoot) => normalized === syncRoot || normalized.startsWith(`${syncRoot}${path8.sep}`)) || normalized === htmlSyncRoot || normalized.startsWith(`${htmlSyncRoot}${path8.sep}`);
4490
+ const normalized = path9.normalize(repoPath);
4491
+ return syncRoots.some((syncRoot) => normalized === syncRoot || normalized.startsWith(`${syncRoot}${path9.sep}`)) || normalized === htmlSyncRoot || normalized.startsWith(`${htmlSyncRoot}${path9.sep}`);
4330
4492
  }
4331
4493
  function canonicalControlPlaneRepoPath(repoPath) {
4332
4494
  const normalized = repoPath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\/+/, "");
@@ -4337,16 +4499,16 @@ function canonicalControlPlaneRepoPath(repoPath) {
4337
4499
  return normalized;
4338
4500
  }
4339
4501
  function toRepoPath(rootDir, fullPath) {
4340
- return path8.relative(rootDir, fullPath).split(path8.sep).join("/");
4502
+ return path9.relative(rootDir, fullPath).split(path9.sep).join("/");
4341
4503
  }
4342
4504
  function inferTitle(content, repoPath) {
4343
4505
  const heading = content.split("\n").find((line) => line.startsWith("# "))?.replace(/^#\s+/, "").trim();
4344
4506
  if (heading) return heading;
4345
4507
  const htmlHeading = content.match(/<h1\b[^>]*>([\s\S]*?)<\/h1>/i)?.[1]?.replace(/<[^>]+>/g, "").trim();
4346
- return htmlHeading || path8.basename(repoPath, path8.extname(repoPath));
4508
+ return htmlHeading || path9.basename(repoPath, path9.extname(repoPath));
4347
4509
  }
4348
4510
  async function collectExternalBrainDocumentsForPush(rootDir, metadata, existingDocuments, options) {
4349
- const root = path8.resolve(rootDir);
4511
+ const root = path9.resolve(rootDir);
4350
4512
  const maxBytes = (options.maxFileKb ?? defaultAutoSyncMaxFileKb) * 1024;
4351
4513
  const syncedAt = options.syncedAt ?? (/* @__PURE__ */ new Date()).toISOString();
4352
4514
  const existingById = new Map(existingDocuments.map((document) => [document.documentId, document]));
@@ -4371,7 +4533,7 @@ async function collectExternalBrainDocumentsForPush(rootDir, metadata, existingD
4371
4533
  skipped.push({ repoPath: normalizedRepoPath, reason: "tooLarge" });
4372
4534
  continue;
4373
4535
  }
4374
- const content = await readFile6(fullPath, "utf8").catch(() => void 0);
4536
+ const content = await readFile7(fullPath, "utf8").catch(() => void 0);
4375
4537
  if (content === void 0) {
4376
4538
  skipped.push({ repoPath: normalizedRepoPath, reason: "unreadable" });
4377
4539
  continue;
@@ -4436,7 +4598,7 @@ async function listAutoSyncCandidatePaths(rootDir) {
4436
4598
  }
4437
4599
  const files = [];
4438
4600
  for (const syncRoot of [...syncRoots, htmlSyncRoot, ...legacySyncRoots]) {
4439
- const fullRoot = path8.join(rootDir, syncRoot);
4601
+ const fullRoot = path9.join(rootDir, syncRoot);
4440
4602
  if (await exists2(fullRoot)) {
4441
4603
  await walkAutoSyncFiles(rootDir, fullRoot, files);
4442
4604
  }
@@ -4444,9 +4606,9 @@ async function listAutoSyncCandidatePaths(rootDir) {
4444
4606
  return uniqueSortedRepoPaths(files);
4445
4607
  }
4446
4608
  async function walkAutoSyncFiles(rootDir, directory, files) {
4447
- for (const entry of await readdir3(directory, { withFileTypes: true }).catch(() => [])) {
4448
- const fullPath = path8.join(directory, entry.name);
4449
- const repoPath = normalizeRepoPath3(path8.relative(rootDir, fullPath));
4609
+ for (const entry of await readdir4(directory, { withFileTypes: true }).catch(() => [])) {
4610
+ const fullPath = path9.join(directory, entry.name);
4611
+ const repoPath = normalizeRepoPath3(path9.relative(rootDir, fullPath));
4450
4612
  if (entry.isDirectory()) {
4451
4613
  if (!autoSyncExcludedDirectoryNames.has(entry.name)) {
4452
4614
  await walkAutoSyncFiles(rootDir, fullPath, files);
@@ -4480,7 +4642,7 @@ function legacyDocumentTypeForRepoPath(repoPath) {
4480
4642
  return root && root in documentTypeByRoot ? documentTypeByRoot[root] : void 0;
4481
4643
  }
4482
4644
  function stableExternalDocumentId(metadata, repoPath) {
4483
- return `doc_external_${createHash4("sha256").update(`${metadata.amistioAccountId}:${metadata.amistioProjectId}:${metadata.repositoryLinkId}:${repoPath}`).digest("hex").slice(0, 24)}`;
4645
+ return `doc_external_${createHash5("sha256").update(`${metadata.amistioAccountId}:${metadata.amistioProjectId}:${metadata.repositoryLinkId}:${repoPath}`).digest("hex").slice(0, 24)}`;
4484
4646
  }
4485
4647
  function normalizeRepoPath3(repoPath) {
4486
4648
  return repoPath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\/+/, "");
@@ -4508,9 +4670,9 @@ async function exists2(filePath) {
4508
4670
  }
4509
4671
 
4510
4672
  // src/tool-session-store.ts
4511
- import { mkdir as mkdir8, readFile as readFile7, writeFile as writeFile8 } from "node:fs/promises";
4512
- import os5 from "node:os";
4513
- import path9 from "node:path";
4673
+ import { mkdir as mkdir9, readFile as readFile8, writeFile as writeFile9 } from "node:fs/promises";
4674
+ import os6 from "node:os";
4675
+ import path10 from "node:path";
4514
4676
  var LocalToolSessionStore = class {
4515
4677
  constructor(filePath = defaultSessionStorePath()) {
4516
4678
  this.filePath = filePath;
@@ -4524,12 +4686,12 @@ var LocalToolSessionStore = class {
4524
4686
  async setProviderSessionId(toolSessionId, toolName, providerSessionId) {
4525
4687
  const data = await this.read();
4526
4688
  data[toolSessionId] = { toolName, providerSessionId, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
4527
- await mkdir8(path9.dirname(this.filePath), { recursive: true });
4528
- await writeFile8(this.filePath, JSON.stringify(data, null, 2), "utf8");
4689
+ await mkdir9(path10.dirname(this.filePath), { recursive: true });
4690
+ await writeFile9(this.filePath, JSON.stringify(data, null, 2), "utf8");
4529
4691
  }
4530
4692
  async read() {
4531
4693
  try {
4532
- return JSON.parse(await readFile7(this.filePath, "utf8"));
4694
+ return JSON.parse(await readFile8(this.filePath, "utf8"));
4533
4695
  } catch {
4534
4696
  return {};
4535
4697
  }
@@ -4537,16 +4699,16 @@ var LocalToolSessionStore = class {
4537
4699
  };
4538
4700
  function defaultSessionStorePath() {
4539
4701
  if (process.platform === "darwin") {
4540
- return path9.join(os5.homedir(), "Library", "Application Support", "Amistio", "tool-sessions.json");
4702
+ return path10.join(os6.homedir(), "Library", "Application Support", "Amistio", "tool-sessions.json");
4541
4703
  }
4542
4704
  if (process.platform === "win32") {
4543
- return path9.join(process.env.APPDATA ?? os5.homedir(), "Amistio", "tool-sessions.json");
4705
+ return path10.join(process.env.APPDATA ?? os6.homedir(), "Amistio", "tool-sessions.json");
4544
4706
  }
4545
- return path9.join(process.env.XDG_STATE_HOME ?? path9.join(os5.homedir(), ".local", "state"), "amistio", "tool-sessions.json");
4707
+ return path10.join(process.env.XDG_STATE_HOME ?? path10.join(os6.homedir(), ".local", "state"), "amistio", "tool-sessions.json");
4546
4708
  }
4547
4709
 
4548
4710
  // src/work-runner.ts
4549
- import path10 from "node:path";
4711
+ import path11 from "node:path";
4550
4712
  var generationResultStart = "AMISTIO_BRAIN_GENERATION_RESULT_START";
4551
4713
  var generationResultEnd = "AMISTIO_BRAIN_GENERATION_RESULT_END";
4552
4714
  var assistantAnswerStart = "AMISTIO_ASSISTANT_ANSWER_START";
@@ -5430,15 +5592,15 @@ function normalizeProjectContextRepoPath(value, options) {
5430
5592
  if (!trimmed || /^[A-Za-z][A-Za-z0-9+.-]*:\/\//.test(trimmed) || /^file:/i.test(trimmed) || /^[A-Za-z]:($|[^\\/])/.test(trimmed)) {
5431
5593
  throwUnsafeProjectContextPath();
5432
5594
  }
5433
- const absolute = trimmed.startsWith("/") || trimmed.startsWith("\\\\") || path10.isAbsolute(trimmed) || path10.win32.isAbsolute(trimmed);
5595
+ const absolute = trimmed.startsWith("/") || trimmed.startsWith("\\\\") || path11.isAbsolute(trimmed) || path11.win32.isAbsolute(trimmed);
5434
5596
  if (!absolute) {
5435
5597
  return normalizeRelativeProjectContextPath(trimmed);
5436
5598
  }
5437
5599
  if (!options.repositoryRoot) {
5438
5600
  throwUnsafeProjectContextPath();
5439
5601
  }
5440
- const useWindowsPathRules = path10.win32.isAbsolute(trimmed) && !trimmed.startsWith("/");
5441
- const relativePath = useWindowsPathRules ? path10.win32.relative(path10.win32.resolve(options.repositoryRoot), path10.win32.resolve(trimmed)) : path10.relative(path10.resolve(options.repositoryRoot), path10.resolve(trimmed));
5602
+ const useWindowsPathRules = path11.win32.isAbsolute(trimmed) && !trimmed.startsWith("/");
5603
+ const relativePath = useWindowsPathRules ? path11.win32.relative(path11.win32.resolve(options.repositoryRoot), path11.win32.resolve(trimmed)) : path11.relative(path11.resolve(options.repositoryRoot), path11.resolve(trimmed));
5442
5604
  return normalizeRelativeProjectContextPath(relativePath);
5443
5605
  }
5444
5606
  function normalizeRelativeProjectContextPath(value) {
@@ -5490,7 +5652,7 @@ function stripJsonFence(value) {
5490
5652
  }
5491
5653
 
5492
5654
  // src/runner-status.ts
5493
- import { createHash as createHash5 } from "node:crypto";
5655
+ import { createHash as createHash6 } from "node:crypto";
5494
5656
  var watchStateReminderMs = 60 * 1e3;
5495
5657
  function formatWatchStartupContext(input) {
5496
5658
  return [
@@ -5517,20 +5679,20 @@ function watchStateKey(action) {
5517
5679
  return [action.kind, action.message, action.workItemId, action.documentId, action.runnerId].filter(Boolean).join(":");
5518
5680
  }
5519
5681
  function stableRunnerId(input) {
5520
- const digest = createHash5("sha256").update(`${input.accountId}:${input.projectId}:${input.repositoryLinkId}:${input.machineId}`).digest("hex").slice(0, 20);
5682
+ const digest = createHash6("sha256").update(`${input.accountId}:${input.projectId}:${input.repositoryLinkId}:${input.machineId}`).digest("hex").slice(0, 20);
5521
5683
  return `runner_${digest}`;
5522
5684
  }
5523
5685
 
5524
5686
  // src/runner-resources.ts
5525
- import os6 from "node:os";
5687
+ import os7 from "node:os";
5526
5688
  var defaultRuntime = {
5527
5689
  nowMs: () => Date.now(),
5528
5690
  memoryUsage: () => process.memoryUsage(),
5529
5691
  uptime: () => process.uptime(),
5530
5692
  cpuUsage: () => process.cpuUsage(),
5531
- totalmem: () => os6.totalmem(),
5532
- freemem: () => os6.freemem(),
5533
- loadavg: () => os6.loadavg()
5693
+ totalmem: () => os7.totalmem(),
5694
+ freemem: () => os7.freemem(),
5695
+ loadavg: () => os7.loadavg()
5534
5696
  };
5535
5697
  var previousRunnerResourceSample;
5536
5698
  function sampleCurrentRunnerResourceUsage() {
@@ -5642,9 +5804,9 @@ function roundNumber(value, digits) {
5642
5804
 
5643
5805
  // src/importer.ts
5644
5806
  import { execFile as execFile4 } from "node:child_process";
5645
- import { createHash as createHash6 } from "node:crypto";
5646
- import { readdir as readdir4, readFile as readFile8, stat as stat4 } from "node:fs/promises";
5647
- import path11 from "node:path";
5807
+ import { createHash as createHash7 } from "node:crypto";
5808
+ import { readdir as readdir5, readFile as readFile9, stat as stat4 } from "node:fs/promises";
5809
+ import path12 from "node:path";
5648
5810
  import { promisify as promisify4 } from "node:util";
5649
5811
  var execFileAsync4 = promisify4(execFile4);
5650
5812
  var defaultMaxFileKb = 256;
@@ -5665,12 +5827,12 @@ var documentFolderByType = {
5665
5827
  workflow: "docs/workflows"
5666
5828
  };
5667
5829
  async function inspectLocalRepository(rootDir, defaultBranch) {
5668
- const requestedRoot = path11.resolve(rootDir);
5830
+ const requestedRoot = path12.resolve(rootDir);
5669
5831
  const root = await runGit2(["-C", requestedRoot, "rev-parse", "--show-toplevel"]).catch(() => requestedRoot);
5670
5832
  const detectedBranch = await runGit2(["-C", root, "symbolic-ref", "--quiet", "--short", "HEAD"]).catch(() => defaultBranch);
5671
5833
  const originUrl = await runGit2(["-C", root, "remote", "get-url", "origin"]).catch(() => void 0);
5672
5834
  const parsedCloneUrl = originUrl ? parseOptionalOriginCloneUrl(originUrl) : void 0;
5673
- const repoName = (parsedCloneUrl?.repoName ?? path11.basename(root)) || "repository";
5835
+ const repoName = (parsedCloneUrl?.repoName ?? path12.basename(root)) || "repository";
5674
5836
  const fingerprintSeed = parsedCloneUrl ? `origin:${parsedCloneUrl.normalizedKey}` : `repo:${repoName}:${detectedBranch || defaultBranch}`;
5675
5837
  return {
5676
5838
  rootDir: root,
@@ -5682,7 +5844,7 @@ async function inspectLocalRepository(rootDir, defaultBranch) {
5682
5844
  };
5683
5845
  }
5684
5846
  async function scanLegacyDocuments(options) {
5685
- const rootDir = path11.resolve(options.rootDir);
5847
+ const rootDir = path12.resolve(options.rootDir);
5686
5848
  const maxBytes = (options.maxFileKb ?? defaultMaxFileKb) * 1024;
5687
5849
  const skipped = [];
5688
5850
  const candidates = [];
@@ -5702,7 +5864,7 @@ async function scanLegacyDocuments(options) {
5702
5864
  skipped.push({ repoPath, reason: "excluded" });
5703
5865
  continue;
5704
5866
  }
5705
- const fullPath = path11.join(rootDir, ...repoPath.split("/"));
5867
+ const fullPath = path12.join(rootDir, ...repoPath.split("/"));
5706
5868
  const fileStat = await stat4(fullPath).catch(() => void 0);
5707
5869
  if (!fileStat?.isFile()) {
5708
5870
  skipped.push({ repoPath, reason: "unreadable" });
@@ -5712,7 +5874,7 @@ async function scanLegacyDocuments(options) {
5712
5874
  skipped.push({ repoPath, reason: "tooLarge" });
5713
5875
  continue;
5714
5876
  }
5715
- const content = await readFile8(fullPath, "utf8").catch(() => void 0);
5877
+ const content = await readFile9(fullPath, "utf8").catch(() => void 0);
5716
5878
  if (content === void 0) {
5717
5879
  skipped.push({ repoPath, reason: "unreadable" });
5718
5880
  continue;
@@ -5802,10 +5964,10 @@ async function listRepositoryPaths(rootDir) {
5802
5964
  return files;
5803
5965
  }
5804
5966
  async function walkRepository(rootDir, directory, files) {
5805
- const entries = await readdir4(directory, { withFileTypes: true }).catch(() => []);
5967
+ const entries = await readdir5(directory, { withFileTypes: true }).catch(() => []);
5806
5968
  for (const entry of entries) {
5807
- const fullPath = path11.join(directory, entry.name);
5808
- const repoPath = normalizeRepoPath4(path11.relative(rootDir, fullPath));
5969
+ const fullPath = path12.join(directory, entry.name);
5970
+ const repoPath = normalizeRepoPath4(path12.relative(rootDir, fullPath));
5809
5971
  if (entry.isDirectory()) {
5810
5972
  if (!excludedDirectoryNames.has(entry.name)) {
5811
5973
  await walkRepository(rootDir, fullPath, files);
@@ -5873,9 +6035,9 @@ function uniqueDestinationPath(basePath, sourcePath, usedPaths) {
5873
6035
  usedPaths.add(basePath);
5874
6036
  return basePath;
5875
6037
  }
5876
- const extension = path11.posix.extname(basePath) || ".md";
5877
- const directory = path11.posix.dirname(basePath);
5878
- const basename = path11.posix.basename(basePath, extension);
6038
+ const extension = path12.posix.extname(basePath) || ".md";
6039
+ const directory = path12.posix.dirname(basePath);
6040
+ const basename = path12.posix.basename(basePath, extension);
5879
6041
  const uniquePath = `${directory}/${basename}-${hashText(sourcePath, 8)}${extension}`;
5880
6042
  usedPaths.add(uniquePath);
5881
6043
  return uniquePath;
@@ -5948,7 +6110,7 @@ function inferTitle2(content, repoPath) {
5948
6110
  if (heading) return heading;
5949
6111
  const htmlHeading = body.match(/<h1\b[^>]*>([\s\S]*?)<\/h1>/i)?.[1]?.replace(/<[^>]+>/g, "").trim();
5950
6112
  if (htmlHeading) return htmlHeading;
5951
- const basename = path11.posix.basename(repoPath, path11.posix.extname(repoPath)).replace(/[-_]+/g, " ").trim();
6113
+ const basename = path12.posix.basename(repoPath, path12.posix.extname(repoPath)).replace(/[-_]+/g, " ").trim();
5952
6114
  return titleCase(basename || "Imported Document");
5953
6115
  }
5954
6116
  function stripFrontmatter(content) {
@@ -5970,7 +6132,7 @@ function stableImportDocumentId(accountId, projectId, repositoryLinkId, sourcePa
5970
6132
  return `doc_import_${hashText(`${accountId}\0${projectId}\0${repositoryLinkId}\0${sourcePath}`, 24)}`;
5971
6133
  }
5972
6134
  function hashText(value, length) {
5973
- return createHash6("sha256").update(value).digest("hex").slice(0, length);
6135
+ return createHash7("sha256").update(value).digest("hex").slice(0, length);
5974
6136
  }
5975
6137
  function normalizeRepoPath4(value) {
5976
6138
  return value.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\/+/, "");
@@ -5982,7 +6144,7 @@ async function runGit2(args) {
5982
6144
 
5983
6145
  // src/runner-actions.ts
5984
6146
  import { spawn as spawn4 } from "node:child_process";
5985
- import path12 from "node:path";
6147
+ import path13 from "node:path";
5986
6148
  function buildBackgroundRunnerArgs(options) {
5987
6149
  const args = [
5988
6150
  "run",
@@ -5992,7 +6154,7 @@ function buildBackgroundRunnerArgs(options) {
5992
6154
  "--runner-id",
5993
6155
  options.runnerId,
5994
6156
  "--root",
5995
- path12.resolve(options.root),
6157
+ path13.resolve(options.root),
5996
6158
  "--session",
5997
6159
  options.session,
5998
6160
  "--interval-seconds",
@@ -6109,8 +6271,8 @@ function truncateProcessOutput(value) {
6109
6271
 
6110
6272
  // src/git-worktree.ts
6111
6273
  import { execFile as execFile5 } from "node:child_process";
6112
- import { mkdir as mkdir9, stat as stat5 } from "node:fs/promises";
6113
- import path13 from "node:path";
6274
+ import { mkdir as mkdir10, stat as stat5 } from "node:fs/promises";
6275
+ import path14 from "node:path";
6114
6276
  import { promisify as promisify5 } from "node:util";
6115
6277
  var execFileAsync5 = promisify5(execFile5);
6116
6278
  function needsGitWorktreeIsolation(workItem) {
@@ -6139,7 +6301,7 @@ async function prepareGitWorktreeIsolation(rootDir, workItem) {
6139
6301
  await assertExistingWorktree(worktreePath, identity.branch);
6140
6302
  return { ...identity, baseRevision, worktreePath };
6141
6303
  }
6142
- await mkdir9(path13.dirname(worktreePath), { recursive: true });
6304
+ await mkdir10(path14.dirname(worktreePath), { recursive: true });
6143
6305
  const branchExists = await gitCommandSucceeds(repoRoot, ["show-ref", "--verify", "--quiet", `refs/heads/${identity.branch}`]);
6144
6306
  const worktreeArgs = branchExists ? ["worktree", "add", worktreePath, identity.branch] : ["worktree", "add", "-b", identity.branch, worktreePath, baseRevision];
6145
6307
  await gitOutput(repoRoot, worktreeArgs).catch((error) => {
@@ -6148,9 +6310,9 @@ async function prepareGitWorktreeIsolation(rootDir, workItem) {
6148
6310
  return { ...identity, baseRevision, worktreePath };
6149
6311
  }
6150
6312
  function localWorktreePath(repoRoot, worktreeKey) {
6151
- const repoName = path13.basename(repoRoot);
6313
+ const repoName = path14.basename(repoRoot);
6152
6314
  const worktreeSlug = worktreeKey.split("/").filter(Boolean).pop() ?? "work";
6153
- return path13.join(path13.dirname(repoRoot), `${repoName}.worktrees`, worktreeSlug);
6315
+ return path14.join(path14.dirname(repoRoot), `${repoName}.worktrees`, worktreeSlug);
6154
6316
  }
6155
6317
  async function assertExistingWorktree(worktreePath, branch) {
6156
6318
  await gitOutput(worktreePath, ["rev-parse", "--is-inside-work-tree"]);
@@ -6197,7 +6359,7 @@ function errorMessage2(error) {
6197
6359
 
6198
6360
  // src/implementation-handoff.ts
6199
6361
  import { execFile as execFile6 } from "node:child_process";
6200
- import path14 from "node:path";
6362
+ import path15 from "node:path";
6201
6363
  import { promisify as promisify6 } from "node:util";
6202
6364
  var execFileAsync6 = promisify6(execFile6);
6203
6365
  async function completeImplementationHandoff(input) {
@@ -6283,7 +6445,7 @@ async function cleanupWorktree(run, input) {
6283
6445
  return { status: "failed", message: "Cleanup skipped because the worktree is not clean after PR handoff." };
6284
6446
  }
6285
6447
  try {
6286
- await gitOutput2(run, input.primaryRepoRoot || path14.dirname(input.worktreePath), ["worktree", "remove", input.worktreePath]);
6448
+ await gitOutput2(run, input.primaryRepoRoot || path15.dirname(input.worktreePath), ["worktree", "remove", input.worktreePath]);
6287
6449
  return { status: "completed" };
6288
6450
  } catch (error) {
6289
6451
  return { status: "failed", message: `Cleanup failed: ${safeErrorMessage(error)}` };
@@ -6694,7 +6856,7 @@ work.command("prompt").description("Print or write an approved work prompt witho
6694
6856
  }
6695
6857
  const prompt = await createRunnerWorkPrompt(context.client, context.metadata.amistioProjectId, workItem);
6696
6858
  if (options.out) {
6697
- await writeFile9(options.out, prompt, "utf8");
6859
+ await writeFile10(options.out, prompt, "utf8");
6698
6860
  console.log(`Wrote work prompt to ${options.out}.`);
6699
6861
  } else {
6700
6862
  console.log(prompt);
@@ -6772,7 +6934,7 @@ program.command("run").description("Claim and run approved Amistio work locally"
6772
6934
  projectId: context.metadata.amistioProjectId,
6773
6935
  repositoryLinkId: context.metadata.repositoryLinkId,
6774
6936
  runnerId,
6775
- rootDir: path15.resolve(options.root),
6937
+ rootDir: path16.resolve(options.root),
6776
6938
  apiUrl: options.apiUrl,
6777
6939
  args: buildBackgroundRunnerArgs(resolvedOptions)
6778
6940
  });
@@ -6944,7 +7106,7 @@ runnerService.command("install").description("Install a user-level startup servi
6944
7106
  projectId: context.metadata.amistioProjectId,
6945
7107
  repositoryLinkId: context.metadata.repositoryLinkId,
6946
7108
  runnerId,
6947
- rootDir: path15.resolve(options.root),
7109
+ rootDir: path16.resolve(options.root),
6948
7110
  apiUrl: options.apiUrl,
6949
7111
  args,
6950
7112
  platform
@@ -7015,6 +7177,18 @@ async function runWatchIteration({ command, context, options, runnerId }) {
7015
7177
  runnerId
7016
7178
  });
7017
7179
  }
7180
+ if (!options.dryRun) {
7181
+ const replayResult = await replayPendingBrainGenerationFinalizations({
7182
+ accountId: context.metadata.amistioAccountId,
7183
+ apiClient: context.client,
7184
+ projectId: context.metadata.amistioProjectId,
7185
+ repositoryLinkId: context.metadata.repositoryLinkId,
7186
+ runnerId
7187
+ });
7188
+ if (replayResult) {
7189
+ return replayResult;
7190
+ }
7191
+ }
7018
7192
  return await runNextWorkItem({
7019
7193
  apiClient: context.client,
7020
7194
  projectId: context.metadata.amistioProjectId,
@@ -7762,6 +7936,58 @@ function runnerCommandLabel(commandKind) {
7762
7936
  if (commandKind === "restart") return "restart";
7763
7937
  return "remove";
7764
7938
  }
7939
+ async function replayPendingBrainGenerationFinalizations({ accountId, apiClient, projectId, repositoryLinkId, runnerId }) {
7940
+ const pendingEntries = await listPendingBrainGenerationFinalizations({ accountId, projectId, repositoryLinkId, runnerId });
7941
+ if (!pendingEntries.length) {
7942
+ return void 0;
7943
+ }
7944
+ let completedCount = 0;
7945
+ for (const entry of pendingEntries) {
7946
+ const replay = await submitBrainGenerationFinalizationEntry(apiClient, entry, { recordReplayTelemetry: true });
7947
+ if (replay.status === "completed") {
7948
+ completedCount += 1;
7949
+ continue;
7950
+ }
7951
+ return { status: "failed", exitCode: 1, message: replay.message };
7952
+ }
7953
+ const message = `Replayed ${completedCount} pending brain generation finalization${completedCount === 1 ? "" : "s"}.`;
7954
+ console.log(message);
7955
+ return { status: "completed", exitCode: 0, message };
7956
+ }
7957
+ async function submitBrainGenerationFinalizationEntry(apiClient, entry, options = {}) {
7958
+ let result;
7959
+ try {
7960
+ result = await apiClient.submitBrainGenerationResult(entry.projectId, entry.workItemId, entry.result);
7961
+ } catch (error) {
7962
+ const detail = truncateLogExcerpt(errorMessage3(error));
7963
+ if (isRetryableApiError(error)) {
7964
+ const updated = await markBrainGenerationFinalizationRetry(entry, detail);
7965
+ const message2 = `Pending brain generation finalization ${entry.workItemId} could not be replayed yet (${updated.retryCount} attempt${updated.retryCount === 1 ? "" : "s"}): ${detail}`;
7966
+ console.error(message2);
7967
+ return { status: "failed", message: message2, retryable: true };
7968
+ }
7969
+ await markBrainGenerationFinalizationTerminal(entry, detail);
7970
+ const message = `Pending brain generation finalization ${entry.workItemId} reached a terminal API failure: ${detail}`;
7971
+ console.error(message);
7972
+ return { status: "failed", message, retryable: false };
7973
+ }
7974
+ await deleteBrainGenerationFinalizationEntry(entry).catch((error) => {
7975
+ console.error(`delete pending brain generation finalization ${entry.workItemId} failed: ${errorMessage3(error)}`);
7976
+ });
7977
+ if (options.recordReplayTelemetry) {
7978
+ await recordRunnerMilestone(apiClient, entry.projectId, result.workItem, entry.runnerId, entry.repositoryLinkId, {
7979
+ status: entry.result.status,
7980
+ summary: entry.result.status === "completed" ? "Replayed pending brain generation result finalization." : "Replayed pending brain generation failure finalization.",
7981
+ idempotencyKey: `runner_milestone_generation_replayed_${entry.workItemId}_${result.workItem.idempotencyKey}`,
7982
+ metadata: { artifactCount: result.documents.length, replayedFinalization: true, workKind: entry.workKind }
7983
+ });
7984
+ await apiClient.sendRunnerHeartbeat(entry.projectId, entry.runnerId, entry.repositoryLinkId, "online", {
7985
+ ...runnerHeartbeatMetadata(),
7986
+ preferenceMessage: "Pending result finalization replayed."
7987
+ }).catch(() => void 0);
7988
+ }
7989
+ return { status: "completed", workItem: result.workItem, documentCount: result.documents.length };
7990
+ }
7765
7991
  async function finalizeBrainGenerationWork({
7766
7992
  apiClient,
7767
7993
  durationMs,
@@ -7787,55 +8013,97 @@ ${toolResult.stderr}`);
7787
8013
  generationError = truncateLogExcerpt(toolResult.stderr || toolResult.stdout) || `${toolName} exited with code ${toolResult.exitCode}.`;
7788
8014
  }
7789
8015
  const finalStatus = artifacts ? "completed" : "failed";
7790
- const updatedToolSession = await finalizeToolSession({
7791
- apiClient,
7792
- projectId,
7793
- status: finalStatus,
7794
- runnerId,
7795
- workItemId: workItem.workItemId,
7796
- stdout: toolResult.stdout,
7797
- ...sessionContext.toolSession ? { session: sessionContext.toolSession } : {},
7798
- ...toolResult.messageCount !== void 0 ? { messageCount: toolResult.messageCount } : {},
7799
- ...toolResult.tokensIn !== void 0 ? { tokensIn: toolResult.tokensIn } : {},
7800
- ...toolResult.tokensOut !== void 0 ? { tokensOut: toolResult.tokensOut } : {},
7801
- ...toolResult.costUsd !== void 0 ? { costUsd: toolResult.costUsd } : {}
7802
- });
7803
8016
  const sessionTelemetry = {
7804
8017
  sessionPolicy: sessionContext.policy,
7805
8018
  sessionDecision: sessionContext.decision,
7806
8019
  sessionDecisionReason: sessionContext.reason,
7807
- ...updatedToolSession ? { toolSessionId: updatedToolSession.toolSessionId } : {},
7808
- ...updatedToolSession?.sessionGroupKey ? { sessionGroupKey: updatedToolSession.sessionGroupKey } : {}
8020
+ ...sessionContext.toolSession ? { toolSessionId: sessionContext.toolSession.toolSessionId } : {},
8021
+ ...sessionContext.toolSession?.sessionGroupKey ? { sessionGroupKey: sessionContext.toolSession.sessionGroupKey } : {}
7809
8022
  };
7810
8023
  if (artifacts) {
7811
8024
  const completionMessage = workItem.workKind === "planRevision" ? `${toolName} returned a revised plan for review.` : `${toolName} generated ${artifacts.length} brain artifact${artifacts.length === 1 ? "" : "s"}.`;
7812
- const result = await apiClient.submitBrainGenerationResult(projectId, workItem.workItemId, {
8025
+ const resultMutation = {
7813
8026
  status: "completed",
7814
8027
  runnerId,
7815
- idempotencyKey: `generation_${workItem.workItemId}_${randomUUID()}`,
8028
+ idempotencyKey: `generation_${workItem.workItemId}_${workItem.attempt}_${randomUUID()}`,
7816
8029
  artifacts,
7817
8030
  tool: toolName,
7818
8031
  durationMs,
7819
8032
  ...sessionTelemetry,
7820
8033
  message: completionMessage
8034
+ };
8035
+ const entry = createBrainGenerationFinalizationEntry({
8036
+ accountId: workItem.accountId,
8037
+ projectId,
8038
+ repositoryLinkId,
8039
+ runnerId,
8040
+ workItemId: workItem.workItemId,
8041
+ workKind: brainGenerationFinalizationWorkKind(workItem.workKind),
8042
+ attempt: workItem.attempt,
8043
+ idempotencyKey: resultMutation.idempotencyKey,
8044
+ result: resultMutation
7821
8045
  });
8046
+ await upsertBrainGenerationFinalizationEntry(entry);
8047
+ const replay = await submitBrainGenerationFinalizationEntry(apiClient, entry);
8048
+ if (replay.status === "failed") {
8049
+ if (!replay.retryable) {
8050
+ throw new Error(replay.message);
8051
+ }
8052
+ return { status: "failed", exitCode: 1 };
8053
+ }
8054
+ const toolSessionSettlement = await Promise.allSettled([
8055
+ finalizeToolSession({
8056
+ apiClient,
8057
+ projectId,
8058
+ status: finalStatus,
8059
+ runnerId,
8060
+ workItemId: workItem.workItemId,
8061
+ stdout: toolResult.stdout,
8062
+ ...sessionContext.toolSession ? { session: sessionContext.toolSession } : {},
8063
+ ...toolResult.messageCount !== void 0 ? { messageCount: toolResult.messageCount } : {},
8064
+ ...toolResult.tokensIn !== void 0 ? { tokensIn: toolResult.tokensIn } : {},
8065
+ ...toolResult.tokensOut !== void 0 ? { tokensOut: toolResult.tokensOut } : {},
8066
+ ...toolResult.costUsd !== void 0 ? { costUsd: toolResult.costUsd } : {}
8067
+ })
8068
+ ]);
8069
+ logRejectedSettlements("finalize generation tool session", toolSessionSettlement);
7822
8070
  await recordRunnerMilestone(apiClient, projectId, workItem, runnerId, repositoryLinkId, {
7823
8071
  status: "completed",
7824
8072
  summary: completionMessage,
7825
- idempotencyKey: `runner_milestone_generation_completed_${workItem.workItemId}_${result.workItem.idempotencyKey}`,
7826
- metadata: { tool: toolName, durationMs, artifactCount: result.documents.length, verificationSummary: "Generated artifacts were accepted by the Amistio API for review." }
8073
+ idempotencyKey: `runner_milestone_generation_completed_${workItem.workItemId}_${entry.idempotencyKey}`,
8074
+ metadata: { tool: toolName, durationMs, artifactCount: replay.documentCount, verificationSummary: "Generated artifacts were accepted by the Amistio API for review." }
7827
8075
  });
7828
- await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig));
7829
- console.log(workItem.workKind === "planRevision" ? "Revised plan returned for review." : `Generated ${result.documents.length} brain artifact${result.documents.length === 1 ? "" : "s"} for review.`);
8076
+ await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig)).catch((error) => {
8077
+ console.error(`send generation completion heartbeat failed: ${errorMessage3(error)}`);
8078
+ });
8079
+ console.log(workItem.workKind === "planRevision" ? "Revised plan returned for review." : `Generated ${replay.documentCount} brain artifact${replay.documentCount === 1 ? "" : "s"} for review.`);
7830
8080
  return { status: "completed", exitCode: 0 };
7831
8081
  }
8082
+ const updatedToolSession = await finalizeToolSession({
8083
+ apiClient,
8084
+ projectId,
8085
+ status: finalStatus,
8086
+ runnerId,
8087
+ workItemId: workItem.workItemId,
8088
+ stdout: toolResult.stdout,
8089
+ ...sessionContext.toolSession ? { session: sessionContext.toolSession } : {},
8090
+ ...toolResult.messageCount !== void 0 ? { messageCount: toolResult.messageCount } : {},
8091
+ ...toolResult.tokensIn !== void 0 ? { tokensIn: toolResult.tokensIn } : {},
8092
+ ...toolResult.tokensOut !== void 0 ? { tokensOut: toolResult.tokensOut } : {},
8093
+ ...toolResult.costUsd !== void 0 ? { costUsd: toolResult.costUsd } : {}
8094
+ });
8095
+ const failedSessionTelemetry = {
8096
+ ...sessionTelemetry,
8097
+ ...updatedToolSession ? { toolSessionId: updatedToolSession.toolSessionId } : {},
8098
+ ...updatedToolSession?.sessionGroupKey ? { sessionGroupKey: updatedToolSession.sessionGroupKey } : {}
8099
+ };
7832
8100
  const failedResult = await apiClient.submitBrainGenerationResult(projectId, workItem.workItemId, {
7833
8101
  status: "failed",
7834
8102
  runnerId,
7835
8103
  idempotencyKey: `generation_${workItem.workItemId}_${randomUUID()}`,
7836
8104
  tool: toolName,
7837
8105
  durationMs,
7838
- ...sessionTelemetry,
8106
+ ...failedSessionTelemetry,
7839
8107
  message: `${toolName} did not produce valid brain artifacts.`,
7840
8108
  ...generationError ? { error: generationError } : {}
7841
8109
  });
@@ -7849,6 +8117,9 @@ ${toolResult.stderr}`);
7849
8117
  console.error(generationError ?? "Local runner generation failed.");
7850
8118
  return { status: "failed", exitCode: toolResult.exitCode || 1 };
7851
8119
  }
8120
+ function brainGenerationFinalizationWorkKind(workKind) {
8121
+ return workKind === "planRevision" ? "planRevision" : "brainGeneration";
8122
+ }
7852
8123
  async function finalizeAssistantQuestionWork({
7853
8124
  apiClient,
7854
8125
  durationMs,
@@ -8767,10 +9038,10 @@ function parseReasoningEffort(value) {
8767
9038
  throw new Error(`Expected reasoning effort auto, low, medium, high, or xhigh; received ${value}.`);
8768
9039
  }
8769
9040
  function inferRepoName(root) {
8770
- return path15.basename(path15.resolve(root)) || "repository";
9041
+ return path16.basename(path16.resolve(root)) || "repository";
8771
9042
  }
8772
9043
  function createRepoFingerprint(accountId, projectId, repositoryLinkId) {
8773
- return createHash7("sha256").update(`${accountId}:${projectId}:${repositoryLinkId}`).digest("hex");
9044
+ return createHash8("sha256").update(`${accountId}:${projectId}:${repositoryLinkId}`).digest("hex");
8774
9045
  }
8775
9046
  function defaultApiUrl() {
8776
9047
  const envApiUrl = process.env[AMISTIO_API_URL_ENV]?.trim();
@@ -9028,7 +9299,7 @@ function runnerHeartbeatMetadata(toolConfig, mode = currentRunnerMode()) {
9028
9299
  return {
9029
9300
  version: CLI_VERSION,
9030
9301
  mode,
9031
- hostname: os7.hostname(),
9302
+ hostname: os8.hostname(),
9032
9303
  ...runnerIsolationCapabilityMetadata(),
9033
9304
  resourceUsage: sampleCurrentRunnerResourceUsage(),
9034
9305
  ...toolConfig?.capabilities ? { capabilities: toolConfig.capabilities } : {},
@@ -9051,7 +9322,7 @@ function runnerHeartbeatMetadata(toolConfig, mode = currentRunnerMode()) {
9051
9322
  };
9052
9323
  }
9053
9324
  function runnerMachineId() {
9054
- return createHash7("sha256").update(`${os7.hostname()}:${os7.platform()}:${os7.arch()}`).digest("hex").slice(0, 20);
9325
+ return createHash8("sha256").update(`${os8.hostname()}:${os8.platform()}:${os8.arch()}`).digest("hex").slice(0, 20);
9055
9326
  }
9056
9327
  async function delay(milliseconds) {
9057
9328
  await new Promise((resolve) => setTimeout(resolve, milliseconds));