@inbrowser/agent 0.0.0-placeholder → 0.1.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/AGENTS.md +270 -0
- package/README.md +117 -2
- package/bin/agent.ts +10 -0
- package/dist/cli/commands/describe.d.ts +14 -0
- package/dist/cli/commands/describe.d.ts.map +1 -0
- package/dist/cli/commands/describe.js +179 -0
- package/dist/cli/commands/describe.js.map +1 -0
- package/dist/cli/commands/events.d.ts +21 -0
- package/dist/cli/commands/events.d.ts.map +1 -0
- package/dist/cli/commands/events.js +59 -0
- package/dist/cli/commands/events.js.map +1 -0
- package/dist/cli/commands/fleet.d.ts +15 -0
- package/dist/cli/commands/fleet.d.ts.map +1 -0
- package/dist/cli/commands/fleet.js +149 -0
- package/dist/cli/commands/fleet.js.map +1 -0
- package/dist/cli/commands/help.d.ts +15 -0
- package/dist/cli/commands/help.d.ts.map +1 -0
- package/dist/cli/commands/help.js +93 -0
- package/dist/cli/commands/help.js.map +1 -0
- package/dist/cli/commands/migrate.d.ts +27 -0
- package/dist/cli/commands/migrate.d.ts.map +1 -0
- package/dist/cli/commands/migrate.js +109 -0
- package/dist/cli/commands/migrate.js.map +1 -0
- package/dist/cli/commands/run.d.ts +38 -0
- package/dist/cli/commands/run.d.ts.map +1 -0
- package/dist/cli/commands/run.js +535 -0
- package/dist/cli/commands/run.js.map +1 -0
- package/dist/cli/commands/schema.d.ts +8 -0
- package/dist/cli/commands/schema.d.ts.map +1 -0
- package/dist/cli/commands/schema.js +12 -0
- package/dist/cli/commands/schema.js.map +1 -0
- package/dist/cli/commands/serve.d.ts +39 -0
- package/dist/cli/commands/serve.d.ts.map +1 -0
- package/dist/cli/commands/serve.js +65 -0
- package/dist/cli/commands/serve.js.map +1 -0
- package/dist/cli/commands/undo.d.ts +36 -0
- package/dist/cli/commands/undo.d.ts.map +1 -0
- package/dist/cli/commands/undo.js +132 -0
- package/dist/cli/commands/undo.js.map +1 -0
- package/dist/cli/fixtures.d.ts +17 -0
- package/dist/cli/fixtures.d.ts.map +1 -0
- package/dist/cli/fixtures.js +107 -0
- package/dist/cli/fixtures.js.map +1 -0
- package/dist/cli/hardening.d.ts +39 -0
- package/dist/cli/hardening.d.ts.map +1 -0
- package/dist/cli/hardening.js +68 -0
- package/dist/cli/hardening.js.map +1 -0
- package/dist/cli/index.d.ts +28 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +19 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/llm/openrouter.d.ts +33 -0
- package/dist/cli/llm/openrouter.d.ts.map +1 -0
- package/dist/cli/llm/openrouter.js +285 -0
- package/dist/cli/llm/openrouter.js.map +1 -0
- package/dist/cli/main.d.ts +32 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/main.js +106 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/output.d.ts +36 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +95 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/parse.d.ts +26 -0
- package/dist/cli/parse.d.ts.map +1 -0
- package/dist/cli/parse.js +160 -0
- package/dist/cli/parse.js.map +1 -0
- package/dist/cli/session-log.d.ts +34 -0
- package/dist/cli/session-log.d.ts.map +1 -0
- package/dist/cli/session-log.js +52 -0
- package/dist/cli/session-log.js.map +1 -0
- package/dist/cli/spec.d.ts +62 -0
- package/dist/cli/spec.d.ts.map +1 -0
- package/dist/cli/spec.js +510 -0
- package/dist/cli/spec.js.map +1 -0
- package/dist/cli/ui/RunView.d.ts +134 -0
- package/dist/cli/ui/RunView.d.ts.map +1 -0
- package/dist/cli/ui/RunView.js +341 -0
- package/dist/cli/ui/RunView.js.map +1 -0
- package/dist/events/codec.d.ts +79 -0
- package/dist/events/codec.d.ts.map +1 -0
- package/dist/events/codec.js +142 -0
- package/dist/events/codec.js.map +1 -0
- package/dist/events/log-core.d.ts +76 -0
- package/dist/events/log-core.d.ts.map +1 -0
- package/dist/events/log-core.js +73 -0
- package/dist/events/log-core.js.map +1 -0
- package/dist/events/log.d.ts +60 -0
- package/dist/events/log.d.ts.map +1 -0
- package/dist/events/log.js +193 -0
- package/dist/events/log.js.map +1 -0
- package/dist/events/replay.d.ts +106 -0
- package/dist/events/replay.d.ts.map +1 -0
- package/dist/events/replay.js +137 -0
- package/dist/events/replay.js.map +1 -0
- package/dist/events/wrap.d.ts +100 -0
- package/dist/events/wrap.d.ts.map +1 -0
- package/dist/events/wrap.js +141 -0
- package/dist/events/wrap.js.map +1 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/llm-adapter.d.ts +96 -0
- package/dist/llm-adapter.d.ts.map +1 -0
- package/dist/llm-adapter.js +132 -0
- package/dist/llm-adapter.js.map +1 -0
- package/dist/mcp/serve.d.ts +70 -0
- package/dist/mcp/serve.d.ts.map +1 -0
- package/dist/mcp/serve.js +154 -0
- package/dist/mcp/serve.js.map +1 -0
- package/dist/metrics/runs.d.ts +58 -0
- package/dist/metrics/runs.d.ts.map +1 -0
- package/dist/metrics/runs.js +99 -0
- package/dist/metrics/runs.js.map +1 -0
- package/dist/metrics.d.ts +38 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +123 -0
- package/dist/metrics.js.map +1 -0
- package/dist/node.d.ts +22 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +22 -0
- package/dist/node.js.map +1 -0
- package/dist/session.d.ts +10 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +179 -0
- package/dist/session.js.map +1 -0
- package/dist/storage.d.ts +14 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +58 -0
- package/dist/storage.js.map +1 -0
- package/dist/strategy.d.ts +26 -0
- package/dist/strategy.d.ts.map +1 -0
- package/dist/strategy.js +200 -0
- package/dist/strategy.js.map +1 -0
- package/dist/tools.d.ts +26 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +129 -0
- package/dist/tools.js.map +1 -0
- package/dist/types/agent.d.ts +94 -0
- package/dist/types/agent.d.ts.map +1 -0
- package/dist/types/agent.js +17 -0
- package/dist/types/agent.js.map +1 -0
- package/dist/types/capabilities.d.ts +17 -0
- package/dist/types/capabilities.d.ts.map +1 -0
- package/dist/types/capabilities.js +13 -0
- package/dist/types/capabilities.js.map +1 -0
- package/dist/types/chat.d.ts +74 -0
- package/dist/types/chat.d.ts.map +1 -0
- package/dist/types/chat.js +10 -0
- package/dist/types/chat.js.map +1 -0
- package/dist/types/events.d.ts +115 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/events.js +30 -0
- package/dist/types/events.js.map +1 -0
- package/dist/types/llm.d.ts +89 -0
- package/dist/types/llm.d.ts.map +1 -0
- package/dist/types/llm.js +12 -0
- package/dist/types/llm.js.map +1 -0
- package/dist/types/metrics.d.ts +34 -0
- package/dist/types/metrics.d.ts.map +1 -0
- package/dist/types/metrics.js +10 -0
- package/dist/types/metrics.js.map +1 -0
- package/dist/types/observer.d.ts +41 -0
- package/dist/types/observer.d.ts.map +1 -0
- package/dist/types/observer.js +41 -0
- package/dist/types/observer.js.map +1 -0
- package/dist/types/project-context.d.ts +18 -0
- package/dist/types/project-context.d.ts.map +1 -0
- package/dist/types/project-context.js +11 -0
- package/dist/types/project-context.js.map +1 -0
- package/dist/types/runtime.d.ts +71 -0
- package/dist/types/runtime.d.ts.map +1 -0
- package/dist/types/runtime.js +21 -0
- package/dist/types/runtime.js.map +1 -0
- package/dist/types/session.d.ts +103 -0
- package/dist/types/session.d.ts.map +1 -0
- package/dist/types/session.js +11 -0
- package/dist/types/session.js.map +1 -0
- package/dist/types/storage.d.ts +20 -0
- package/dist/types/storage.d.ts.map +1 -0
- package/dist/types/storage.js +41 -0
- package/dist/types/storage.js.map +1 -0
- package/dist/types/strategy.d.ts +76 -0
- package/dist/types/strategy.d.ts.map +1 -0
- package/dist/types/strategy.js +10 -0
- package/dist/types/strategy.js.map +1 -0
- package/dist/types/tools.d.ts +136 -0
- package/dist/types/tools.d.ts.map +1 -0
- package/dist/types/tools.js +11 -0
- package/dist/types/tools.js.map +1 -0
- package/dist/types/trace.d.ts +125 -0
- package/dist/types/trace.d.ts.map +1 -0
- package/dist/types/trace.js +24 -0
- package/dist/types/trace.js.map +1 -0
- package/dist/types/workspace.d.ts +29 -0
- package/dist/types/workspace.d.ts.map +1 -0
- package/dist/types/workspace.js +18 -0
- package/dist/types/workspace.js.map +1 -0
- package/package.json +45 -14
- package/skills/agent-cli.md +218 -0
- package/index.js +0 -2
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure / browser-safe pieces of the event log surface:
|
|
3
|
+
*
|
|
4
|
+
* - `EventLog`, `AppendDraft` — types describing the writer's
|
|
5
|
+
* contract; consumers (wrap, replay) describe handlers without
|
|
6
|
+
* pulling in the writer implementation.
|
|
7
|
+
* - `HOST_AGENT_ID` — string constant; canonical declaration is
|
|
8
|
+
* `types/events.ts` (also browser-safe).
|
|
9
|
+
* - `generateEventId`, `buildRollbackEvent`, `EventTooLargeError`,
|
|
10
|
+
* `DEFAULT_MAX_EVENT_BYTES` — pure helpers used by both the
|
|
11
|
+
* Node-side writer (`log.ts`) and the browser-safe `wrapMutating`
|
|
12
|
+
* decorator.
|
|
13
|
+
*
|
|
14
|
+
* The Node-side writer (`openEventLog`, `defaultProjectLogDir`) lives
|
|
15
|
+
* in `./log.ts` and imports `node:fs` / `node:os`. Splitting along
|
|
16
|
+
* this axis lets `wrap.ts` and the universal `@inbrowser/agent` entry
|
|
17
|
+
* use the pure helpers without dragging Node imports into browser
|
|
18
|
+
* bundles.
|
|
19
|
+
*/
|
|
20
|
+
import type { MutationEvent, MutationEventFilter, ReverseOp } from '../types/events.js';
|
|
21
|
+
export { HOST_AGENT_ID } from '../types/events.js';
|
|
22
|
+
/**
|
|
23
|
+
* Default per-event byte cap. Matches the Linux PIPE_BUF default and
|
|
24
|
+
* stays well inside macOS's atomic-write window. Above this, append
|
|
25
|
+
* atomicity isn't guaranteed and concurrent writers can interleave.
|
|
26
|
+
*/
|
|
27
|
+
export declare const DEFAULT_MAX_EVENT_BYTES: number;
|
|
28
|
+
/**
|
|
29
|
+
* Time-prefixed base36 id with an optional per-log sequence so two
|
|
30
|
+
* appends within the same millisecond stay strictly sortable by
|
|
31
|
+
* emission order. Without the sequence the only tiebreaker is the
|
|
32
|
+
* random suffix, which can flip ordering — a real bug for
|
|
33
|
+
* `replayEvents`'s sinceEventId cursor.
|
|
34
|
+
*/
|
|
35
|
+
export declare function generateEventId(now?: () => number, sequence?: number): string;
|
|
36
|
+
export declare class EventTooLargeError extends Error {
|
|
37
|
+
readonly bytes: number;
|
|
38
|
+
readonly cap: number;
|
|
39
|
+
readonly tool: string;
|
|
40
|
+
readonly name = "EventTooLargeError";
|
|
41
|
+
constructor(bytes: number, cap: number, tool: string);
|
|
42
|
+
}
|
|
43
|
+
export interface EventLog {
|
|
44
|
+
readonly path: string;
|
|
45
|
+
readonly projectId: string;
|
|
46
|
+
/**
|
|
47
|
+
* Append a single event. `id` + `ts` are auto-populated when absent
|
|
48
|
+
* so callers can pass a partial draft. Returns the full event for
|
|
49
|
+
* convenience (e.g. wrapMutating's plan-then-commit flow).
|
|
50
|
+
*/
|
|
51
|
+
append(draft: AppendDraft): MutationEvent;
|
|
52
|
+
/**
|
|
53
|
+
* Read all events matching the filter. Returns an array, not a
|
|
54
|
+
* stream — the log is small (tens to thousands of events).
|
|
55
|
+
*/
|
|
56
|
+
read(filter?: MutationEventFilter): MutationEvent[];
|
|
57
|
+
/**
|
|
58
|
+
* Lazily-built cache of event ids that have already been applied
|
|
59
|
+
* by `replayEvents` (i.e. an event with
|
|
60
|
+
* `metadata.type === 'migrate_applied'` referencing them exists).
|
|
61
|
+
* Invalidated on every `append`.
|
|
62
|
+
*/
|
|
63
|
+
appliedEventIds(): Set<string>;
|
|
64
|
+
/** Release resources. Idempotent. */
|
|
65
|
+
close(): void;
|
|
66
|
+
}
|
|
67
|
+
export type AppendDraft = Omit<MutationEvent, 'id' | 'ts'> & Partial<Pick<MutationEvent, 'id' | 'ts'>>;
|
|
68
|
+
export declare function buildRollbackEvent(opts: {
|
|
69
|
+
original: MutationEvent;
|
|
70
|
+
reason: 'failure' | 'undo';
|
|
71
|
+
reverseOp?: ReverseOp;
|
|
72
|
+
agent: string;
|
|
73
|
+
sessionId: string;
|
|
74
|
+
now?: () => number;
|
|
75
|
+
}): AppendDraft;
|
|
76
|
+
//# sourceMappingURL=log-core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-core.d.ts","sourceRoot":"","sources":["../../src/events/log-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EACV,aAAa,EACb,mBAAmB,EAEnB,SAAS,EACV,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,QAAY,CAAC;AAEjD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAM,MAAiB,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAKvF;AAED,qBAAa,kBAAmB,SAAQ,KAAK;IAGzC,QAAQ,CAAC,KAAK,EAAE,MAAM;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM;IAJvB,SAAkB,IAAI,wBAAwB;gBAEnC,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM;CASxB;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;;OAIG;IACH,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,aAAa,CAAC;IAC1C;;;OAGG;IACH,IAAI,CAAC,MAAM,CAAC,EAAE,mBAAmB,GAAG,aAAa,EAAE,CAAC;IACpD;;;;;OAKG;IACH,eAAe,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;IAC/B,qCAAqC;IACrC,KAAK,IAAI,IAAI,CAAC;CACf;AAED,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,EAAE,IAAI,GAAG,IAAI,CAAC,GACxD,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC;AAE5C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACvC,QAAQ,EAAE,aAAa,CAAC;IACxB,MAAM,EAAE,SAAS,GAAG,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB,GAAG,WAAW,CAiBd"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure / browser-safe pieces of the event log surface:
|
|
3
|
+
*
|
|
4
|
+
* - `EventLog`, `AppendDraft` — types describing the writer's
|
|
5
|
+
* contract; consumers (wrap, replay) describe handlers without
|
|
6
|
+
* pulling in the writer implementation.
|
|
7
|
+
* - `HOST_AGENT_ID` — string constant; canonical declaration is
|
|
8
|
+
* `types/events.ts` (also browser-safe).
|
|
9
|
+
* - `generateEventId`, `buildRollbackEvent`, `EventTooLargeError`,
|
|
10
|
+
* `DEFAULT_MAX_EVENT_BYTES` — pure helpers used by both the
|
|
11
|
+
* Node-side writer (`log.ts`) and the browser-safe `wrapMutating`
|
|
12
|
+
* decorator.
|
|
13
|
+
*
|
|
14
|
+
* The Node-side writer (`openEventLog`, `defaultProjectLogDir`) lives
|
|
15
|
+
* in `./log.ts` and imports `node:fs` / `node:os`. Splitting along
|
|
16
|
+
* this axis lets `wrap.ts` and the universal `@inbrowser/agent` entry
|
|
17
|
+
* use the pure helpers without dragging Node imports into browser
|
|
18
|
+
* bundles.
|
|
19
|
+
*/
|
|
20
|
+
export { HOST_AGENT_ID } from '../types/events.js';
|
|
21
|
+
/**
|
|
22
|
+
* Default per-event byte cap. Matches the Linux PIPE_BUF default and
|
|
23
|
+
* stays well inside macOS's atomic-write window. Above this, append
|
|
24
|
+
* atomicity isn't guaranteed and concurrent writers can interleave.
|
|
25
|
+
*/
|
|
26
|
+
export const DEFAULT_MAX_EVENT_BYTES = 64 * 1024;
|
|
27
|
+
/**
|
|
28
|
+
* Time-prefixed base36 id with an optional per-log sequence so two
|
|
29
|
+
* appends within the same millisecond stay strictly sortable by
|
|
30
|
+
* emission order. Without the sequence the only tiebreaker is the
|
|
31
|
+
* random suffix, which can flip ordering — a real bug for
|
|
32
|
+
* `replayEvents`'s sinceEventId cursor.
|
|
33
|
+
*/
|
|
34
|
+
export function generateEventId(now = Date.now, sequence) {
|
|
35
|
+
const ts = now().toString(36).padStart(9, '0');
|
|
36
|
+
const seq = sequence !== undefined ? `-${sequence.toString(36).padStart(4, '0')}` : '';
|
|
37
|
+
const rand = Math.random().toString(36).slice(2, 6);
|
|
38
|
+
return `${ts}${seq}-${rand}`;
|
|
39
|
+
}
|
|
40
|
+
export class EventTooLargeError extends Error {
|
|
41
|
+
bytes;
|
|
42
|
+
cap;
|
|
43
|
+
tool;
|
|
44
|
+
name = 'EventTooLargeError';
|
|
45
|
+
constructor(bytes, cap, tool) {
|
|
46
|
+
super(`event for tool=${tool} is ${bytes} bytes, exceeds cap ${cap}. ` +
|
|
47
|
+
`Atomic append is not guaranteed above this size; concurrent writers can interleave. ` +
|
|
48
|
+
`Raise via openEventLog({ maxEventBytes }) only if you accept the loss of atomicity guarantees, ` +
|
|
49
|
+
`or shrink the payload (truncate before/after snapshots, omit large args).`);
|
|
50
|
+
this.bytes = bytes;
|
|
51
|
+
this.cap = cap;
|
|
52
|
+
this.tool = tool;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export function buildRollbackEvent(opts) {
|
|
56
|
+
const nowFn = opts.now ?? Date.now;
|
|
57
|
+
void nowFn;
|
|
58
|
+
return {
|
|
59
|
+
agent: opts.agent,
|
|
60
|
+
sessionId: opts.sessionId,
|
|
61
|
+
tool: opts.original.tool,
|
|
62
|
+
phase: 'rollback',
|
|
63
|
+
target: opts.original.target,
|
|
64
|
+
reversible: false,
|
|
65
|
+
irreversibleReason: 'rollback events are terminal',
|
|
66
|
+
...(opts.reverseOp ? { reverseOp: opts.reverseOp } : {}),
|
|
67
|
+
metadata: {
|
|
68
|
+
reason: opts.reason,
|
|
69
|
+
originalEventId: opts.original.id,
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=log-core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-core.js","sourceRoot":"","sources":["../../src/events/log-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AASH,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,GAAG,IAAI,CAAC;AAEjD;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,MAAoB,IAAI,CAAC,GAAG,EAAE,QAAiB;IAC7E,MAAM,EAAE,GAAG,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC/C,MAAM,GAAG,GAAG,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACvF,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACpD,OAAO,GAAG,EAAE,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;AAC/B,CAAC;AAED,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAGhC;IACA;IACA;IAJO,IAAI,GAAG,oBAAoB,CAAC;IAC9C,YACW,KAAa,EACb,GAAW,EACX,IAAY;QAErB,KAAK,CACH,kBAAkB,IAAI,OAAO,KAAK,uBAAuB,GAAG,IAAI;YAC9D,sFAAsF;YACtF,iGAAiG;YACjG,2EAA2E,CAC9E,CAAC;QATO,UAAK,GAAL,KAAK,CAAQ;QACb,QAAG,GAAH,GAAG,CAAQ;QACX,SAAI,GAAJ,IAAI,CAAQ;IAQvB,CAAC;CACF;AA8BD,MAAM,UAAU,kBAAkB,CAAC,IAOlC;IACC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IACnC,KAAK,KAAK,CAAC;IACX,OAAO;QACL,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI;QACxB,KAAK,EAAE,UAAkC;QACzC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM;QAC5B,UAAU,EAAE,KAAK;QACjB,kBAAkB,EAAE,8BAA8B;QAClD,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxD,QAAQ,EAAE;YACR,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,eAAe,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE;SAClC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project event log — NDJSON append-only writer. Node-only.
|
|
3
|
+
*
|
|
4
|
+
* Pure helpers (`generateEventId`, `buildRollbackEvent`, `HOST_AGENT_ID`,
|
|
5
|
+
* `EventTooLargeError`, `DEFAULT_MAX_EVENT_BYTES`) and the `EventLog`
|
|
6
|
+
* + `AppendDraft` types live in `./log-core.ts` — that file is
|
|
7
|
+
* browser-safe and is what `wrap.ts` / `replay.ts` import.
|
|
8
|
+
*
|
|
9
|
+
* Each Firebase project gets one log at
|
|
10
|
+
* `~/.pyric/projects/<projectId>/events.ndjson`. Every mutating tool
|
|
11
|
+
* call emits at least two lines (plan + commit); failures get a
|
|
12
|
+
* rollback line. `agent events` reads + filters; `agent undo` consults
|
|
13
|
+
* the log to find the matching commit event and invoke its reverseOp.
|
|
14
|
+
*
|
|
15
|
+
* Design notes:
|
|
16
|
+
* - **Append-only.** Never rewrite. `agent undo` doesn't delete the
|
|
17
|
+
* committed event; it appends a new `rollback`-phase event that
|
|
18
|
+
* references the original id. This keeps the file replayable.
|
|
19
|
+
* - **Atomic per-event writes.** Each `append()` is one
|
|
20
|
+
* `appendFileSync` call so multi-process writers can't interleave
|
|
21
|
+
* within an event. Events have a hard byte cap (default 64KB) to
|
|
22
|
+
* stay inside the kernel's atomic-append window on Linux + macOS.
|
|
23
|
+
* - **Synchronous IO.** The log is small. A streaming reader would
|
|
24
|
+
* be over-engineering today.
|
|
25
|
+
* - **Injectable fs.** Tests pass a fake `io` object so they don't
|
|
26
|
+
* hit the real disk.
|
|
27
|
+
* - **Codec hook.** `args`, `before`, `after` are run through an
|
|
28
|
+
* `EventValueCodec` on append + decoded on read.
|
|
29
|
+
*/
|
|
30
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync } from 'node:fs';
|
|
31
|
+
import { type EventValueCodec } from './codec.js';
|
|
32
|
+
import { type EventLog } from './log-core.js';
|
|
33
|
+
export { HOST_AGENT_ID, DEFAULT_MAX_EVENT_BYTES, generateEventId, EventTooLargeError, buildRollbackEvent, } from './log-core.js';
|
|
34
|
+
export type { EventLog, AppendDraft } from './log-core.js';
|
|
35
|
+
export declare function defaultProjectLogDir(): string;
|
|
36
|
+
export interface EventLogIO {
|
|
37
|
+
existsSync: typeof existsSync;
|
|
38
|
+
mkdirSync: typeof mkdirSync;
|
|
39
|
+
appendFileSync: typeof appendFileSync;
|
|
40
|
+
readFileSync: typeof readFileSync;
|
|
41
|
+
}
|
|
42
|
+
export interface OpenEventLogOptions {
|
|
43
|
+
projectId: string;
|
|
44
|
+
/** Absolute path to the directory containing per-project subdirs.
|
|
45
|
+
* Defaults to `~/.pyric/projects`. */
|
|
46
|
+
logDir?: string;
|
|
47
|
+
/** Defaults to fs primitives; injectable for tests. */
|
|
48
|
+
io?: EventLogIO;
|
|
49
|
+
/** Injectable clock; defaults to `Date.now`. */
|
|
50
|
+
now?: () => number;
|
|
51
|
+
/** Codec for `args` / `before` / `after`. Default round-trips
|
|
52
|
+
* Date / Uint8Array / bigint / undefined. Pass a composed codec
|
|
53
|
+
* for Firestore types — see `codec.ts:composeCodecs`. */
|
|
54
|
+
codec?: EventValueCodec;
|
|
55
|
+
/** Per-event byte cap. Defaults to 64KB. Exceeding throws
|
|
56
|
+
* `EventTooLargeError`. */
|
|
57
|
+
maxEventBytes?: number;
|
|
58
|
+
}
|
|
59
|
+
export declare function openEventLog(opts: OpenEventLogOptions): EventLog;
|
|
60
|
+
//# sourceMappingURL=log.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../src/events/log.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG9E,OAAO,EAAE,KAAK,eAAe,EAA0B,MAAM,YAAY,CAAC;AAC1E,OAAO,EAGL,KAAK,QAAQ,EAGd,MAAM,eAAe,CAAC;AAMvB,OAAO,EACL,aAAa,EACb,uBAAuB,EACvB,eAAe,EACf,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE3D,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,SAAS,EAAE,OAAO,SAAS,CAAC;IAC5B,cAAc,EAAE,OAAO,cAAc,CAAC;IACtC,YAAY,EAAE,OAAO,YAAY,CAAC;CACnC;AASD,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB;2CACuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,EAAE,CAAC,EAAE,UAAU,CAAC;IAChB,gDAAgD;IAChD,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB;;8DAE0D;IAC1D,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB;gCAC4B;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,mBAAmB,GAAG,QAAQ,CA+GhE"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project event log — NDJSON append-only writer. Node-only.
|
|
3
|
+
*
|
|
4
|
+
* Pure helpers (`generateEventId`, `buildRollbackEvent`, `HOST_AGENT_ID`,
|
|
5
|
+
* `EventTooLargeError`, `DEFAULT_MAX_EVENT_BYTES`) and the `EventLog`
|
|
6
|
+
* + `AppendDraft` types live in `./log-core.ts` — that file is
|
|
7
|
+
* browser-safe and is what `wrap.ts` / `replay.ts` import.
|
|
8
|
+
*
|
|
9
|
+
* Each Firebase project gets one log at
|
|
10
|
+
* `~/.pyric/projects/<projectId>/events.ndjson`. Every mutating tool
|
|
11
|
+
* call emits at least two lines (plan + commit); failures get a
|
|
12
|
+
* rollback line. `agent events` reads + filters; `agent undo` consults
|
|
13
|
+
* the log to find the matching commit event and invoke its reverseOp.
|
|
14
|
+
*
|
|
15
|
+
* Design notes:
|
|
16
|
+
* - **Append-only.** Never rewrite. `agent undo` doesn't delete the
|
|
17
|
+
* committed event; it appends a new `rollback`-phase event that
|
|
18
|
+
* references the original id. This keeps the file replayable.
|
|
19
|
+
* - **Atomic per-event writes.** Each `append()` is one
|
|
20
|
+
* `appendFileSync` call so multi-process writers can't interleave
|
|
21
|
+
* within an event. Events have a hard byte cap (default 64KB) to
|
|
22
|
+
* stay inside the kernel's atomic-append window on Linux + macOS.
|
|
23
|
+
* - **Synchronous IO.** The log is small. A streaming reader would
|
|
24
|
+
* be over-engineering today.
|
|
25
|
+
* - **Injectable fs.** Tests pass a fake `io` object so they don't
|
|
26
|
+
* hit the real disk.
|
|
27
|
+
* - **Codec hook.** `args`, `before`, `after` are run through an
|
|
28
|
+
* `EventValueCodec` on append + decoded on read.
|
|
29
|
+
*/
|
|
30
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync } from 'node:fs';
|
|
31
|
+
import { homedir } from 'node:os';
|
|
32
|
+
import { defaultEventValueCodec } from './codec.js';
|
|
33
|
+
import { DEFAULT_MAX_EVENT_BYTES, EventTooLargeError, generateEventId, } from './log-core.js';
|
|
34
|
+
// Convenience re-exports — Node-side callers can grab everything
|
|
35
|
+
// log-related from one entry. Browser-safe callers (wrap.ts,
|
|
36
|
+
// replay.ts) import from `./log-core.js` directly to avoid pulling
|
|
37
|
+
// `node:fs` into the universal `@inbrowser/agent` entry.
|
|
38
|
+
export { HOST_AGENT_ID, DEFAULT_MAX_EVENT_BYTES, generateEventId, EventTooLargeError, buildRollbackEvent, } from './log-core.js';
|
|
39
|
+
export function defaultProjectLogDir() {
|
|
40
|
+
return `${homedir()}/.pyric/projects`;
|
|
41
|
+
}
|
|
42
|
+
const DEFAULT_IO = {
|
|
43
|
+
existsSync,
|
|
44
|
+
mkdirSync,
|
|
45
|
+
appendFileSync,
|
|
46
|
+
readFileSync,
|
|
47
|
+
};
|
|
48
|
+
export function openEventLog(opts) {
|
|
49
|
+
if (!/^[a-zA-Z0-9_.-]+$/.test(opts.projectId)) {
|
|
50
|
+
throw new Error(`openEventLog: projectId ${JSON.stringify(opts.projectId)} contains disallowed characters; use [a-zA-Z0-9_.-]+`);
|
|
51
|
+
}
|
|
52
|
+
const io = opts.io ?? DEFAULT_IO;
|
|
53
|
+
const now = opts.now ?? Date.now;
|
|
54
|
+
const baseDir = opts.logDir ?? defaultProjectLogDir();
|
|
55
|
+
const projectDir = `${baseDir.replace(/\/$/, '')}/${opts.projectId}`;
|
|
56
|
+
const path = `${projectDir}/events.ndjson`;
|
|
57
|
+
const codec = opts.codec ?? defaultEventValueCodec;
|
|
58
|
+
const maxBytes = opts.maxEventBytes ?? DEFAULT_MAX_EVENT_BYTES;
|
|
59
|
+
if (!io.existsSync(projectDir))
|
|
60
|
+
io.mkdirSync(projectDir, { recursive: true });
|
|
61
|
+
// Strictly-monotonic counter — combined with the millisecond
|
|
62
|
+
// timestamp, makes ids sortable in emission order even when many
|
|
63
|
+
// appends share a `Date.now()` value.
|
|
64
|
+
let sequence = 0;
|
|
65
|
+
let closed = false;
|
|
66
|
+
// Lazy-built cache of `migrate_applied` originalEventIds. Invalidated
|
|
67
|
+
// on every append so the next read rebuilds it.
|
|
68
|
+
let _appliedCache = null;
|
|
69
|
+
function ensureOpen() {
|
|
70
|
+
if (closed)
|
|
71
|
+
throw new Error(`event log ${path} is closed`);
|
|
72
|
+
}
|
|
73
|
+
function appendEvent(draft) {
|
|
74
|
+
ensureOpen();
|
|
75
|
+
const event = {
|
|
76
|
+
id: draft.id ?? generateEventId(now, sequence++),
|
|
77
|
+
ts: draft.ts ?? new Date(now()).toISOString(),
|
|
78
|
+
agent: draft.agent,
|
|
79
|
+
sessionId: draft.sessionId,
|
|
80
|
+
tool: draft.tool,
|
|
81
|
+
...(draft.args !== undefined ? { args: codec.encode(draft.args) } : {}),
|
|
82
|
+
phase: draft.phase,
|
|
83
|
+
target: draft.target,
|
|
84
|
+
...(draft.before !== undefined ? { before: codec.encode(draft.before) } : {}),
|
|
85
|
+
...(draft.after !== undefined ? { after: codec.encode(draft.after) } : {}),
|
|
86
|
+
reversible: draft.reversible,
|
|
87
|
+
...(draft.irreversibleReason ? { irreversibleReason: draft.irreversibleReason } : {}),
|
|
88
|
+
...(draft.reverseOp ? { reverseOp: encodeReverseOp(draft.reverseOp, codec) } : {}),
|
|
89
|
+
...(draft.metadata ? { metadata: draft.metadata } : {}),
|
|
90
|
+
};
|
|
91
|
+
const line = JSON.stringify(event) + '\n';
|
|
92
|
+
const bytes = Buffer.byteLength(line, 'utf8');
|
|
93
|
+
if (bytes > maxBytes) {
|
|
94
|
+
throw new EventTooLargeError(bytes, maxBytes, draft.tool);
|
|
95
|
+
}
|
|
96
|
+
io.appendFileSync(path, line);
|
|
97
|
+
_appliedCache = null;
|
|
98
|
+
return event;
|
|
99
|
+
}
|
|
100
|
+
function readAll(filter) {
|
|
101
|
+
ensureOpen();
|
|
102
|
+
if (!io.existsSync(path))
|
|
103
|
+
return [];
|
|
104
|
+
const raw = io.readFileSync(path, 'utf8');
|
|
105
|
+
if (!raw)
|
|
106
|
+
return [];
|
|
107
|
+
const out = [];
|
|
108
|
+
for (const line of raw.split('\n')) {
|
|
109
|
+
if (!line)
|
|
110
|
+
continue;
|
|
111
|
+
let parsed;
|
|
112
|
+
try {
|
|
113
|
+
parsed = JSON.parse(line);
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// Skip malformed lines — append-only files can become corrupt
|
|
117
|
+
// if a writer crashes mid-write. Surfacing as a hard error
|
|
118
|
+
// would prevent `agent events` from ever working again.
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
const decoded = {
|
|
122
|
+
...parsed,
|
|
123
|
+
...(parsed.args !== undefined ? { args: codec.decode(parsed.args) } : {}),
|
|
124
|
+
...(parsed.before !== undefined ? { before: codec.decode(parsed.before) } : {}),
|
|
125
|
+
...(parsed.after !== undefined ? { after: codec.decode(parsed.after) } : {}),
|
|
126
|
+
...(parsed.reverseOp ? { reverseOp: decodeReverseOp(parsed.reverseOp, codec) } : {}),
|
|
127
|
+
};
|
|
128
|
+
if (filter && !matches(decoded, filter))
|
|
129
|
+
continue;
|
|
130
|
+
out.push(decoded);
|
|
131
|
+
}
|
|
132
|
+
return out;
|
|
133
|
+
}
|
|
134
|
+
function appliedEventIds() {
|
|
135
|
+
if (_appliedCache !== null)
|
|
136
|
+
return _appliedCache;
|
|
137
|
+
const set = new Set();
|
|
138
|
+
for (const ev of readAll()) {
|
|
139
|
+
const md = ev.metadata;
|
|
140
|
+
if (md?.type === 'migrate_applied' && typeof md.appliedEventId === 'string') {
|
|
141
|
+
set.add(md.appliedEventId);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
_appliedCache = set;
|
|
145
|
+
return set;
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
path,
|
|
149
|
+
projectId: opts.projectId,
|
|
150
|
+
append: appendEvent,
|
|
151
|
+
read: readAll,
|
|
152
|
+
appliedEventIds,
|
|
153
|
+
close() {
|
|
154
|
+
if (closed)
|
|
155
|
+
return;
|
|
156
|
+
closed = true;
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function encodeReverseOp(op, codec) {
|
|
161
|
+
return {
|
|
162
|
+
tool: op.tool,
|
|
163
|
+
args: codec.encode(op.args),
|
|
164
|
+
...(op.description ? { description: op.description } : {}),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
function decodeReverseOp(op, codec) {
|
|
168
|
+
return {
|
|
169
|
+
tool: op.tool,
|
|
170
|
+
args: codec.decode(op.args),
|
|
171
|
+
...(op.description ? { description: op.description } : {}),
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
function matches(event, filter) {
|
|
175
|
+
if (filter.id && event.id !== filter.id)
|
|
176
|
+
return false;
|
|
177
|
+
if (filter.sessionId && event.sessionId !== filter.sessionId)
|
|
178
|
+
return false;
|
|
179
|
+
if (filter.tool && event.tool !== filter.tool)
|
|
180
|
+
return false;
|
|
181
|
+
if (filter.agent && event.agent !== filter.agent)
|
|
182
|
+
return false;
|
|
183
|
+
if (filter.phase && event.phase !== filter.phase)
|
|
184
|
+
return false;
|
|
185
|
+
if (filter.targetKind && event.target.kind !== filter.targetKind)
|
|
186
|
+
return false;
|
|
187
|
+
if (filter.since && event.ts < filter.since)
|
|
188
|
+
return false;
|
|
189
|
+
if (filter.until && event.ts >= filter.until)
|
|
190
|
+
return false;
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/events/log.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `replayEvents()` — forward replay of a project's event log against a
|
|
3
|
+
* caller-supplied `ToolDispatch`.
|
|
4
|
+
*
|
|
5
|
+
* Pair to `wrapMutating()` + `agent undo`:
|
|
6
|
+
* - `wrapMutating` writes structured events as a side effect of
|
|
7
|
+
* running tools.
|
|
8
|
+
* - `undoCommand` walks the log backwards (commit → rollback) to
|
|
9
|
+
* reverse a single mutation.
|
|
10
|
+
* - `replayEvents()` walks the log forwards (`commit` events in id
|
|
11
|
+
* order) and re-dispatches each tool with its recorded args, so
|
|
12
|
+
* the same mutations can be re-applied to a *different* dispatch
|
|
13
|
+
* (typical case: dev simulator → production registry).
|
|
14
|
+
*
|
|
15
|
+
* Idempotency:
|
|
16
|
+
* - Each successfully-applied event gets a `migrate_applied` marker
|
|
17
|
+
* event written back to the same log (or a separate target log
|
|
18
|
+
* when `targetLog` is provided). Re-running `replayEvents()` skips
|
|
19
|
+
* events whose marker is already present, so partial-failure +
|
|
20
|
+
* retry is safe.
|
|
21
|
+
* - The caller can additionally provide `shouldApply` to gate
|
|
22
|
+
* events. The callback fires for every event (it is NOT a
|
|
23
|
+
* conflict-only hook); the caller is responsible for whatever
|
|
24
|
+
* state-read or business logic decides apply / skip / abort.
|
|
25
|
+
*
|
|
26
|
+
* Boundaries:
|
|
27
|
+
* - This function calls `dispatch.execute()`. It is therefore
|
|
28
|
+
* *not* CLI-safe — it expects a real dispatch wired to real
|
|
29
|
+
* services. The `agent migrate` subcommand only PLANS replay; the
|
|
30
|
+
* host runs `replayEvents()` against its prod dispatch.
|
|
31
|
+
* - **The dispatch handlers MUST be unwrapped.** If you re-apply
|
|
32
|
+
* `wrapMutating()` at replay time, each replayed event spawns a
|
|
33
|
+
* fresh plan/commit pair on the target log — and a subsequent
|
|
34
|
+
* replay run would try to re-replay those. Wrap on the system
|
|
35
|
+
* that PRODUCES the log; do not wrap on the system that CONSUMES
|
|
36
|
+
* it via replay.
|
|
37
|
+
*/
|
|
38
|
+
import type { MutationEvent } from '../types/events.js';
|
|
39
|
+
import type { ToolContext, ToolDispatch, ToolResult } from '../types/tools.js';
|
|
40
|
+
import type { EventLog } from './log-core.js';
|
|
41
|
+
export interface ReplayOptions {
|
|
42
|
+
/** Source log to read commits from. */
|
|
43
|
+
log: EventLog;
|
|
44
|
+
/** Dispatch to invoke each replayed tool against.
|
|
45
|
+
* **MUST register unwrapped handlers** — see file header. */
|
|
46
|
+
dispatch: ToolDispatch;
|
|
47
|
+
/** Factory producing a fresh `ToolContext` per dispatch call. */
|
|
48
|
+
toolContext(): ToolContext;
|
|
49
|
+
/** Replay only events with id >= this id (inclusive). Lexically
|
|
50
|
+
* compared — works because event ids are time-prefixed base36. */
|
|
51
|
+
sinceEventId?: string;
|
|
52
|
+
/** Restrict to these tool names. Unset → replay every commit. */
|
|
53
|
+
toolAllowlist?: readonly string[];
|
|
54
|
+
/** Skip events whose `target.path` matches any of these. */
|
|
55
|
+
pathDenyList?: readonly string[];
|
|
56
|
+
/**
|
|
57
|
+
* Per-event resolver. Fires for every event *after* it passes the
|
|
58
|
+
* tool / path / already-applied filters. Use it to read target
|
|
59
|
+
* state and decide apply / skip / abort — replayEvents itself does
|
|
60
|
+
* not read target state. Default: 'apply' for all events.
|
|
61
|
+
*
|
|
62
|
+
* Renamed from the previous `onConflict` to better reflect what it
|
|
63
|
+
* actually does (it is not a conflict-only hook).
|
|
64
|
+
*/
|
|
65
|
+
shouldApply?: (event: MutationEvent) => 'apply' | 'skip' | 'abort';
|
|
66
|
+
/** When true: emit `plan` progress events but do NOT call dispatch.
|
|
67
|
+
* No `migrate_applied` markers are written. */
|
|
68
|
+
dryRun?: boolean;
|
|
69
|
+
/** Optional separate log to write the `migrate_applied` markers
|
|
70
|
+
* into. Defaults to the source log. Useful when the prod
|
|
71
|
+
* environment maintains its own event log. */
|
|
72
|
+
targetLog?: EventLog;
|
|
73
|
+
/** Agent identifier stamped on the `migrate_applied` markers.
|
|
74
|
+
* Defaults to 'replay'. */
|
|
75
|
+
agent?: string;
|
|
76
|
+
/** Session id stamped on markers. Defaults to a synthesized id. */
|
|
77
|
+
sessionId?: string;
|
|
78
|
+
}
|
|
79
|
+
export type ReplayProgress = {
|
|
80
|
+
type: 'plan';
|
|
81
|
+
event: MutationEvent;
|
|
82
|
+
} | {
|
|
83
|
+
type: 'applied';
|
|
84
|
+
event: MutationEvent;
|
|
85
|
+
markerId: string;
|
|
86
|
+
result: ToolResult;
|
|
87
|
+
} | {
|
|
88
|
+
type: 'skipped';
|
|
89
|
+
event: MutationEvent;
|
|
90
|
+
reason: 'already_applied' | 'tool_denied' | 'path_denied' | 'shouldapply_skip';
|
|
91
|
+
} | {
|
|
92
|
+
type: 'error';
|
|
93
|
+
event: MutationEvent;
|
|
94
|
+
message: string;
|
|
95
|
+
} | {
|
|
96
|
+
type: 'done';
|
|
97
|
+
total: number;
|
|
98
|
+
applied: number;
|
|
99
|
+
skipped: number;
|
|
100
|
+
errors: number;
|
|
101
|
+
};
|
|
102
|
+
export declare class ReplayInvariantError extends Error {
|
|
103
|
+
readonly name = "ReplayInvariantError";
|
|
104
|
+
}
|
|
105
|
+
export declare function replayEvents(opts: ReplayOptions): AsyncIterable<ReplayProgress>;
|
|
106
|
+
//# sourceMappingURL=replay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../../src/events/replay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,WAAW,aAAa;IAC5B,uCAAuC;IACvC,GAAG,EAAE,QAAQ,CAAC;IACd;kEAC8D;IAC9D,QAAQ,EAAE,YAAY,CAAC;IACvB,iEAAiE;IACjE,WAAW,IAAI,WAAW,CAAC;IAC3B;uEACmE;IACnE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iEAAiE;IACjE,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,4DAA4D;IAC5D,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;IACnE;oDACgD;IAChD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;mDAE+C;IAC/C,SAAS,CAAC,EAAE,QAAQ,CAAC;IACrB;gCAC4B;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,aAAa,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,aAAa,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GAC/E;IACE,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,aAAa,CAAC;IACrB,MAAM,EAAE,iBAAiB,GAAG,aAAa,GAAG,aAAa,GAAG,kBAAkB,CAAC;CAChF,GACD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACxD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAItF,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,SAAkB,IAAI,0BAA0B;CACjD;AAED,wBAAuB,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,aAAa,CAAC,cAAc,CAAC,CAyGtF"}
|