aiden-runtime 4.8.0 → 4.9.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.
Files changed (99) hide show
  1. package/README.md +88 -1
  2. package/dist/cli/v4/aidenCLI.js +35 -4
  3. package/dist/cli/v4/chatSession.js +43 -16
  4. package/dist/cli/v4/commands/daemon.js +47 -2
  5. package/dist/cli/v4/commands/daemonDoctor.js +212 -0
  6. package/dist/cli/v4/commands/daemonStatus.js +1 -1
  7. package/dist/cli/v4/commands/help.js +2 -0
  8. package/dist/cli/v4/commands/hooks.js +428 -0
  9. package/dist/cli/v4/commands/index.js +5 -1
  10. package/dist/cli/v4/commands/mcp.js +89 -1
  11. package/dist/cli/v4/commands/mcpClientInstall.js +359 -0
  12. package/dist/cli/v4/commands/memory.js +702 -0
  13. package/dist/cli/v4/commands/recovery.js +1 -1
  14. package/dist/cli/v4/commands/skin.js +7 -0
  15. package/dist/cli/v4/commands/theme.js +217 -0
  16. package/dist/cli/v4/commands/trigger.js +1 -1
  17. package/dist/cli/v4/commands/update.js +14 -2
  18. package/dist/cli/v4/design/tokens.js +52 -4
  19. package/dist/cli/v4/display.js +102 -46
  20. package/dist/cli/v4/pasteIntercept.js +214 -70
  21. package/dist/cli/v4/replyRenderer.js +145 -5
  22. package/dist/cli/v4/skinEngine.js +67 -0
  23. package/dist/core/v4/aidenAgent.js +45 -2
  24. package/dist/core/v4/daemon/api/runs.js +131 -0
  25. package/dist/core/v4/daemon/bootstrap.js +368 -13
  26. package/dist/core/v4/daemon/db/migrations.js +169 -0
  27. package/dist/core/v4/daemon/idempotency/runIdempotencyStore.js +128 -0
  28. package/dist/core/v4/daemon/incarnationStore.js +47 -0
  29. package/dist/core/v4/daemon/runs/attemptStore.js +67 -0
  30. package/dist/core/v4/daemon/runs/reclaim.js +88 -0
  31. package/dist/core/v4/daemon/runs/retryPolicy.js +73 -0
  32. package/dist/core/v4/daemon/runs/runWithRetry.js +80 -0
  33. package/dist/core/v4/daemon/runs/stuckAttemptWatchdog.js +72 -0
  34. package/dist/core/v4/daemon/spans/spanHelpers.js +272 -0
  35. package/dist/core/v4/daemon/spans/spanStore.js +113 -0
  36. package/dist/core/v4/daemon/triggerBus.js +50 -19
  37. package/dist/core/v4/hooks/auditQuery.js +67 -0
  38. package/dist/core/v4/hooks/dispatcher.js +286 -0
  39. package/dist/core/v4/hooks/index.js +46 -0
  40. package/dist/core/v4/hooks/lifecycle.js +27 -0
  41. package/dist/core/v4/hooks/manifest.js +142 -0
  42. package/dist/core/v4/hooks/registry.js +149 -0
  43. package/dist/core/v4/hooks/runtime/subprocessRunner.js +188 -0
  44. package/dist/core/v4/hooks/toolHookGate.js +76 -0
  45. package/dist/core/v4/hooks/trust.js +14 -0
  46. package/dist/core/v4/identity/contextManager.js +83 -0
  47. package/dist/core/v4/identity/daemonId.js +85 -0
  48. package/dist/core/v4/identity/enforcement.js +103 -0
  49. package/dist/core/v4/identity/executionContext.js +153 -0
  50. package/dist/core/v4/identity/hookExecution.js +62 -0
  51. package/dist/core/v4/identity/httpContext.js +68 -0
  52. package/dist/core/v4/identity/ids.js +185 -0
  53. package/dist/core/v4/identity/index.js +60 -0
  54. package/dist/core/v4/identity/subprocessContext.js +98 -0
  55. package/dist/core/v4/identity/traceparent.js +114 -0
  56. package/dist/core/v4/logger/index.js +3 -1
  57. package/dist/core/v4/logger/logger.js +28 -1
  58. package/dist/core/v4/logger/redact.js +149 -0
  59. package/dist/core/v4/logger/sinks/fileSink.js +13 -0
  60. package/dist/core/v4/logger/sinks/stdSink.js +19 -1
  61. package/dist/core/v4/mcp/install/backup.js +78 -0
  62. package/dist/core/v4/mcp/install/clientPaths.js +90 -0
  63. package/dist/core/v4/mcp/install/clients.js +203 -0
  64. package/dist/core/v4/mcp/install/healthCheck.js +83 -0
  65. package/dist/core/v4/mcp/install/jsoncMerge.js +174 -0
  66. package/dist/core/v4/mcp/install/profiles.js +109 -0
  67. package/dist/core/v4/mcp/install/wslDetect.js +62 -0
  68. package/dist/core/v4/memory/namespaceRegistry.js +117 -0
  69. package/dist/core/v4/memory/projectRoot.js +76 -0
  70. package/dist/core/v4/memory/reviewer/index.js +162 -0
  71. package/dist/core/v4/memory/reviewer/pendingStore.js +136 -0
  72. package/dist/core/v4/memory/reviewer/prompt.js +105 -0
  73. package/dist/core/v4/memory/reviewer/skipRules.js +92 -0
  74. package/dist/core/v4/memoryManager.js +57 -10
  75. package/dist/core/v4/paths.js +2 -0
  76. package/dist/core/v4/promptBuilder.js +6 -0
  77. package/dist/core/v4/subagent/spawnSubAgent.js +20 -7
  78. package/dist/core/v4/theme/bundledThemes.js +106 -0
  79. package/dist/core/v4/theme/themeLoader.js +160 -0
  80. package/dist/core/v4/theme/themeRegistry.js +97 -0
  81. package/dist/core/v4/theme/themeWatcher.js +95 -0
  82. package/dist/core/v4/toolRegistry.js +71 -8
  83. package/dist/core/v4/update/executeInstall.js +10 -6
  84. package/dist/core/v4/update/installMethodDetect.js +7 -0
  85. package/dist/core/version.js +67 -2
  86. package/dist/moat/approvalEngine.js +4 -0
  87. package/dist/moat/memoryGuard.js +8 -1
  88. package/dist/providers/v4/anthropicAdapter.js +10 -4
  89. package/dist/tools/v4/backends/local.js +19 -2
  90. package/dist/tools/v4/sessions/recallSession.js +6 -1
  91. package/package.json +3 -3
  92. package/plugins/aiden-plugin-chatgpt-plus/index.js +10 -1
  93. package/themes/default.yaml +52 -0
  94. package/themes/dracula.yaml +32 -0
  95. package/themes/light.yaml +32 -0
  96. package/themes/monochrome.yaml +31 -0
  97. package/themes/tokyo-night.yaml +32 -0
  98. package/dist/core/pluginSystem.js +0 -121
  99. package/dist/tools/v4/ui/_uiSmokeTool.js +0 -60
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.serializeContext = serializeContext;
4
+ exports.deserializeContext = deserializeContext;
5
+ exports.childSpan = childSpan;
6
+ /**
7
+ * Copyright (c) 2026 Shiva Deore (Taracod).
8
+ * Licensed under AGPL-3.0. See LICENSE for details.
9
+ *
10
+ * Aiden — local-first agent.
11
+ */
12
+ /**
13
+ * core/v4/identity/executionContext.ts — v4.9.0 Slice 4.
14
+ *
15
+ * The `ExecutionContext` is the per-unit-of-work envelope every layer
16
+ * of the runtime can reach via `currentContext()`. It carries the
17
+ * stable correlation IDs (daemon, incarnation, run, trace, span) plus
18
+ * the situational metadata (source, attempt, deadline, optional
19
+ * external request id, optional baggage).
20
+ *
21
+ * Slice 4 is **additive only** — nothing in the existing code paths
22
+ * required a context yet; this file just defines the shape and the
23
+ * (de)serialisation primitives so later slices can plumb it through
24
+ * tool dispatch, hooks, trigger bus claims, and the agent loop.
25
+ *
26
+ * Serialisation is JSON. We could compact this further (e.g. msgpack
27
+ * over a base64url envelope) but JSON keeps it grep-friendly in env
28
+ * vars and log lines — and the contexts we'll be ferrying are <300 bytes.
29
+ */
30
+ const ids_1 = require("./ids");
31
+ const VALID_SOURCES = new Set([
32
+ 'cli', 'api', 'webhook', 'cron', 'email', 'folder', 'subagent', 'unknown',
33
+ ]);
34
+ /**
35
+ * Serialise a context to a single string suitable for stuffing into an
36
+ * env var, a log field, or a tracestate-style header. Round-trippable
37
+ * via `deserializeContext`.
38
+ *
39
+ * We don't ship undefined fields — keeps the payload tight when most
40
+ * of the optional surface is empty (the common case).
41
+ */
42
+ function serializeContext(ctx) {
43
+ const payload = {
44
+ d: ctx.daemonId,
45
+ i: ctx.incarnationId,
46
+ r: ctx.runId,
47
+ t: ctx.traceId,
48
+ s: ctx.spanId,
49
+ sr: ctx.source,
50
+ a: ctx.attempt,
51
+ };
52
+ if (ctx.parentSpanId)
53
+ payload.ps = ctx.parentSpanId;
54
+ if (ctx.requestId)
55
+ payload.rq = ctx.requestId;
56
+ if (ctx.externalRequestId)
57
+ payload.er = ctx.externalRequestId;
58
+ if (ctx.triggerId)
59
+ payload.tg = ctx.triggerId;
60
+ if (ctx.sessionId)
61
+ payload.se = ctx.sessionId;
62
+ if (ctx.deadlineAt)
63
+ payload.dl = ctx.deadlineAt;
64
+ if (ctx.baggage && Object.keys(ctx.baggage).length > 0)
65
+ payload.b = ctx.baggage;
66
+ return JSON.stringify(payload);
67
+ }
68
+ /**
69
+ * Parse a serialised context. Throws on malformed input — this is a
70
+ * trust-boundary deserialise (env var that's supposed to exist), so
71
+ * "fail loud" beats silent context loss.
72
+ */
73
+ function deserializeContext(s) {
74
+ if (typeof s !== 'string' || s.length === 0) {
75
+ throw new Error('deserializeContext: input must be a non-empty string');
76
+ }
77
+ let raw;
78
+ try {
79
+ raw = JSON.parse(s);
80
+ }
81
+ catch (e) {
82
+ throw new Error(`deserializeContext: invalid JSON (${e instanceof Error ? e.message : String(e)})`);
83
+ }
84
+ const need = (k) => {
85
+ const v = raw[k];
86
+ if (typeof v !== 'string' || v.length === 0) {
87
+ throw new Error(`deserializeContext: missing or non-string field '${k}'`);
88
+ }
89
+ return v;
90
+ };
91
+ // Validate required string fields FIRST so a malformed payload gets
92
+ // a useful "missing field 'X'" message rather than a downstream
93
+ // "invalid source 'undefined'" surprise.
94
+ const daemonId = need('d');
95
+ const incarnationId = need('i');
96
+ const runId = need('r');
97
+ const traceId = need('t');
98
+ const spanId = need('s');
99
+ const source = need('sr');
100
+ if (!VALID_SOURCES.has(source)) {
101
+ throw new Error(`deserializeContext: invalid source '${source}'`);
102
+ }
103
+ const attempt = Number(raw.a);
104
+ if (!Number.isFinite(attempt) || attempt < 0) {
105
+ throw new Error(`deserializeContext: invalid attempt '${String(raw.a)}'`);
106
+ }
107
+ const ctx = {
108
+ daemonId,
109
+ incarnationId,
110
+ runId,
111
+ traceId,
112
+ spanId,
113
+ source: source,
114
+ attempt,
115
+ };
116
+ if (typeof raw.ps === 'string')
117
+ ctx.parentSpanId = raw.ps;
118
+ if (typeof raw.rq === 'string')
119
+ ctx.requestId = raw.rq;
120
+ if (typeof raw.er === 'string')
121
+ ctx.externalRequestId = raw.er;
122
+ if (typeof raw.tg === 'string')
123
+ ctx.triggerId = raw.tg;
124
+ if (typeof raw.se === 'string')
125
+ ctx.sessionId = raw.se;
126
+ if (typeof raw.dl === 'string')
127
+ ctx.deadlineAt = raw.dl;
128
+ if (raw.b && typeof raw.b === 'object' && !Array.isArray(raw.b)) {
129
+ // Defensive cast: only string-valued entries survive.
130
+ const bag = {};
131
+ for (const [k, v] of Object.entries(raw.b)) {
132
+ if (typeof v === 'string')
133
+ bag[k] = v;
134
+ }
135
+ if (Object.keys(bag).length > 0)
136
+ ctx.baggage = bag;
137
+ }
138
+ return ctx;
139
+ }
140
+ /**
141
+ * Fork a child span: returns a new context with the same trace/run but
142
+ * a fresh `spanId` and `parentSpanId` set to the parent's `spanId`.
143
+ *
144
+ * Pass `newSpanIdOverride` only in tests where determinism matters; in
145
+ * normal operation the freshly-minted span id is what you want.
146
+ */
147
+ function childSpan(ctx, newSpanIdOverride) {
148
+ return {
149
+ ...ctx,
150
+ spanId: newSpanIdOverride ?? (0, ids_1.newSpanId)(),
151
+ parentSpanId: ctx.spanId,
152
+ };
153
+ }
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2026 Shiva Deore (Taracod).
4
+ * Licensed under AGPL-3.0. See LICENSE for details.
5
+ *
6
+ * Aiden — local-first agent.
7
+ */
8
+ /**
9
+ * core/v4/identity/hookExecution.ts — v4.9.0 Slice 7.
10
+ *
11
+ * Ergonomic boundary helper for hook execution. Wraps a hook callback
12
+ * with:
13
+ *
14
+ * - Timeout enforcement (default 5s; configurable per call)
15
+ * - Structured outcome shape (`'ok' | 'timeout' | 'error'`) — caller
16
+ * decides whether a hook timeout/error should block the operation
17
+ * or fail-open
18
+ * - A span via Slice 6's `runHookWithSpan` so every firing is durable
19
+ *
20
+ * Slice 7 lands the helper. Slice 9 wires it into the actual lifecycle
21
+ * dispatcher.
22
+ */
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.HookTimeoutError = void 0;
25
+ exports.executeHookWithBoundary = executeHookWithBoundary;
26
+ /**
27
+ * Execute `fn` inside a hook boundary. Returns a structured outcome —
28
+ * the caller decides whether to block or fail-open on timeout/error.
29
+ * Never throws.
30
+ *
31
+ * Uses Slice 6's `runHookWithSpan` for the durable span side; here we
32
+ * adapt the spanned result into the explicit `{outcome}` envelope.
33
+ */
34
+ async function executeHookWithBoundary(_ctx, opts, fn) {
35
+ const timeoutMs = opts.timeoutMs ?? 5000;
36
+ let timer = null;
37
+ try {
38
+ const timeoutPromise = new Promise((_resolve, reject) => {
39
+ timer = setTimeout(() => reject(new HookTimeoutError(opts.hookName, timeoutMs)), timeoutMs);
40
+ });
41
+ const value = await Promise.race([fn(), timeoutPromise]);
42
+ if (timer)
43
+ clearTimeout(timer);
44
+ return { outcome: 'ok', value: value };
45
+ }
46
+ catch (err) {
47
+ if (timer)
48
+ clearTimeout(timer);
49
+ if (err instanceof HookTimeoutError) {
50
+ return { outcome: 'timeout', error: err };
51
+ }
52
+ const wrapped = err instanceof Error ? err : new Error(String(err));
53
+ return { outcome: 'error', error: wrapped };
54
+ }
55
+ }
56
+ class HookTimeoutError extends Error {
57
+ constructor(hookName, ms) {
58
+ super(`hook '${hookName}' timed out after ${ms}ms`);
59
+ this.name = 'HookTimeout';
60
+ }
61
+ }
62
+ exports.HookTimeoutError = HookTimeoutError;
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2026 Shiva Deore (Taracod).
4
+ * Licensed under AGPL-3.0. See LICENSE for details.
5
+ *
6
+ * Aiden — local-first agent.
7
+ */
8
+ /**
9
+ * core/v4/identity/httpContext.ts — v4.9.0 Slice 7.
10
+ *
11
+ * Inject outbound HTTP headers carrying ExecutionContext correlation
12
+ * data so downstream services + log aggregators can stitch the call
13
+ * back to its originating run/trace/span. Emits both:
14
+ *
15
+ * - W3C-standard `traceparent` (32-hex/16-hex/sampled)
16
+ * - `X-Aiden-*` companion headers for fine-grained run/incarnation
17
+ * correlation that doesn't fit in `traceparent`
18
+ *
19
+ * `injectContextHeaders` is pure — it does not read ambient context
20
+ * itself. Callers pass an explicit ctx (either current or one they
21
+ * forked). Outside a `runWithContext` frame, callers can pass
22
+ * `currentContext()` and receive the same headers, or short-circuit
23
+ * to skip header injection entirely.
24
+ */
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.injectContextHeaders = injectContextHeaders;
27
+ exports.maybeInjectContextHeaders = maybeInjectContextHeaders;
28
+ const traceparent_1 = require("./traceparent");
29
+ const ids_1 = require("./ids");
30
+ const enforcement_1 = require("./enforcement");
31
+ /**
32
+ * Headers Aiden adds to outbound requests when an ExecutionContext
33
+ * is active. Caller-supplied headers in the merge target win on key
34
+ * collision so a tool that needs to override (e.g. `User-Agent`) can.
35
+ */
36
+ function injectContextHeaders(ctx, headers = {}) {
37
+ const traceparent = (() => {
38
+ try {
39
+ return (0, traceparent_1.emitTraceparent)((0, traceparent_1.stripPrefix)(ctx.traceId, 'trc_'), (0, traceparent_1.stripPrefix)(ctx.spanId, 'spn_'), true);
40
+ }
41
+ catch {
42
+ return undefined;
43
+ }
44
+ })();
45
+ const out = {};
46
+ if (traceparent)
47
+ out['traceparent'] = traceparent;
48
+ out['X-Request-Id'] = ctx.requestId ?? (0, ids_1.newRequestId)();
49
+ out['X-Aiden-Run-Id'] = ctx.runId;
50
+ out['X-Aiden-Trace-Id'] = ctx.traceId;
51
+ out['X-Aiden-Span-Id'] = ctx.spanId;
52
+ // Caller-supplied headers win on collision.
53
+ return { ...out, ...headers };
54
+ }
55
+ /**
56
+ * Convenience: pass-through helper when the caller may or may not
57
+ * have a context. Returns the original headers unchanged when ctx
58
+ * is undefined (no trace propagation outside a context frame).
59
+ */
60
+ function maybeInjectContextHeaders(ctx, headers = {}) {
61
+ if (ctx)
62
+ return injectContextHeaders(ctx, headers);
63
+ // v4.9.0 Slice 8 — report missing-context on the outbound HTTP path.
64
+ // 'silent' / 'warn' degrade to pass-through (no trace propagation
65
+ // outside a context frame); 'strict' throws via the enforcement.
66
+ (0, enforcement_1.reportMissingContext)('http_outbound', 'maybeInjectContextHeaders');
67
+ return headers;
68
+ }
@@ -0,0 +1,185 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2026 Shiva Deore (Taracod).
4
+ * Licensed under AGPL-3.0. See LICENSE for details.
5
+ *
6
+ * Aiden — local-first agent.
7
+ */
8
+ /**
9
+ * core/v4/identity/ids.ts — v4.9.0 Slice 4.
10
+ *
11
+ * UUIDv7 generation per RFC 9562 §5.7 + typed-prefix wrappers.
12
+ *
13
+ * UUIDv7 lays a millisecond timestamp in the top 48 bits, so lexicographic
14
+ * sort == time sort. That property is the reason we picked v7 over v4:
15
+ * `runs.id`-style auto-increment is wedded to one SQLite file; UUIDv7
16
+ * gives us a globally-unique, time-orderable id we can correlate across
17
+ * the daemon DB, the structured log, future remote sinks, and crash
18
+ * reports without needing a central counter.
19
+ *
20
+ * The `uuid` package on disk is v9, which doesn't ship UUIDv7 (added in
21
+ * uuid@10). We hand-roll the 16-byte layout from RFC 9562 §5.7:
22
+ *
23
+ * 0 1 2 3
24
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
25
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
26
+ * | unix_ts_ms |
27
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
28
+ * | unix_ts_ms | ver | rand_a |
29
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
30
+ * |var| rand_b |
31
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
32
+ * | rand_b |
33
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34
+ *
35
+ * - 48 bits unix_ts_ms (big-endian)
36
+ * - 4 bits version = 0b0111 (UUIDv7)
37
+ * - 12 bits rand_a (random)
38
+ * - 2 bits variant = 0b10 (RFC 4122)
39
+ * - 62 bits rand_b (random)
40
+ *
41
+ * Output canonical hex with dashes (e.g. `01919c34-8e21-7c8c-bcd7-...`).
42
+ * That's then base32-cased for prefixed IDs — keeps the output URL-safe
43
+ * and short while preserving the millisecond ordering at the prefix.
44
+ */
45
+ Object.defineProperty(exports, "__esModule", { value: true });
46
+ exports.newHookExecId = exports.newHookSubId = exports.newHookId = exports.newMemoryId = exports.newToolCallId = exports.newRequestId = exports.newSpanId = exports.newTraceId = exports.newAttemptId = exports.newRunId = exports.newTriggerId = exports.newIncarnationId = exports.newDaemonId = exports.ID_PREFIXES = void 0;
47
+ exports.uuidv7Bytes = uuidv7Bytes;
48
+ exports.newUuidV7 = newUuidV7;
49
+ exports.newUuidV7Compact = newUuidV7Compact;
50
+ exports.parseId = parseId;
51
+ exports.isIdWithPrefix = isIdWithPrefix;
52
+ const node_crypto_1 = require("node:crypto");
53
+ /**
54
+ * Allowed prefixes. Adding a new ID kind means adding the prefix here
55
+ * and the helper. `parseId` validates against this set so a stray
56
+ * `xyz_...` string can't masquerade as one of ours.
57
+ */
58
+ exports.ID_PREFIXES = [
59
+ 'dmn', // daemon identity (persists across incarnations)
60
+ 'inc', // single daemon process incarnation
61
+ 'trg', // trigger event
62
+ 'run', // agent run (one turn or daemon-fired job)
63
+ 'att', // v4.9.0 Slice 5 — execution attempt within a run
64
+ 'trc', // trace (top-level correlation across runs/spans)
65
+ 'spn', // span (sub-unit of a trace)
66
+ 'req', // external request id (e.g. webhook delivery)
67
+ 'tool', // tool invocation
68
+ 'mem', // memory write
69
+ 'hook', // hook firing (legacy generic id)
70
+ 'hsub', // v4.9.0 Slice 12a — hook subscription
71
+ 'hexec', // v4.9.0 Slice 12a — hook execution (subprocess invocation)
72
+ ];
73
+ const PREFIX_SET = new Set(exports.ID_PREFIXES);
74
+ /**
75
+ * Generate one UUIDv7 byte buffer.
76
+ * Exported for tests; consumers should use `newUuidV7()` or one of the
77
+ * typed helpers below.
78
+ */
79
+ function uuidv7Bytes(now = Date.now()) {
80
+ if (!Number.isFinite(now) || now < 0) {
81
+ throw new Error(`uuidv7Bytes: invalid timestamp ${now}`);
82
+ }
83
+ const buf = (0, node_crypto_1.randomBytes)(16);
84
+ // 48-bit timestamp, big-endian, into bytes 0-5.
85
+ // JS bitwise ops are 32-bit, so split into high/low halves first.
86
+ const tsHi = Math.floor(now / 4294967296); // top 16 of the 48-bit ts
87
+ const tsLo = now >>> 0; // bottom 32
88
+ buf[0] = (tsHi >>> 8) & 0xff;
89
+ buf[1] = tsHi & 0xff;
90
+ buf[2] = (tsLo >>> 24) & 0xff;
91
+ buf[3] = (tsLo >>> 16) & 0xff;
92
+ buf[4] = (tsLo >>> 8) & 0xff;
93
+ buf[5] = tsLo & 0xff;
94
+ // Version 0b0111 in the top nibble of byte 6.
95
+ buf[6] = (buf[6] & 0x0f) | 0x70;
96
+ // Variant 0b10 in the top 2 bits of byte 8.
97
+ buf[8] = (buf[8] & 0x3f) | 0x80;
98
+ return buf;
99
+ }
100
+ /** Format 16 bytes as canonical UUID string with dashes. */
101
+ function bytesToUuidString(buf) {
102
+ const hex = Buffer.from(buf).toString('hex');
103
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
104
+ }
105
+ /** Strip dashes; canonical UUID → 32-char lowercase hex. */
106
+ function bytesToCompact(buf) {
107
+ return Buffer.from(buf).toString('hex');
108
+ }
109
+ /** One fresh UUIDv7 in canonical dashed form. */
110
+ function newUuidV7() {
111
+ return bytesToUuidString(uuidv7Bytes());
112
+ }
113
+ /** One fresh UUIDv7 in compact (dashless lowercase hex) form. */
114
+ function newUuidV7Compact() {
115
+ return bytesToCompact(uuidv7Bytes());
116
+ }
117
+ /**
118
+ * Build a typed ID: `<prefix>_<compactHex>`. The compact form keeps the
119
+ * output URL-safe and shorter than the canonical dashed form, while
120
+ * preserving the millisecond-ordered prefix.
121
+ */
122
+ function makeId(prefix) {
123
+ return `${prefix}_${newUuidV7Compact()}`;
124
+ }
125
+ const newDaemonId = () => makeId('dmn');
126
+ exports.newDaemonId = newDaemonId;
127
+ const newIncarnationId = () => makeId('inc');
128
+ exports.newIncarnationId = newIncarnationId;
129
+ const newTriggerId = () => makeId('trg');
130
+ exports.newTriggerId = newTriggerId;
131
+ const newRunId = () => makeId('run');
132
+ exports.newRunId = newRunId;
133
+ const newAttemptId = () => makeId('att');
134
+ exports.newAttemptId = newAttemptId;
135
+ const newTraceId = () => makeId('trc');
136
+ exports.newTraceId = newTraceId;
137
+ const newSpanId = () => makeId('spn');
138
+ exports.newSpanId = newSpanId;
139
+ const newRequestId = () => makeId('req');
140
+ exports.newRequestId = newRequestId;
141
+ const newToolCallId = () => makeId('tool');
142
+ exports.newToolCallId = newToolCallId;
143
+ const newMemoryId = () => makeId('mem');
144
+ exports.newMemoryId = newMemoryId;
145
+ const newHookId = () => makeId('hook');
146
+ exports.newHookId = newHookId;
147
+ const newHookSubId = () => makeId('hsub');
148
+ exports.newHookSubId = newHookSubId;
149
+ const newHookExecId = () => makeId('hexec');
150
+ exports.newHookExecId = newHookExecId;
151
+ /**
152
+ * Parse a prefixed ID. Returns `null` if the prefix is unknown or the
153
+ * UUID payload is malformed. Never throws — callers are expected to
154
+ * branch on `null` (think "trusted input boundary check, not parse-or-die").
155
+ *
156
+ * Accepts both compact (no dashes) and canonical (with dashes) UUID
157
+ * forms in the payload — the typed helpers emit compact, but
158
+ * deserialised IDs from external sources (logs, env vars, query strings)
159
+ * could carry either shape.
160
+ */
161
+ function parseId(s) {
162
+ if (typeof s !== 'string' || s.length === 0)
163
+ return null;
164
+ const idx = s.indexOf('_');
165
+ if (idx <= 0)
166
+ return null;
167
+ const prefix = s.slice(0, idx);
168
+ if (!PREFIX_SET.has(prefix))
169
+ return null;
170
+ let payload = s.slice(idx + 1);
171
+ // Strip dashes if the caller passed canonical form.
172
+ if (payload.includes('-'))
173
+ payload = payload.replace(/-/g, '');
174
+ if (!/^[0-9a-f]{32}$/i.test(payload))
175
+ return null;
176
+ return { prefix: prefix, uuid: payload.toLowerCase() };
177
+ }
178
+ /**
179
+ * Type guard — `true` when `s` is a well-formed typed ID with the
180
+ * expected prefix. Cheap; used at API boundaries.
181
+ */
182
+ function isIdWithPrefix(s, prefix) {
183
+ const parsed = parseId(s);
184
+ return parsed !== null && parsed.prefix === prefix;
185
+ }
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports._resetContextMissingCountersForTests = exports.getAllContextMissingCounters = exports.getContextMissingCounter = exports.ContextMissingError = exports.reportMissingContext = exports.getEnforcementMode = exports.HookTimeoutError = exports.executeHookWithBoundary = exports.readContextFromEnv = exports.spawnEnvWithContext = exports.maybeInjectContextHeaders = exports.injectContextHeaders = exports.validateExternalRequestId = exports.stripPrefix = exports.emitTraceparent = exports.parseTraceparent = exports.daemonIdFilePath = exports.loadOrCreateDaemonId = exports.requireContext = exports.currentContext = exports.runWithContext = exports.childSpan = exports.deserializeContext = exports.serializeContext = exports.isIdWithPrefix = exports.parseId = exports.newHookExecId = exports.newHookSubId = exports.newHookId = exports.newMemoryId = exports.newToolCallId = exports.newRequestId = exports.newSpanId = exports.newTraceId = exports.newAttemptId = exports.newRunId = exports.newTriggerId = exports.newIncarnationId = exports.newDaemonId = exports.newUuidV7Compact = exports.newUuidV7 = exports.uuidv7Bytes = exports.ID_PREFIXES = void 0;
4
+ /**
5
+ * core/v4/identity/index.ts — v4.9.0 Slice 4 barrel.
6
+ */
7
+ var ids_1 = require("./ids");
8
+ Object.defineProperty(exports, "ID_PREFIXES", { enumerable: true, get: function () { return ids_1.ID_PREFIXES; } });
9
+ Object.defineProperty(exports, "uuidv7Bytes", { enumerable: true, get: function () { return ids_1.uuidv7Bytes; } });
10
+ Object.defineProperty(exports, "newUuidV7", { enumerable: true, get: function () { return ids_1.newUuidV7; } });
11
+ Object.defineProperty(exports, "newUuidV7Compact", { enumerable: true, get: function () { return ids_1.newUuidV7Compact; } });
12
+ Object.defineProperty(exports, "newDaemonId", { enumerable: true, get: function () { return ids_1.newDaemonId; } });
13
+ Object.defineProperty(exports, "newIncarnationId", { enumerable: true, get: function () { return ids_1.newIncarnationId; } });
14
+ Object.defineProperty(exports, "newTriggerId", { enumerable: true, get: function () { return ids_1.newTriggerId; } });
15
+ Object.defineProperty(exports, "newRunId", { enumerable: true, get: function () { return ids_1.newRunId; } });
16
+ Object.defineProperty(exports, "newAttemptId", { enumerable: true, get: function () { return ids_1.newAttemptId; } });
17
+ Object.defineProperty(exports, "newTraceId", { enumerable: true, get: function () { return ids_1.newTraceId; } });
18
+ Object.defineProperty(exports, "newSpanId", { enumerable: true, get: function () { return ids_1.newSpanId; } });
19
+ Object.defineProperty(exports, "newRequestId", { enumerable: true, get: function () { return ids_1.newRequestId; } });
20
+ Object.defineProperty(exports, "newToolCallId", { enumerable: true, get: function () { return ids_1.newToolCallId; } });
21
+ Object.defineProperty(exports, "newMemoryId", { enumerable: true, get: function () { return ids_1.newMemoryId; } });
22
+ Object.defineProperty(exports, "newHookId", { enumerable: true, get: function () { return ids_1.newHookId; } });
23
+ Object.defineProperty(exports, "newHookSubId", { enumerable: true, get: function () { return ids_1.newHookSubId; } });
24
+ Object.defineProperty(exports, "newHookExecId", { enumerable: true, get: function () { return ids_1.newHookExecId; } });
25
+ Object.defineProperty(exports, "parseId", { enumerable: true, get: function () { return ids_1.parseId; } });
26
+ Object.defineProperty(exports, "isIdWithPrefix", { enumerable: true, get: function () { return ids_1.isIdWithPrefix; } });
27
+ var executionContext_1 = require("./executionContext");
28
+ Object.defineProperty(exports, "serializeContext", { enumerable: true, get: function () { return executionContext_1.serializeContext; } });
29
+ Object.defineProperty(exports, "deserializeContext", { enumerable: true, get: function () { return executionContext_1.deserializeContext; } });
30
+ Object.defineProperty(exports, "childSpan", { enumerable: true, get: function () { return executionContext_1.childSpan; } });
31
+ var contextManager_1 = require("./contextManager");
32
+ Object.defineProperty(exports, "runWithContext", { enumerable: true, get: function () { return contextManager_1.runWithContext; } });
33
+ Object.defineProperty(exports, "currentContext", { enumerable: true, get: function () { return contextManager_1.currentContext; } });
34
+ Object.defineProperty(exports, "requireContext", { enumerable: true, get: function () { return contextManager_1.requireContext; } });
35
+ var daemonId_1 = require("./daemonId");
36
+ Object.defineProperty(exports, "loadOrCreateDaemonId", { enumerable: true, get: function () { return daemonId_1.loadOrCreateDaemonId; } });
37
+ Object.defineProperty(exports, "daemonIdFilePath", { enumerable: true, get: function () { return daemonId_1.daemonIdFilePath; } });
38
+ // v4.9.0 Slice 7 — HTTP / subprocess / hook boundaries.
39
+ var traceparent_1 = require("./traceparent");
40
+ Object.defineProperty(exports, "parseTraceparent", { enumerable: true, get: function () { return traceparent_1.parseTraceparent; } });
41
+ Object.defineProperty(exports, "emitTraceparent", { enumerable: true, get: function () { return traceparent_1.emitTraceparent; } });
42
+ Object.defineProperty(exports, "stripPrefix", { enumerable: true, get: function () { return traceparent_1.stripPrefix; } });
43
+ Object.defineProperty(exports, "validateExternalRequestId", { enumerable: true, get: function () { return traceparent_1.validateExternalRequestId; } });
44
+ var httpContext_1 = require("./httpContext");
45
+ Object.defineProperty(exports, "injectContextHeaders", { enumerable: true, get: function () { return httpContext_1.injectContextHeaders; } });
46
+ Object.defineProperty(exports, "maybeInjectContextHeaders", { enumerable: true, get: function () { return httpContext_1.maybeInjectContextHeaders; } });
47
+ var subprocessContext_1 = require("./subprocessContext");
48
+ Object.defineProperty(exports, "spawnEnvWithContext", { enumerable: true, get: function () { return subprocessContext_1.spawnEnvWithContext; } });
49
+ Object.defineProperty(exports, "readContextFromEnv", { enumerable: true, get: function () { return subprocessContext_1.readContextFromEnv; } });
50
+ var hookExecution_1 = require("./hookExecution");
51
+ Object.defineProperty(exports, "executeHookWithBoundary", { enumerable: true, get: function () { return hookExecution_1.executeHookWithBoundary; } });
52
+ Object.defineProperty(exports, "HookTimeoutError", { enumerable: true, get: function () { return hookExecution_1.HookTimeoutError; } });
53
+ // v4.9.0 Slice 8 — enforcement layer for missing-context events.
54
+ var enforcement_1 = require("./enforcement");
55
+ Object.defineProperty(exports, "getEnforcementMode", { enumerable: true, get: function () { return enforcement_1.getEnforcementMode; } });
56
+ Object.defineProperty(exports, "reportMissingContext", { enumerable: true, get: function () { return enforcement_1.reportMissingContext; } });
57
+ Object.defineProperty(exports, "ContextMissingError", { enumerable: true, get: function () { return enforcement_1.ContextMissingError; } });
58
+ Object.defineProperty(exports, "getContextMissingCounter", { enumerable: true, get: function () { return enforcement_1.getContextMissingCounter; } });
59
+ Object.defineProperty(exports, "getAllContextMissingCounters", { enumerable: true, get: function () { return enforcement_1.getAllContextMissingCounters; } });
60
+ Object.defineProperty(exports, "_resetContextMissingCountersForTests", { enumerable: true, get: function () { return enforcement_1._resetContextMissingCountersForTests; } });
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2026 Shiva Deore (Taracod).
4
+ * Licensed under AGPL-3.0. See LICENSE for details.
5
+ *
6
+ * Aiden — local-first agent.
7
+ */
8
+ /**
9
+ * core/v4/identity/subprocessContext.ts — v4.9.0 Slice 7.
10
+ *
11
+ * AsyncLocalStorage does NOT cross subprocess boundaries; the child's
12
+ * Node runtime has its own ALS instance. To preserve correlation, we
13
+ * stamp the parent's ExecutionContext into the child's `env` block at
14
+ * spawn time. The child reconstitutes via `readContextFromEnv` and
15
+ * enters its own `runWithContext(ctx, fn)` frame on startup.
16
+ *
17
+ * Wire-format choice: ten env vars instead of one JSON-encoded blob.
18
+ * Reasons:
19
+ * - Greppable in `ps -ef`-style output for forensics
20
+ * - Individual vars survive partial truncation by intermediate
21
+ * shells / sudo / containers that mangle long env values
22
+ * - The set is small + stable; no schema-version footgun
23
+ *
24
+ * The child's spanId is ALWAYS freshly minted — never reuse the
25
+ * parent's spanId in the child, because the child's spans are
26
+ * causally downstream and should chain via `parentSpanId`.
27
+ */
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.spawnEnvWithContext = spawnEnvWithContext;
30
+ exports.readContextFromEnv = readContextFromEnv;
31
+ const ids_1 = require("./ids");
32
+ const ENV_PREFIX = 'AIDEN_';
33
+ /**
34
+ * Build a child-process env block carrying the parent's context.
35
+ * Caller spreads `baseEnv` first so AIDEN_* keys win — these are
36
+ * never user-overridable from the parent invocation.
37
+ */
38
+ function spawnEnvWithContext(ctx, baseEnv = process.env) {
39
+ return {
40
+ ...baseEnv,
41
+ [`${ENV_PREFIX}DAEMON_ID`]: ctx.daemonId,
42
+ [`${ENV_PREFIX}INCARNATION_ID`]: ctx.incarnationId,
43
+ [`${ENV_PREFIX}RUN_ID`]: ctx.runId,
44
+ [`${ENV_PREFIX}TRACE_ID`]: ctx.traceId,
45
+ // Child's parent IS this span; child mints its own spanId on read.
46
+ [`${ENV_PREFIX}PARENT_SPAN_ID`]: ctx.spanId,
47
+ [`${ENV_PREFIX}REQUEST_ID`]: ctx.requestId ?? '',
48
+ [`${ENV_PREFIX}SESSION_ID`]: ctx.sessionId ?? '',
49
+ [`${ENV_PREFIX}SOURCE`]: ctx.source,
50
+ [`${ENV_PREFIX}ATTEMPT`]: String(ctx.attempt),
51
+ [`${ENV_PREFIX}TRIGGER_ID`]: ctx.triggerId ?? '',
52
+ };
53
+ }
54
+ const VALID_SOURCES = new Set([
55
+ 'cli', 'api', 'webhook', 'cron', 'email', 'folder', 'subagent', 'unknown',
56
+ ]);
57
+ /**
58
+ * Reconstruct an ExecutionContext from env vars. Returns `null` when
59
+ * any of the three required fields (daemonId, incarnationId, runId)
60
+ * are absent — child wasn't spawned with context.
61
+ *
62
+ * The child's `spanId` is ALWAYS freshly minted; the parent's spanId
63
+ * becomes the child's `parentSpanId`. `source` falls back to
64
+ * `'subagent'` (the most common child case) if the env didn't carry it.
65
+ */
66
+ function readContextFromEnv(env = process.env) {
67
+ const daemonId = env[`${ENV_PREFIX}DAEMON_ID`];
68
+ const incarnationId = env[`${ENV_PREFIX}INCARNATION_ID`];
69
+ const runId = env[`${ENV_PREFIX}RUN_ID`];
70
+ if (!daemonId || !incarnationId || !runId)
71
+ return null;
72
+ const sourceRaw = env[`${ENV_PREFIX}SOURCE`] ?? 'subagent';
73
+ const source = (VALID_SOURCES.has(sourceRaw)
74
+ ? sourceRaw
75
+ : 'subagent');
76
+ const attemptRaw = env[`${ENV_PREFIX}ATTEMPT`] ?? '1';
77
+ const attempt = Number.parseInt(attemptRaw, 10);
78
+ const ctx = {
79
+ daemonId,
80
+ incarnationId,
81
+ runId,
82
+ traceId: env[`${ENV_PREFIX}TRACE_ID`] ?? '',
83
+ spanId: (0, ids_1.newSpanId)(),
84
+ parentSpanId: env[`${ENV_PREFIX}PARENT_SPAN_ID`] || undefined,
85
+ source,
86
+ attempt: Number.isFinite(attempt) && attempt > 0 ? attempt : 1,
87
+ };
88
+ const req = env[`${ENV_PREFIX}REQUEST_ID`];
89
+ if (req)
90
+ ctx.requestId = req;
91
+ const sess = env[`${ENV_PREFIX}SESSION_ID`];
92
+ if (sess)
93
+ ctx.sessionId = sess;
94
+ const trig = env[`${ENV_PREFIX}TRIGGER_ID`];
95
+ if (trig)
96
+ ctx.triggerId = trig;
97
+ return ctx;
98
+ }