@femtomc/mu-control-plane 26.2.28
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/README.md +29 -0
- package/dist/adapter_audit.d.ts +27 -0
- package/dist/adapter_audit.d.ts.map +1 -0
- package/dist/adapter_audit.js +57 -0
- package/dist/channel_adapters.d.ts +53 -0
- package/dist/channel_adapters.d.ts.map +1 -0
- package/dist/channel_adapters.js +734 -0
- package/dist/command_context.d.ts +31 -0
- package/dist/command_context.d.ts.map +1 -0
- package/dist/command_context.js +221 -0
- package/dist/command_journal.d.ts +308 -0
- package/dist/command_journal.d.ts.map +1 -0
- package/dist/command_journal.js +197 -0
- package/dist/command_parser.d.ts +31 -0
- package/dist/command_parser.d.ts.map +1 -0
- package/dist/command_parser.js +130 -0
- package/dist/command_pipeline.d.ts +100 -0
- package/dist/command_pipeline.d.ts.map +1 -0
- package/dist/command_pipeline.js +637 -0
- package/dist/command_record.d.ts +89 -0
- package/dist/command_record.d.ts.map +1 -0
- package/dist/command_record.js +138 -0
- package/dist/command_state.d.ts +29 -0
- package/dist/command_state.d.ts.map +1 -0
- package/dist/command_state.js +64 -0
- package/dist/confirmation_manager.d.ts +54 -0
- package/dist/confirmation_manager.d.ts.map +1 -0
- package/dist/confirmation_manager.js +99 -0
- package/dist/idempotency_ledger.d.ts +84 -0
- package/dist/idempotency_ledger.d.ts.map +1 -0
- package/dist/idempotency_ledger.js +174 -0
- package/dist/identity_store.d.ts +219 -0
- package/dist/identity_store.d.ts.map +1 -0
- package/dist/identity_store.js +323 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/meta_agent.d.ts +127 -0
- package/dist/meta_agent.d.ts.map +1 -0
- package/dist/meta_agent.js +415 -0
- package/dist/models.d.ts +132 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +62 -0
- package/dist/mu_cli_runner.d.ts +76 -0
- package/dist/mu_cli_runner.d.ts.map +1 -0
- package/dist/mu_cli_runner.js +364 -0
- package/dist/operator_tooling.d.ts +19 -0
- package/dist/operator_tooling.d.ts.map +1 -0
- package/dist/operator_tooling.js +126 -0
- package/dist/outbox.d.ts +253 -0
- package/dist/outbox.d.ts.map +1 -0
- package/dist/outbox.js +313 -0
- package/dist/paths.d.ts +13 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +15 -0
- package/dist/policy.d.ts +182 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +434 -0
- package/dist/runtime.d.ts +79 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +260 -0
- package/dist/serialized_mutation_executor.d.ts +5 -0
- package/dist/serialized_mutation_executor.d.ts.map +1 -0
- package/dist/serialized_mutation_executor.js +8 -0
- package/dist/writer_lock.d.ts +28 -0
- package/dist/writer_lock.d.ts.map +1 -0
- package/dist/writer_lock.js +97 -0
- package/package.json +18 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { appendJsonl, readJsonl } from "@femtomc/mu-core/node";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { CommandRecordSchema, correlationFromCommandRecord } from "./command_record.js";
|
|
4
|
+
import { assertValidTransition, isTerminalCommandState, lifecycleEventTypeForState, } from "./command_state.js";
|
|
5
|
+
import { CorrelationMetadataSchema } from "./models.js";
|
|
6
|
+
export const CommandLifecycleJournalEntrySchema = z.object({
|
|
7
|
+
kind: z.literal("command.lifecycle"),
|
|
8
|
+
ts_ms: z.number().int(),
|
|
9
|
+
event_type: z.string().min(1),
|
|
10
|
+
command: CommandRecordSchema,
|
|
11
|
+
correlation: CorrelationMetadataSchema,
|
|
12
|
+
});
|
|
13
|
+
export const MutatingDomainJournalEntrySchema = z.object({
|
|
14
|
+
kind: z.literal("domain.mutating"),
|
|
15
|
+
ts_ms: z.number().int(),
|
|
16
|
+
event_type: z.string().min(1),
|
|
17
|
+
payload: z.record(z.string(), z.unknown()),
|
|
18
|
+
correlation: CorrelationMetadataSchema,
|
|
19
|
+
});
|
|
20
|
+
export const CommandJournalEntrySchema = z.discriminatedUnion("kind", [
|
|
21
|
+
CommandLifecycleJournalEntrySchema,
|
|
22
|
+
MutatingDomainJournalEntrySchema,
|
|
23
|
+
]);
|
|
24
|
+
function orderCommands(a, b) {
|
|
25
|
+
if (a.created_at_ms !== b.created_at_ms) {
|
|
26
|
+
return a.created_at_ms - b.created_at_ms;
|
|
27
|
+
}
|
|
28
|
+
return a.command_id.localeCompare(b.command_id);
|
|
29
|
+
}
|
|
30
|
+
function cloneCommandRecord(record) {
|
|
31
|
+
return CommandRecordSchema.parse(record);
|
|
32
|
+
}
|
|
33
|
+
function cloneLifecycleEntry(entry) {
|
|
34
|
+
return CommandLifecycleJournalEntrySchema.parse(entry);
|
|
35
|
+
}
|
|
36
|
+
function cloneMutatingEntry(entry) {
|
|
37
|
+
return MutatingDomainJournalEntrySchema.parse(entry);
|
|
38
|
+
}
|
|
39
|
+
export class CommandJournal {
|
|
40
|
+
#path;
|
|
41
|
+
#loaded = false;
|
|
42
|
+
#entries = [];
|
|
43
|
+
#latestByCommandId = new Map();
|
|
44
|
+
#lifecycleByCommandId = new Map();
|
|
45
|
+
#mutatingByCommandId = new Map();
|
|
46
|
+
constructor(path) {
|
|
47
|
+
this.#path = path;
|
|
48
|
+
}
|
|
49
|
+
get path() {
|
|
50
|
+
return this.#path;
|
|
51
|
+
}
|
|
52
|
+
async load() {
|
|
53
|
+
const rows = await readJsonl(this.#path);
|
|
54
|
+
const entries = [];
|
|
55
|
+
const latestByCommandId = new Map();
|
|
56
|
+
const lifecycleByCommandId = new Map();
|
|
57
|
+
const mutatingByCommandId = new Map();
|
|
58
|
+
for (let idx = 0; idx < rows.length; idx++) {
|
|
59
|
+
const parsed = CommandJournalEntrySchema.safeParse(rows[idx]);
|
|
60
|
+
if (!parsed.success) {
|
|
61
|
+
throw new Error(`invalid command journal row ${idx}: ${parsed.error.message}`);
|
|
62
|
+
}
|
|
63
|
+
const entry = parsed.data;
|
|
64
|
+
entries.push(entry);
|
|
65
|
+
if (entry.kind === "command.lifecycle") {
|
|
66
|
+
latestByCommandId.set(entry.command.command_id, entry.command);
|
|
67
|
+
const lifecycle = lifecycleByCommandId.get(entry.command.command_id) ?? [];
|
|
68
|
+
lifecycle.push(entry);
|
|
69
|
+
lifecycleByCommandId.set(entry.command.command_id, lifecycle);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
const arr = mutatingByCommandId.get(entry.correlation.command_id) ?? [];
|
|
73
|
+
arr.push(entry);
|
|
74
|
+
mutatingByCommandId.set(entry.correlation.command_id, arr);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
this.#entries = entries;
|
|
78
|
+
this.#latestByCommandId.clear();
|
|
79
|
+
this.#lifecycleByCommandId.clear();
|
|
80
|
+
this.#mutatingByCommandId.clear();
|
|
81
|
+
for (const [key, value] of latestByCommandId.entries()) {
|
|
82
|
+
this.#latestByCommandId.set(key, cloneCommandRecord(value));
|
|
83
|
+
}
|
|
84
|
+
for (const [key, value] of lifecycleByCommandId.entries()) {
|
|
85
|
+
this.#lifecycleByCommandId.set(key, value.map((entry) => cloneLifecycleEntry(entry)));
|
|
86
|
+
}
|
|
87
|
+
for (const [key, value] of mutatingByCommandId.entries()) {
|
|
88
|
+
this.#mutatingByCommandId.set(key, value.map((entry) => cloneMutatingEntry(entry)));
|
|
89
|
+
}
|
|
90
|
+
this.#loaded = true;
|
|
91
|
+
}
|
|
92
|
+
async #ensureLoaded() {
|
|
93
|
+
if (!this.#loaded) {
|
|
94
|
+
await this.load();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
get(commandId) {
|
|
98
|
+
const record = this.#latestByCommandId.get(commandId);
|
|
99
|
+
return record ? cloneCommandRecord(record) : null;
|
|
100
|
+
}
|
|
101
|
+
lifecycleEvents(commandId) {
|
|
102
|
+
const rows = this.#lifecycleByCommandId.get(commandId) ?? [];
|
|
103
|
+
return rows.map((entry) => cloneLifecycleEntry(entry));
|
|
104
|
+
}
|
|
105
|
+
hasMutatingEvents(commandId) {
|
|
106
|
+
const rows = this.#mutatingByCommandId.get(commandId);
|
|
107
|
+
return (rows?.length ?? 0) > 0;
|
|
108
|
+
}
|
|
109
|
+
mutatingEvents(commandId) {
|
|
110
|
+
const rows = this.#mutatingByCommandId.get(commandId) ?? [];
|
|
111
|
+
return rows.map((entry) => cloneMutatingEntry(entry));
|
|
112
|
+
}
|
|
113
|
+
nonTerminalCommands() {
|
|
114
|
+
const out = [];
|
|
115
|
+
for (const record of this.#latestByCommandId.values()) {
|
|
116
|
+
if (!isTerminalCommandState(record.state)) {
|
|
117
|
+
out.push(cloneCommandRecord(record));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
out.sort(orderCommands);
|
|
121
|
+
return out;
|
|
122
|
+
}
|
|
123
|
+
snapshot() {
|
|
124
|
+
const latestByCommandId = new Map();
|
|
125
|
+
for (const [key, value] of this.#latestByCommandId.entries()) {
|
|
126
|
+
latestByCommandId.set(key, cloneCommandRecord(value));
|
|
127
|
+
}
|
|
128
|
+
const lifecycleByCommandId = new Map();
|
|
129
|
+
for (const [key, value] of this.#lifecycleByCommandId.entries()) {
|
|
130
|
+
lifecycleByCommandId.set(key, value.map((entry) => cloneLifecycleEntry(entry)));
|
|
131
|
+
}
|
|
132
|
+
const mutatingByCommandId = new Map();
|
|
133
|
+
for (const [key, value] of this.#mutatingByCommandId.entries()) {
|
|
134
|
+
mutatingByCommandId.set(key, value.map((entry) => cloneMutatingEntry(entry)));
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
entries: this.#entries.map((entry) => CommandJournalEntrySchema.parse(entry)),
|
|
138
|
+
latestByCommandId,
|
|
139
|
+
lifecycleByCommandId,
|
|
140
|
+
mutatingByCommandId,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
async appendLifecycle(command, opts = {}) {
|
|
144
|
+
await this.#ensureLoaded();
|
|
145
|
+
const parsed = CommandRecordSchema.parse(command);
|
|
146
|
+
const previous = this.#latestByCommandId.get(parsed.command_id);
|
|
147
|
+
if (previous) {
|
|
148
|
+
assertValidTransition(previous.state, parsed.state);
|
|
149
|
+
if (parsed.created_at_ms !== previous.created_at_ms) {
|
|
150
|
+
throw new Error(`command ${parsed.command_id} created_at_ms changed across transitions (${previous.created_at_ms} -> ${parsed.created_at_ms})`);
|
|
151
|
+
}
|
|
152
|
+
if (parsed.updated_at_ms < previous.updated_at_ms) {
|
|
153
|
+
throw new Error(`command ${parsed.command_id} updated_at_ms regressed (${previous.updated_at_ms} -> ${parsed.updated_at_ms})`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const eventType = opts.eventType ?? lifecycleEventTypeForState(parsed.state);
|
|
157
|
+
const correlation = correlationFromCommandRecord(parsed);
|
|
158
|
+
const entry = CommandLifecycleJournalEntrySchema.parse({
|
|
159
|
+
kind: "command.lifecycle",
|
|
160
|
+
ts_ms: Math.trunc(opts.tsMs ?? parsed.updated_at_ms),
|
|
161
|
+
event_type: eventType,
|
|
162
|
+
command: parsed,
|
|
163
|
+
correlation,
|
|
164
|
+
});
|
|
165
|
+
await appendJsonl(this.#path, entry);
|
|
166
|
+
this.#entries.push(entry);
|
|
167
|
+
this.#latestByCommandId.set(parsed.command_id, cloneCommandRecord(parsed));
|
|
168
|
+
const lifecycle = this.#lifecycleByCommandId.get(parsed.command_id) ?? [];
|
|
169
|
+
lifecycle.push(cloneLifecycleEntry(entry));
|
|
170
|
+
this.#lifecycleByCommandId.set(parsed.command_id, lifecycle);
|
|
171
|
+
}
|
|
172
|
+
async appendMutatingDomainEvent(opts) {
|
|
173
|
+
await this.#ensureLoaded();
|
|
174
|
+
const parsedCommand = CommandRecordSchema.parse(opts.command);
|
|
175
|
+
const payload = opts.payload;
|
|
176
|
+
if (typeof payload !== "object" || payload == null || Array.isArray(payload)) {
|
|
177
|
+
throw new TypeError("payload must be an object");
|
|
178
|
+
}
|
|
179
|
+
const correlation = CorrelationMetadataSchema.parse({
|
|
180
|
+
...correlationFromCommandRecord(parsedCommand),
|
|
181
|
+
state: opts.state ?? parsedCommand.state,
|
|
182
|
+
error_code: opts.errorCode ?? parsedCommand.error_code ?? null,
|
|
183
|
+
});
|
|
184
|
+
const entry = MutatingDomainJournalEntrySchema.parse({
|
|
185
|
+
kind: "domain.mutating",
|
|
186
|
+
ts_ms: Math.trunc(opts.tsMs ?? parsedCommand.updated_at_ms),
|
|
187
|
+
event_type: opts.eventType,
|
|
188
|
+
payload,
|
|
189
|
+
correlation,
|
|
190
|
+
});
|
|
191
|
+
await appendJsonl(this.#path, entry);
|
|
192
|
+
this.#entries.push(entry);
|
|
193
|
+
const rows = this.#mutatingByCommandId.get(correlation.command_id) ?? [];
|
|
194
|
+
rows.push(cloneMutatingEntry(entry));
|
|
195
|
+
this.#mutatingByCommandId.set(correlation.command_id, rows);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export type CommandInvocation = "slash" | "mu_bang" | "mu_question";
|
|
2
|
+
export type ParsedCommand = {
|
|
3
|
+
kind: "noop";
|
|
4
|
+
reason: "not_command" | "empty_input";
|
|
5
|
+
raw: string;
|
|
6
|
+
} | {
|
|
7
|
+
kind: "invalid";
|
|
8
|
+
reason: "empty_command" | "missing_command_id";
|
|
9
|
+
raw: string;
|
|
10
|
+
} | {
|
|
11
|
+
kind: "command";
|
|
12
|
+
invocation: CommandInvocation;
|
|
13
|
+
requestedMode: "auto" | "mutation" | "readonly";
|
|
14
|
+
commandKey: string;
|
|
15
|
+
args: string[];
|
|
16
|
+
normalized: string;
|
|
17
|
+
} | {
|
|
18
|
+
kind: "confirm";
|
|
19
|
+
invocation: CommandInvocation;
|
|
20
|
+
requestedMode: "auto" | "mutation" | "readonly";
|
|
21
|
+
commandId: string;
|
|
22
|
+
normalized: string;
|
|
23
|
+
} | {
|
|
24
|
+
kind: "cancel";
|
|
25
|
+
invocation: CommandInvocation;
|
|
26
|
+
requestedMode: "auto" | "mutation" | "readonly";
|
|
27
|
+
commandId: string;
|
|
28
|
+
normalized: string;
|
|
29
|
+
};
|
|
30
|
+
export declare function parseSeriousWorkCommand(raw: string): ParsedCommand;
|
|
31
|
+
//# sourceMappingURL=command_parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command_parser.d.ts","sourceRoot":"","sources":["../src/command_parser.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,SAAS,GAAG,aAAa,CAAC;AAEpE,MAAM,MAAM,aAAa,GACtB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,aAAa,GAAG,aAAa,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACpE;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,eAAe,GAAG,oBAAoB,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAChF;IACA,IAAI,EAAE,SAAS,CAAC;IAChB,UAAU,EAAE,iBAAiB,CAAC;IAC9B,aAAa,EAAE,MAAM,GAAG,UAAU,GAAG,UAAU,CAAC;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CAClB,GACD;IACA,IAAI,EAAE,SAAS,CAAC;IAChB,UAAU,EAAE,iBAAiB,CAAC;IAC9B,aAAa,EAAE,MAAM,GAAG,UAAU,GAAG,UAAU,CAAC;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CAClB,GACD;IACA,IAAI,EAAE,QAAQ,CAAC;IACf,UAAU,EAAE,iBAAiB,CAAC;IAC9B,aAAa,EAAE,MAAM,GAAG,UAAU,GAAG,UAAU,CAAC;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CAClB,CAAC;AA8FL,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAwDlE"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
const KNOWN_THREE_TOKEN_COMMANDS = new Set([
|
|
2
|
+
"issue dep add",
|
|
3
|
+
"issue dep remove",
|
|
4
|
+
"kill-switch set",
|
|
5
|
+
"rate-limit override",
|
|
6
|
+
]);
|
|
7
|
+
const KNOWN_TWO_TOKEN_COMMANDS = new Set([
|
|
8
|
+
"issue get",
|
|
9
|
+
"issue list",
|
|
10
|
+
"issue create",
|
|
11
|
+
"issue update",
|
|
12
|
+
"issue claim",
|
|
13
|
+
"issue close",
|
|
14
|
+
"forum read",
|
|
15
|
+
"forum post",
|
|
16
|
+
"audit get",
|
|
17
|
+
"link begin",
|
|
18
|
+
"link finish",
|
|
19
|
+
"unlink self",
|
|
20
|
+
"grant scope",
|
|
21
|
+
"policy update",
|
|
22
|
+
"dlq list",
|
|
23
|
+
"dlq inspect",
|
|
24
|
+
"dlq replay",
|
|
25
|
+
"run start",
|
|
26
|
+
"run resume",
|
|
27
|
+
]);
|
|
28
|
+
const KNOWN_ONE_TOKEN_COMMANDS = new Set(["status", "ready", "revoke"]);
|
|
29
|
+
function parseInvocation(raw) {
|
|
30
|
+
const trimmed = raw.trim();
|
|
31
|
+
if (trimmed.length === 0) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
const slashMatch = /^\/mu(?:\s+(.*))?$/.exec(trimmed);
|
|
35
|
+
if (slashMatch) {
|
|
36
|
+
return {
|
|
37
|
+
invocation: "slash",
|
|
38
|
+
requestedMode: "auto",
|
|
39
|
+
body: (slashMatch[1] ?? "").trim(),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const textMatch = /^mu([!?])(?:\s+(.*))?$/.exec(trimmed);
|
|
43
|
+
if (!textMatch) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
invocation: textMatch[1] === "!" ? "mu_bang" : "mu_question",
|
|
48
|
+
requestedMode: textMatch[1] === "!" ? "mutation" : "readonly",
|
|
49
|
+
body: (textMatch[2] ?? "").trim(),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function splitTokens(body) {
|
|
53
|
+
return body
|
|
54
|
+
.split(/\s+/)
|
|
55
|
+
.map((token) => token.trim())
|
|
56
|
+
.filter((token) => token.length > 0);
|
|
57
|
+
}
|
|
58
|
+
function deriveCommandKey(tokensLower) {
|
|
59
|
+
if (tokensLower.length >= 3) {
|
|
60
|
+
const key = `${tokensLower[0]} ${tokensLower[1]} ${tokensLower[2]}`;
|
|
61
|
+
if (KNOWN_THREE_TOKEN_COMMANDS.has(key)) {
|
|
62
|
+
return { commandKey: key, tokenCount: 3 };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (tokensLower.length >= 2) {
|
|
66
|
+
const key = `${tokensLower[0]} ${tokensLower[1]}`;
|
|
67
|
+
if (KNOWN_TWO_TOKEN_COMMANDS.has(key)) {
|
|
68
|
+
return { commandKey: key, tokenCount: 2 };
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (KNOWN_ONE_TOKEN_COMMANDS.has(tokensLower[0])) {
|
|
72
|
+
return { commandKey: tokensLower[0], tokenCount: 1 };
|
|
73
|
+
}
|
|
74
|
+
if (tokensLower.length >= 2) {
|
|
75
|
+
return { commandKey: `${tokensLower[0]} ${tokensLower[1]}`, tokenCount: 2 };
|
|
76
|
+
}
|
|
77
|
+
return { commandKey: tokensLower[0], tokenCount: 1 };
|
|
78
|
+
}
|
|
79
|
+
export function parseSeriousWorkCommand(raw) {
|
|
80
|
+
const trimmed = raw.trim();
|
|
81
|
+
if (trimmed.length === 0) {
|
|
82
|
+
return { kind: "noop", reason: "empty_input", raw };
|
|
83
|
+
}
|
|
84
|
+
const invocation = parseInvocation(raw);
|
|
85
|
+
if (!invocation) {
|
|
86
|
+
return { kind: "noop", reason: "not_command", raw };
|
|
87
|
+
}
|
|
88
|
+
if (invocation.body.length === 0) {
|
|
89
|
+
return { kind: "invalid", reason: "empty_command", raw };
|
|
90
|
+
}
|
|
91
|
+
const tokens = splitTokens(invocation.body);
|
|
92
|
+
if (tokens.length === 0) {
|
|
93
|
+
return { kind: "invalid", reason: "empty_command", raw };
|
|
94
|
+
}
|
|
95
|
+
const lower = tokens.map((token) => token.toLowerCase());
|
|
96
|
+
if (lower[0] === "confirm") {
|
|
97
|
+
if (!tokens[1]) {
|
|
98
|
+
return { kind: "invalid", reason: "missing_command_id", raw };
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
kind: "confirm",
|
|
102
|
+
invocation: invocation.invocation,
|
|
103
|
+
requestedMode: invocation.requestedMode,
|
|
104
|
+
commandId: tokens[1],
|
|
105
|
+
normalized: `confirm ${tokens[1]}`,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
if (lower[0] === "cancel") {
|
|
109
|
+
if (!tokens[1]) {
|
|
110
|
+
return { kind: "invalid", reason: "missing_command_id", raw };
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
kind: "cancel",
|
|
114
|
+
invocation: invocation.invocation,
|
|
115
|
+
requestedMode: invocation.requestedMode,
|
|
116
|
+
commandId: tokens[1],
|
|
117
|
+
normalized: `cancel ${tokens[1]}`,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
const { commandKey, tokenCount } = deriveCommandKey(lower);
|
|
121
|
+
const args = tokens.slice(tokenCount);
|
|
122
|
+
return {
|
|
123
|
+
kind: "command",
|
|
124
|
+
invocation: invocation.invocation,
|
|
125
|
+
requestedMode: invocation.requestedMode,
|
|
126
|
+
commandKey,
|
|
127
|
+
args,
|
|
128
|
+
normalized: [commandKey, ...args].join(" ").trim(),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { CommandContextResolver } from "./command_context.js";
|
|
2
|
+
import { type CommandRecord, type CommandRecordTraceUpdate } from "./command_record.js";
|
|
3
|
+
import { ConfirmationManager } from "./confirmation_manager.js";
|
|
4
|
+
import { IdentityStore } from "./identity_store.js";
|
|
5
|
+
import type { MessagingMetaAgentRuntime } from "./meta_agent.js";
|
|
6
|
+
import { type InboundEnvelope } from "./models.js";
|
|
7
|
+
import { MuCliCommandSurface, type MuCliRunnerLike } from "./mu_cli_runner.js";
|
|
8
|
+
import { PolicyEngine } from "./policy.js";
|
|
9
|
+
import type { ControlPlaneRuntime } from "./runtime.js";
|
|
10
|
+
export type CommandPipelineResult = {
|
|
11
|
+
kind: "noop";
|
|
12
|
+
reason: string;
|
|
13
|
+
} | {
|
|
14
|
+
kind: "invalid";
|
|
15
|
+
reason: string;
|
|
16
|
+
} | {
|
|
17
|
+
kind: "meta_response";
|
|
18
|
+
message: string;
|
|
19
|
+
} | {
|
|
20
|
+
kind: "denied";
|
|
21
|
+
reason: string;
|
|
22
|
+
} | {
|
|
23
|
+
kind: "awaiting_confirmation";
|
|
24
|
+
command: CommandRecord;
|
|
25
|
+
} | {
|
|
26
|
+
kind: "completed";
|
|
27
|
+
command: CommandRecord;
|
|
28
|
+
} | {
|
|
29
|
+
kind: "cancelled";
|
|
30
|
+
command: CommandRecord;
|
|
31
|
+
} | {
|
|
32
|
+
kind: "expired";
|
|
33
|
+
command: CommandRecord;
|
|
34
|
+
} | {
|
|
35
|
+
kind: "deferred";
|
|
36
|
+
command: CommandRecord;
|
|
37
|
+
} | {
|
|
38
|
+
kind: "failed";
|
|
39
|
+
command: CommandRecord;
|
|
40
|
+
reason: string;
|
|
41
|
+
};
|
|
42
|
+
export type MutationCommandExecutionEvent = {
|
|
43
|
+
eventType: string;
|
|
44
|
+
payload: Record<string, unknown>;
|
|
45
|
+
};
|
|
46
|
+
export type CommandExecutionTrace = Pick<CommandRecordTraceUpdate, "metaSessionId" | "metaTurnId" | "cliInvocationId" | "cliCommandKind" | "runRootId">;
|
|
47
|
+
export type MutationCommandExecutionResult = {
|
|
48
|
+
terminalState: "completed";
|
|
49
|
+
result?: Record<string, unknown> | null;
|
|
50
|
+
errorCode?: string | null;
|
|
51
|
+
mutatingEvents?: readonly MutationCommandExecutionEvent[];
|
|
52
|
+
trace?: CommandExecutionTrace;
|
|
53
|
+
} | {
|
|
54
|
+
terminalState: "failed";
|
|
55
|
+
errorCode: string;
|
|
56
|
+
mutatingEvents?: readonly MutationCommandExecutionEvent[];
|
|
57
|
+
trace?: CommandExecutionTrace;
|
|
58
|
+
} | {
|
|
59
|
+
terminalState: "cancelled";
|
|
60
|
+
errorCode?: string | null;
|
|
61
|
+
mutatingEvents?: readonly MutationCommandExecutionEvent[];
|
|
62
|
+
trace?: CommandExecutionTrace;
|
|
63
|
+
} | {
|
|
64
|
+
terminalState: "deferred";
|
|
65
|
+
retryAtMs: number;
|
|
66
|
+
errorCode?: string | null;
|
|
67
|
+
mutatingEvents?: readonly MutationCommandExecutionEvent[];
|
|
68
|
+
trace?: CommandExecutionTrace;
|
|
69
|
+
};
|
|
70
|
+
export type MutationCommandExecutor = (record: CommandRecord) => Promise<MutationCommandExecutionResult | null>;
|
|
71
|
+
export type ReadonlyCommandExecutor = (record: CommandRecord) => Promise<Record<string, unknown> | null>;
|
|
72
|
+
export type ControlPlaneCommandPipelineOpts = {
|
|
73
|
+
runtime: ControlPlaneRuntime;
|
|
74
|
+
identityStore?: IdentityStore;
|
|
75
|
+
policyEngine?: PolicyEngine;
|
|
76
|
+
policyPath?: string;
|
|
77
|
+
confirmationTtlMs?: number;
|
|
78
|
+
nowMs?: () => number;
|
|
79
|
+
commandIdFactory?: () => string;
|
|
80
|
+
cliInvocationIdFactory?: () => string;
|
|
81
|
+
mutationExecutor?: MutationCommandExecutor;
|
|
82
|
+
readonlyExecutor?: ReadonlyCommandExecutor;
|
|
83
|
+
metaAgent?: MessagingMetaAgentRuntime | null;
|
|
84
|
+
contextResolver?: CommandContextResolver;
|
|
85
|
+
cliCommandSurface?: MuCliCommandSurface | null;
|
|
86
|
+
cliRunner?: MuCliRunnerLike | null;
|
|
87
|
+
};
|
|
88
|
+
export declare class ControlPlaneCommandPipeline {
|
|
89
|
+
#private;
|
|
90
|
+
readonly runtime: ControlPlaneRuntime;
|
|
91
|
+
readonly identities: IdentityStore;
|
|
92
|
+
readonly policy: PolicyEngine;
|
|
93
|
+
readonly confirmations: ConfirmationManager;
|
|
94
|
+
constructor(opts: ControlPlaneCommandPipelineOpts);
|
|
95
|
+
start(): Promise<void>;
|
|
96
|
+
stop(): Promise<void>;
|
|
97
|
+
handleInbound(inboundInput: InboundEnvelope): Promise<CommandPipelineResult>;
|
|
98
|
+
expirePendingConfirmations(nowMs?: number): Promise<CommandRecord[]>;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=command_pipeline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command_pipeline.d.ts","sourceRoot":"","sources":["../src/command_pipeline.ts"],"names":[],"mappings":"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"}
|