@drisp/cli 0.5.4 → 0.5.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2241,7 +2241,7 @@ var cachedVersion = null;
2241
2241
  function readVersion() {
2242
2242
  if (cachedVersion !== null) return cachedVersion;
2243
2243
  try {
2244
- const injected = "0.5.4";
2244
+ const injected = "0.5.7";
2245
2245
  if (typeof injected === "string" && injected.length > 0) {
2246
2246
  cachedVersion = injected;
2247
2247
  return cachedVersion;
@@ -2876,17 +2876,18 @@ var InboundQueue = class {
2876
2876
  const row = this.db.prepare("SELECT COUNT(*) as n FROM inbound_queue").get();
2877
2877
  return row.n;
2878
2878
  }
2879
- enqueue(inbound) {
2879
+ enqueue(inbound, key) {
2880
2880
  if (this.size() >= this.maxEntries) {
2881
2881
  return { kind: "rejected", reason: "queue_full" };
2882
2882
  }
2883
2883
  const stmt = this.db.prepare(
2884
2884
  `INSERT INTO inbound_queue
2885
- (channel_id, account_id, idempotency_key, payload_json, created_at)
2886
- VALUES (?, ?, ?, ?, ?)
2885
+ (attachment_id, channel_id, account_id, idempotency_key, payload_json, created_at)
2886
+ VALUES (?, ?, ?, ?, ?, ?)
2887
2887
  ON CONFLICT(channel_id, account_id, idempotency_key) DO NOTHING`
2888
2888
  );
2889
2889
  const result = stmt.run(
2890
+ key ?? null,
2890
2891
  inbound.location.channelId,
2891
2892
  inbound.location.accountId,
2892
2893
  inbound.idempotencyKey,
@@ -2898,12 +2899,17 @@ var InboundQueue = class {
2898
2899
  }
2899
2900
  return { kind: "queued", id: Number(result.lastInsertRowid) };
2900
2901
  }
2901
- /** Atomically read and remove all parked entries in FIFO order. */
2902
- drain() {
2902
+ /** Atomically read and remove parked entries for one attachment slot. */
2903
+ drain(key) {
2903
2904
  return this.db.transaction(() => {
2904
- const rows = this.db.prepare("SELECT id, payload_json FROM inbound_queue ORDER BY id ASC").all();
2905
+ const rows = this.db.prepare(
2906
+ `SELECT id, payload_json
2907
+ FROM inbound_queue
2908
+ WHERE attachment_id IS ?
2909
+ ORDER BY id ASC`
2910
+ ).all(key ?? null);
2905
2911
  if (rows.length > 0) {
2906
- this.db.prepare("DELETE FROM inbound_queue").run();
2912
+ this.db.prepare("DELETE FROM inbound_queue WHERE attachment_id IS ?").run(key ?? null);
2907
2913
  }
2908
2914
  return rows.map((r) => ({
2909
2915
  id: r.id,
@@ -3022,7 +3028,7 @@ var DispatchPipeline = class {
3022
3028
  const key = options.attachmentId;
3023
3029
  const current = this.bindingStore.getCurrentByAttachment(key);
3024
3030
  if (!current || !this.bindingStore.hasActiveBindingForAttachment(key)) {
3025
- const result = this.inboundQueue.enqueue(inbound);
3031
+ const result = this.inboundQueue.enqueue(inbound, key);
3026
3032
  if (result.kind === "queued") {
3027
3033
  this.log?.(
3028
3034
  "info",
@@ -3207,9 +3213,9 @@ var DispatchPipeline = class {
3207
3213
  }
3208
3214
  drainPending(key) {
3209
3215
  const current = this.bindingStore.getCurrentByAttachment(key);
3210
- if (!current || !this.bindingStore.hasActiveBinding(current.runtimeId))
3216
+ if (!current || !this.bindingStore.hasActiveBindingForAttachment(key))
3211
3217
  return;
3212
- const parked = this.inboundQueue.drain();
3218
+ const parked = this.inboundQueue.drain(key);
3213
3219
  let dispatched = 0;
3214
3220
  let dropped = 0;
3215
3221
  for (const { inbound } of parked) {
@@ -3548,7 +3554,7 @@ function questionFingerprint(req) {
3548
3554
  import fs3 from "fs";
3549
3555
  import path3 from "path";
3550
3556
  import Database from "better-sqlite3";
3551
- var GATEWAY_STATE_VERSION = 1;
3557
+ var GATEWAY_STATE_VERSION = 2;
3552
3558
  function openGatewayState(dbPath) {
3553
3559
  if (dbPath !== ":memory:") {
3554
3560
  fs3.mkdirSync(path3.dirname(dbPath), { recursive: true, mode: 448 });
@@ -3576,6 +3582,7 @@ function initGatewayStateSchema(db) {
3576
3582
  -- same provider message from being parked twice if an adapter retries.
3577
3583
  CREATE TABLE IF NOT EXISTS inbound_queue (
3578
3584
  id INTEGER PRIMARY KEY AUTOINCREMENT,
3585
+ attachment_id TEXT,
3579
3586
  channel_id TEXT NOT NULL,
3580
3587
  account_id TEXT NOT NULL,
3581
3588
  idempotency_key TEXT NOT NULL,
@@ -3611,6 +3618,16 @@ function initGatewayStateSchema(db) {
3611
3618
  db.prepare("INSERT INTO schema_version (version) VALUES (?)").run(
3612
3619
  GATEWAY_STATE_VERSION
3613
3620
  );
3621
+ return;
3622
+ }
3623
+ const inboundColumns = db.prepare("PRAGMA table_info(inbound_queue)").all();
3624
+ if (!inboundColumns.some((column) => column.name === "attachment_id")) {
3625
+ db.prepare("ALTER TABLE inbound_queue ADD COLUMN attachment_id TEXT").run();
3626
+ }
3627
+ if (existing.version < GATEWAY_STATE_VERSION) {
3628
+ db.prepare("UPDATE schema_version SET version = ?").run(
3629
+ GATEWAY_STATE_VERSION
3630
+ );
3614
3631
  }
3615
3632
  }
3616
3633
 
@@ -7700,6 +7700,8 @@ function generateNeutralTitle(event, g) {
7700
7700
  return truncate(
7701
7701
  `Cloud fn \u2717 ${event.data.function_name}: ${event.data.error_message}`
7702
7702
  );
7703
+ case "artifacts.manifest":
7704
+ return "Artifacts manifest";
7703
7705
  }
7704
7706
  }
7705
7707
 
@@ -11665,6 +11667,7 @@ async function runExec(options) {
11665
11667
  let mappedFinalMessage = null;
11666
11668
  let adapterSessionId = null;
11667
11669
  let activeRunId = null;
11670
+ let beforeTerminalCompletionRan = false;
11668
11671
  let store;
11669
11672
  try {
11670
11673
  store = sessionStoreFactory({
@@ -11787,6 +11790,57 @@ async function runExec(options) {
11787
11790
  feedEvents
11788
11791
  });
11789
11792
  }
11793
+ const runBeforeTerminalCompletion = async () => {
11794
+ if (beforeTerminalCompletionRan || latch.hasFailure() || !options.beforeTerminalCompletion) {
11795
+ return;
11796
+ }
11797
+ beforeTerminalCompletionRan = true;
11798
+ const resolved = resolveFinalMessage({
11799
+ streamMessage: streamFinalMessage,
11800
+ mappedMessage: mappedFinalMessage
11801
+ });
11802
+ const provisionalResult = {
11803
+ success: true,
11804
+ exitCode: EXEC_EXIT_CODE.SUCCESS,
11805
+ athenaSessionId: options.ephemeral ? null : athenaSessionId,
11806
+ adapterSessionId,
11807
+ finalMessage: resolved.message,
11808
+ tokens: cumulativeTokens,
11809
+ durationMs: Math.max(0, now() - startTs)
11810
+ };
11811
+ try {
11812
+ const feedEvents = await options.beforeTerminalCompletion({
11813
+ result: provisionalResult,
11814
+ runId: activeRunId
11815
+ });
11816
+ if (feedEvents && feedEvents.length > 0) {
11817
+ publishFeedEvents(feedEvents);
11818
+ }
11819
+ } catch (error) {
11820
+ latch.register({
11821
+ kind: "output",
11822
+ message: `Artifact upload failed: ${error instanceof Error ? error.message : String(error)}`
11823
+ });
11824
+ }
11825
+ };
11826
+ const writeLastMessageBeforeTerminalCompletion = async () => {
11827
+ if (latch.hasFailure() || !options.outputLastMessagePath) return;
11828
+ const resolved = resolveFinalMessage({
11829
+ streamMessage: streamFinalMessage,
11830
+ mappedMessage: mappedFinalMessage
11831
+ });
11832
+ try {
11833
+ await output.writeLastMessage(
11834
+ options.outputLastMessagePath,
11835
+ resolved.message
11836
+ );
11837
+ } catch (error) {
11838
+ latch.register({
11839
+ kind: "output",
11840
+ message: `Failed writing --output-last-message: ${error instanceof Error ? error.message : String(error)}`
11841
+ });
11842
+ }
11843
+ };
11790
11844
  const unsubscribeEvent = runtime.onEvent((runtimeEvent) => {
11791
11845
  adapterSessionId = runtimeEvent.sessionId;
11792
11846
  if (runtimeEvent.sessionId && activeRunId && !linkedAdapterSessions.has(runtimeEvent.sessionId)) {
@@ -11956,6 +12010,8 @@ async function runExec(options) {
11956
12010
  if (dashboardDecisionTimer) {
11957
12011
  clearInterval(dashboardDecisionTimer);
11958
12012
  }
12013
+ await writeLastMessageBeforeTerminalCompletion();
12014
+ await runBeforeTerminalCompletion();
11959
12015
  await sessionController.kill();
11960
12016
  unsubscribeEvent();
11961
12017
  unsubscribeDecision();
@@ -11974,19 +12030,6 @@ async function runExec(options) {
11974
12030
  output.warn(warning);
11975
12031
  output.emitJsonEvent("exec.warning", { message: warning });
11976
12032
  }
11977
- if (!latch.hasFailure() && options.outputLastMessagePath) {
11978
- try {
11979
- await output.writeLastMessage(
11980
- options.outputLastMessagePath,
11981
- resolvedFinalMessage.message
11982
- );
11983
- } catch (error) {
11984
- latch.register({
11985
- kind: "output",
11986
- message: `Failed writing --output-last-message: ${error instanceof Error ? error.message : String(error)}`
11987
- });
11988
- }
11989
- }
11990
12033
  const failure = latch.current();
11991
12034
  const exitCode = exitCodeFromFailure(failure);
11992
12035
  const success = exitCode === EXEC_EXIT_CODE.SUCCESS;
@@ -12586,6 +12629,370 @@ async function createRemoteRunEventPublisher({
12586
12629
  };
12587
12630
  }
12588
12631
 
12632
+ // src/app/dashboard/artifactCapture.ts
12633
+ import { execFile } from "child_process";
12634
+ import crypto3 from "crypto";
12635
+ import fs21 from "fs/promises";
12636
+ import path19 from "path";
12637
+ import { promisify } from "util";
12638
+ var execFileAsync = promisify(execFile);
12639
+ function parseArtifactUploadSpec(value) {
12640
+ if (typeof value !== "object" || value === null) return null;
12641
+ const obj = value;
12642
+ const hasArtifactUpload = Object.hasOwn(obj, "artifactUpload");
12643
+ const hasArtifacts = Object.hasOwn(obj, "artifacts");
12644
+ if (!hasArtifactUpload && !hasArtifacts) return null;
12645
+ const candidate = hasArtifactUpload ? obj["artifactUpload"] : obj["artifacts"];
12646
+ if (typeof candidate !== "object" || candidate === null) {
12647
+ throw new Error("artifact upload spec must be an object");
12648
+ }
12649
+ const spec = candidate;
12650
+ const bucket = spec["bucket"];
12651
+ const prefix = spec["prefix"];
12652
+ const normalizedPrefix = typeof prefix === "string" ? prefix.replace(/^\/+|\/+$/g, "") : null;
12653
+ const accessToken = spec["accessToken"] ?? (typeof spec["credentials"] === "object" && spec["credentials"] !== null ? spec["credentials"]["accessToken"] : void 0);
12654
+ if (typeof bucket !== "string" || bucket.length === 0 || !normalizedPrefix || typeof accessToken !== "string" || accessToken.length === 0) {
12655
+ throw new Error(
12656
+ "artifact upload spec must include bucket, prefix, and accessToken"
12657
+ );
12658
+ }
12659
+ return {
12660
+ bucket,
12661
+ prefix: normalizedPrefix,
12662
+ accessToken,
12663
+ includeIgnored: stringArray(spec["includeIgnored"]),
12664
+ hardDeny: [...DEFAULT_HARD_DENY, ...stringArray(spec["hardDeny"])]
12665
+ };
12666
+ }
12667
+ async function captureAndUploadArtifacts(input) {
12668
+ const now = input.now ?? Date.now;
12669
+ const uploadObject = input.uploadObject ?? uploadGcsObject;
12670
+ const payloads = await collectArtifactPayloads({
12671
+ projectDir: input.projectDir,
12672
+ includeIgnored: input.spec.includeIgnored,
12673
+ hardDeny: input.spec.hardDeny
12674
+ });
12675
+ const entries = [];
12676
+ for (const [idx, payload] of payloads.entries()) {
12677
+ const id = `${String(idx + 1).padStart(4, "0")}-${safeObjectSegment(
12678
+ payload.kind
12679
+ )}`;
12680
+ const object = joinObjectName(
12681
+ input.spec.prefix,
12682
+ "payloads",
12683
+ `${id}-${safeObjectSegment(payload.path)}`
12684
+ );
12685
+ await uploadObject({
12686
+ bucket: input.spec.bucket,
12687
+ objectName: object,
12688
+ body: payload.bytes,
12689
+ contentType: contentTypeFor(payload.path),
12690
+ accessToken: input.spec.accessToken
12691
+ });
12692
+ entries.push({
12693
+ id,
12694
+ kind: payload.kind,
12695
+ path: payload.path,
12696
+ object,
12697
+ size: payload.bytes.byteLength,
12698
+ sha256: sha256(payload.bytes)
12699
+ });
12700
+ }
12701
+ const manifestObject = joinObjectName(input.spec.prefix, "manifest.json");
12702
+ const manifest = {
12703
+ version: 1,
12704
+ runId: input.runId,
12705
+ athenaSessionId: input.result.athenaSessionId,
12706
+ adapterSessionId: input.result.adapterSessionId,
12707
+ createdAt: new Date(now()).toISOString(),
12708
+ entries,
12709
+ objects: {
12710
+ bucket: input.spec.bucket,
12711
+ prefix: input.spec.prefix,
12712
+ manifest: manifestObject
12713
+ }
12714
+ };
12715
+ await uploadObject({
12716
+ bucket: input.spec.bucket,
12717
+ objectName: manifestObject,
12718
+ body: Buffer.from(`${JSON.stringify(manifest, null, 2)}
12719
+ `),
12720
+ contentType: "application/json",
12721
+ accessToken: input.spec.accessToken
12722
+ });
12723
+ return {
12724
+ manifest,
12725
+ feedEvent: makeArtifactManifestFeedEvent({
12726
+ manifest,
12727
+ result: input.result,
12728
+ runId: input.runId,
12729
+ ts: now()
12730
+ })
12731
+ };
12732
+ }
12733
+ async function collectArtifactPayloads(input) {
12734
+ const hardDeny = input.hardDeny ?? DEFAULT_HARD_DENY;
12735
+ const payloads = [];
12736
+ if (!await isGitWorkspace(input.projectDir)) {
12737
+ return payloads;
12738
+ }
12739
+ const trackedDiff = await gitDiffForAllowedPaths({
12740
+ projectDir: input.projectDir,
12741
+ nameArgs: ["diff", "--name-only", "-z", "--"],
12742
+ diffArgs: ["diff", "--binary", "--"],
12743
+ hardDeny
12744
+ });
12745
+ if (trackedDiff.length > 0) {
12746
+ payloads.push({
12747
+ kind: "tracked_diff",
12748
+ path: "git/tracked.diff",
12749
+ bytes: Buffer.from(trackedDiff)
12750
+ });
12751
+ }
12752
+ const stagedDiff = await gitDiffForAllowedPaths({
12753
+ projectDir: input.projectDir,
12754
+ nameArgs: ["diff", "--name-only", "-z", "--cached", "--"],
12755
+ diffArgs: ["diff", "--binary", "--cached", "--"],
12756
+ hardDeny
12757
+ });
12758
+ if (stagedDiff.length > 0) {
12759
+ payloads.push({
12760
+ kind: "staged_diff",
12761
+ path: "git/staged.diff",
12762
+ bytes: Buffer.from(stagedDiff)
12763
+ });
12764
+ }
12765
+ const upstream = await gitMaybe(input.projectDir, [
12766
+ "rev-parse",
12767
+ "--abbrev-ref",
12768
+ "--symbolic-full-name",
12769
+ "@{u}"
12770
+ ]);
12771
+ if (upstream.trim().length > 0) {
12772
+ const range = `${upstream.trim()}..HEAD`;
12773
+ const commits = await gitDiffForAllowedPaths({
12774
+ projectDir: input.projectDir,
12775
+ nameArgs: ["diff", "--name-only", "-z", range, "--"],
12776
+ diffArgs: ["format-patch", "--stdout", range, "--"],
12777
+ hardDeny
12778
+ });
12779
+ if (commits.length > 0) {
12780
+ payloads.push({
12781
+ kind: "unpushed_commits",
12782
+ path: "git/unpushed.patch",
12783
+ bytes: Buffer.from(commits)
12784
+ });
12785
+ }
12786
+ }
12787
+ const untracked = splitNul(
12788
+ await git(input.projectDir, [
12789
+ "ls-files",
12790
+ "--others",
12791
+ "--exclude-standard",
12792
+ "-z"
12793
+ ])
12794
+ );
12795
+ for (const rel of untracked) {
12796
+ if (!isAllowedRelativePath(rel, hardDeny)) continue;
12797
+ const bytes = await readWorkspaceFile(input.projectDir, rel);
12798
+ if (!bytes) continue;
12799
+ payloads.push({
12800
+ kind: "untracked_file",
12801
+ path: rel,
12802
+ bytes
12803
+ });
12804
+ }
12805
+ for (const rel of input.includeIgnored ?? []) {
12806
+ if (!isAllowedRelativePath(rel, hardDeny)) continue;
12807
+ if (!await isIgnored(input.projectDir, rel)) continue;
12808
+ const bytes = await readWorkspaceFile(input.projectDir, rel);
12809
+ if (!bytes) continue;
12810
+ payloads.push({
12811
+ kind: "included_ignored_file",
12812
+ path: rel,
12813
+ bytes
12814
+ });
12815
+ }
12816
+ return payloads;
12817
+ }
12818
+ async function readWorkspaceFile(projectDir, rel) {
12819
+ const absolute = path19.resolve(projectDir, rel);
12820
+ const workspaceRoot = await fs21.realpath(projectDir);
12821
+ let stat;
12822
+ try {
12823
+ stat = await fs21.lstat(absolute);
12824
+ } catch {
12825
+ return null;
12826
+ }
12827
+ if (!stat.isFile() || stat.isSymbolicLink()) return null;
12828
+ const real = await fs21.realpath(absolute);
12829
+ const relativeToRoot = path19.relative(workspaceRoot, real);
12830
+ if (relativeToRoot === ".." || relativeToRoot.startsWith(`..${path19.sep}`) || path19.isAbsolute(relativeToRoot)) {
12831
+ return null;
12832
+ }
12833
+ return fs21.readFile(absolute);
12834
+ }
12835
+ async function gitDiffForAllowedPaths(input) {
12836
+ const paths = splitNul(await git(input.projectDir, input.nameArgs)).filter(
12837
+ (rel) => isAllowedRelativePath(rel, input.hardDeny)
12838
+ );
12839
+ if (paths.length === 0) return "";
12840
+ return git(input.projectDir, [...input.diffArgs, ...paths]);
12841
+ }
12842
+ async function uploadGcsObject(input) {
12843
+ const url = new URL(
12844
+ `https://storage.googleapis.com/upload/storage/v1/b/${encodeURIComponent(
12845
+ input.bucket
12846
+ )}/o`
12847
+ );
12848
+ url.searchParams.set("uploadType", "media");
12849
+ url.searchParams.set("name", input.objectName);
12850
+ const response = await fetch(url, {
12851
+ method: "POST",
12852
+ headers: {
12853
+ authorization: `Bearer ${input.accessToken}`,
12854
+ "content-type": input.contentType
12855
+ },
12856
+ body: input.body.buffer.slice(
12857
+ input.body.byteOffset,
12858
+ input.body.byteOffset + input.body.byteLength
12859
+ )
12860
+ });
12861
+ if (!response.ok) {
12862
+ throw new Error(
12863
+ `GCS upload ${input.objectName} failed with HTTP ${response.status}`
12864
+ );
12865
+ }
12866
+ }
12867
+ function makeArtifactManifestFeedEvent(input) {
12868
+ return {
12869
+ event_id: `${input.runId}:artifacts-manifest`,
12870
+ seq: 0,
12871
+ ts: input.ts,
12872
+ session_id: input.result.athenaSessionId ?? input.runId,
12873
+ run_id: input.runId,
12874
+ kind: "artifacts.manifest",
12875
+ level: "info",
12876
+ actor_id: "system",
12877
+ title: "Artifacts manifest",
12878
+ data: { manifest: input.manifest }
12879
+ };
12880
+ }
12881
+ async function git(cwd, args) {
12882
+ const result = await execFileAsync("git", args, {
12883
+ cwd,
12884
+ encoding: "buffer",
12885
+ maxBuffer: 50 * 1024 * 1024
12886
+ });
12887
+ return result.stdout.toString("utf8");
12888
+ }
12889
+ async function gitMaybe(cwd, args) {
12890
+ try {
12891
+ return await git(cwd, args);
12892
+ } catch {
12893
+ return "";
12894
+ }
12895
+ }
12896
+ async function isGitWorkspace(cwd) {
12897
+ return (await gitMaybe(cwd, ["rev-parse", "--is-inside-work-tree"])).trim() === "true";
12898
+ }
12899
+ async function isIgnored(cwd, rel) {
12900
+ try {
12901
+ await execFileAsync("git", ["check-ignore", "--quiet", "--", rel], { cwd });
12902
+ return true;
12903
+ } catch {
12904
+ return false;
12905
+ }
12906
+ }
12907
+ function splitNul(value) {
12908
+ return value.split("\0").filter(Boolean);
12909
+ }
12910
+ function stringArray(value) {
12911
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
12912
+ }
12913
+ var DEFAULT_HARD_DENY = [
12914
+ ".git",
12915
+ ".git/**",
12916
+ ".env",
12917
+ ".env.*",
12918
+ "**/.env",
12919
+ "**/.env.*",
12920
+ ".ssh",
12921
+ ".ssh/**"
12922
+ ];
12923
+ function isAllowedRelativePath(rel, hardDeny) {
12924
+ if (path19.isAbsolute(rel) || rel.includes("\0")) return false;
12925
+ const normalized = path19.posix.normalize(rel.replaceAll(path19.sep, "/"));
12926
+ if (normalized === ".." || normalized.startsWith("../")) return false;
12927
+ return !hardDeny.some((pattern) => matchesDenyPattern(normalized, pattern));
12928
+ }
12929
+ function matchesDenyPattern(rel, pattern) {
12930
+ const normalized = pattern.replaceAll(path19.sep, "/");
12931
+ if (normalized.includes("*") || normalized.includes("?")) {
12932
+ return globToRegExp(normalized).test(rel);
12933
+ }
12934
+ if (normalized.endsWith("/**")) {
12935
+ const prefix = normalized.slice(0, -3);
12936
+ return rel === prefix || rel.startsWith(`${prefix}/`);
12937
+ }
12938
+ if (normalized.startsWith("**/")) {
12939
+ const suffix = normalized.slice(3);
12940
+ return rel === suffix || rel.endsWith(`/${suffix}`);
12941
+ }
12942
+ if (normalized.endsWith(".*")) {
12943
+ const prefix = normalized.slice(0, -1);
12944
+ return rel.startsWith(prefix);
12945
+ }
12946
+ return rel === normalized;
12947
+ }
12948
+ function globToRegExp(pattern) {
12949
+ let source = "^";
12950
+ for (let i = 0; i < pattern.length; i += 1) {
12951
+ const char = pattern[i];
12952
+ const next = pattern[i + 1];
12953
+ if (char === "*") {
12954
+ if (next === "*") {
12955
+ const after = pattern[i + 2];
12956
+ if (after === "/") {
12957
+ source += "(?:.*/)?";
12958
+ i += 2;
12959
+ } else {
12960
+ source += ".*";
12961
+ i += 1;
12962
+ }
12963
+ } else {
12964
+ source += "[^/]*";
12965
+ }
12966
+ } else if (char === "?") {
12967
+ source += "[^/]";
12968
+ } else {
12969
+ source += escapeRegExp(char);
12970
+ }
12971
+ }
12972
+ source += "$";
12973
+ return new RegExp(source);
12974
+ }
12975
+ function escapeRegExp(value) {
12976
+ return value.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
12977
+ }
12978
+ function sha256(bytes) {
12979
+ return crypto3.createHash("sha256").update(bytes).digest("hex");
12980
+ }
12981
+ function joinObjectName(...parts) {
12982
+ return parts.map((part) => part.replace(/^\/+|\/+$/g, "")).filter(Boolean).join("/");
12983
+ }
12984
+ function safeObjectSegment(value) {
12985
+ const safe = value.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
12986
+ return safe.length > 0 ? safe.slice(0, 160) : "artifact";
12987
+ }
12988
+ function contentTypeFor(filePath) {
12989
+ if (filePath.endsWith(".json")) return "application/json";
12990
+ if (filePath.endsWith(".diff") || filePath.endsWith(".patch")) {
12991
+ return "text/x-diff";
12992
+ }
12993
+ return "application/octet-stream";
12994
+ }
12995
+
12589
12996
  // src/app/dashboard/remoteRunExecutor.ts
12590
12997
  var DEFAULT_MARKETPLACE_SLUG = "lespaceman/athena-workflow-marketplace";
12591
12998
  function parseRemoteRunSpec(value) {
@@ -12704,7 +13111,7 @@ function mergeRunSpecEnvIntoWorkflow(workflow, env) {
12704
13111
  async function executeRemoteAssignment({
12705
13112
  frame,
12706
13113
  client,
12707
- projectDir: fallbackProjectDir = process.cwd(),
13114
+ projectDir,
12708
13115
  log = () => {
12709
13116
  },
12710
13117
  runExecFn = runExec,
@@ -12717,6 +13124,8 @@ async function executeRemoteAssignment({
12717
13124
  resolveWorkflowInstallFn = resolveWorkflowInstall,
12718
13125
  installWorkflowFromSourceFn = installWorkflowFromSource,
12719
13126
  readGlobalConfigFn = readGlobalConfig,
13127
+ uploadArtifactObjectFn,
13128
+ dashboardFeedPublisher,
12720
13129
  runStreamConnectTimeoutMs = 5e3
12721
13130
  }) {
12722
13131
  const lastTerminalFailureMessage = { current: null };
@@ -12746,7 +13155,15 @@ async function executeRemoteAssignment({
12746
13155
  send("error", { message: "remote assignment missing prompt" });
12747
13156
  return;
12748
13157
  }
12749
- const projectDir = spec.projectDir ?? fallbackProjectDir;
13158
+ let artifactUploadSpec;
13159
+ try {
13160
+ artifactUploadSpec = parseArtifactUploadSpec(frame.runSpec);
13161
+ } catch (err) {
13162
+ send("error", {
13163
+ message: err instanceof Error ? err.message : String(err)
13164
+ });
13165
+ return;
13166
+ }
12750
13167
  let runtimeConfig;
12751
13168
  try {
12752
13169
  const workflowOverride = ensureRemoteWorkflowInstalled({
@@ -12832,7 +13249,22 @@ async function executeRemoteAssignment({
12832
13249
  signal: abortSignal,
12833
13250
  stdout,
12834
13251
  stderr,
12835
- ...decisionInbox ? { dashboardDecisionInbox: decisionInbox } : {}
13252
+ ...decisionInbox ? { dashboardDecisionInbox: decisionInbox } : {},
13253
+ ...dashboardFeedPublisher ? { dashboardFeedPublisher } : {},
13254
+ ...artifactUploadSpec ? {
13255
+ beforeTerminalCompletion: async ({ result: result2, runId }) => {
13256
+ const artifactRunId = runId ?? frame.runId;
13257
+ const { feedEvent } = await captureAndUploadArtifacts({
13258
+ spec: artifactUploadSpec,
13259
+ projectDir,
13260
+ runId: artifactRunId,
13261
+ result: result2,
13262
+ now,
13263
+ ...uploadArtifactObjectFn ? { uploadObject: uploadArtifactObjectFn } : {}
13264
+ });
13265
+ return [feedEvent];
13266
+ }
13267
+ } : {}
12836
13268
  });
12837
13269
  const failedCompletion = deferredFailedCompletion.current;
12838
13270
  if (failedCompletion) {
@@ -12877,19 +13309,19 @@ async function executeRemoteAssignment({
12877
13309
  }
12878
13310
 
12879
13311
  // src/infra/config/attachmentMirror.ts
12880
- import crypto3 from "crypto";
12881
- import fs21 from "fs";
13312
+ import crypto4 from "crypto";
13313
+ import fs22 from "fs";
12882
13314
  import os12 from "os";
12883
- import path19 from "path";
13315
+ import path20 from "path";
12884
13316
  function attachmentMirrorPath(env = process.env) {
12885
13317
  const home = env["HOME"] ?? os12.homedir();
12886
- return path19.join(home, ".config", "athena", "attachments.json");
13318
+ return path20.join(home, ".config", "athena", "attachments.json");
12887
13319
  }
12888
13320
  function readAttachmentMirror(env = process.env) {
12889
13321
  const file = attachmentMirrorPath(env);
12890
13322
  let raw;
12891
13323
  try {
12892
- raw = fs21.readFileSync(file, "utf-8");
13324
+ raw = fs22.readFileSync(file, "utf-8");
12893
13325
  } catch (err) {
12894
13326
  if (err.code === "ENOENT") return null;
12895
13327
  throw err;
@@ -12913,29 +13345,29 @@ function readAttachmentMirror(env = process.env) {
12913
13345
  function writeAttachmentMirror(mirror, env = process.env) {
12914
13346
  const validated = parseAttachmentMirror(mirror);
12915
13347
  const file = attachmentMirrorPath(env);
12916
- const dir = path19.dirname(file);
12917
- fs21.mkdirSync(dir, { recursive: true, mode: 448 });
12918
- const tmp = `${file}.${process.pid}.${crypto3.randomBytes(4).toString("hex")}.tmp`;
12919
- const fd = fs21.openSync(tmp, "w", 384);
13348
+ const dir = path20.dirname(file);
13349
+ fs22.mkdirSync(dir, { recursive: true, mode: 448 });
13350
+ const tmp = `${file}.${process.pid}.${crypto4.randomBytes(4).toString("hex")}.tmp`;
13351
+ const fd = fs22.openSync(tmp, "w", 384);
12920
13352
  try {
12921
- fs21.writeSync(fd, JSON.stringify(validated, null, 2) + "\n");
12922
- fs21.fsyncSync(fd);
13353
+ fs22.writeSync(fd, JSON.stringify(validated, null, 2) + "\n");
13354
+ fs22.fsyncSync(fd);
12923
13355
  } finally {
12924
- fs21.closeSync(fd);
13356
+ fs22.closeSync(fd);
12925
13357
  }
12926
13358
  try {
12927
- fs21.renameSync(tmp, file);
13359
+ fs22.renameSync(tmp, file);
12928
13360
  } catch (err) {
12929
13361
  try {
12930
- fs21.unlinkSync(tmp);
13362
+ fs22.unlinkSync(tmp);
12931
13363
  } catch {
12932
13364
  }
12933
13365
  throw err;
12934
13366
  }
12935
13367
  if (process.platform !== "win32") {
12936
13368
  try {
12937
- fs21.chmodSync(dir, 448);
12938
- fs21.chmodSync(file, 384);
13369
+ fs22.chmodSync(dir, 448);
13370
+ fs22.chmodSync(file, 384);
12939
13371
  } catch {
12940
13372
  }
12941
13373
  }
@@ -12943,7 +13375,7 @@ function writeAttachmentMirror(mirror, env = process.env) {
12943
13375
  function removeAttachmentMirror(env = process.env) {
12944
13376
  const file = attachmentMirrorPath(env);
12945
13377
  try {
12946
- fs21.unlinkSync(file);
13378
+ fs22.unlinkSync(file);
12947
13379
  } catch (err) {
12948
13380
  if (err.code !== "ENOENT") throw err;
12949
13381
  }
@@ -13209,6 +13641,7 @@ function createDashboardPairedExecution(options) {
13209
13641
  });
13210
13642
  const maxConcurrentRuns = options.maxConcurrentRuns ?? DEFAULT_MAX_CONCURRENT_RUNS;
13211
13643
  const runHistoryLimit = options.runHistoryLimit ?? DEFAULT_RUN_HISTORY_LIMIT;
13644
+ const pairedFeedPublisher = options.pairedFeedPublisher;
13212
13645
  const now = options.now ?? (() => Date.now());
13213
13646
  let completedRuns = 0;
13214
13647
  const active = /* @__PURE__ */ new Map();
@@ -13248,7 +13681,7 @@ function createDashboardPairedExecution(options) {
13248
13681
  entry.record.status = "cancelled";
13249
13682
  entry.controller.abort();
13250
13683
  }
13251
- function handleAssignment(frame) {
13684
+ function handleAssignment(frame, input = {}) {
13252
13685
  if (active.has(frame.runId)) {
13253
13686
  const rejection = {
13254
13687
  reason: "duplicate",
@@ -13279,10 +13712,11 @@ function createDashboardPairedExecution(options) {
13279
13712
  const promise = executor({
13280
13713
  frame,
13281
13714
  client,
13282
- projectDir,
13715
+ projectDir: input.projectDir ?? projectDir,
13283
13716
  log,
13284
13717
  abortSignal: controller.signal,
13285
- decisionInbox
13718
+ decisionInbox,
13719
+ ...pairedFeedPublisher ? { dashboardFeedPublisher: pairedFeedPublisher } : {}
13286
13720
  }).then(() => {
13287
13721
  if (record.status === "running") record.status = "completed";
13288
13722
  }).catch((err) => {
@@ -13323,8 +13757,8 @@ function createDashboardPairedExecution(options) {
13323
13757
  }
13324
13758
  return false;
13325
13759
  },
13326
- admitAssignment(frame) {
13327
- return handleAssignment(frame);
13760
+ admitAssignment(frame, input) {
13761
+ return handleAssignment(frame, input);
13328
13762
  },
13329
13763
  rejectAssignment,
13330
13764
  snapshot() {
@@ -13352,10 +13786,125 @@ function createDashboardPairedExecution(options) {
13352
13786
  };
13353
13787
  }
13354
13788
 
13789
+ // src/app/dashboard/remoteWorkspaceResolver.ts
13790
+ import fs23 from "fs";
13791
+ import os13 from "os";
13792
+ import path21 from "path";
13793
+ function resolveRemoteWorkspace(frame, options = {}) {
13794
+ const spec = parseRemoteRunSpec(frame.runSpec);
13795
+ if (!spec) {
13796
+ return {
13797
+ kind: "rejected",
13798
+ rejection: {
13799
+ reason: "workspace_unresolved",
13800
+ message: "remote assignment missing prompt"
13801
+ }
13802
+ };
13803
+ }
13804
+ if (spec.projectDir) {
13805
+ return validateProjectDir(spec.projectDir, options.env);
13806
+ }
13807
+ const sessionId = spec.athenaSessionId ?? spec.sessionId;
13808
+ const runnerId = frame.runnerId ?? "legacy";
13809
+ const deploymentSlug = deploymentSlugFromUrl(options.dashboardUrl);
13810
+ const stateDir = daemonStatePaths(options.env).dir;
13811
+ const projectDir = sessionId ? path21.join(
13812
+ stateDir,
13813
+ "remote-workspaces",
13814
+ deploymentSlug,
13815
+ sanitizePathSegment(runnerId),
13816
+ "sessions",
13817
+ sanitizePathSegment(sessionId)
13818
+ ) : path21.join(
13819
+ stateDir,
13820
+ "remote-workspaces",
13821
+ deploymentSlug,
13822
+ sanitizePathSegment(runnerId),
13823
+ "runs",
13824
+ sanitizePathSegment(frame.runId)
13825
+ );
13826
+ try {
13827
+ fs23.mkdirSync(projectDir, { recursive: true, mode: 448 });
13828
+ if (process.platform !== "win32") {
13829
+ try {
13830
+ fs23.chmodSync(projectDir, 448);
13831
+ } catch {
13832
+ }
13833
+ }
13834
+ } catch (err) {
13835
+ return {
13836
+ kind: "rejected",
13837
+ rejection: {
13838
+ reason: "workspace_unresolved",
13839
+ message: `failed to create remote workspace: ${err instanceof Error ? err.message : String(err)}`
13840
+ }
13841
+ };
13842
+ }
13843
+ return validateProjectDir(projectDir, options.env);
13844
+ }
13845
+ function validateProjectDir(projectDir, env = process.env) {
13846
+ const resolved = path21.resolve(projectDir);
13847
+ if (!path21.isAbsolute(projectDir)) {
13848
+ return {
13849
+ kind: "rejected",
13850
+ rejection: {
13851
+ reason: "workspace_invalid",
13852
+ message: `remote workspace must be an absolute path: ${projectDir}`
13853
+ }
13854
+ };
13855
+ }
13856
+ const home = path21.resolve(env["HOME"] ?? os13.homedir());
13857
+ if (resolved === home) {
13858
+ return {
13859
+ kind: "rejected",
13860
+ rejection: {
13861
+ reason: "workspace_invalid",
13862
+ message: "remote workspace cannot be the user home directory"
13863
+ }
13864
+ };
13865
+ }
13866
+ let stat;
13867
+ try {
13868
+ stat = fs23.statSync(resolved);
13869
+ } catch {
13870
+ return {
13871
+ kind: "rejected",
13872
+ rejection: {
13873
+ reason: "workspace_invalid",
13874
+ message: `remote workspace does not exist: ${resolved}`
13875
+ }
13876
+ };
13877
+ }
13878
+ if (!stat.isDirectory()) {
13879
+ return {
13880
+ kind: "rejected",
13881
+ rejection: {
13882
+ reason: "workspace_invalid",
13883
+ message: `remote workspace is not a directory: ${resolved}`
13884
+ }
13885
+ };
13886
+ }
13887
+ return { kind: "resolved", projectDir: resolved };
13888
+ }
13889
+ function deploymentSlugFromUrl(dashboardUrl) {
13890
+ if (!dashboardUrl) return "unknown-dashboard";
13891
+ try {
13892
+ const url = new URL(dashboardUrl);
13893
+ return sanitizePathSegment(url.host);
13894
+ } catch {
13895
+ return sanitizePathSegment(dashboardUrl);
13896
+ }
13897
+ }
13898
+ function sanitizePathSegment(value) {
13899
+ const cleaned = value.trim().replaceAll(/[^a-zA-Z0-9._-]+/g, "-").replaceAll(/^-+|-+$/g, "");
13900
+ return cleaned.length > 0 ? cleaned : "unknown";
13901
+ }
13902
+
13355
13903
  // src/app/dashboard/dashboardAssignmentIntake.ts
13356
13904
  function createDashboardAssignmentIntake(options) {
13357
13905
  const log = options.log ?? (() => {
13358
13906
  });
13907
+ const resolveWorkspace = options.resolveWorkspace ?? ((frame) => resolveRemoteWorkspace(frame));
13359
13908
  const pending = [];
13360
13909
  let ready = false;
13361
13910
  function handle(frame) {
@@ -13371,7 +13920,18 @@ function createDashboardAssignmentIntake(options) {
13371
13920
  });
13372
13921
  return;
13373
13922
  }
13374
- const outcome = options.execution.admitAssignment(frame);
13923
+ const workspace = resolveWorkspace(frame);
13924
+ if (workspace.kind === "rejected") {
13925
+ options.execution.rejectAssignment(frame.runId, workspace.rejection);
13926
+ options.client.sendAssignmentRejected({
13927
+ runId: frame.runId,
13928
+ ...workspace.rejection
13929
+ });
13930
+ return;
13931
+ }
13932
+ const outcome = options.execution.admitAssignment(frame, {
13933
+ projectDir: workspace.projectDir
13934
+ });
13375
13935
  if (outcome.kind === "accepted") {
13376
13936
  options.client.sendAssignmentAccepted(frame.runId);
13377
13937
  return;
@@ -13487,6 +14047,7 @@ async function runDashboardRuntimeDaemon(options = {}) {
13487
14047
  executor,
13488
14048
  projectDir,
13489
14049
  decisionInbox,
14050
+ pairedFeedPublisher,
13490
14051
  log,
13491
14052
  maxConcurrentRuns,
13492
14053
  now,
@@ -13511,7 +14072,8 @@ async function runDashboardRuntimeDaemon(options = {}) {
13511
14072
  }
13512
14073
  },
13513
14074
  execution: pairedExecution,
13514
- log
14075
+ log,
14076
+ resolveWorkspace: (frame) => resolveRemoteWorkspace(frame, { dashboardUrl: currentDashboardUrl })
13515
14077
  });
13516
14078
  function nextReconnectDelay() {
13517
14079
  if (reconnectDelays.length === 0) return 0;
@@ -13659,9 +14221,9 @@ async function runDashboardRuntimeDaemon(options = {}) {
13659
14221
  next.close("attachment reconciliation failed");
13660
14222
  throw err;
13661
14223
  }
13662
- assignmentIntake.markReady();
13663
14224
  currentInstanceId = token.instanceId;
13664
14225
  currentDashboardUrl = config.dashboardUrl;
14226
+ assignmentIntake.markReady();
13665
14227
  reconnectAttempt = 0;
13666
14228
  scheduleRefresh(token.expiresInSec);
13667
14229
  pairedFeedPublisher.attachTransport(next);
@@ -13729,18 +14291,18 @@ async function runDashboardRuntimeDaemon(options = {}) {
13729
14291
  }
13730
14292
 
13731
14293
  // src/infra/daemon/pidLock.ts
13732
- import fs22 from "fs";
14294
+ import fs24 from "fs";
13733
14295
  function acquirePidLock(pidPath) {
13734
14296
  const ownPid = process.pid;
13735
14297
  for (let attempt = 0; attempt < 2; attempt += 1) {
13736
14298
  try {
13737
- const fd = fs22.openSync(pidPath, "wx", 384);
14299
+ const fd = fs24.openSync(pidPath, "wx", 384);
13738
14300
  try {
13739
- fs22.writeSync(fd, `${ownPid}
14301
+ fs24.writeSync(fd, `${ownPid}
13740
14302
  `);
13741
- fs22.fsyncSync(fd);
14303
+ fs24.fsyncSync(fd);
13742
14304
  } finally {
13743
- fs22.closeSync(fd);
14305
+ fs24.closeSync(fd);
13744
14306
  }
13745
14307
  return makeHandle(pidPath, ownPid);
13746
14308
  } catch (err) {
@@ -13754,7 +14316,7 @@ function acquirePidLock(pidPath) {
13754
14316
  }
13755
14317
  if (existing.state === "stale") {
13756
14318
  try {
13757
- fs22.unlinkSync(pidPath);
14319
+ fs24.unlinkSync(pidPath);
13758
14320
  } catch (err) {
13759
14321
  if (err.code !== "ENOENT") throw err;
13760
14322
  }
@@ -13768,7 +14330,7 @@ function acquirePidLock(pidPath) {
13768
14330
  function readPidLock(pidPath) {
13769
14331
  let raw;
13770
14332
  try {
13771
- raw = fs22.readFileSync(pidPath, "utf-8");
14333
+ raw = fs24.readFileSync(pidPath, "utf-8");
13772
14334
  } catch (err) {
13773
14335
  if (err.code === "ENOENT") {
13774
14336
  return { state: "absent" };
@@ -13792,9 +14354,9 @@ function makeHandle(pidPath, pid) {
13792
14354
  if (released) return;
13793
14355
  released = true;
13794
14356
  try {
13795
- const raw = fs22.readFileSync(pidPath, "utf-8").trim();
14357
+ const raw = fs24.readFileSync(pidPath, "utf-8").trim();
13796
14358
  if (raw === String(pid)) {
13797
- fs22.unlinkSync(pidPath);
14359
+ fs24.unlinkSync(pidPath);
13798
14360
  }
13799
14361
  } catch (err) {
13800
14362
  if (err.code !== "ENOENT") {
@@ -13820,7 +14382,7 @@ function isProcessAlive(pid) {
13820
14382
  }
13821
14383
 
13822
14384
  // src/infra/daemon/udsIpc.ts
13823
- import fs23 from "fs";
14385
+ import fs25 from "fs";
13824
14386
  import net2 from "net";
13825
14387
 
13826
14388
  // src/infra/daemon/udsFrameCodec.ts
@@ -13865,7 +14427,7 @@ async function startUdsServer(socketPath, handler, log) {
13865
14427
  });
13866
14428
  if (process.platform !== "win32") {
13867
14429
  try {
13868
- fs23.chmodSync(socketPath, 384);
14430
+ fs25.chmodSync(socketPath, 384);
13869
14431
  } catch {
13870
14432
  }
13871
14433
  }
@@ -13875,7 +14437,7 @@ async function startUdsServer(socketPath, handler, log) {
13875
14437
  server.close(() => resolve());
13876
14438
  });
13877
14439
  try {
13878
- fs23.unlinkSync(socketPath);
14440
+ fs25.unlinkSync(socketPath);
13879
14441
  } catch (err) {
13880
14442
  if (err.code !== "ENOENT") {
13881
14443
  }
@@ -13993,7 +14555,7 @@ async function sendUdsRequest(socketPath, request, options = {}) {
13993
14555
  async function unlinkStaleSocket(socketPath) {
13994
14556
  let stat;
13995
14557
  try {
13996
- stat = fs23.statSync(socketPath);
14558
+ stat = fs25.statSync(socketPath);
13997
14559
  } catch (err) {
13998
14560
  if (err.code === "ENOENT") return;
13999
14561
  throw err;
@@ -14020,7 +14582,7 @@ async function unlinkStaleSocket(socketPath) {
14020
14582
  `uds path ${socketPath} is in use by another process; aborting`
14021
14583
  );
14022
14584
  }
14023
- fs23.unlinkSync(socketPath);
14585
+ fs25.unlinkSync(socketPath);
14024
14586
  }
14025
14587
 
14026
14588
  export {
@@ -14098,4 +14660,4 @@ export {
14098
14660
  startUdsServer,
14099
14661
  sendUdsRequest
14100
14662
  };
14101
- //# sourceMappingURL=chunk-QVXHUJPH.js.map
14663
+ //# sourceMappingURL=chunk-UKMVFGY2.js.map
package/dist/cli.js CHANGED
@@ -74,7 +74,7 @@ import {
74
74
  writeAttachmentMirror,
75
75
  writeGatewayClientConfig,
76
76
  wsClientOptionsForEndpoint
77
- } from "./chunk-QVXHUJPH.js";
77
+ } from "./chunk-UKMVFGY2.js";
78
78
  import {
79
79
  generateId as generateId2
80
80
  } from "./chunk-BTKQ67RE.js";
@@ -5910,6 +5910,13 @@ var gatewayFunctionCompleted = defaultRenderer(
5910
5910
  var gatewayFunctionFailed = defaultRenderer(
5911
5911
  (event) => `fn ${event.data.reason}: ${event.data.function_name} \u2014 ${event.data.error_message}`
5912
5912
  );
5913
+ var artifactsManifest = defaultRenderer(
5914
+ (event) => {
5915
+ const manifest = event.data.manifest;
5916
+ const count = Array.isArray(manifest.entries) ? manifest.entries.length : 0;
5917
+ return `artifacts manifest (${count} item${count === 1 ? "" : "s"})`;
5918
+ }
5919
+ );
5913
5920
  var RENDERERS = {
5914
5921
  "session.start": sessionStart,
5915
5922
  "session.end": sessionEnd,
@@ -5968,7 +5975,8 @@ var RENDERERS = {
5968
5975
  "channel.chat.outbound": channelChatOutbound,
5969
5976
  "gateway.function.invoked": gatewayFunctionInvoked,
5970
5977
  "gateway.function.completed": gatewayFunctionCompleted,
5971
- "gateway.function.failed": gatewayFunctionFailed
5978
+ "gateway.function.failed": gatewayFunctionFailed,
5979
+ "artifacts.manifest": artifactsManifest
5972
5980
  };
5973
5981
  function rendererFor(event) {
5974
5982
  return RENDERERS[event.kind];
@@ -6814,6 +6822,7 @@ function resolveEventToolColumn(event) {
6814
6822
  case "gateway.function.invoked":
6815
6823
  case "gateway.function.completed":
6816
6824
  case "gateway.function.failed":
6825
+ case "artifacts.manifest":
6817
6826
  return "";
6818
6827
  }
6819
6828
  }
@@ -8548,7 +8557,8 @@ function renderDetailLines(event, width, pairedPostEvent, theme = darkTheme) {
8548
8557
  case "channel.chat.outbound":
8549
8558
  case "gateway.function.invoked":
8550
8559
  case "gateway.function.completed":
8551
- case "gateway.function.failed": {
8560
+ case "gateway.function.failed":
8561
+ case "artifacts.manifest": {
8552
8562
  const header = buildCompactHeader(event, width, { theme });
8553
8563
  const json = JSON.stringify(event.raw ?? event.data, null, 2);
8554
8564
  const content = highlightCode(json, cw, "json");
@@ -15695,7 +15705,7 @@ var cachedVersion = null;
15695
15705
  function readPackageVersion() {
15696
15706
  if (cachedVersion !== null) return cachedVersion;
15697
15707
  try {
15698
- const injected = "0.5.4";
15708
+ const injected = "0.5.7";
15699
15709
  if (typeof injected === "string" && injected.length > 0) {
15700
15710
  cachedVersion = injected;
15701
15711
  return cachedVersion;
@@ -3,7 +3,7 @@ import {
3
3
  ensureDaemonStateDir,
4
4
  runDashboardRuntimeDaemon,
5
5
  startUdsServer
6
- } from "./chunk-QVXHUJPH.js";
6
+ } from "./chunk-UKMVFGY2.js";
7
7
  import "./chunk-BTKQ67RE.js";
8
8
  import {
9
9
  readDashboardClientConfig,
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "hooks",
18
18
  "dashboard"
19
19
  ],
20
- "version": "0.5.4",
20
+ "version": "0.5.7",
21
21
  "license": "MIT",
22
22
  "bin": {
23
23
  "athena": "dist/cli.js",