tickmarkr 1.77.0 → 1.78.0

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.
@@ -2,6 +2,10 @@ import { type ExecutorDriver, type NotifyOpts, type Slot, type SlotOpts } from "
2
2
  export declare const TRAILER_SAFE_FLOOR_COLS = 108;
3
3
  export declare const TRAILER_WIDTH_MARGIN = 2;
4
4
  export declare const DELIVERY_ATTEMPTS = 3;
5
+ export interface HerdrTimeSource {
6
+ now: () => number;
7
+ sleep: (ms: number) => Promise<void>;
8
+ }
5
9
  export declare class DeliveryReadinessError extends Error {
6
10
  readonly waitedMs: number;
7
11
  readonly transcript: string;
@@ -13,6 +17,7 @@ export declare function workerSplitDirection(paneCols: number | null, safeFloor?
13
17
  export declare class HerdrDriver implements ExecutorDriver {
14
18
  private bin;
15
19
  private workersPerTab;
20
+ private time;
16
21
  id: string;
17
22
  interactive: boolean;
18
23
  private groups;
@@ -24,12 +29,13 @@ export declare class HerdrDriver implements ExecutorDriver {
24
29
  private ws;
25
30
  private callerPane;
26
31
  private watches;
27
- constructor(bin?: string, workersPerTab?: number);
32
+ constructor(bin?: string, workersPerTab?: number, time?: HerdrTimeSource);
28
33
  private serial;
29
34
  private deliveryQueue;
30
35
  private reserveDispatch;
31
36
  private verifyPaneIdentityBinding;
32
37
  private deliveryMatches;
38
+ private shellExecutionEchoed;
33
39
  private submissionRegistered;
34
40
  static available(): boolean;
35
41
  private herdr;
@@ -14,6 +14,10 @@ const DELIVERY_READ_LINES = 80;
14
14
  const DELIVERY_SETTLE_READ_ATTEMPTS = 6;
15
15
  const DELIVERY_SETTLE_POLL_MS = 100;
16
16
  const DELIVERY_READINESS_TIMEOUT_MS = 1_000;
17
+ const SYSTEM_TIME = {
18
+ now: () => Date.now(),
19
+ sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
20
+ };
17
21
  // OBS-142: a typed identity lets the daemon's next task distinguish cold-start variance from
18
22
  // structural driver faults without parsing prose. The message also carries the bounded wait and
19
23
  // final pane evidence so a terminal failure is diagnosable on its own.
@@ -37,6 +41,7 @@ export function workerSplitDirection(paneCols, safeFloor = TRAILER_SAFE_FLOOR_CO
37
41
  export class HerdrDriver {
38
42
  bin;
39
43
  workersPerTab;
44
+ time;
40
45
  id = "herdr";
41
46
  interactive = true;
42
47
  groups = new Map();
@@ -55,9 +60,10 @@ export class HerdrDriver {
55
60
  ws = process.env.HERDR_WORKSPACE_ID;
56
61
  callerPane = process.env.HERDR_PANE_ID;
57
62
  watches = new Map();
58
- constructor(bin = "herdr", workersPerTab = 3) {
63
+ constructor(bin = "herdr", workersPerTab = 3, time = SYSTEM_TIME) {
59
64
  this.bin = bin;
60
65
  this.workersPerTab = workersPerTab;
66
+ this.time = time;
61
67
  }
62
68
  serial(fn) {
63
69
  const p = this.groupSerial.then(fn, fn);
@@ -111,9 +117,27 @@ export class HerdrDriver {
111
117
  const needle = norm(cmd);
112
118
  return needle.length > 0 && hay.includes(needle);
113
119
  }
120
+ shellExecutionEchoed(transcript, cmd) {
121
+ const norm = (s) => s.replace(/\u001B\[[0-9;?]*[ -/]*[@-~]/g, "").replace(/\s+/g, " ").trim();
122
+ const needle = norm(cmd);
123
+ if (!needle)
124
+ return false;
125
+ return transcript.split("\n").some((rawLine) => {
126
+ const line = norm(rawLine);
127
+ if (line === needle || !line.endsWith(needle))
128
+ return false;
129
+ const prefix = line.slice(0, -needle.length).trimEnd();
130
+ if (/[│┃╭╰┌└]/.test(prefix))
131
+ return false;
132
+ return /^(?:[$%#>]|[➜❯❱›»λ])(?:\s|$)/.test(prefix)
133
+ || /[$%#>✗❯❱›»λ]$/.test(prefix);
134
+ });
135
+ }
114
136
  // Submission requires positive post-Enter evidence. A prompt echoed above a fresh input target
115
137
  // proves registration; a declared box that is visibly empty after the verified paste also proves
116
- // it consumed the prompt. Prompt absence alone is never success (OBS-142).
138
+ // it consumed the prompt. At the launch stage, a structurally prompt-prefixed shell execution echo
139
+ // is stronger evidence than waiting for first paint from the launched interface (OBS-144).
140
+ // Prompt absence alone is never success (OBS-142).
117
141
  submissionRegistered(transcript, cmd, inputBox) {
118
142
  const norm = (s) => s.replace(/\s+/g, "");
119
143
  const hay = norm(transcript);
@@ -121,6 +145,8 @@ export class HerdrDriver {
121
145
  const promptAt = hay.lastIndexOf(needle);
122
146
  if (needle.length === 0)
123
147
  return false;
148
+ if (inputBox?.launchCommand?.(cmd) === true && this.shellExecutionEchoed(transcript, cmd))
149
+ return true;
124
150
  if (promptAt < 0)
125
151
  return inputBox !== undefined && matchesEmptyInputBox(transcript, inputBox);
126
152
  if (inputBox && matchesInputBox(transcript, inputBox)) {
@@ -527,7 +553,7 @@ export class HerdrDriver {
527
553
  }
528
554
  transcript = read.stdout;
529
555
  if (readAttempt < readAttempts - 1) {
530
- await new Promise((resolve) => setTimeout(resolve, DELIVERY_SETTLE_POLL_MS));
556
+ await this.time.sleep(DELIVERY_SETTLE_POLL_MS);
531
557
  }
532
558
  }
533
559
  return { ok: false, transcript, recognizedInputBox: false };
@@ -536,19 +562,19 @@ export class HerdrDriver {
536
562
  const inputBox = this.inputBoxes.get(slot);
537
563
  const requireInputBox = inputBox !== undefined && inputBox.launchCommand?.(cmd) !== true;
538
564
  const timeoutMs = inputBox?.readinessTimeoutMs ?? DELIVERY_READINESS_TIMEOUT_MS;
539
- const started = Date.now();
565
+ const started = this.time.now();
540
566
  let previous;
541
567
  let transcript = "";
542
568
  let reads = 0;
543
569
  while (true) {
544
- const elapsedBeforeRead = Date.now() - started;
570
+ const elapsedBeforeRead = this.time.now() - started;
545
571
  const remainingBeforeRead = timeoutMs - elapsedBeforeRead;
546
572
  if (remainingBeforeRead <= 0)
547
573
  throw new DeliveryReadinessError(elapsedBeforeRead, transcript);
548
574
  const read = await this.herdr(`pane read ${shq(pane)} --source recent-unwrapped --lines ${DELIVERY_READ_LINES}`, slot.cwd, Math.max(1, Math.ceil(remainingBeforeRead)));
549
575
  reads++;
550
576
  transcript = read.stdout || transcript;
551
- const waitedMs = Date.now() - started;
577
+ const waitedMs = this.time.now() - started;
552
578
  if (read.code !== 0) {
553
579
  // Once at least one valid frame has been observed, a read that consumes the remainder of
554
580
  // the readiness budget is the bounded window expiring, not a new submission/protocol
@@ -574,7 +600,7 @@ export class HerdrDriver {
574
600
  // The second read is immediate: an already-painted stable target proves readiness with no
575
601
  // added delay. Only observed change spends a poll interval, and every path remains bounded.
576
602
  if (reads > 1) {
577
- await new Promise((resolve) => setTimeout(resolve, Math.min(DELIVERY_SETTLE_POLL_MS, remaining)));
603
+ await this.time.sleep(Math.min(DELIVERY_SETTLE_POLL_MS, remaining));
578
604
  }
579
605
  }
580
606
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tickmarkr",
3
- "version": "1.77.0",
3
+ "version": "1.78.0",
4
4
  "description": "Spec in, verified work out.",
5
5
  "type": "module",
6
6
  "license": "MIT",