@agent-arc-status/reference 0.3.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Joe Fisher
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,114 @@
1
+ # `@agent-arc-status/reference`: Node reference implementation
2
+
3
+ Reference TypeScript implementation of the [Agent Arc Status Protocol](../../README.md) v0.2.
4
+
5
+ Provides:
6
+
7
+ - Types matching the wire schema (`ArcStatusEvent`, `ArcStatusPhase`)
8
+ - A structural validator (`validate`)
9
+ - A sequence validator for per-arc phase ordering (`validateSequence`)
10
+ - JSON / JSON Lines parsers that never throw (`parse`, `parseJsonl`)
11
+ - A default human-line renderer (`render`)
12
+ - Cadence helpers (`CadenceController` and `SilenceWatchdog`) that drive the
13
+ silence backstop and cadence-floor gating
14
+ - `reduceArc`, which folds an event stream into current arc state
15
+
16
+ Zero runtime dependencies.
17
+
18
+ ## Install
19
+
20
+ ```bash
21
+ npm install @agent-arc-status/reference
22
+ ```
23
+
24
+ > Working from a clone instead? This package is a workspace in the
25
+ > [monorepo](https://github.com/joethefisher/agent-arc-status); run `npm install` at the repo
26
+ > root and the `prepare` script builds `dist/`. The surface is small enough to vendor `src/` too.
27
+
28
+ ## Use
29
+
30
+ ### Emit and validate an event
31
+
32
+ ```ts
33
+ import { validate, type ArcStatusEvent } from "@agent-arc-status/reference";
34
+
35
+ const event: ArcStatusEvent = {
36
+ arc_id: crypto.randomUUID(),
37
+ phase: "milestone",
38
+ title: "receiver booted, smoke test passes",
39
+ step: 5,
40
+ total: 11,
41
+ eta_minutes: 25,
42
+ sent_at: new Date().toISOString(),
43
+ protocol_version: "0.1",
44
+ };
45
+
46
+ const result = validate(event);
47
+ if (!result.ok) {
48
+ for (const issue of result.issues) {
49
+ console.error(`${issue.path}: ${issue.message}`);
50
+ }
51
+ throw new Error("malformed arc.status event");
52
+ }
53
+
54
+ await postWebhook("https://...", JSON.stringify(result.event));
55
+ ```
56
+
57
+ ### Parse a JSON Lines stream of events
58
+
59
+ ```ts
60
+ import { parseJsonl, validateSequence } from "@agent-arc-status/reference";
61
+ import { readFileSync } from "node:fs";
62
+
63
+ const { events, errors } = parseJsonl(readFileSync("./arc.jsonl", "utf8"));
64
+
65
+ if (errors.length > 0) {
66
+ console.warn(`${errors.length} malformed events skipped`);
67
+ }
68
+
69
+ const seq = validateSequence(events);
70
+ if (!seq.ok) {
71
+ console.error("arc phase ordering invalid:", seq.issues);
72
+ }
73
+ ```
74
+
75
+ ### Render for human surfaces
76
+
77
+ ```ts
78
+ import { render } from "@agent-arc-status/reference";
79
+
80
+ // "▶ build Pulsefeed v0.1"
81
+ render({ ... phase: "started", title: "build Pulsefeed v0.1" });
82
+
83
+ // "✓ [5/11] receiver booted (ETA 25m)"
84
+ render({ ... phase: "milestone", title: "receiver booted", step: 5, total: 11, eta_minutes: 25 });
85
+
86
+ // "⛔ need finance sign-off on plan-B reclassification\ndetails about what would unblock"
87
+ render(event, { body: true });
88
+ ```
89
+
90
+ ## Development
91
+
92
+ ```bash
93
+ npm install
94
+ npm test # vitest
95
+ npm run build # tsc → dist/
96
+ npm run typecheck
97
+ ```
98
+
99
+ Tests include end-to-end runs against the shipped [`examples/`](../../examples/) JSONL fixtures, so any deviation from the documented examples is caught immediately.
100
+
101
+ ## Scope
102
+
103
+ This package implements **structural conformance plus cadence discipline**. It does not implement:
104
+
105
+ - Transport (HTTP/queue/etc.): the Protocol is transport-agnostic; bring your own.
106
+ - Persistence: emitters and consumers store events as fits their architecture.
107
+
108
+ The silence backstop and cadence-floor gating ship as `CadenceController` and
109
+ `SilenceWatchdog` (see [`src/cadence.ts`](src/cadence.ts)); drive them from a
110
+ timer independent of your work loop, since an emitter that heartbeats from its
111
+ own work loop cannot signal liveness in the one case that matters: when that
112
+ loop has stalled.
113
+
114
+ For the canonical schema, see [`spec/schema.json`](../../spec/schema.json). For the full specification, see [`spec/v0.2.md`](../../spec/v0.2.md).
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Cadence discipline as executable code: the part of the Protocol that the
3
+ * v0.1 reference left as prose.
4
+ *
5
+ * - `CadenceController` drives one arc's emission discipline: it gates
6
+ * sub-floor arcs (§5.1), emits a (possibly retroactive) `started` once the
7
+ * cadence floor is crossed, and fires a `heartbeat` when the silence window
8
+ * (§5.2) would otherwise elapse with no event.
9
+ * - `SilenceWatchdog` is a consumer/sidecar that detects stalls across many
10
+ * arcs using LOCAL receipt time, never the event's `sent_at` (§7.5).
11
+ *
12
+ * Both take an injectable `now()` so behaviour is deterministic under test, and
13
+ * are meant to be driven by a timer INDEPENDENT of the work loop (§5.2): an
14
+ * emitter that drives its own heartbeat from the work loop cannot honour the
15
+ * silence backstop in the one case it exists for: when the work loop is what
16
+ * stalled. Zero dependencies.
17
+ */
18
+ import type { ArcStatusEvent } from "./types.js";
19
+ export interface CadenceConfig {
20
+ /** Minimum arc age before any event is emitted. Default 5 min (§5.1). */
21
+ cadenceFloorMs?: number;
22
+ /** Max silence before a heartbeat is required. Default 20 min (§5.2). */
23
+ silenceWindowMs?: number;
24
+ /** Injectable clock in ms epoch. Default `Date.now`. */
25
+ now?: () => number;
26
+ }
27
+ /** The minimum an arc needs to begin emitting; threaded onto generated events. */
28
+ export interface ArcSeed {
29
+ arc_id: string;
30
+ title: string;
31
+ arc_kind?: string;
32
+ protocol_version?: string;
33
+ }
34
+ /**
35
+ * Per-arc emission controller. Owns the `started` and `heartbeat` events; the
36
+ * caller emits `milestone`/`blocked`/`done` itself and reports them via
37
+ * {@link CadenceController.onEmit} so the silence timer resets.
38
+ */
39
+ export declare class CadenceController {
40
+ private readonly floorMs;
41
+ private readonly windowMs;
42
+ private readonly now;
43
+ private seed;
44
+ private beganAt;
45
+ private startedEmitted;
46
+ private terminal;
47
+ private lastEmitAt;
48
+ constructor(config?: CadenceConfig);
49
+ /**
50
+ * Register the start of an arc. Per §5.1 the floor is a DELAY threshold, not
51
+ * a prediction: nothing is emitted until the arc has been alive for the
52
+ * cadence floor, so an arc that was expected to be short but runs long still
53
+ * becomes visible at the floor. Returns a `started` event immediately only
54
+ * when the floor is 0.
55
+ */
56
+ begin(seed: ArcSeed): ArcStatusEvent | null;
57
+ /**
58
+ * Report an event the caller emitted (milestone, blocked, done) so the
59
+ * silence timer resets. `done` marks the arc terminal.
60
+ */
61
+ onEmit(event: ArcStatusEvent): void;
62
+ /**
63
+ * Drive the cadence. Call on a timer independent of the work loop. Returns an
64
+ * event to emit, or null: the (possibly retroactive) `started` once the floor
65
+ * is crossed, then a `heartbeat` once the silence window elapses with no
66
+ * emit. `currentActivity` becomes the heartbeat title (§4.3).
67
+ */
68
+ tick(currentActivity?: string): ArcStatusEvent | null;
69
+ /** True once a `done` has been reported. */
70
+ isTerminal(): boolean;
71
+ private maybeEmitStarted;
72
+ private emit;
73
+ }
74
+ /** An arc that has been silent past the window. */
75
+ export interface StalledArc {
76
+ arc_id: string;
77
+ /** Local receipt time of the arc's most recent event. */
78
+ lastReceiptMs: number;
79
+ /** How long the arc has been silent, in ms. */
80
+ silentMs: number;
81
+ }
82
+ /**
83
+ * Multi-arc stall detector for a consumer or sidecar. Tracks the LOCAL receipt
84
+ * time of each arc's most recent event and reports the arcs that have gone
85
+ * quiet past the silence window, including those whose own heartbeat is
86
+ * missing, which is the failure the backstop exists to surface.
87
+ */
88
+ export declare class SilenceWatchdog {
89
+ private readonly windowMs;
90
+ private readonly now;
91
+ private readonly lastReceipt;
92
+ constructor(config?: CadenceConfig);
93
+ /**
94
+ * Record receipt of an event for an arc. Uses LOCAL receipt time, never the
95
+ * event's `sent_at` (§7.5: `sent_at` is for ordering/display, so a sender
96
+ * with a skewed clock or a delayed delivery must not be able to look alive).
97
+ */
98
+ record(arcId: string, receiptMs?: number): void;
99
+ /** Arcs whose last receipt is older than the silence window. */
100
+ stalled(nowMs?: number): StalledArc[];
101
+ /** Stop tracking an arc (e.g. after it reaches a terminal event). */
102
+ forget(arcId: string): void;
103
+ }
104
+ //# sourceMappingURL=cadence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cadence.d.ts","sourceRoot":"","sources":["../src/cadence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAkB,MAAM,YAAY,CAAC;AAKjE,MAAM,WAAW,aAAa;IAC5B,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,wDAAwD;IACxD,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,kFAAkF;AAClF,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;GAIG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,IAAI,CAAwB;IACpC,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAAK;gBAEX,MAAM,GAAE,aAAkB;IAMtC;;;;;;OAMG;IACH,KAAK,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,GAAG,IAAI;IAS3C;;;OAGG;IACH,MAAM,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IAMnC;;;;;OAKG;IACH,IAAI,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI;IASrD,4CAA4C;IAC5C,UAAU,IAAI,OAAO;IAIrB,OAAO,CAAC,gBAAgB;IAOxB,OAAO,CAAC,IAAI;CAcb;AAED,mDAAmD;AACnD,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,aAAa,EAAE,MAAM,CAAC;IACtB,+CAA+C;IAC/C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;gBAE7C,MAAM,GAAE,aAAkB;IAKtC;;;;OAIG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,GAAE,MAAmB,GAAG,IAAI;IAI3D,gEAAgE;IAChE,OAAO,CAAC,KAAK,GAAE,MAAmB,GAAG,UAAU,EAAE;IASjD,qEAAqE;IACrE,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;CAG5B"}
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Cadence discipline as executable code: the part of the Protocol that the
3
+ * v0.1 reference left as prose.
4
+ *
5
+ * - `CadenceController` drives one arc's emission discipline: it gates
6
+ * sub-floor arcs (§5.1), emits a (possibly retroactive) `started` once the
7
+ * cadence floor is crossed, and fires a `heartbeat` when the silence window
8
+ * (§5.2) would otherwise elapse with no event.
9
+ * - `SilenceWatchdog` is a consumer/sidecar that detects stalls across many
10
+ * arcs using LOCAL receipt time, never the event's `sent_at` (§7.5).
11
+ *
12
+ * Both take an injectable `now()` so behaviour is deterministic under test, and
13
+ * are meant to be driven by a timer INDEPENDENT of the work loop (§5.2): an
14
+ * emitter that drives its own heartbeat from the work loop cannot honour the
15
+ * silence backstop in the one case it exists for: when the work loop is what
16
+ * stalled. Zero dependencies.
17
+ */
18
+ const DEFAULT_FLOOR_MS = 5 * 60_000;
19
+ const DEFAULT_WINDOW_MS = 20 * 60_000;
20
+ /**
21
+ * Per-arc emission controller. Owns the `started` and `heartbeat` events; the
22
+ * caller emits `milestone`/`blocked`/`done` itself and reports them via
23
+ * {@link CadenceController.onEmit} so the silence timer resets.
24
+ */
25
+ export class CadenceController {
26
+ floorMs;
27
+ windowMs;
28
+ now;
29
+ seed = null;
30
+ beganAt = 0;
31
+ startedEmitted = false;
32
+ terminal = false;
33
+ lastEmitAt = 0;
34
+ constructor(config = {}) {
35
+ this.floorMs = config.cadenceFloorMs ?? DEFAULT_FLOOR_MS;
36
+ this.windowMs = config.silenceWindowMs ?? DEFAULT_WINDOW_MS;
37
+ this.now = config.now ?? (() => Date.now());
38
+ }
39
+ /**
40
+ * Register the start of an arc. Per §5.1 the floor is a DELAY threshold, not
41
+ * a prediction: nothing is emitted until the arc has been alive for the
42
+ * cadence floor, so an arc that was expected to be short but runs long still
43
+ * becomes visible at the floor. Returns a `started` event immediately only
44
+ * when the floor is 0.
45
+ */
46
+ begin(seed) {
47
+ this.seed = seed;
48
+ this.beganAt = this.now();
49
+ this.startedEmitted = false;
50
+ this.terminal = false;
51
+ this.lastEmitAt = 0;
52
+ return this.maybeEmitStarted();
53
+ }
54
+ /**
55
+ * Report an event the caller emitted (milestone, blocked, done) so the
56
+ * silence timer resets. `done` marks the arc terminal.
57
+ */
58
+ onEmit(event) {
59
+ this.lastEmitAt = this.now();
60
+ if (event.phase === "started")
61
+ this.startedEmitted = true;
62
+ if (event.phase === "done")
63
+ this.terminal = true;
64
+ }
65
+ /**
66
+ * Drive the cadence. Call on a timer independent of the work loop. Returns an
67
+ * event to emit, or null: the (possibly retroactive) `started` once the floor
68
+ * is crossed, then a `heartbeat` once the silence window elapses with no
69
+ * emit. `currentActivity` becomes the heartbeat title (§4.3).
70
+ */
71
+ tick(currentActivity) {
72
+ if (this.terminal || !this.seed)
73
+ return null;
74
+ if (!this.startedEmitted)
75
+ return this.maybeEmitStarted();
76
+ if (this.now() - this.lastEmitAt >= this.windowMs) {
77
+ return this.emit("heartbeat", currentActivity ?? "still working");
78
+ }
79
+ return null;
80
+ }
81
+ /** True once a `done` has been reported. */
82
+ isTerminal() {
83
+ return this.terminal;
84
+ }
85
+ maybeEmitStarted() {
86
+ if (this.startedEmitted || this.terminal || !this.seed)
87
+ return null;
88
+ if (this.now() - this.beganAt < this.floorMs)
89
+ return null;
90
+ this.startedEmitted = true;
91
+ return this.emit("started", this.seed.title);
92
+ }
93
+ emit(phase, title) {
94
+ const t = this.now();
95
+ this.lastEmitAt = t;
96
+ const seed = this.seed;
97
+ const event = {
98
+ arc_id: seed.arc_id,
99
+ phase,
100
+ title,
101
+ sent_at: new Date(t).toISOString(),
102
+ };
103
+ if (seed.arc_kind)
104
+ event.arc_kind = seed.arc_kind;
105
+ if (seed.protocol_version)
106
+ event.protocol_version = seed.protocol_version;
107
+ return event;
108
+ }
109
+ }
110
+ /**
111
+ * Multi-arc stall detector for a consumer or sidecar. Tracks the LOCAL receipt
112
+ * time of each arc's most recent event and reports the arcs that have gone
113
+ * quiet past the silence window, including those whose own heartbeat is
114
+ * missing, which is the failure the backstop exists to surface.
115
+ */
116
+ export class SilenceWatchdog {
117
+ windowMs;
118
+ now;
119
+ lastReceipt = new Map();
120
+ constructor(config = {}) {
121
+ this.windowMs = config.silenceWindowMs ?? DEFAULT_WINDOW_MS;
122
+ this.now = config.now ?? (() => Date.now());
123
+ }
124
+ /**
125
+ * Record receipt of an event for an arc. Uses LOCAL receipt time, never the
126
+ * event's `sent_at` (§7.5: `sent_at` is for ordering/display, so a sender
127
+ * with a skewed clock or a delayed delivery must not be able to look alive).
128
+ */
129
+ record(arcId, receiptMs = this.now()) {
130
+ this.lastReceipt.set(arcId, receiptMs);
131
+ }
132
+ /** Arcs whose last receipt is older than the silence window. */
133
+ stalled(nowMs = this.now()) {
134
+ const out = [];
135
+ for (const [arc_id, lastReceiptMs] of this.lastReceipt) {
136
+ const silentMs = nowMs - lastReceiptMs;
137
+ if (silentMs >= this.windowMs)
138
+ out.push({ arc_id, lastReceiptMs, silentMs });
139
+ }
140
+ return out;
141
+ }
142
+ /** Stop tracking an arc (e.g. after it reaches a terminal event). */
143
+ forget(arcId) {
144
+ this.lastReceipt.delete(arcId);
145
+ }
146
+ }
147
+ //# sourceMappingURL=cadence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cadence.js","sourceRoot":"","sources":["../src/cadence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,MAAM,gBAAgB,GAAG,CAAC,GAAG,MAAM,CAAC;AACpC,MAAM,iBAAiB,GAAG,EAAE,GAAG,MAAM,CAAC;AAmBtC;;;;GAIG;AACH,MAAM,OAAO,iBAAiB;IACX,OAAO,CAAS;IAChB,QAAQ,CAAS;IACjB,GAAG,CAAe;IAC3B,IAAI,GAAmB,IAAI,CAAC;IAC5B,OAAO,GAAG,CAAC,CAAC;IACZ,cAAc,GAAG,KAAK,CAAC;IACvB,QAAQ,GAAG,KAAK,CAAC;IACjB,UAAU,GAAG,CAAC,CAAC;IAEvB,YAAY,SAAwB,EAAE;QACpC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,cAAc,IAAI,gBAAgB,CAAC;QACzD,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,eAAe,IAAI,iBAAiB,CAAC;QAC5D,IAAI,CAAC,GAAG,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,IAAa;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC1B,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC;QAC5B,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;QACpB,OAAO,IAAI,CAAC,gBAAgB,EAAE,CAAC;IACjC,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,KAAqB;QAC1B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;YAAE,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAC1D,IAAI,KAAK,CAAC,KAAK,KAAK,MAAM;YAAE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;IACnD,CAAC;IAED;;;;;OAKG;IACH,IAAI,CAAC,eAAwB;QAC3B,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC;QAC7C,IAAI,CAAC,IAAI,CAAC,cAAc;YAAE,OAAO,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACzD,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClD,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,eAAe,IAAI,eAAe,CAAC,CAAC;QACpE,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,4CAA4C;IAC5C,UAAU;QACR,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAEO,gBAAgB;QACtB,IAAI,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC;QACpE,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAC1D,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAC3B,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/C,CAAC;IAEO,IAAI,CAAC,KAAqB,EAAE,KAAa;QAC/C,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACrB,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;QACpB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAK,CAAC;QACxB,MAAM,KAAK,GAAmB;YAC5B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,KAAK;YACL,KAAK;YACL,OAAO,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE;SACnC,CAAC;QACF,IAAI,IAAI,CAAC,QAAQ;YAAE,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAClD,IAAI,IAAI,CAAC,gBAAgB;YAAE,KAAK,CAAC,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,CAAC;QAC1E,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AAWD;;;;;GAKG;AACH,MAAM,OAAO,eAAe;IACT,QAAQ,CAAS;IACjB,GAAG,CAAe;IAClB,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;IAEzD,YAAY,SAAwB,EAAE;QACpC,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,eAAe,IAAI,iBAAiB,CAAC;QAC5D,IAAI,CAAC,GAAG,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,KAAa,EAAE,YAAoB,IAAI,CAAC,GAAG,EAAE;QAClD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IACzC,CAAC;IAED,gEAAgE;IAChE,OAAO,CAAC,QAAgB,IAAI,CAAC,GAAG,EAAE;QAChC,MAAM,GAAG,GAAiB,EAAE,CAAC;QAC7B,KAAK,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACvD,MAAM,QAAQ,GAAG,KAAK,GAAG,aAAa,CAAC;YACvC,IAAI,QAAQ,IAAI,IAAI,CAAC,QAAQ;gBAAE,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC/E,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,qEAAqE;IACrE,MAAM,CAAC,KAAa;QAClB,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;CACF"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Delegation-tree tooling built on the INTERIM `x_parent_arc_id` convention
3
+ * (spec §12.1). This does NOT promote `parent_arc_id` to a first-class field:
4
+ * the parent link is read from the `x_`-prefixed extension, so every event
5
+ * stays schema-valid and no wire change is implied. The final field shape will
6
+ * be derived from real delegation usage and only then promoted in a future
7
+ * minor. Consumers MUST tolerate the convention's absence — with no
8
+ * `x_parent_arc_id` present this degrades to a flat list of roots.
9
+ *
10
+ * `reduceArcForest` groups per-arc event streams into parent/child trees;
11
+ * `renderArcForest` prints an indented tree. Orphans (a named parent absent from
12
+ * the input) are surfaced AND rooted so delegated work is never hidden; cycles
13
+ * are broken deterministically so the result is always a forest.
14
+ */
15
+ import { type ArcState } from "./state.js";
16
+ import type { ArcStatusEvent } from "./types.js";
17
+ export interface ArcTreeNode {
18
+ state: ArcState;
19
+ children: ArcTreeNode[];
20
+ /** Distance from a root (0 for roots). */
21
+ depth: number;
22
+ }
23
+ export interface ArcForest {
24
+ roots: ArcTreeNode[];
25
+ /** Nodes whose `x_parent_arc_id` names a parent not present in the input.
26
+ * These are also included in `roots` so nothing is hidden. */
27
+ orphans: ArcTreeNode[];
28
+ /** arc_ids whose parent link was dropped to break a cycle. */
29
+ cycleBroken: string[];
30
+ }
31
+ /**
32
+ * Group per-arc event streams into a forest by the `x_parent_arc_id` convention.
33
+ * Empty streams are skipped. Returns roots, orphans, and any arc_ids whose link
34
+ * was cut to break a cycle.
35
+ */
36
+ export declare function reduceArcForest(eventsByArc: Map<string, ArcStatusEvent[]> | Record<string, ArcStatusEvent[]>): ArcForest;
37
+ export interface RenderForestOptions {
38
+ /** Indent unit per depth level. Default two spaces. */
39
+ indent?: string;
40
+ /** Render one node's state to a line. Default: phase symbol + title + status. */
41
+ line?: (state: ArcState) => string;
42
+ }
43
+ /** Render a forest to an indented, newline-joined tree of arc states. */
44
+ export declare function renderArcForest(forest: ArcForest, options?: RenderForestOptions): string;
45
+ //# sourceMappingURL=forest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forest.d.ts","sourceRoot":"","sources":["../src/forest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,QAAQ,CAAC;IAChB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB;mEAC+D;IAC/D,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,8DAA8D;IAC9D,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAyBD;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC,GAC5E,SAAS,CAyEX;AAED,MAAM,WAAW,mBAAmB;IAClC,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,MAAM,CAAC;CACpC;AAeD,yEAAyE;AACzE,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,GAAE,mBAAwB,GAAG,MAAM,CAY5F"}
package/dist/forest.js ADDED
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Delegation-tree tooling built on the INTERIM `x_parent_arc_id` convention
3
+ * (spec §12.1). This does NOT promote `parent_arc_id` to a first-class field:
4
+ * the parent link is read from the `x_`-prefixed extension, so every event
5
+ * stays schema-valid and no wire change is implied. The final field shape will
6
+ * be derived from real delegation usage and only then promoted in a future
7
+ * minor. Consumers MUST tolerate the convention's absence — with no
8
+ * `x_parent_arc_id` present this degrades to a flat list of roots.
9
+ *
10
+ * `reduceArcForest` groups per-arc event streams into parent/child trees;
11
+ * `renderArcForest` prints an indented tree. Orphans (a named parent absent from
12
+ * the input) are surfaced AND rooted so delegated work is never hidden; cycles
13
+ * are broken deterministically so the result is always a forest.
14
+ */
15
+ import { reduceArc } from "./state.js";
16
+ import { render } from "./render.js";
17
+ function asString(value) {
18
+ return typeof value === "string" ? value : undefined;
19
+ }
20
+ /** Read the interim parent link: the `started` event's `x_parent_arc_id` if
21
+ * present, else the first event that carries one. Non-string values are ignored. */
22
+ function parentIdOf(events) {
23
+ const started = events.find((e) => e.phase === "started");
24
+ const fromStarted = started ? asString(started["x_parent_arc_id"]) : undefined;
25
+ if (fromStarted !== undefined)
26
+ return fromStarted;
27
+ for (const e of events) {
28
+ const v = asString(e["x_parent_arc_id"]);
29
+ if (v !== undefined)
30
+ return v;
31
+ }
32
+ return undefined;
33
+ }
34
+ function toEntries(input) {
35
+ return input instanceof Map ? [...input.entries()] : Object.entries(input);
36
+ }
37
+ /**
38
+ * Group per-arc event streams into a forest by the `x_parent_arc_id` convention.
39
+ * Empty streams are skipped. Returns roots, orphans, and any arc_ids whose link
40
+ * was cut to break a cycle.
41
+ */
42
+ export function reduceArcForest(eventsByArc) {
43
+ const nodes = new Map();
44
+ const rawParent = new Map();
45
+ for (const [arcId, events] of toEntries(eventsByArc)) {
46
+ const state = reduceArc(events);
47
+ if (state === null)
48
+ continue;
49
+ nodes.set(arcId, { state, children: [], depth: 0 });
50
+ const pid = parentIdOf(events);
51
+ if (pid !== undefined)
52
+ rawParent.set(arcId, pid);
53
+ }
54
+ // Effective parent links: only those whose parent is present in the input.
55
+ const parentOf = new Map();
56
+ for (const [arcId, pid] of rawParent) {
57
+ if (nodes.has(pid))
58
+ parentOf.set(arcId, pid);
59
+ }
60
+ // Break cycles: the parent graph is functional (≤1 parent per node), so a
61
+ // cycle is a simple loop. Walk up from each node; on revisiting a node, cut
62
+ // that node's parent link (making it a root) and record it.
63
+ const cycleBroken = [];
64
+ for (const start of nodes.keys()) {
65
+ const seen = new Set();
66
+ let cur = start;
67
+ while (cur !== undefined) {
68
+ if (seen.has(cur)) {
69
+ if (parentOf.has(cur)) {
70
+ parentOf.delete(cur);
71
+ cycleBroken.push(cur);
72
+ }
73
+ break;
74
+ }
75
+ seen.add(cur);
76
+ cur = parentOf.get(cur);
77
+ }
78
+ }
79
+ const roots = [];
80
+ const orphans = [];
81
+ for (const [arcId, node] of nodes) {
82
+ const parent = parentOf.get(arcId);
83
+ if (parent !== undefined) {
84
+ const parentNode = nodes.get(parent);
85
+ if (parentNode)
86
+ parentNode.children.push(node);
87
+ continue;
88
+ }
89
+ roots.push(node);
90
+ const pid = rawParent.get(arcId);
91
+ if (pid !== undefined && !nodes.has(pid))
92
+ orphans.push(node);
93
+ }
94
+ const byStart = (a, b) => a.state.startedAt < b.state.startedAt
95
+ ? -1
96
+ : a.state.startedAt > b.state.startedAt
97
+ ? 1
98
+ : a.state.arc_id < b.state.arc_id
99
+ ? -1
100
+ : a.state.arc_id > b.state.arc_id
101
+ ? 1
102
+ : 0;
103
+ const assignDepth = (node, depth) => {
104
+ node.depth = depth;
105
+ node.children.sort(byStart);
106
+ for (const child of node.children)
107
+ assignDepth(child, depth + 1);
108
+ };
109
+ roots.sort(byStart);
110
+ for (const root of roots)
111
+ assignDepth(root, 0);
112
+ return { roots, orphans, cycleBroken };
113
+ }
114
+ function defaultLine(state) {
115
+ const event = {
116
+ arc_id: state.arc_id,
117
+ phase: state.phase,
118
+ title: state.title,
119
+ sent_at: state.lastEventAt,
120
+ };
121
+ if (state.step !== undefined)
122
+ event.step = state.step;
123
+ if (state.total !== undefined)
124
+ event.total = state.total;
125
+ if (state.eta_minutes !== undefined)
126
+ event.eta_minutes = state.eta_minutes;
127
+ return `${render(event)} (${state.status})`;
128
+ }
129
+ /** Render a forest to an indented, newline-joined tree of arc states. */
130
+ export function renderArcForest(forest, options = {}) {
131
+ const indent = options.indent ?? " ";
132
+ const line = options.line ?? defaultLine;
133
+ const out = [];
134
+ const walk = (node) => {
135
+ out.push(indent.repeat(node.depth) + line(node.state));
136
+ for (const child of node.children)
137
+ walk(child);
138
+ };
139
+ for (const root of forest.roots)
140
+ walk(root);
141
+ return out.join("\n");
142
+ }
143
+ //# sourceMappingURL=forest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forest.js","sourceRoot":"","sources":["../src/forest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,SAAS,EAAiB,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAmBrC,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACvD,CAAC;AAED;qFACqF;AACrF,SAAS,UAAU,CAAC,MAAwB;IAC1C,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC;IAC1D,MAAM,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/E,IAAI,WAAW,KAAK,SAAS;QAAE,OAAO,WAAW,CAAC;IAClD,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC;QACzC,IAAI,CAAC,KAAK,SAAS;YAAE,OAAO,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,SAAS,CAChB,KAAuE;IAEvE,OAAO,KAAK,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC7E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAC7B,WAA6E;IAE7E,MAAM,KAAK,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC7C,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;IAE5C,KAAK,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,SAAS,CAAC,WAAW,CAAC,EAAE,CAAC;QACrD,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;QAChC,IAAI,KAAK,KAAK,IAAI;YAAE,SAAS;QAC7B,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;QACpD,MAAM,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,GAAG,KAAK,SAAS;YAAE,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACnD,CAAC;IAED,2EAA2E;IAC3E,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC3C,KAAK,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,SAAS,EAAE,CAAC;QACrC,IAAI,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC/C,CAAC;IAED,0EAA0E;IAC1E,4EAA4E;IAC5E,4DAA4D;IAC5D,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QACjC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,IAAI,GAAG,GAAuB,KAAK,CAAC;QACpC,OAAO,GAAG,KAAK,SAAS,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBAClB,IAAI,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;oBACtB,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;oBACrB,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACxB,CAAC;gBACD,MAAM;YACR,CAAC;YACD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACd,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAkB,EAAE,CAAC;IAChC,MAAM,OAAO,GAAkB,EAAE,CAAC;IAElC,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC;QAClC,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,UAAU,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACrC,IAAI,UAAU;gBAAE,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/C,SAAS;QACX,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjB,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACjC,IAAI,GAAG,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,OAAO,GAAG,CAAC,CAAc,EAAE,CAAc,EAAU,EAAE,CACzD,CAAC,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,SAAS;QACnC,CAAC,CAAC,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,SAAS;YACrC,CAAC,CAAC,CAAC;YACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM;gBAC/B,CAAC,CAAC,CAAC,CAAC;gBACJ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM;oBAC/B,CAAC,CAAC,CAAC;oBACH,CAAC,CAAC,CAAC,CAAC;IAEd,MAAM,WAAW,GAAG,CAAC,IAAiB,EAAE,KAAa,EAAQ,EAAE;QAC7D,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC5B,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ;YAAE,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;IACnE,CAAC,CAAC;IACF,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACpB,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAE/C,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;AACzC,CAAC;AASD,SAAS,WAAW,CAAC,KAAe;IAClC,MAAM,KAAK,GAAmB;QAC5B,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,OAAO,EAAE,KAAK,CAAC,WAAW;KAC3B,CAAC;IACF,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS;QAAE,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;IACtD,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;QAAE,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IACzD,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS;QAAE,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;IAC3E,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,MAAM,GAAG,CAAC;AAC/C,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,eAAe,CAAC,MAAiB,EAAE,UAA+B,EAAE;IAClF,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC;IACtC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,WAAW,CAAC;IACzC,MAAM,GAAG,GAAa,EAAE,CAAC;IAEzB,MAAM,IAAI,GAAG,CAAC,IAAiB,EAAQ,EAAE;QACvC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QACvD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ;YAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IACjD,CAAC,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK;QAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IAE5C,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACxB,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Agent Arc Status Protocol: reference implementation (v0.2).
3
+ *
4
+ * Spec: https://github.com/joethefisher/agent-arc-status
5
+ *
6
+ * This package provides:
7
+ * - TypeScript types matching the wire schema
8
+ * - Structural validator (single event)
9
+ * - Sequence validator (phase-ordering rules per arc)
10
+ * - JSON / JSON Lines parsers
11
+ * - A default human-line renderer
12
+ *
13
+ * It is intentionally tiny and has zero runtime dependencies. If you need
14
+ * canonical-schema validation against `spec/schema.json`, use any standard
15
+ * JSON Schema validator (ajv, etc.). The schema is the source of truth and
16
+ * this validator mirrors it.
17
+ */
18
+ export { ARC_STATUS_PHASES, type ArcStatusEvent, type ArcStatusPhase, type EmitFn, } from "./types.js";
19
+ export { validate, validateSequence, RFC3339_PATTERN, type ValidationResult, type ValidationIssue, type SequenceIssue, type SequenceOptions, } from "./validate.js";
20
+ export { parse, parseJsonl, type JsonlParseResult, } from "./parse.js";
21
+ export { render, type RenderOptions, } from "./render.js";
22
+ export { CadenceController, SilenceWatchdog, type CadenceConfig, type ArcSeed, type StalledArc, } from "./cadence.js";
23
+ export { reduceArc, type ArcState, type ArcMilestone, } from "./state.js";
24
+ export { reduceArcForest, renderArcForest, type ArcForest, type ArcTreeNode, type RenderForestOptions, } from "./forest.js";
25
+ /** The Protocol version this package implements. */
26
+ export declare const PROTOCOL_VERSION = "0.2.0";
27
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EACL,iBAAiB,EACjB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,MAAM,GACZ,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,QAAQ,EACR,gBAAgB,EAChB,eAAe,EACf,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,eAAe,GACrB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,KAAK,EACL,UAAU,EACV,KAAK,gBAAgB,GACtB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,MAAM,EACN,KAAK,aAAa,GACnB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,KAAK,aAAa,EAClB,KAAK,OAAO,EACZ,KAAK,UAAU,GAChB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,SAAS,EACT,KAAK,QAAQ,EACb,KAAK,YAAY,GAClB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,eAAe,EACf,eAAe,EACf,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,mBAAmB,GACzB,MAAM,aAAa,CAAC;AAErB,oDAAoD;AACpD,eAAO,MAAM,gBAAgB,UAAU,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Agent Arc Status Protocol: reference implementation (v0.2).
3
+ *
4
+ * Spec: https://github.com/joethefisher/agent-arc-status
5
+ *
6
+ * This package provides:
7
+ * - TypeScript types matching the wire schema
8
+ * - Structural validator (single event)
9
+ * - Sequence validator (phase-ordering rules per arc)
10
+ * - JSON / JSON Lines parsers
11
+ * - A default human-line renderer
12
+ *
13
+ * It is intentionally tiny and has zero runtime dependencies. If you need
14
+ * canonical-schema validation against `spec/schema.json`, use any standard
15
+ * JSON Schema validator (ajv, etc.). The schema is the source of truth and
16
+ * this validator mirrors it.
17
+ */
18
+ export { ARC_STATUS_PHASES, } from "./types.js";
19
+ export { validate, validateSequence, RFC3339_PATTERN, } from "./validate.js";
20
+ export { parse, parseJsonl, } from "./parse.js";
21
+ export { render, } from "./render.js";
22
+ export { CadenceController, SilenceWatchdog, } from "./cadence.js";
23
+ export { reduceArc, } from "./state.js";
24
+ export { reduceArcForest, renderArcForest, } from "./forest.js";
25
+ /** The Protocol version this package implements. */
26
+ export const PROTOCOL_VERSION = "0.2.0";
27
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EACL,iBAAiB,GAIlB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,QAAQ,EACR,gBAAgB,EAChB,eAAe,GAKhB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,KAAK,EACL,UAAU,GAEX,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,MAAM,GAEP,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,iBAAiB,EACjB,eAAe,GAIhB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,SAAS,GAGV,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,eAAe,EACf,eAAe,GAIhB,MAAM,aAAa,CAAC;AAErB,oDAAoD;AACpD,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC"}