@primitive.ai/prim 0.1.0-alpha.91 → 0.1.0-alpha.93

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +34 -2
  2. package/dist/{chunk-67VNLLBN.js → chunk-2GP5UFV7.js} +1 -0
  3. package/dist/{chunk-VW3FDYRT.js → chunk-36TWVNBE.js} +6 -6
  4. package/dist/{chunk-HU4PW6I6.js → chunk-C3VAA5CG.js} +1 -1
  5. package/dist/{chunk-FOLKHXLJ.js → chunk-DCJN6LZH.js} +37 -5
  6. package/dist/{chunk-M6RIJVRE.js → chunk-DSWT6BCC.js} +78 -4
  7. package/dist/{chunk-FBAYCS3X.js → chunk-DXJQR4QI.js} +150 -38
  8. package/dist/{chunk-PCVGBE5B.js → chunk-G2VMA2QO.js} +2 -1
  9. package/dist/{chunk-NAHHFSLH.js → chunk-ICM2XCXS.js} +2 -2
  10. package/dist/{chunk-OAAP2MY6.js → chunk-K7D2EYBS.js} +2 -2
  11. package/dist/{chunk-5AFRMOPX.js → chunk-OH3EZXYX.js} +1 -1
  12. package/dist/{chunk-KFXF2V5G.js → chunk-OTHKG76J.js} +1 -1
  13. package/dist/chunk-OYHYCK4K.js +13 -0
  14. package/dist/{chunk-FKXFUUWJ.js → chunk-TYAHC25F.js} +1 -1
  15. package/dist/{chunk-5GYQ4J3D.js → chunk-UKUAAAXE.js} +2 -2
  16. package/dist/{chunk-EWZMDD44.js → chunk-X64HTHUF.js} +22 -3
  17. package/dist/{chunk-WX52U7Z2.js → chunk-ZU563PQI.js} +58 -2
  18. package/dist/daemon/server.js +382 -124
  19. package/dist/hook-runtime/daemon/server.js +382 -124
  20. package/dist/hook-runtime/hooks/post-commit.js +57 -39
  21. package/dist/hook-runtime/hooks/post-rewrite.js +58 -40
  22. package/dist/hook-runtime/hooks/post-tool-use.js +111 -78
  23. package/dist/hook-runtime/hooks/pre-tool-use.js +48 -26
  24. package/dist/hook-runtime/hooks/prim-hook.js +157 -117
  25. package/dist/hook-runtime/hooks/session-end.js +1 -1
  26. package/dist/hook-runtime/hooks/session-start.js +38 -4
  27. package/dist/hook-runtime/index.js +1293 -526
  28. package/dist/hook-runtime/statusline-main.js +23 -1
  29. package/dist/hooks/post-commit.js +11 -8
  30. package/dist/hooks/post-rewrite.js +11 -8
  31. package/dist/hooks/post-tool-use.js +13 -15
  32. package/dist/hooks/pre-commit.js +4 -4
  33. package/dist/hooks/pre-tool-use.js +10 -12
  34. package/dist/hooks/prim-hook.js +17 -14
  35. package/dist/hooks/session-end.js +4 -4
  36. package/dist/hooks/session-start.js +12 -36
  37. package/dist/index.js +867 -291
  38. package/dist/statusline-main.js +23 -1
  39. package/package.json +1 -1
  40. package/dist/chunk-BTNNEH2W.js +0 -79
@@ -52,8 +52,8 @@ var require_ucs2length = __commonJS({
52
52
  });
53
53
 
54
54
  // src/hooks/post-tool-use.ts
55
- import { readFileSync as readFileSync14 } from "fs";
56
- import { dirname as dirname11, join as join16 } from "path";
55
+ import { readFileSync as readFileSync15 } from "fs";
56
+ import { dirname as dirname12, join as join17 } from "path";
57
57
  import { fileURLToPath as fileURLToPath2 } from "url";
58
58
 
59
59
  // src/binding.ts
@@ -20022,6 +20022,67 @@ function detachedHookShimCommand(bin, args = "") {
20022
20022
  return `payload=$(cat); { trap '' HUP; printf '%s' "$payload" | { ${stableHookCommand(bin, args)}; }; } </dev/null >/dev/null 2>&1 &`;
20023
20023
  }
20024
20024
 
20025
+ // src/lib/ansi.ts
20026
+ var ANSI_CODES = {
20027
+ yellow: "\x1B[33m",
20028
+ magenta: "\x1B[35m",
20029
+ blue: "\x1B[34m",
20030
+ cyan: "\x1B[36m",
20031
+ green: "\x1B[32m",
20032
+ red: "\x1B[31m",
20033
+ // 256-color approximation of the orange trigger marker (xterm 208).
20034
+ orange: "\x1B[38;5;208m",
20035
+ gray: "\x1B[90m"
20036
+ };
20037
+ var ANSI_RESET = "\x1B[0m";
20038
+ var ANSI_BOLD = "\x1B[1m";
20039
+ function supportsColor() {
20040
+ if (process.env.NO_COLOR !== void 0 && process.env.NO_COLOR !== "") {
20041
+ return false;
20042
+ }
20043
+ return process.stderr.isTTY === true;
20044
+ }
20045
+ function color(text, c) {
20046
+ if (!supportsColor()) {
20047
+ return text;
20048
+ }
20049
+ return `${ANSI_CODES[c]}${text}${ANSI_RESET}`;
20050
+ }
20051
+ function bold(text) {
20052
+ if (!supportsColor()) {
20053
+ return text;
20054
+ }
20055
+ return `${ANSI_BOLD}${text}${ANSI_RESET}`;
20056
+ }
20057
+ var MAX_HEALTH_ERROR_LENGTH = 240;
20058
+ function boundedHealthError(value) {
20059
+ if (!value) return void 0;
20060
+ const clean = terminalSafeLine(value);
20061
+ if (!clean) return void 0;
20062
+ return clean.length <= MAX_HEALTH_ERROR_LENGTH ? clean : `${clean.slice(0, MAX_HEALTH_ERROR_LENGTH - 1)}\u2026`;
20063
+ }
20064
+
20065
+ // src/lib/delivery-backlog.ts
20066
+ var MS_PER_SECOND = 1e3;
20067
+ var MS_PER_MINUTE = 60 * MS_PER_SECOND;
20068
+ var MS_PER_HOUR = 60 * MS_PER_MINUTE;
20069
+ var MS_PER_DAY = 24 * MS_PER_HOUR;
20070
+ function isNonNegativeInteger(value) {
20071
+ return typeof value === "number" && Number.isInteger(value) && value >= 0;
20072
+ }
20073
+ function isPositiveInteger(value) {
20074
+ return isNonNegativeInteger(value) && value > 0;
20075
+ }
20076
+ function deliveryBacklogState(ingestion) {
20077
+ if (ingestion?.healthy !== false) return void 0;
20078
+ const failures = ingestion.consecutiveFailures;
20079
+ const failedWithoutProgress = failures !== 0 && !(isPositiveInteger(failures) && isPositiveInteger(ingestion.lastFailedDrainAcknowledgedCount));
20080
+ if (failedWithoutProgress) return "failing";
20081
+ const retained = ingestion.lastRetainedBucketCount;
20082
+ if (!isNonNegativeInteger(retained)) return "failing";
20083
+ return retained > 0 ? "retained" : "draining";
20084
+ }
20085
+
20025
20086
  // src/lib/presence.ts
20026
20087
  var DECISION_ORIGIN = "https://app.getprimitive.ai";
20027
20088
  function validDecisionUrl(value) {
@@ -20096,7 +20157,8 @@ function formatStatusline(version, snapshot, resolveIngestionStatus, options = {
20096
20157
  if (snapshot.ingestion?.healthy === false) {
20097
20158
  const pending = snapshot.ingestion.pendingCount;
20098
20159
  const qualifier = snapshot.ingestion.pendingSampled ? "at least " : "";
20099
- return `primitive ${version} (daemon: degraded \xB7 delivery: stalled${typeof pending === "number" ? ` \xB7 ${qualifier}${String(pending)} pending` : ""}${repositorySuffix}${ingestionSuffix(ingestionStatus)})`;
20160
+ const delivery = deliveryBacklogState(snapshot.ingestion) === "draining" && snapshot.heartbeat?.healthy === true ? "draining" : "stalled";
20161
+ return `primitive ${version} (daemon: degraded \xB7 delivery: ${delivery}${typeof pending === "number" ? ` \xB7 ${qualifier}${String(pending)} pending` : ""}${repositorySuffix}${ingestionSuffix(ingestionStatus)})`;
20100
20162
  }
20101
20163
  if (snapshot.heartbeat?.healthy === false) {
20102
20164
  return `primitive ${version} (daemon: degraded \xB7 presence: unavailable${repositorySuffix}${ingestionSuffix(ingestionStatus)})`;
@@ -20598,7 +20660,7 @@ import {
20598
20660
  utimesSync,
20599
20661
  writeFileSync as writeFileSync5
20600
20662
  } from "fs";
20601
- import { dirname as dirname8, isAbsolute as isAbsolute5, join as join11, resolve as resolve4 } from "path";
20663
+ import { delimiter, dirname as dirname8, isAbsolute as isAbsolute5, join as join11, resolve as resolve4 } from "path";
20602
20664
  var RELEASE_PREFIX = "release-";
20603
20665
  var MAX_MANIFEST_BYTES = 64 * 1024;
20604
20666
  var RELEASE_GRACE_MS = 10 * 60 * 1e3;
@@ -22241,16 +22303,16 @@ var Lexer = class {
22241
22303
  readHereDocDelimiter() {
22242
22304
  const src = this.src;
22243
22305
  const len = this.srcEnd;
22244
- let delimiter = "";
22306
+ let delimiter2 = "";
22245
22307
  if (this.pos < len && src.charCodeAt(this.pos) === CH_SQUOTE) {
22246
22308
  this.pos++;
22247
22309
  const start = this.pos;
22248
22310
  while (this.pos < len && src.charCodeAt(this.pos) !== CH_SQUOTE)
22249
22311
  this.pos++;
22250
- delimiter = src.slice(start, this.pos);
22312
+ delimiter2 = src.slice(start, this.pos);
22251
22313
  if (this.pos < len)
22252
22314
  this.pos++;
22253
- this._hereDelim = delimiter;
22315
+ this._hereDelim = delimiter2;
22254
22316
  this._hereQuoted = true;
22255
22317
  return;
22256
22318
  } else if (this.pos < len && src.charCodeAt(this.pos) === CH_DQUOTE) {
@@ -22258,12 +22320,12 @@ var Lexer = class {
22258
22320
  while (this.pos < len && src.charCodeAt(this.pos) !== CH_DQUOTE) {
22259
22321
  if (src.charCodeAt(this.pos) === CH_BACKSLASH)
22260
22322
  this.pos++;
22261
- delimiter += src[this.pos];
22323
+ delimiter2 += src[this.pos];
22262
22324
  this.pos++;
22263
22325
  }
22264
22326
  if (this.pos < len)
22265
22327
  this.pos++;
22266
- this._hereDelim = delimiter;
22328
+ this._hereDelim = delimiter2;
22267
22329
  this._hereQuoted = true;
22268
22330
  return;
22269
22331
  } else if (this.pos < len && src.charCodeAt(this.pos) === CH_BACKSLASH) {
@@ -22274,11 +22336,11 @@ var Lexer = class {
22274
22336
  if (c === CH_BACKSLASH)
22275
22337
  this.pos++;
22276
22338
  if (this.pos < len) {
22277
- delimiter += src[this.pos];
22339
+ delimiter2 += src[this.pos];
22278
22340
  this.pos++;
22279
22341
  }
22280
22342
  }
22281
- this._hereDelim = delimiter;
22343
+ this._hereDelim = delimiter2;
22282
22344
  this._hereQuoted = true;
22283
22345
  return;
22284
22346
  } else {
@@ -22310,9 +22372,9 @@ var Lexer = class {
22310
22372
  }
22311
22373
  this.pendingHereDocs.length = 0;
22312
22374
  }
22313
- readHereDocBody(delimiter, strip) {
22375
+ readHereDocBody(delimiter2, strip) {
22314
22376
  const bodyStart = this.pos;
22315
- const bodyEnd = this.skipHereDocBody(delimiter, strip);
22377
+ const bodyEnd = this.skipHereDocBody(delimiter2, strip);
22316
22378
  return this.src.slice(bodyStart, bodyEnd);
22317
22379
  }
22318
22380
  // Advance past the heredoc body and its delimiter line; return the body end
@@ -22320,10 +22382,10 @@ var Lexer = class {
22320
22382
  // With parenEnds (inside $(...)), a line starting with the delimiter directly
22321
22383
  // followed by ")" also terminates the body, resuming at the ")" — bash treats
22322
22384
  // the substitution's closing paren as end-of-file for its heredocs.
22323
- skipHereDocBody(delimiter, strip, parenEnds = false) {
22385
+ skipHereDocBody(delimiter2, strip, parenEnds = false) {
22324
22386
  const src = this.src;
22325
22387
  const len = this.srcEnd;
22326
- const dLen = delimiter.length;
22388
+ const dLen = delimiter2.length;
22327
22389
  while (this.pos < len) {
22328
22390
  let lineStart = this.pos;
22329
22391
  let lineEnd = src.indexOf("\n", this.pos);
@@ -22333,12 +22395,12 @@ var Lexer = class {
22333
22395
  while (lineStart < lineEnd && src.charCodeAt(lineStart) === CH_TAB)
22334
22396
  lineStart++;
22335
22397
  }
22336
- if (lineEnd - lineStart === dLen && src.startsWith(delimiter, lineStart)) {
22398
+ if (lineEnd - lineStart === dLen && src.startsWith(delimiter2, lineStart)) {
22337
22399
  const bodyEnd = this.pos;
22338
22400
  this.pos = lineEnd < len ? lineEnd + 1 : lineEnd;
22339
22401
  return bodyEnd;
22340
22402
  }
22341
- if (parenEnds && lineEnd - lineStart > dLen && src.charCodeAt(lineStart + dLen) === CH_RPAREN && src.startsWith(delimiter, lineStart)) {
22403
+ if (parenEnds && lineEnd - lineStart > dLen && src.charCodeAt(lineStart + dLen) === CH_RPAREN && src.startsWith(delimiter2, lineStart)) {
22342
22404
  const bodyEnd = this.pos;
22343
22405
  this.pos = lineStart + dLen;
22344
22406
  return bodyEnd;
@@ -25050,7 +25112,7 @@ function safeSedProgram(program) {
25050
25112
  return true;
25051
25113
  const match = /^(?:(?:\d+|\$)(?:,(?:\d+|\$))?)?s(.)(.*)$/s.exec(program);
25052
25114
  if (!match || /[\\\nA-Za-z0-9]/.test(match[1])) return false;
25053
- const delimiter = match[1];
25115
+ const delimiter2 = match[1];
25054
25116
  const tail = match[2];
25055
25117
  let offset = 0;
25056
25118
  for (let section = 0; section < 2; section += 1) {
@@ -25058,7 +25120,7 @@ function safeSedProgram(program) {
25058
25120
  while (offset < tail.length) {
25059
25121
  if (tail[offset] === "\\") {
25060
25122
  offset += 2;
25061
- } else if (tail[offset] === delimiter) {
25123
+ } else if (tail[offset] === delimiter2) {
25062
25124
  offset += 1;
25063
25125
  closed = true;
25064
25126
  break;
@@ -25682,17 +25744,30 @@ function requireDurableIngestAcknowledgement(value, expected, cwd = process.cwd(
25682
25744
  import {
25683
25745
  appendFileSync,
25684
25746
  closeSync as closeSync3,
25685
- existsSync as existsSync10,
25747
+ existsSync as existsSync11,
25686
25748
  fstatSync,
25687
25749
  mkdirSync as mkdirSync7,
25688
25750
  openSync as openSync3,
25689
25751
  opendirSync,
25690
- readFileSync as readFileSync12,
25752
+ readFileSync as readFileSync13,
25691
25753
  readSync,
25692
- readdirSync as readdirSync3
25754
+ readdirSync as readdirSync4
25693
25755
  } from "fs";
25694
- import { dirname as dirname10, join as join14 } from "path";
25695
- var JOURNAL_DIR = join14(primConfigDirectory(), "moves");
25756
+ import { dirname as dirname11, join as join15 } from "path";
25757
+
25758
+ // src/drain-progress.ts
25759
+ import {
25760
+ chmodSync as chmodSync5,
25761
+ existsSync as existsSync10,
25762
+ readFileSync as readFileSync12,
25763
+ readdirSync as readdirSync3,
25764
+ rmSync as rmSync6,
25765
+ rmdirSync
25766
+ } from "fs";
25767
+ import { basename as basename2, dirname as dirname10, join as join14 } from "path";
25768
+
25769
+ // src/journal.ts
25770
+ var JOURNAL_DIR = join15(primConfigDirectory(), "moves");
25696
25771
  var UNBOUND_BUCKET = "_unbound";
25697
25772
  var JOURNAL_BASENAME = "journal.ndjson";
25698
25773
  var JOURNAL_STATS_SAMPLE_BYTES = 64 * 1024;
@@ -25704,15 +25779,15 @@ function envSlug(apiUrl) {
25704
25779
  return slug;
25705
25780
  }
25706
25781
  function currentEnvDir() {
25707
- return join14(JOURNAL_DIR, envSlug(getSiteUrl()));
25782
+ return join15(JOURNAL_DIR, envSlug(getSiteUrl()));
25708
25783
  }
25709
25784
  var DIR_MODE = 448;
25710
25785
  var FILE_MODE2 = 384;
25711
25786
  var SAFE_BUCKET = /^[A-Za-z0-9_-]+$/;
25712
25787
  var RESERVED_BUCKETS = /* @__PURE__ */ new Set([UNBOUND_BUCKET, "_legacy"]);
25713
25788
  function appendMoveToPath(path, move) {
25714
- const dir = dirname10(path);
25715
- if (!existsSync10(dir)) {
25789
+ const dir = dirname11(path);
25790
+ if (!existsSync11(dir)) {
25716
25791
  mkdirSync7(dir, { recursive: true, mode: DIR_MODE });
25717
25792
  }
25718
25793
  appendFileSync(path, `${JSON.stringify(move)}
@@ -25720,10 +25795,10 @@ function appendMoveToPath(path, move) {
25720
25795
  }
25721
25796
  function bucketDir(orgId) {
25722
25797
  const safe = orgId !== void 0 && SAFE_BUCKET.test(orgId) && !RESERVED_BUCKETS.has(orgId);
25723
- return join14(currentEnvDir(), safe ? orgId : UNBOUND_BUCKET);
25798
+ return join15(currentEnvDir(), safe ? orgId : UNBOUND_BUCKET);
25724
25799
  }
25725
25800
  function journalPath(orgId) {
25726
- return join14(bucketDir(orgId), JOURNAL_BASENAME);
25801
+ return join15(bucketDir(orgId), JOURNAL_BASENAME);
25727
25802
  }
25728
25803
  function appendMove(move, orgId) {
25729
25804
  appendMoveToPath(journalPath(orgId), move);
@@ -25750,51 +25825,9 @@ import { platform } from "os";
25750
25825
  var AGENT_ENVELOPE_VERSION = 3;
25751
25826
 
25752
25827
  // src/hooks/redact.ts
25753
- import { existsSync as existsSync11, readFileSync as readFileSync13, statSync as statSync5 } from "fs";
25754
- import { join as join15 } from "path";
25828
+ import { existsSync as existsSync12, readFileSync as readFileSync14, statSync as statSync5 } from "fs";
25829
+ import { join as join16 } from "path";
25755
25830
  import { Worker } from "worker_threads";
25756
-
25757
- // src/lib/ansi.ts
25758
- var ANSI_CODES = {
25759
- yellow: "\x1B[33m",
25760
- magenta: "\x1B[35m",
25761
- blue: "\x1B[34m",
25762
- cyan: "\x1B[36m",
25763
- green: "\x1B[32m",
25764
- red: "\x1B[31m",
25765
- // 256-color approximation of the orange trigger marker (xterm 208).
25766
- orange: "\x1B[38;5;208m",
25767
- gray: "\x1B[90m"
25768
- };
25769
- var ANSI_RESET = "\x1B[0m";
25770
- var ANSI_BOLD = "\x1B[1m";
25771
- function supportsColor() {
25772
- if (process.env.NO_COLOR !== void 0 && process.env.NO_COLOR !== "") {
25773
- return false;
25774
- }
25775
- return process.stderr.isTTY === true;
25776
- }
25777
- function color(text, c) {
25778
- if (!supportsColor()) {
25779
- return text;
25780
- }
25781
- return `${ANSI_CODES[c]}${text}${ANSI_RESET}`;
25782
- }
25783
- function bold(text) {
25784
- if (!supportsColor()) {
25785
- return text;
25786
- }
25787
- return `${ANSI_BOLD}${text}${ANSI_RESET}`;
25788
- }
25789
- var MAX_HEALTH_ERROR_LENGTH = 240;
25790
- function boundedHealthError(value) {
25791
- if (!value) return void 0;
25792
- const clean = terminalSafeLine(value);
25793
- if (!clean) return void 0;
25794
- return clean.length <= MAX_HEALTH_ERROR_LENGTH ? clean : `${clean.slice(0, MAX_HEALTH_ERROR_LENGTH - 1)}\u2026`;
25795
- }
25796
-
25797
- // src/hooks/redact.ts
25798
25831
  var USER_HOME_RULES = [
25799
25832
  {
25800
25833
  pattern: /\/Users\/[^/\\\s"'`]+/g,
@@ -25869,15 +25902,15 @@ function normalizedWorkspaceFlags(value) {
25869
25902
  return [...new Set(`g${requested}`)].sort().join("");
25870
25903
  }
25871
25904
  function loadWorkspaceRules(cwd) {
25872
- const path = join15(cwd, WORKSPACE_FILE2);
25873
- if (!existsSync11(path)) return [];
25905
+ const path = join16(cwd, WORKSPACE_FILE2);
25906
+ if (!existsSync12(path)) return [];
25874
25907
  let cfg;
25875
25908
  try {
25876
25909
  if (statSync5(path).size > MAX_WORKSPACE_CONFIG_BYTES) {
25877
25910
  debugRedaction(`ignoring oversized ${WORKSPACE_FILE2}`);
25878
25911
  return [];
25879
25912
  }
25880
- cfg = JSON.parse(readFileSync13(path, "utf-8"));
25913
+ cfg = JSON.parse(readFileSync14(path, "utf-8"));
25881
25914
  } catch {
25882
25915
  debugRedaction(`ignoring unparseable ${WORKSPACE_FILE2}`);
25883
25916
  return [];
@@ -26182,10 +26215,10 @@ function editingToolsFor(agent) {
26182
26215
  }
26183
26216
  return EDITING_TOOLS;
26184
26217
  }
26185
- var here = dirname11(fileURLToPath2(import.meta.url));
26218
+ var here = dirname12(fileURLToPath2(import.meta.url));
26186
26219
  function resolveCliVersion() {
26187
26220
  try {
26188
- const pkg = JSON.parse(readFileSync14(join16(here, "..", "..", "package.json"), "utf-8"));
26221
+ const pkg = JSON.parse(readFileSync15(join17(here, "..", "..", "package.json"), "utf-8"));
26189
26222
  return pkg.version ?? "unknown";
26190
26223
  } catch {
26191
26224
  return "unknown";
@@ -19677,6 +19677,36 @@ function isActionablePrivateDraft(row) {
19677
19677
  return typeof candidate.id === "string" && SAFE_PRIVATE_DRAFT_ID.test(candidate.id) && typeof candidate.intent === "string" && candidate.authorIsSelf === true && candidate.stage === "draft" && (candidate.intentKind === void 0 || candidate.intentKind === "change");
19678
19678
  }
19679
19679
 
19680
+ // src/lib/ansi.ts
19681
+ var MAX_HEALTH_ERROR_LENGTH = 240;
19682
+ function boundedHealthError(value) {
19683
+ if (!value) return void 0;
19684
+ const clean = terminalSafeLine(value);
19685
+ if (!clean) return void 0;
19686
+ return clean.length <= MAX_HEALTH_ERROR_LENGTH ? clean : `${clean.slice(0, MAX_HEALTH_ERROR_LENGTH - 1)}\u2026`;
19687
+ }
19688
+
19689
+ // src/lib/delivery-backlog.ts
19690
+ var MS_PER_SECOND = 1e3;
19691
+ var MS_PER_MINUTE = 60 * MS_PER_SECOND;
19692
+ var MS_PER_HOUR = 60 * MS_PER_MINUTE;
19693
+ var MS_PER_DAY = 24 * MS_PER_HOUR;
19694
+ function isNonNegativeInteger(value) {
19695
+ return typeof value === "number" && Number.isInteger(value) && value >= 0;
19696
+ }
19697
+ function isPositiveInteger(value) {
19698
+ return isNonNegativeInteger(value) && value > 0;
19699
+ }
19700
+ function deliveryBacklogState(ingestion) {
19701
+ if (ingestion?.healthy !== false) return void 0;
19702
+ const failures = ingestion.consecutiveFailures;
19703
+ const failedWithoutProgress = failures !== 0 && !(isPositiveInteger(failures) && isPositiveInteger(ingestion.lastFailedDrainAcknowledgedCount));
19704
+ if (failedWithoutProgress) return "failing";
19705
+ const retained = ingestion.lastRetainedBucketCount;
19706
+ if (!isNonNegativeInteger(retained)) return "failing";
19707
+ return retained > 0 ? "retained" : "draining";
19708
+ }
19709
+
19680
19710
  // src/lib/presence.ts
19681
19711
  var DECISION_ORIGIN = "https://app.getprimitive.ai";
19682
19712
  function validDecisionUrl(value) {
@@ -19751,7 +19781,8 @@ function formatStatusline(version, snapshot, resolveIngestionStatus, options = {
19751
19781
  if (snapshot.ingestion?.healthy === false) {
19752
19782
  const pending = snapshot.ingestion.pendingCount;
19753
19783
  const qualifier = snapshot.ingestion.pendingSampled ? "at least " : "";
19754
- return `primitive ${version} (daemon: degraded \xB7 delivery: stalled${typeof pending === "number" ? ` \xB7 ${qualifier}${String(pending)} pending` : ""}${repositorySuffix}${ingestionSuffix(ingestionStatus)})`;
19784
+ const delivery = deliveryBacklogState(snapshot.ingestion) === "draining" && snapshot.heartbeat?.healthy === true ? "draining" : "stalled";
19785
+ return `primitive ${version} (daemon: degraded \xB7 delivery: ${delivery}${typeof pending === "number" ? ` \xB7 ${qualifier}${String(pending)} pending` : ""}${repositorySuffix}${ingestionSuffix(ingestionStatus)})`;
19755
19786
  }
19756
19787
  if (snapshot.heartbeat?.healthy === false) {
19757
19788
  return `primitive ${version} (daemon: degraded \xB7 presence: unavailable${repositorySuffix}${ingestionSuffix(ingestionStatus)})`;
@@ -20260,7 +20291,7 @@ import {
20260
20291
  utimesSync,
20261
20292
  writeFileSync as writeFileSync4
20262
20293
  } from "fs";
20263
- import { dirname as dirname6, isAbsolute as isAbsolute4, join as join9, resolve as resolve3 } from "path";
20294
+ import { delimiter, dirname as dirname6, isAbsolute as isAbsolute4, join as join9, resolve as resolve3 } from "path";
20264
20295
  var RELEASE_PREFIX = "release-";
20265
20296
  var MAX_MANIFEST_BYTES = 64 * 1024;
20266
20297
  var RELEASE_GRACE_MS = 10 * 60 * 1e3;
@@ -20945,15 +20976,6 @@ function demoteForMode(verdict, mode) {
20945
20976
  // src/hooks/preflight-v3.ts
20946
20977
  import { Buffer as Buffer2 } from "buffer";
20947
20978
 
20948
- // src/lib/ansi.ts
20949
- var MAX_HEALTH_ERROR_LENGTH = 240;
20950
- function boundedHealthError(value) {
20951
- if (!value) return void 0;
20952
- const clean = terminalSafeLine(value);
20953
- if (!clean) return void 0;
20954
- return clean.length <= MAX_HEALTH_ERROR_LENGTH ? clean : `${clean.slice(0, MAX_HEALTH_ERROR_LENGTH - 1)}\u2026`;
20955
- }
20956
-
20957
20979
  // src/hooks/redact.ts
20958
20980
  import { existsSync as existsSync9, readFileSync as readFileSync10, statSync as statSync4 } from "fs";
20959
20981
  import { join as join12 } from "path";
@@ -22363,16 +22385,16 @@ var Lexer = class {
22363
22385
  readHereDocDelimiter() {
22364
22386
  const src = this.src;
22365
22387
  const len = this.srcEnd;
22366
- let delimiter = "";
22388
+ let delimiter2 = "";
22367
22389
  if (this.pos < len && src.charCodeAt(this.pos) === CH_SQUOTE) {
22368
22390
  this.pos++;
22369
22391
  const start = this.pos;
22370
22392
  while (this.pos < len && src.charCodeAt(this.pos) !== CH_SQUOTE)
22371
22393
  this.pos++;
22372
- delimiter = src.slice(start, this.pos);
22394
+ delimiter2 = src.slice(start, this.pos);
22373
22395
  if (this.pos < len)
22374
22396
  this.pos++;
22375
- this._hereDelim = delimiter;
22397
+ this._hereDelim = delimiter2;
22376
22398
  this._hereQuoted = true;
22377
22399
  return;
22378
22400
  } else if (this.pos < len && src.charCodeAt(this.pos) === CH_DQUOTE) {
@@ -22380,12 +22402,12 @@ var Lexer = class {
22380
22402
  while (this.pos < len && src.charCodeAt(this.pos) !== CH_DQUOTE) {
22381
22403
  if (src.charCodeAt(this.pos) === CH_BACKSLASH)
22382
22404
  this.pos++;
22383
- delimiter += src[this.pos];
22405
+ delimiter2 += src[this.pos];
22384
22406
  this.pos++;
22385
22407
  }
22386
22408
  if (this.pos < len)
22387
22409
  this.pos++;
22388
- this._hereDelim = delimiter;
22410
+ this._hereDelim = delimiter2;
22389
22411
  this._hereQuoted = true;
22390
22412
  return;
22391
22413
  } else if (this.pos < len && src.charCodeAt(this.pos) === CH_BACKSLASH) {
@@ -22396,11 +22418,11 @@ var Lexer = class {
22396
22418
  if (c === CH_BACKSLASH)
22397
22419
  this.pos++;
22398
22420
  if (this.pos < len) {
22399
- delimiter += src[this.pos];
22421
+ delimiter2 += src[this.pos];
22400
22422
  this.pos++;
22401
22423
  }
22402
22424
  }
22403
- this._hereDelim = delimiter;
22425
+ this._hereDelim = delimiter2;
22404
22426
  this._hereQuoted = true;
22405
22427
  return;
22406
22428
  } else {
@@ -22432,9 +22454,9 @@ var Lexer = class {
22432
22454
  }
22433
22455
  this.pendingHereDocs.length = 0;
22434
22456
  }
22435
- readHereDocBody(delimiter, strip) {
22457
+ readHereDocBody(delimiter2, strip) {
22436
22458
  const bodyStart = this.pos;
22437
- const bodyEnd = this.skipHereDocBody(delimiter, strip);
22459
+ const bodyEnd = this.skipHereDocBody(delimiter2, strip);
22438
22460
  return this.src.slice(bodyStart, bodyEnd);
22439
22461
  }
22440
22462
  // Advance past the heredoc body and its delimiter line; return the body end
@@ -22442,10 +22464,10 @@ var Lexer = class {
22442
22464
  // With parenEnds (inside $(...)), a line starting with the delimiter directly
22443
22465
  // followed by ")" also terminates the body, resuming at the ")" — bash treats
22444
22466
  // the substitution's closing paren as end-of-file for its heredocs.
22445
- skipHereDocBody(delimiter, strip, parenEnds = false) {
22467
+ skipHereDocBody(delimiter2, strip, parenEnds = false) {
22446
22468
  const src = this.src;
22447
22469
  const len = this.srcEnd;
22448
- const dLen = delimiter.length;
22470
+ const dLen = delimiter2.length;
22449
22471
  while (this.pos < len) {
22450
22472
  let lineStart = this.pos;
22451
22473
  let lineEnd = src.indexOf("\n", this.pos);
@@ -22455,12 +22477,12 @@ var Lexer = class {
22455
22477
  while (lineStart < lineEnd && src.charCodeAt(lineStart) === CH_TAB)
22456
22478
  lineStart++;
22457
22479
  }
22458
- if (lineEnd - lineStart === dLen && src.startsWith(delimiter, lineStart)) {
22480
+ if (lineEnd - lineStart === dLen && src.startsWith(delimiter2, lineStart)) {
22459
22481
  const bodyEnd = this.pos;
22460
22482
  this.pos = lineEnd < len ? lineEnd + 1 : lineEnd;
22461
22483
  return bodyEnd;
22462
22484
  }
22463
- if (parenEnds && lineEnd - lineStart > dLen && src.charCodeAt(lineStart + dLen) === CH_RPAREN && src.startsWith(delimiter, lineStart)) {
22485
+ if (parenEnds && lineEnd - lineStart > dLen && src.charCodeAt(lineStart + dLen) === CH_RPAREN && src.startsWith(delimiter2, lineStart)) {
22464
22486
  const bodyEnd = this.pos;
22465
22487
  this.pos = lineStart + dLen;
22466
22488
  return bodyEnd;
@@ -25172,7 +25194,7 @@ function safeSedProgram(program) {
25172
25194
  return true;
25173
25195
  const match = /^(?:(?:\d+|\$)(?:,(?:\d+|\$))?)?s(.)(.*)$/s.exec(program);
25174
25196
  if (!match || /[\\\nA-Za-z0-9]/.test(match[1])) return false;
25175
- const delimiter = match[1];
25197
+ const delimiter2 = match[1];
25176
25198
  const tail = match[2];
25177
25199
  let offset = 0;
25178
25200
  for (let section = 0; section < 2; section += 1) {
@@ -25180,7 +25202,7 @@ function safeSedProgram(program) {
25180
25202
  while (offset < tail.length) {
25181
25203
  if (tail[offset] === "\\") {
25182
25204
  offset += 2;
25183
- } else if (tail[offset] === delimiter) {
25205
+ } else if (tail[offset] === delimiter2) {
25184
25206
  offset += 1;
25185
25207
  closed = true;
25186
25208
  break;