@katyella/legio 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/CHANGELOG.md +422 -0
- package/LICENSE +21 -0
- package/README.md +555 -0
- package/agents/builder.md +141 -0
- package/agents/coordinator.md +351 -0
- package/agents/cto.md +196 -0
- package/agents/gateway.md +276 -0
- package/agents/lead.md +281 -0
- package/agents/merger.md +156 -0
- package/agents/monitor.md +212 -0
- package/agents/reviewer.md +142 -0
- package/agents/scout.md +131 -0
- package/agents/supervisor.md +416 -0
- package/bin/legio.mjs +38 -0
- package/package.json +77 -0
- package/src/agents/checkpoint.test.ts +88 -0
- package/src/agents/checkpoint.ts +102 -0
- package/src/agents/hooks-deployer.test.ts +1820 -0
- package/src/agents/hooks-deployer.ts +574 -0
- package/src/agents/identity.test.ts +614 -0
- package/src/agents/identity.ts +385 -0
- package/src/agents/lifecycle.test.ts +202 -0
- package/src/agents/lifecycle.ts +184 -0
- package/src/agents/manifest.test.ts +558 -0
- package/src/agents/manifest.ts +297 -0
- package/src/agents/overlay.test.ts +592 -0
- package/src/agents/overlay.ts +316 -0
- package/src/beads/client.test.ts +210 -0
- package/src/beads/client.ts +227 -0
- package/src/beads/molecules.test.ts +320 -0
- package/src/beads/molecules.ts +209 -0
- package/src/commands/agents.test.ts +325 -0
- package/src/commands/agents.ts +286 -0
- package/src/commands/clean.test.ts +730 -0
- package/src/commands/clean.ts +653 -0
- package/src/commands/completions.test.ts +346 -0
- package/src/commands/completions.ts +950 -0
- package/src/commands/coordinator.test.ts +1524 -0
- package/src/commands/coordinator.ts +880 -0
- package/src/commands/costs.test.ts +1015 -0
- package/src/commands/costs.ts +473 -0
- package/src/commands/dashboard.test.ts +94 -0
- package/src/commands/dashboard.ts +607 -0
- package/src/commands/doctor.test.ts +295 -0
- package/src/commands/doctor.ts +213 -0
- package/src/commands/down.test.ts +308 -0
- package/src/commands/down.ts +124 -0
- package/src/commands/errors.test.ts +648 -0
- package/src/commands/errors.ts +255 -0
- package/src/commands/feed.test.ts +579 -0
- package/src/commands/feed.ts +368 -0
- package/src/commands/gateway.test.ts +698 -0
- package/src/commands/gateway.ts +419 -0
- package/src/commands/group.test.ts +262 -0
- package/src/commands/group.ts +539 -0
- package/src/commands/hooks.test.ts +292 -0
- package/src/commands/hooks.ts +210 -0
- package/src/commands/init.test.ts +211 -0
- package/src/commands/init.ts +622 -0
- package/src/commands/inspect.test.ts +670 -0
- package/src/commands/inspect.ts +455 -0
- package/src/commands/log.test.ts +1556 -0
- package/src/commands/log.ts +752 -0
- package/src/commands/logs.test.ts +379 -0
- package/src/commands/logs.ts +544 -0
- package/src/commands/mail.test.ts +1726 -0
- package/src/commands/mail.ts +926 -0
- package/src/commands/merge.test.ts +676 -0
- package/src/commands/merge.ts +374 -0
- package/src/commands/metrics.test.ts +444 -0
- package/src/commands/metrics.ts +150 -0
- package/src/commands/monitor.test.ts +151 -0
- package/src/commands/monitor.ts +394 -0
- package/src/commands/nudge.test.ts +230 -0
- package/src/commands/nudge.ts +373 -0
- package/src/commands/prime.test.ts +467 -0
- package/src/commands/prime.ts +386 -0
- package/src/commands/replay.test.ts +742 -0
- package/src/commands/replay.ts +367 -0
- package/src/commands/run.test.ts +443 -0
- package/src/commands/run.ts +365 -0
- package/src/commands/server.test.ts +626 -0
- package/src/commands/server.ts +298 -0
- package/src/commands/sling.test.ts +810 -0
- package/src/commands/sling.ts +700 -0
- package/src/commands/spec.test.ts +206 -0
- package/src/commands/spec.ts +171 -0
- package/src/commands/status.test.ts +276 -0
- package/src/commands/status.ts +339 -0
- package/src/commands/stop.test.ts +357 -0
- package/src/commands/stop.ts +119 -0
- package/src/commands/supervisor.test.ts +186 -0
- package/src/commands/supervisor.ts +544 -0
- package/src/commands/trace.test.ts +746 -0
- package/src/commands/trace.ts +332 -0
- package/src/commands/up.test.ts +597 -0
- package/src/commands/up.ts +275 -0
- package/src/commands/watch.test.ts +152 -0
- package/src/commands/watch.ts +238 -0
- package/src/commands/worktree.test.ts +648 -0
- package/src/commands/worktree.ts +266 -0
- package/src/config.test.ts +496 -0
- package/src/config.ts +616 -0
- package/src/doctor/agents.test.ts +448 -0
- package/src/doctor/agents.ts +396 -0
- package/src/doctor/config-check.test.ts +184 -0
- package/src/doctor/config-check.ts +185 -0
- package/src/doctor/consistency.test.ts +645 -0
- package/src/doctor/consistency.ts +294 -0
- package/src/doctor/databases.test.ts +284 -0
- package/src/doctor/databases.ts +211 -0
- package/src/doctor/dependencies.test.ts +150 -0
- package/src/doctor/dependencies.ts +179 -0
- package/src/doctor/logs.test.ts +244 -0
- package/src/doctor/logs.ts +295 -0
- package/src/doctor/merge-queue.test.ts +210 -0
- package/src/doctor/merge-queue.ts +144 -0
- package/src/doctor/structure.test.ts +285 -0
- package/src/doctor/structure.ts +195 -0
- package/src/doctor/types.ts +37 -0
- package/src/doctor/version.test.ts +130 -0
- package/src/doctor/version.ts +131 -0
- package/src/e2e/chat-flow.test.ts +346 -0
- package/src/e2e/init-sling-lifecycle.test.ts +288 -0
- package/src/errors.test.ts +21 -0
- package/src/errors.ts +246 -0
- package/src/events/store.test.ts +660 -0
- package/src/events/store.ts +344 -0
- package/src/events/tool-filter.test.ts +330 -0
- package/src/events/tool-filter.ts +126 -0
- package/src/global-setup.ts +14 -0
- package/src/index.ts +339 -0
- package/src/insights/analyzer.test.ts +466 -0
- package/src/insights/analyzer.ts +203 -0
- package/src/logging/color.test.ts +118 -0
- package/src/logging/color.ts +71 -0
- package/src/logging/logger.test.ts +812 -0
- package/src/logging/logger.ts +266 -0
- package/src/logging/reporter.test.ts +258 -0
- package/src/logging/reporter.ts +109 -0
- package/src/logging/sanitizer.test.ts +190 -0
- package/src/logging/sanitizer.ts +57 -0
- package/src/mail/broadcast.test.ts +203 -0
- package/src/mail/broadcast.ts +92 -0
- package/src/mail/client.test.ts +873 -0
- package/src/mail/client.ts +236 -0
- package/src/mail/store.test.ts +815 -0
- package/src/mail/store.ts +402 -0
- package/src/merge/queue.test.ts +449 -0
- package/src/merge/queue.ts +262 -0
- package/src/merge/resolver.test.ts +1453 -0
- package/src/merge/resolver.ts +759 -0
- package/src/metrics/store.test.ts +1167 -0
- package/src/metrics/store.ts +511 -0
- package/src/metrics/summary.test.ts +397 -0
- package/src/metrics/summary.ts +178 -0
- package/src/metrics/transcript.test.ts +643 -0
- package/src/metrics/transcript.ts +351 -0
- package/src/mulch/client.test.ts +547 -0
- package/src/mulch/client.ts +416 -0
- package/src/server/audit-store.test.ts +384 -0
- package/src/server/audit-store.ts +257 -0
- package/src/server/headless.test.ts +180 -0
- package/src/server/headless.ts +151 -0
- package/src/server/index.test.ts +241 -0
- package/src/server/index.ts +317 -0
- package/src/server/public/app.js +187 -0
- package/src/server/public/apple-touch-icon.png +0 -0
- package/src/server/public/components/agent-badge.js +37 -0
- package/src/server/public/components/data-table.js +114 -0
- package/src/server/public/components/gateway-chat.js +256 -0
- package/src/server/public/components/issue-card.js +96 -0
- package/src/server/public/components/layout.js +88 -0
- package/src/server/public/components/message-bubble.js +120 -0
- package/src/server/public/components/stat-card.js +26 -0
- package/src/server/public/components/terminal-panel.js +140 -0
- package/src/server/public/favicon-16.png +0 -0
- package/src/server/public/favicon-32.png +0 -0
- package/src/server/public/favicon.ico +0 -0
- package/src/server/public/favicon.png +0 -0
- package/src/server/public/index.html +64 -0
- package/src/server/public/lib/api.js +35 -0
- package/src/server/public/lib/markdown.js +8 -0
- package/src/server/public/lib/preact-setup.js +8 -0
- package/src/server/public/lib/state.js +99 -0
- package/src/server/public/lib/utils.js +309 -0
- package/src/server/public/lib/ws.js +79 -0
- package/src/server/public/views/chat.js +983 -0
- package/src/server/public/views/costs.js +692 -0
- package/src/server/public/views/dashboard.js +781 -0
- package/src/server/public/views/gateway-chat.js +622 -0
- package/src/server/public/views/inspect.js +399 -0
- package/src/server/public/views/issues.js +470 -0
- package/src/server/public/views/setup.js +94 -0
- package/src/server/public/views/task-detail.js +422 -0
- package/src/server/routes.test.ts +3816 -0
- package/src/server/routes.ts +1964 -0
- package/src/server/websocket.test.ts +288 -0
- package/src/server/websocket.ts +196 -0
- package/src/sessions/compat.test.ts +109 -0
- package/src/sessions/compat.ts +17 -0
- package/src/sessions/store.test.ts +969 -0
- package/src/sessions/store.ts +480 -0
- package/src/test-helpers.test.ts +97 -0
- package/src/test-helpers.ts +143 -0
- package/src/types.ts +708 -0
- package/src/watchdog/daemon.test.ts +1233 -0
- package/src/watchdog/daemon.ts +533 -0
- package/src/watchdog/health.test.ts +371 -0
- package/src/watchdog/health.ts +248 -0
- package/src/watchdog/triage.test.ts +162 -0
- package/src/watchdog/triage.ts +193 -0
- package/src/worktree/manager.test.ts +444 -0
- package/src/worktree/manager.ts +224 -0
- package/src/worktree/tmux.test.ts +1238 -0
- package/src/worktree/tmux.ts +644 -0
- package/templates/CLAUDE.md.tmpl +89 -0
- package/templates/hooks.json.tmpl +132 -0
- package/templates/overlay.md.tmpl +79 -0
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mulch CLI client.
|
|
3
|
+
*
|
|
4
|
+
* Wraps the `mulch` command-line tool for structured expertise operations.
|
|
5
|
+
* Uses node:child_process — zero runtime npm dependencies.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { spawn } from "node:child_process";
|
|
9
|
+
import { AgentError } from "../errors.ts";
|
|
10
|
+
import type {
|
|
11
|
+
MulchCompactResult,
|
|
12
|
+
MulchDiffResult,
|
|
13
|
+
MulchDoctorResult,
|
|
14
|
+
MulchLearnResult,
|
|
15
|
+
MulchPruneResult,
|
|
16
|
+
MulchReadyResult,
|
|
17
|
+
MulchStatus,
|
|
18
|
+
} from "../types.ts";
|
|
19
|
+
|
|
20
|
+
export interface MulchClient {
|
|
21
|
+
/** Generate a priming prompt, optionally scoped to specific domains. */
|
|
22
|
+
prime(
|
|
23
|
+
domains?: string[],
|
|
24
|
+
format?: "markdown" | "xml" | "json",
|
|
25
|
+
options?: {
|
|
26
|
+
files?: string[];
|
|
27
|
+
excludeDomain?: string[];
|
|
28
|
+
},
|
|
29
|
+
): Promise<string>;
|
|
30
|
+
|
|
31
|
+
/** Show domain statistics. */
|
|
32
|
+
status(): Promise<MulchStatus>;
|
|
33
|
+
|
|
34
|
+
/** Record an expertise entry for a domain. */
|
|
35
|
+
record(
|
|
36
|
+
domain: string,
|
|
37
|
+
options: {
|
|
38
|
+
type: string;
|
|
39
|
+
name?: string;
|
|
40
|
+
description?: string;
|
|
41
|
+
title?: string;
|
|
42
|
+
rationale?: string;
|
|
43
|
+
tags?: string[];
|
|
44
|
+
classification?: string;
|
|
45
|
+
stdin?: boolean;
|
|
46
|
+
evidenceBead?: string;
|
|
47
|
+
},
|
|
48
|
+
): Promise<void>;
|
|
49
|
+
|
|
50
|
+
/** Query expertise records, optionally scoped to a domain. */
|
|
51
|
+
query(domain?: string): Promise<string>;
|
|
52
|
+
|
|
53
|
+
/** Search records across all domains. */
|
|
54
|
+
search(query: string): Promise<string>;
|
|
55
|
+
|
|
56
|
+
/** Show expertise record changes since a git ref. */
|
|
57
|
+
diff(options?: { since?: string }): Promise<MulchDiffResult>;
|
|
58
|
+
|
|
59
|
+
/** Show changed files and suggest domains for recording learnings. */
|
|
60
|
+
learn(options?: { since?: string }): Promise<MulchLearnResult>;
|
|
61
|
+
|
|
62
|
+
/** Remove unused or stale records. */
|
|
63
|
+
prune(options?: { dryRun?: boolean }): Promise<MulchPruneResult>;
|
|
64
|
+
|
|
65
|
+
/** Run health checks on mulch repository. */
|
|
66
|
+
doctor(options?: { fix?: boolean }): Promise<MulchDoctorResult>;
|
|
67
|
+
|
|
68
|
+
/** Show recently added or updated expertise records. */
|
|
69
|
+
ready(options?: { limit?: number; domain?: string; since?: string }): Promise<MulchReadyResult>;
|
|
70
|
+
|
|
71
|
+
/** Compact and optimize domain storage. */
|
|
72
|
+
compact(
|
|
73
|
+
domain?: string,
|
|
74
|
+
options?: {
|
|
75
|
+
analyze?: boolean;
|
|
76
|
+
apply?: boolean;
|
|
77
|
+
auto?: boolean;
|
|
78
|
+
dryRun?: boolean;
|
|
79
|
+
minGroup?: number;
|
|
80
|
+
maxRecords?: number;
|
|
81
|
+
yes?: boolean;
|
|
82
|
+
records?: string[];
|
|
83
|
+
},
|
|
84
|
+
): Promise<MulchCompactResult>;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Run a shell command and capture its output.
|
|
89
|
+
*/
|
|
90
|
+
async function runCommand(
|
|
91
|
+
cmd: string[],
|
|
92
|
+
cwd: string,
|
|
93
|
+
): Promise<{ stdout: string; stderr: string; exitCode: number }> {
|
|
94
|
+
const [command, ...args] = cmd;
|
|
95
|
+
if (!command) throw new Error("Empty command");
|
|
96
|
+
return new Promise((resolve, reject) => {
|
|
97
|
+
const proc = spawn(command, args, {
|
|
98
|
+
cwd,
|
|
99
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
100
|
+
});
|
|
101
|
+
const chunks: { stdout: Buffer[]; stderr: Buffer[] } = { stdout: [], stderr: [] };
|
|
102
|
+
proc.stdout.on("data", (data: Buffer) => chunks.stdout.push(data));
|
|
103
|
+
proc.stderr.on("data", (data: Buffer) => chunks.stderr.push(data));
|
|
104
|
+
proc.on("error", reject);
|
|
105
|
+
proc.on("close", (code) => {
|
|
106
|
+
resolve({
|
|
107
|
+
stdout: Buffer.concat(chunks.stdout).toString(),
|
|
108
|
+
stderr: Buffer.concat(chunks.stderr).toString(),
|
|
109
|
+
exitCode: code ?? 1,
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Default mapping from glob patterns to mulch domain names.
|
|
117
|
+
* Used by inferDomainsFromFiles() when no custom map is provided.
|
|
118
|
+
*/
|
|
119
|
+
export const DEFAULT_DOMAIN_MAP: Record<string, string[]> = {
|
|
120
|
+
"src/commands/**": ["cli"],
|
|
121
|
+
"src/server/routes*": ["server"],
|
|
122
|
+
"src/server/public/**": ["frontend"],
|
|
123
|
+
"src/sessions/**": ["server"],
|
|
124
|
+
"src/metrics/**": ["server"],
|
|
125
|
+
"src/events/**": ["server"],
|
|
126
|
+
"src/mail/**": ["server"],
|
|
127
|
+
"src/agents/**": ["swarm"],
|
|
128
|
+
"src/worktree/**": ["swarm", "merge"],
|
|
129
|
+
"src/merge/**": ["merge"],
|
|
130
|
+
"src/beads/**": ["cli"],
|
|
131
|
+
"src/*.test.*": ["testing"],
|
|
132
|
+
"src/**/*.test.*": ["testing"],
|
|
133
|
+
"agents/**": ["swarm"],
|
|
134
|
+
"templates/**": ["swarm"],
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Convert a glob pattern to a regular expression and test it against a file path.
|
|
139
|
+
*
|
|
140
|
+
* Rules:
|
|
141
|
+
* - `**` in `/**\/` position matches zero or more path segments (including zero)
|
|
142
|
+
* - `**` at the end of pattern matches any remaining path
|
|
143
|
+
* - `*` matches any characters within a single path segment (no slashes)
|
|
144
|
+
* - All other regex special characters are escaped
|
|
145
|
+
*
|
|
146
|
+
* @internal
|
|
147
|
+
*/
|
|
148
|
+
function matchGlob(pattern: string, filePath: string): boolean {
|
|
149
|
+
let regexStr = "^";
|
|
150
|
+
let i = 0;
|
|
151
|
+
while (i < pattern.length) {
|
|
152
|
+
const ch = pattern[i];
|
|
153
|
+
if (ch === undefined) break;
|
|
154
|
+
if (ch === "*" && i + 1 < pattern.length && pattern[i + 1] === "*") {
|
|
155
|
+
// Check for /**/ in the middle of the pattern
|
|
156
|
+
if (i > 0 && pattern[i - 1] === "/" && i + 2 < pattern.length && pattern[i + 2] === "/") {
|
|
157
|
+
// /**/ → match zero or more path segments (consumes the trailing /)
|
|
158
|
+
regexStr += "(?:.*/)?";
|
|
159
|
+
i += 3; // skip **/
|
|
160
|
+
} else {
|
|
161
|
+
// ** at end (or start, or without surrounding slashes) → match anything
|
|
162
|
+
regexStr += ".*";
|
|
163
|
+
i += 2;
|
|
164
|
+
}
|
|
165
|
+
} else if (ch === "*") {
|
|
166
|
+
// * → match any chars within a single segment (no slashes)
|
|
167
|
+
regexStr += "[^/]*";
|
|
168
|
+
i++;
|
|
169
|
+
} else {
|
|
170
|
+
// Escape regex special chars
|
|
171
|
+
regexStr += ch.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
172
|
+
i++;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
regexStr += "$";
|
|
176
|
+
return new RegExp(regexStr).test(filePath);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Infer mulch domain names from a list of file paths using glob pattern matching.
|
|
181
|
+
*
|
|
182
|
+
* Maps file paths to domain names using the provided domain map (or DEFAULT_DOMAIN_MAP).
|
|
183
|
+
* Returns a deduplicated array of matched domain names.
|
|
184
|
+
*
|
|
185
|
+
* @param files - File paths to match (relative to project root)
|
|
186
|
+
* @param domainMap - Optional custom glob-to-domain mapping; falls back to DEFAULT_DOMAIN_MAP
|
|
187
|
+
* @returns Deduplicated array of matched domain names
|
|
188
|
+
*/
|
|
189
|
+
export function inferDomainsFromFiles(
|
|
190
|
+
files: readonly string[],
|
|
191
|
+
domainMap?: Record<string, string[]>,
|
|
192
|
+
): string[] {
|
|
193
|
+
const map = domainMap ?? DEFAULT_DOMAIN_MAP;
|
|
194
|
+
const domainsSet = new Set<string>();
|
|
195
|
+
for (const file of files) {
|
|
196
|
+
for (const [pattern, domains] of Object.entries(map)) {
|
|
197
|
+
if (matchGlob(pattern, file)) {
|
|
198
|
+
for (const domain of domains) {
|
|
199
|
+
domainsSet.add(domain);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return Array.from(domainsSet);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Create a MulchClient bound to the given working directory.
|
|
209
|
+
*
|
|
210
|
+
* @param cwd - Working directory where mulch commands should run
|
|
211
|
+
* @returns A MulchClient instance wrapping the mulch CLI
|
|
212
|
+
*/
|
|
213
|
+
export function createMulchClient(cwd: string): MulchClient {
|
|
214
|
+
async function runMulch(
|
|
215
|
+
args: string[],
|
|
216
|
+
context: string,
|
|
217
|
+
): Promise<{ stdout: string; stderr: string }> {
|
|
218
|
+
const { stdout, stderr, exitCode } = await runCommand(["mulch", ...args], cwd);
|
|
219
|
+
if (exitCode !== 0) {
|
|
220
|
+
throw new AgentError(`mulch ${context} failed (exit ${exitCode}): ${stderr.trim()}`);
|
|
221
|
+
}
|
|
222
|
+
return { stdout, stderr };
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return {
|
|
226
|
+
async prime(domains, format, options) {
|
|
227
|
+
const args = ["prime"];
|
|
228
|
+
if (domains && domains.length > 0) {
|
|
229
|
+
args.push(...domains);
|
|
230
|
+
}
|
|
231
|
+
if (format) {
|
|
232
|
+
args.push("--format", format);
|
|
233
|
+
}
|
|
234
|
+
if (options?.files && options.files.length > 0) {
|
|
235
|
+
args.push("--files", ...options.files);
|
|
236
|
+
}
|
|
237
|
+
if (options?.excludeDomain && options.excludeDomain.length > 0) {
|
|
238
|
+
args.push("--exclude-domain", ...options.excludeDomain);
|
|
239
|
+
}
|
|
240
|
+
const { stdout } = await runMulch(args, "prime");
|
|
241
|
+
return stdout;
|
|
242
|
+
},
|
|
243
|
+
|
|
244
|
+
async status() {
|
|
245
|
+
const { stdout } = await runMulch(["status", "--json"], "status");
|
|
246
|
+
const trimmed = stdout.trim();
|
|
247
|
+
if (trimmed === "") {
|
|
248
|
+
return { domains: [] };
|
|
249
|
+
}
|
|
250
|
+
try {
|
|
251
|
+
return JSON.parse(trimmed) as MulchStatus;
|
|
252
|
+
} catch {
|
|
253
|
+
throw new AgentError(
|
|
254
|
+
`Failed to parse JSON output from mulch status: ${trimmed.slice(0, 200)}`,
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
|
|
259
|
+
async record(domain, options) {
|
|
260
|
+
const args = ["record", domain, "--type", options.type];
|
|
261
|
+
if (options.name) {
|
|
262
|
+
args.push("--name", options.name);
|
|
263
|
+
}
|
|
264
|
+
if (options.description) {
|
|
265
|
+
args.push("--description", options.description);
|
|
266
|
+
}
|
|
267
|
+
if (options.title) {
|
|
268
|
+
args.push("--title", options.title);
|
|
269
|
+
}
|
|
270
|
+
if (options.rationale) {
|
|
271
|
+
args.push("--rationale", options.rationale);
|
|
272
|
+
}
|
|
273
|
+
if (options.tags && options.tags.length > 0) {
|
|
274
|
+
args.push("--tags", options.tags.join(","));
|
|
275
|
+
}
|
|
276
|
+
if (options.classification) {
|
|
277
|
+
args.push("--classification", options.classification);
|
|
278
|
+
}
|
|
279
|
+
if (options.stdin) {
|
|
280
|
+
args.push("--stdin");
|
|
281
|
+
}
|
|
282
|
+
if (options.evidenceBead) {
|
|
283
|
+
args.push("--evidence-bead", options.evidenceBead);
|
|
284
|
+
}
|
|
285
|
+
await runMulch(args, `record ${domain}`);
|
|
286
|
+
},
|
|
287
|
+
|
|
288
|
+
async query(domain) {
|
|
289
|
+
const args = ["query"];
|
|
290
|
+
if (domain) {
|
|
291
|
+
args.push(domain);
|
|
292
|
+
}
|
|
293
|
+
const { stdout } = await runMulch(args, "query");
|
|
294
|
+
return stdout;
|
|
295
|
+
},
|
|
296
|
+
|
|
297
|
+
async search(query) {
|
|
298
|
+
const { stdout } = await runMulch(["search", query], "search");
|
|
299
|
+
return stdout;
|
|
300
|
+
},
|
|
301
|
+
|
|
302
|
+
async diff(options) {
|
|
303
|
+
const args = ["diff", "--json"];
|
|
304
|
+
if (options?.since) {
|
|
305
|
+
args.push("--since", options.since);
|
|
306
|
+
}
|
|
307
|
+
const { stdout } = await runMulch(args, "diff");
|
|
308
|
+
const trimmed = stdout.trim();
|
|
309
|
+
try {
|
|
310
|
+
return JSON.parse(trimmed) as MulchDiffResult;
|
|
311
|
+
} catch {
|
|
312
|
+
throw new AgentError(`Failed to parse JSON from mulch diff: ${trimmed.slice(0, 200)}`);
|
|
313
|
+
}
|
|
314
|
+
},
|
|
315
|
+
|
|
316
|
+
async learn(options) {
|
|
317
|
+
const args = ["learn", "--json"];
|
|
318
|
+
if (options?.since) {
|
|
319
|
+
args.push("--since", options.since);
|
|
320
|
+
}
|
|
321
|
+
const { stdout } = await runMulch(args, "learn");
|
|
322
|
+
const trimmed = stdout.trim();
|
|
323
|
+
try {
|
|
324
|
+
return JSON.parse(trimmed) as MulchLearnResult;
|
|
325
|
+
} catch {
|
|
326
|
+
throw new AgentError(`Failed to parse JSON from mulch learn: ${trimmed.slice(0, 200)}`);
|
|
327
|
+
}
|
|
328
|
+
},
|
|
329
|
+
|
|
330
|
+
async prune(options) {
|
|
331
|
+
const args = ["prune", "--json"];
|
|
332
|
+
if (options?.dryRun) {
|
|
333
|
+
args.push("--dry-run");
|
|
334
|
+
}
|
|
335
|
+
const { stdout } = await runMulch(args, "prune");
|
|
336
|
+
const trimmed = stdout.trim();
|
|
337
|
+
try {
|
|
338
|
+
return JSON.parse(trimmed) as MulchPruneResult;
|
|
339
|
+
} catch {
|
|
340
|
+
throw new AgentError(`Failed to parse JSON from mulch prune: ${trimmed.slice(0, 200)}`);
|
|
341
|
+
}
|
|
342
|
+
},
|
|
343
|
+
|
|
344
|
+
async doctor(options) {
|
|
345
|
+
const args = ["doctor", "--json"];
|
|
346
|
+
if (options?.fix) {
|
|
347
|
+
args.push("--fix");
|
|
348
|
+
}
|
|
349
|
+
const { stdout } = await runMulch(args, "doctor");
|
|
350
|
+
const trimmed = stdout.trim();
|
|
351
|
+
try {
|
|
352
|
+
return JSON.parse(trimmed) as MulchDoctorResult;
|
|
353
|
+
} catch {
|
|
354
|
+
throw new AgentError(`Failed to parse JSON from mulch doctor: ${trimmed.slice(0, 200)}`);
|
|
355
|
+
}
|
|
356
|
+
},
|
|
357
|
+
|
|
358
|
+
async ready(options) {
|
|
359
|
+
const args = ["ready", "--json"];
|
|
360
|
+
if (options?.limit !== undefined) {
|
|
361
|
+
args.push("--limit", String(options.limit));
|
|
362
|
+
}
|
|
363
|
+
if (options?.domain) {
|
|
364
|
+
args.push("--domain", options.domain);
|
|
365
|
+
}
|
|
366
|
+
if (options?.since) {
|
|
367
|
+
args.push("--since", options.since);
|
|
368
|
+
}
|
|
369
|
+
const { stdout } = await runMulch(args, "ready");
|
|
370
|
+
const trimmed = stdout.trim();
|
|
371
|
+
try {
|
|
372
|
+
return JSON.parse(trimmed) as MulchReadyResult;
|
|
373
|
+
} catch {
|
|
374
|
+
throw new AgentError(`Failed to parse JSON from mulch ready: ${trimmed.slice(0, 200)}`);
|
|
375
|
+
}
|
|
376
|
+
},
|
|
377
|
+
|
|
378
|
+
async compact(domain, options) {
|
|
379
|
+
const args = ["compact", "--json"];
|
|
380
|
+
if (domain) {
|
|
381
|
+
args.push(domain);
|
|
382
|
+
}
|
|
383
|
+
if (options?.analyze) {
|
|
384
|
+
args.push("--analyze");
|
|
385
|
+
}
|
|
386
|
+
if (options?.apply) {
|
|
387
|
+
args.push("--apply");
|
|
388
|
+
}
|
|
389
|
+
if (options?.auto) {
|
|
390
|
+
args.push("--auto");
|
|
391
|
+
}
|
|
392
|
+
if (options?.dryRun) {
|
|
393
|
+
args.push("--dry-run");
|
|
394
|
+
}
|
|
395
|
+
if (options?.minGroup !== undefined) {
|
|
396
|
+
args.push("--min-group", String(options.minGroup));
|
|
397
|
+
}
|
|
398
|
+
if (options?.maxRecords !== undefined) {
|
|
399
|
+
args.push("--max-records", String(options.maxRecords));
|
|
400
|
+
}
|
|
401
|
+
if (options?.yes) {
|
|
402
|
+
args.push("--yes");
|
|
403
|
+
}
|
|
404
|
+
if (options?.records && options.records.length > 0) {
|
|
405
|
+
args.push("--records", options.records.join(","));
|
|
406
|
+
}
|
|
407
|
+
const { stdout } = await runMulch(args, domain ? `compact ${domain}` : "compact");
|
|
408
|
+
const trimmed = stdout.trim();
|
|
409
|
+
try {
|
|
410
|
+
return JSON.parse(trimmed) as MulchCompactResult;
|
|
411
|
+
} catch {
|
|
412
|
+
throw new AgentError(`Failed to parse JSON from mulch compact: ${trimmed.slice(0, 200)}`);
|
|
413
|
+
}
|
|
414
|
+
},
|
|
415
|
+
};
|
|
416
|
+
}
|