ikarmic-forge 0.0.0-stage → 4.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +62 -2
- package/dist/acp/server.d.ts +55 -0
- package/dist/acp/server.d.ts.map +1 -0
- package/dist/acp/server.js +276 -0
- package/dist/acp/server.js.map +1 -0
- package/dist/app.d.ts +22 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +159 -0
- package/dist/app.js.map +1 -0
- package/dist/bin/forge.d.ts +3 -0
- package/dist/bin/forge.d.ts.map +1 -0
- package/dist/bin/forge.js +786 -0
- package/dist/bin/forge.js.map +1 -0
- package/dist/chat-files.d.ts +45 -0
- package/dist/chat-files.d.ts.map +1 -0
- package/dist/chat-files.js +189 -0
- package/dist/chat-files.js.map +1 -0
- package/dist/clipboard.d.ts +38 -0
- package/dist/clipboard.d.ts.map +1 -0
- package/dist/clipboard.js +63 -0
- package/dist/clipboard.js.map +1 -0
- package/dist/commands/acp.d.ts +4 -0
- package/dist/commands/acp.d.ts.map +1 -0
- package/dist/commands/acp.js +36 -0
- package/dist/commands/acp.js.map +1 -0
- package/dist/commands/ai-comments.d.ts +9 -0
- package/dist/commands/ai-comments.d.ts.map +1 -0
- package/dist/commands/ai-comments.js +43 -0
- package/dist/commands/ai-comments.js.map +1 -0
- package/dist/commands/architect.d.ts +9 -0
- package/dist/commands/architect.d.ts.map +1 -0
- package/dist/commands/architect.js +27 -0
- package/dist/commands/architect.js.map +1 -0
- package/dist/commands/checkpoint.d.ts +10 -0
- package/dist/commands/checkpoint.d.ts.map +1 -0
- package/dist/commands/checkpoint.js +168 -0
- package/dist/commands/checkpoint.js.map +1 -0
- package/dist/commands/config.d.ts +15 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +180 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/diff.d.ts +29 -0
- package/dist/commands/diff.d.ts.map +1 -0
- package/dist/commands/diff.js +90 -0
- package/dist/commands/diff.js.map +1 -0
- package/dist/commands/hook.d.ts +10 -0
- package/dist/commands/hook.d.ts.map +1 -0
- package/dist/commands/hook.js +121 -0
- package/dist/commands/hook.js.map +1 -0
- package/dist/commands/mcp.d.ts +10 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +110 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/memory.d.ts +10 -0
- package/dist/commands/memory.d.ts.map +1 -0
- package/dist/commands/memory.js +77 -0
- package/dist/commands/memory.js.map +1 -0
- package/dist/commands/orchestrator.d.ts +22 -0
- package/dist/commands/orchestrator.d.ts.map +1 -0
- package/dist/commands/orchestrator.js +113 -0
- package/dist/commands/orchestrator.js.map +1 -0
- package/dist/commands/plugin.d.ts +3 -0
- package/dist/commands/plugin.d.ts.map +1 -0
- package/dist/commands/plugin.js +62 -0
- package/dist/commands/plugin.js.map +1 -0
- package/dist/commands/policy.d.ts +2 -0
- package/dist/commands/policy.d.ts.map +1 -0
- package/dist/commands/policy.js +21 -0
- package/dist/commands/policy.js.map +1 -0
- package/dist/commands/skill.d.ts +13 -0
- package/dist/commands/skill.d.ts.map +1 -0
- package/dist/commands/skill.js +194 -0
- package/dist/commands/skill.js.map +1 -0
- package/dist/commands/spec.d.ts +23 -0
- package/dist/commands/spec.d.ts.map +1 -0
- package/dist/commands/spec.js +147 -0
- package/dist/commands/spec.js.map +1 -0
- package/dist/commands/watch.d.ts +15 -0
- package/dist/commands/watch.d.ts.map +1 -0
- package/dist/commands/watch.js +83 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/commands/worktree.d.ts +22 -0
- package/dist/commands/worktree.d.ts.map +1 -0
- package/dist/commands/worktree.js +187 -0
- package/dist/commands/worktree.js.map +1 -0
- package/dist/components/Approval.d.ts +9 -0
- package/dist/components/Approval.d.ts.map +1 -0
- package/dist/components/Approval.js +39 -0
- package/dist/components/Approval.js.map +1 -0
- package/dist/components/Footer.d.ts +22 -0
- package/dist/components/Footer.d.ts.map +1 -0
- package/dist/components/Footer.js +59 -0
- package/dist/components/Footer.js.map +1 -0
- package/dist/components/Header.d.ts +11 -0
- package/dist/components/Header.d.ts.map +1 -0
- package/dist/components/Header.js +23 -0
- package/dist/components/Header.js.map +1 -0
- package/dist/components/Spinner.d.ts +3 -0
- package/dist/components/Spinner.d.ts.map +1 -0
- package/dist/components/Spinner.js +8 -0
- package/dist/components/Spinner.js.map +1 -0
- package/dist/components/Stream.d.ts +10 -0
- package/dist/components/Stream.d.ts.map +1 -0
- package/dist/components/Stream.js +13 -0
- package/dist/components/Stream.js.map +1 -0
- package/dist/components/ToolEvent.d.ts +13 -0
- package/dist/components/ToolEvent.d.ts.map +1 -0
- package/dist/components/ToolEvent.js +54 -0
- package/dist/components/ToolEvent.js.map +1 -0
- package/dist/credential-store.d.ts +8 -0
- package/dist/credential-store.d.ts.map +1 -0
- package/dist/credential-store.js +37 -0
- package/dist/credential-store.js.map +1 -0
- package/dist/git-workflow.d.ts +16 -0
- package/dist/git-workflow.d.ts.map +1 -0
- package/dist/git-workflow.js +38 -0
- package/dist/git-workflow.js.map +1 -0
- package/dist/mcp-loader.d.ts +25 -0
- package/dist/mcp-loader.d.ts.map +1 -0
- package/dist/mcp-loader.js +99 -0
- package/dist/mcp-loader.js.map +1 -0
- package/dist/notify.d.ts +12 -0
- package/dist/notify.d.ts.map +1 -0
- package/dist/notify.js +47 -0
- package/dist/notify.js.map +1 -0
- package/dist/options.d.ts +449 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +871 -0
- package/dist/options.js.map +1 -0
- package/dist/repl-commands.d.ts +92 -0
- package/dist/repl-commands.d.ts.map +1 -0
- package/dist/repl-commands.js +228 -0
- package/dist/repl-commands.js.map +1 -0
- package/dist/repl-extras.d.ts +39 -0
- package/dist/repl-extras.d.ts.map +1 -0
- package/dist/repl-extras.js +120 -0
- package/dist/repl-extras.js.map +1 -0
- package/dist/repl.d.ts +76 -0
- package/dist/repl.d.ts.map +1 -0
- package/dist/repl.js +1507 -0
- package/dist/repl.js.map +1 -0
- package/dist/runner.d.ts +64 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +61 -0
- package/dist/runner.js.map +1 -0
- package/dist/session-checkpoints.d.ts +6 -0
- package/dist/session-checkpoints.d.ts.map +1 -0
- package/dist/session-checkpoints.js +25 -0
- package/dist/session-checkpoints.js.map +1 -0
- package/dist/specialists-loader.d.ts +22 -0
- package/dist/specialists-loader.d.ts.map +1 -0
- package/dist/specialists-loader.js +38 -0
- package/dist/specialists-loader.js.map +1 -0
- package/dist/tool-display.d.ts +19 -0
- package/dist/tool-display.d.ts.map +1 -0
- package/dist/tool-display.js +57 -0
- package/dist/tool-display.js.map +1 -0
- package/package.json +70 -3
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `forge hook …` subcommand: list, test, log hooks.
|
|
3
|
+
*
|
|
4
|
+
* Hooks are loaded from `~/.forge/settings.json` + `.forge/settings.json`
|
|
5
|
+
* exactly the way the agent does, so what you see here matches what the
|
|
6
|
+
* agent runs.
|
|
7
|
+
*/
|
|
8
|
+
import { HOOK_EVENT_NAMES, HooksBus, loadHooksConfig } from '@ikarmic/forge-core';
|
|
9
|
+
export async function handleHookCommand(cmd, cwd) {
|
|
10
|
+
if (cmd.list) {
|
|
11
|
+
return listHooks(cwd);
|
|
12
|
+
}
|
|
13
|
+
if (cmd.test) {
|
|
14
|
+
return testHook(cwd, cmd.test.event, cmd.test.tool);
|
|
15
|
+
}
|
|
16
|
+
if (cmd.log) {
|
|
17
|
+
process.stderr.write('forge hook log: not yet implemented (run the agent with hooks configured; entries appear in memory until you wire a logger)\n');
|
|
18
|
+
return 2;
|
|
19
|
+
}
|
|
20
|
+
process.stderr.write(`forge hook: expected one of list|test|log. Events: ${HOOK_EVENT_NAMES.join(', ')}\n`);
|
|
21
|
+
return 2;
|
|
22
|
+
}
|
|
23
|
+
async function listHooks(cwd) {
|
|
24
|
+
const { config, sources, warnings } = await loadHooksConfig(cwd);
|
|
25
|
+
if (sources.length === 0) {
|
|
26
|
+
process.stdout.write('(no hooks configured: neither ~/.forge/settings.json nor .forge/settings.json exists)\n');
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
process.stdout.write(`Sources:\n${sources.map((s) => ` ${s}`).join('\n')}\n\n`);
|
|
30
|
+
const events = Object.keys(config);
|
|
31
|
+
if (events.length === 0) {
|
|
32
|
+
process.stdout.write('(no hooks defined in any settings file)\n');
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
for (const event of events) {
|
|
36
|
+
const entries = config[event] ?? [];
|
|
37
|
+
process.stdout.write(`${event}:\n`);
|
|
38
|
+
for (const entry of entries) {
|
|
39
|
+
for (const hook of entry.hooks) {
|
|
40
|
+
const timeout = hook.timeout ? ` (timeout ${hook.timeout}ms)` : '';
|
|
41
|
+
process.stdout.write(` [${entry.matcher || '*'}] ${hook.type}: ${hook.type === 'agent' ? hook.prompt : hook.command}${timeout}\n`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (warnings.length > 0) {
|
|
46
|
+
process.stdout.write('\nWarnings:\n');
|
|
47
|
+
for (const w of warnings)
|
|
48
|
+
process.stdout.write(` ${w}\n`);
|
|
49
|
+
}
|
|
50
|
+
return 0;
|
|
51
|
+
}
|
|
52
|
+
async function testHook(cwd, eventName, toolName) {
|
|
53
|
+
if (!HOOK_EVENT_NAMES.includes(eventName)) {
|
|
54
|
+
process.stderr.write(`forge hook test: unknown event "${eventName}". Known: ${HOOK_EVENT_NAMES.join(', ')}\n`);
|
|
55
|
+
return 2;
|
|
56
|
+
}
|
|
57
|
+
const { config, warnings } = await loadHooksConfig(cwd);
|
|
58
|
+
if (warnings.length > 0) {
|
|
59
|
+
process.stdout.write('Warnings:\n');
|
|
60
|
+
for (const w of warnings)
|
|
61
|
+
process.stdout.write(` ${w}\n`);
|
|
62
|
+
}
|
|
63
|
+
const bus = new HooksBus(config);
|
|
64
|
+
const synthetic = syntheticEventFor(eventName, toolName, cwd);
|
|
65
|
+
process.stdout.write(`dispatching synthetic ${eventName}${toolName ? ` (tool=${toolName})` : ''}...\n`);
|
|
66
|
+
const log = await bus.dispatch(synthetic);
|
|
67
|
+
if (log.results.length === 0) {
|
|
68
|
+
process.stdout.write('(no hooks matched: nothing ran)\n');
|
|
69
|
+
return 0;
|
|
70
|
+
}
|
|
71
|
+
for (const r of log.results) {
|
|
72
|
+
process.stdout.write(`\n command: ${r.command}\n`);
|
|
73
|
+
process.stdout.write(` exit: ${r.exitCode === null ? 'killed' : r.exitCode}\n`);
|
|
74
|
+
process.stdout.write(` timeout: ${r.timedOut}\n`);
|
|
75
|
+
if (r.stdout)
|
|
76
|
+
process.stdout.write(` stdout: ${r.stdout.trim()}\n`);
|
|
77
|
+
if (r.stderr)
|
|
78
|
+
process.stdout.write(` stderr: ${r.stderr.trim()}\n`);
|
|
79
|
+
if (r.error)
|
|
80
|
+
process.stdout.write(` error: ${r.error}\n`);
|
|
81
|
+
process.stdout.write(` dur: ${r.durationMs}ms\n`);
|
|
82
|
+
}
|
|
83
|
+
return 0;
|
|
84
|
+
}
|
|
85
|
+
function syntheticEventFor(event, toolName, cwd) {
|
|
86
|
+
const t = toolName ?? 'read_file';
|
|
87
|
+
switch (event) {
|
|
88
|
+
case 'SessionStart':
|
|
89
|
+
return { type: event, cwd, startedAt: Date.now() };
|
|
90
|
+
case 'SessionEnd':
|
|
91
|
+
return { type: event, cwd, reason: 'completed', endedAt: Date.now() };
|
|
92
|
+
case 'UserPromptSubmit':
|
|
93
|
+
return { type: event, prompt: 'test prompt', cwd };
|
|
94
|
+
case 'PreToolUse':
|
|
95
|
+
return { type: event, toolName: t, toolArgs: { path: '.' }, toolCallId: 'test-call', cwd };
|
|
96
|
+
case 'PostToolUse':
|
|
97
|
+
return {
|
|
98
|
+
type: event,
|
|
99
|
+
toolName: t,
|
|
100
|
+
toolArgs: { path: '.' },
|
|
101
|
+
toolCallId: 'test-call',
|
|
102
|
+
result: '(synthetic result)',
|
|
103
|
+
isError: false,
|
|
104
|
+
durationMs: 0,
|
|
105
|
+
cwd,
|
|
106
|
+
};
|
|
107
|
+
case 'PreCompact':
|
|
108
|
+
return { type: event, messagesCount: 10, tokens: 1000, cwd };
|
|
109
|
+
case 'SubagentStart':
|
|
110
|
+
return { type: event, task: 'synthetic subagent task', cwd, startedAt: Date.now() };
|
|
111
|
+
case 'SubagentStop':
|
|
112
|
+
return { type: event, task: 'synthetic subagent task', cwd, endedAt: Date.now(), reason: 'completed' };
|
|
113
|
+
case 'Notification':
|
|
114
|
+
return { type: event, message: 'synthetic notification', level: 'info', cwd };
|
|
115
|
+
case 'Stop':
|
|
116
|
+
return { type: event, reason: 'completed', cwd };
|
|
117
|
+
case 'FileChanged':
|
|
118
|
+
return { type: event, path: 'synthetic/path.ts', changeType: 'modified', cwd };
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=hook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook.js","sourceRoot":"","sources":["../../src/commands/hook.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `forge mcp …` subcommand: list, install, remove, browse MCP servers.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors `forge session …` / `forge skill …` / `forge hook …`: soft
|
|
5
|
+
* prefix, no AI provider required, exits 0 on success / 2 on user
|
|
6
|
+
* error / 1 on unexpected failure.
|
|
7
|
+
*/
|
|
8
|
+
import type { ParsedMcpCommand } from '../options.js';
|
|
9
|
+
export declare function handleMcpCommand(cmd: ParsedMcpCommand, _cwd: string): Promise<number>;
|
|
10
|
+
//# sourceMappingURL=mcp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAcH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAOtD,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAiB3F"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `forge mcp …` subcommand: list, install, remove, browse MCP servers.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors `forge session …` / `forge skill …` / `forge hook …`: soft
|
|
5
|
+
* prefix, no AI provider required, exits 0 on success / 2 on user
|
|
6
|
+
* error / 1 on unexpected failure.
|
|
7
|
+
*/
|
|
8
|
+
import { execFileSync } from 'node:child_process';
|
|
9
|
+
import process from 'node:process';
|
|
10
|
+
import { defaultUserMcpPath, installMcpServer, listInstalledServers, MARKETPLACE_CATALOG_VERSION, uninstallMcpServer, } from '@ikarmic/forge-core';
|
|
11
|
+
/** Public marketplace catalog (placeholder for v1). When the marketplace
|
|
12
|
+
* repo ships in Tier 2 we'll fetch this over HTTP. For now we point at
|
|
13
|
+
* the canonical URL and let users browse by hand. */
|
|
14
|
+
const MARKETPLACE_CATALOG_URL = 'https://github.com/ikarmicai/forge-mcp-registry';
|
|
15
|
+
export async function handleMcpCommand(cmd, _cwd) {
|
|
16
|
+
if (cmd.list) {
|
|
17
|
+
return listInstalled();
|
|
18
|
+
}
|
|
19
|
+
if (cmd.install) {
|
|
20
|
+
return installFromSource(cmd.install.source, { overwrite: cmd.install.overwrite });
|
|
21
|
+
}
|
|
22
|
+
if (cmd.remove) {
|
|
23
|
+
return removeServer(cmd.remove.name);
|
|
24
|
+
}
|
|
25
|
+
if (cmd.browse) {
|
|
26
|
+
return browseMarketplace();
|
|
27
|
+
}
|
|
28
|
+
process.stderr.write('forge mcp: expected one of list|install|remove|browse. Try `forge mcp --help` (not yet implemented; read the README).\n');
|
|
29
|
+
return 2;
|
|
30
|
+
}
|
|
31
|
+
async function listInstalled() {
|
|
32
|
+
const installed = await listInstalledServers();
|
|
33
|
+
if (installed.length === 0) {
|
|
34
|
+
process.stdout.write('(no MCP servers installed: try `forge mcp browse`)\n');
|
|
35
|
+
return 0;
|
|
36
|
+
}
|
|
37
|
+
for (const server of installed) {
|
|
38
|
+
process.stdout.write(`${server.name}`);
|
|
39
|
+
if (server.displayName)
|
|
40
|
+
process.stdout.write(` (${server.displayName})`);
|
|
41
|
+
process.stdout.write('\n');
|
|
42
|
+
process.stdout.write(` source: ${server.source}\n`);
|
|
43
|
+
process.stdout.write(` path: ${server.installPath}\n`);
|
|
44
|
+
if (server.installedAt)
|
|
45
|
+
process.stdout.write(` since: ${server.installedAt}\n`);
|
|
46
|
+
const cfg = server.serverConfig;
|
|
47
|
+
if (cfg.command) {
|
|
48
|
+
process.stdout.write(` spawn: ${cfg.command}${cfg.args ? ' ' + cfg.args.join(' ') : ''}\n`);
|
|
49
|
+
}
|
|
50
|
+
else if (cfg.url) {
|
|
51
|
+
process.stdout.write(` url: ${cfg.type ?? 'sse'}: ${cfg.url}\n`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return 0;
|
|
55
|
+
}
|
|
56
|
+
async function installFromSource(source, opts) {
|
|
57
|
+
// Quick pre-check: is `git` on PATH? The installer shells out to git
|
|
58
|
+
// for the clone step; without it we'd surface a confusing ENOENT later.
|
|
59
|
+
if (!hasGit()) {
|
|
60
|
+
process.stderr.write('forge mcp install: this command shells out to `git` for the clone step. Install git and retry.\n');
|
|
61
|
+
return 1;
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
const installed = await installMcpServer({
|
|
65
|
+
source,
|
|
66
|
+
overwrite: opts.overwrite ?? false,
|
|
67
|
+
});
|
|
68
|
+
process.stdout.write(`installed ${installed.name} → ${installed.installPath}\n`);
|
|
69
|
+
process.stdout.write(`registered in ${defaultUserMcpPath()}\n`);
|
|
70
|
+
process.stdout.write('Run `forge mcp list` to verify; remove with `forge mcp remove <name>`.\n');
|
|
71
|
+
return 0;
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
process.stderr.write(`forge mcp install: ${err.message}\n`);
|
|
75
|
+
return 1;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async function removeServer(name) {
|
|
79
|
+
try {
|
|
80
|
+
const { removed } = await uninstallMcpServer({ name });
|
|
81
|
+
if (removed) {
|
|
82
|
+
process.stdout.write(`removed ${name}\n`);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
process.stdout.write(`${name} was not installed (nothing to do)\n`);
|
|
86
|
+
}
|
|
87
|
+
return 0;
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
process.stderr.write(`forge mcp remove: ${err.message}\n`);
|
|
91
|
+
return 1;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function browseMarketplace() {
|
|
95
|
+
process.stdout.write(`IKarmic Forge MCP Marketplace (catalog v${MARKETPLACE_CATALOG_VERSION}):\n ${MARKETPLACE_CATALOG_URL}\n\n`);
|
|
96
|
+
process.stdout.write('Browse community MCP servers there. To install one:\n');
|
|
97
|
+
process.stdout.write(' forge mcp install <github-url> # any GitHub repo with mcp.json\n');
|
|
98
|
+
process.stdout.write(' forge mcp install <owner/repo[#subdir]> # shorthand\n');
|
|
99
|
+
return 0;
|
|
100
|
+
}
|
|
101
|
+
function hasGit() {
|
|
102
|
+
try {
|
|
103
|
+
execFileSync('git', ['--version'], { stdio: 'ignore', windowsHide: true });
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=mcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `forge memory list|check|forget` subcommand: inspect and prune project
|
|
3
|
+
* memory (`.forge/MEMORY.md` and `~/.forge/MEMORY.md`).
|
|
4
|
+
*
|
|
5
|
+
* Needs no AI provider. Exit codes: 0 ok, 1 `check` found stale sections or
|
|
6
|
+
* `forget` found nothing, 2 usage error.
|
|
7
|
+
*/
|
|
8
|
+
import type { ParsedMemoryCommand } from '../options.js';
|
|
9
|
+
export declare function handleMemoryCommand(cmd: ParsedMemoryCommand, cwd: string): Promise<number>;
|
|
10
|
+
//# sourceMappingURL=memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/commands/memory.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAgBH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAKzD,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,mBAAmB,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMhG"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `forge memory list|check|forget` subcommand: inspect and prune project
|
|
3
|
+
* memory (`.forge/MEMORY.md` and `~/.forge/MEMORY.md`).
|
|
4
|
+
*
|
|
5
|
+
* Needs no AI provider. Exit codes: 0 ok, 1 `check` found stale sections or
|
|
6
|
+
* `forget` found nothing, 2 usage error.
|
|
7
|
+
*/
|
|
8
|
+
import { checkStale, findProjectMemoryRoot, globalMemoryPath, loadMemory, projectMemoryPath, readMemoryFile, removeSection, staleKey, tokenize, writeMemoryFile, } from '@ikarmic/forge-core';
|
|
9
|
+
/** Two sections whose heading+body word sets overlap at least this much are flagged as likely duplicates. */
|
|
10
|
+
const DUPLICATE_SIMILARITY = 0.6;
|
|
11
|
+
export async function handleMemoryCommand(cmd, cwd) {
|
|
12
|
+
if (cmd.list)
|
|
13
|
+
return listMemory(cwd);
|
|
14
|
+
if (cmd.check)
|
|
15
|
+
return checkMemory(cwd);
|
|
16
|
+
if (cmd.forget)
|
|
17
|
+
return forgetSection(cwd, cmd.forget.heading, cmd.forget.global);
|
|
18
|
+
process.stderr.write('forge memory: expected one of list|check|forget <heading> [--global].\n');
|
|
19
|
+
return 2;
|
|
20
|
+
}
|
|
21
|
+
const day = (ms) => new Date(ms).toISOString().slice(0, 10);
|
|
22
|
+
const scopeOf = (s) => (s.source === globalMemoryPath() ? 'global' : 'project');
|
|
23
|
+
async function listMemory(cwd) {
|
|
24
|
+
const { sections } = await loadMemory(cwd);
|
|
25
|
+
if (sections.length === 0) {
|
|
26
|
+
process.stdout.write('(no memory found)\n');
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
for (const s of sections) {
|
|
30
|
+
process.stdout.write(`${scopeOf(s)} ${s.type} ${day(s.updatedAt)} ${s.heading}\n`);
|
|
31
|
+
}
|
|
32
|
+
return 0;
|
|
33
|
+
}
|
|
34
|
+
function similarity(a, b) {
|
|
35
|
+
const wa = new Set(tokenize(`${a.heading} ${a.body}`));
|
|
36
|
+
const wb = new Set(tokenize(`${b.heading} ${b.body}`));
|
|
37
|
+
if (wa.size === 0 || wb.size === 0)
|
|
38
|
+
return 0;
|
|
39
|
+
let shared = 0;
|
|
40
|
+
for (const w of wa)
|
|
41
|
+
if (wb.has(w))
|
|
42
|
+
shared++;
|
|
43
|
+
return shared / (wa.size + wb.size - shared);
|
|
44
|
+
}
|
|
45
|
+
async function checkMemory(cwd) {
|
|
46
|
+
const { sections } = await loadMemory(cwd);
|
|
47
|
+
const root = (await findProjectMemoryRoot(cwd)) ?? cwd;
|
|
48
|
+
const stale = await checkStale(sections, root);
|
|
49
|
+
for (const s of sections) {
|
|
50
|
+
const reasons = stale.get(staleKey(s));
|
|
51
|
+
if (reasons)
|
|
52
|
+
process.stdout.write(`stale: ${s.heading} — ${reasons.join('; ')}\n`);
|
|
53
|
+
}
|
|
54
|
+
for (let i = 0; i < sections.length; i++) {
|
|
55
|
+
for (let j = i + 1; j < sections.length; j++) {
|
|
56
|
+
if (similarity(sections[i], sections[j]) >= DUPLICATE_SIMILARITY) {
|
|
57
|
+
process.stdout.write(`duplicate?: ${sections[i].heading} ~ ${sections[j].heading}\n`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (stale.size === 0)
|
|
62
|
+
process.stdout.write('no stale sections\n');
|
|
63
|
+
return stale.size > 0 ? 1 : 0;
|
|
64
|
+
}
|
|
65
|
+
async function forgetSection(cwd, heading, global) {
|
|
66
|
+
const root = await findProjectMemoryRoot(cwd);
|
|
67
|
+
const target = global ? globalMemoryPath() : projectMemoryPath(root ?? cwd);
|
|
68
|
+
const { content, removed } = removeSection(await readMemoryFile(target), heading);
|
|
69
|
+
if (!removed) {
|
|
70
|
+
process.stderr.write(`forge memory: no section named "${heading}" in ${target}\n`);
|
|
71
|
+
return 1;
|
|
72
|
+
}
|
|
73
|
+
await writeMemoryFile(target, content);
|
|
74
|
+
process.stdout.write(`removed "${heading}" from ${target}\n`);
|
|
75
|
+
return 0;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/commands/memory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `forge orchestrator …` subcommand: multi-agent routing.
|
|
3
|
+
*
|
|
4
|
+
* `forge orchestrator list`: show available specialists
|
|
5
|
+
* `forge orchestrator run "<task>"`: dispatch the task via the orchestrator
|
|
6
|
+
* `forge orchestrator plan "<task>"`: preview the routing plan without running it
|
|
7
|
+
*
|
|
8
|
+
* Mirrors the other soft-prefix subcommands: no special parsing,
|
|
9
|
+
* exits 0/1/2.
|
|
10
|
+
*/
|
|
11
|
+
import type { ParsedOrchestratorCommand } from '../options.js';
|
|
12
|
+
export declare function handleOrchestratorCommand(cmd: ParsedOrchestratorCommand, cwd: string, model: {
|
|
13
|
+
provider: string;
|
|
14
|
+
model: string;
|
|
15
|
+
}, options?: {
|
|
16
|
+
worktrees?: 'auto' | 'always' | 'never';
|
|
17
|
+
/** v2.14: delete orchestrator-created branches alongside their worktrees. */
|
|
18
|
+
cleanupBranches?: boolean;
|
|
19
|
+
/** Commit worktree specialists' edits onto kept branches. */
|
|
20
|
+
commitChanges?: boolean;
|
|
21
|
+
}): Promise<number>;
|
|
22
|
+
//# sourceMappingURL=orchestrator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/commands/orchestrator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAYH,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAE/D,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,yBAAyB,EAC9B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAC1C,OAAO,GAAE;IACP,SAAS,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IACxC,6EAA6E;IAC7E,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,6DAA6D;IAC7D,aAAa,CAAC,EAAE,OAAO,CAAC;CACpB,GACL,OAAO,CAAC,MAAM,CAAC,CAmBjB"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `forge orchestrator …` subcommand: multi-agent routing.
|
|
3
|
+
*
|
|
4
|
+
* `forge orchestrator list`: show available specialists
|
|
5
|
+
* `forge orchestrator run "<task>"`: dispatch the task via the orchestrator
|
|
6
|
+
* `forge orchestrator plan "<task>"`: preview the routing plan without running it
|
|
7
|
+
*
|
|
8
|
+
* Mirrors the other soft-prefix subcommands: no special parsing,
|
|
9
|
+
* exits 0/1/2.
|
|
10
|
+
*/
|
|
11
|
+
import process from 'node:process';
|
|
12
|
+
import { BUILTIN_SPECIALISTS, listSpecialists, parseRouterOutput, runOrchestrator, runRouter, } from '@ikarmic/forge-core';
|
|
13
|
+
export async function handleOrchestratorCommand(cmd, cwd, model, options = {}) {
|
|
14
|
+
if (cmd.list) {
|
|
15
|
+
return printSpecialistsList();
|
|
16
|
+
}
|
|
17
|
+
if (cmd.run) {
|
|
18
|
+
return runOrchestratorCli(cmd.run.task, cwd, model, {
|
|
19
|
+
preview: false,
|
|
20
|
+
worktrees: options.worktrees ?? 'auto',
|
|
21
|
+
cleanupBranches: options.cleanupBranches ?? true,
|
|
22
|
+
commitChanges: options.commitChanges ?? false,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
if (cmd.plan) {
|
|
26
|
+
return runOrchestratorCli(cmd.plan.task, cwd, model, { preview: true });
|
|
27
|
+
}
|
|
28
|
+
process.stderr.write('forge orchestrator: expected one of list|run|plan. Try `forge orchestrator --help` (not yet implemented; read docs/ORCHESTRATOR.md).\n');
|
|
29
|
+
return 2;
|
|
30
|
+
}
|
|
31
|
+
async function printSpecialistsList() {
|
|
32
|
+
const builtinIds = new Set(BUILTIN_SPECIALISTS.map((s) => s.id));
|
|
33
|
+
const all = listSpecialists();
|
|
34
|
+
process.stdout.write('Available specialists:\n');
|
|
35
|
+
for (const s of all) {
|
|
36
|
+
const tag = builtinIds.has(s.id) ? 'core' : 'custom';
|
|
37
|
+
process.stdout.write(` ${s.id.padEnd(8)} ${tag.padEnd(6)} ${s.description}\n`);
|
|
38
|
+
}
|
|
39
|
+
const customCount = all.length - BUILTIN_SPECIALISTS.length;
|
|
40
|
+
if (customCount > 0) {
|
|
41
|
+
process.stdout.write(`\n${customCount} custom specialist${customCount === 1 ? '' : 's'} loaded from ~/.forge/specialists.json\n`);
|
|
42
|
+
}
|
|
43
|
+
return 0;
|
|
44
|
+
}
|
|
45
|
+
async function runOrchestratorCli(task, cwd, model, opts) {
|
|
46
|
+
try {
|
|
47
|
+
if (opts.preview) {
|
|
48
|
+
const result = await runRouter({
|
|
49
|
+
task,
|
|
50
|
+
model: model,
|
|
51
|
+
cwd,
|
|
52
|
+
auto: true,
|
|
53
|
+
maxIterations: 5,
|
|
54
|
+
});
|
|
55
|
+
const plan = parseRouterOutput(result.finalText, task);
|
|
56
|
+
process.stdout.write(`Plan:\n rationale: ${plan.rationale ?? '(none)'}\n`);
|
|
57
|
+
for (let i = 0; i < plan.steps.length; i++) {
|
|
58
|
+
const step = plan.steps[i];
|
|
59
|
+
process.stdout.write(` ${i + 1}. [${step.specialist}] ${step.task}${step.parallelGroup ? ` (group: ${step.parallelGroup})` : ''}\n`);
|
|
60
|
+
}
|
|
61
|
+
return 0;
|
|
62
|
+
}
|
|
63
|
+
const result = await runOrchestrator({
|
|
64
|
+
task,
|
|
65
|
+
model: model,
|
|
66
|
+
cwd,
|
|
67
|
+
auto: true,
|
|
68
|
+
worktrees: opts.worktrees ?? 'auto',
|
|
69
|
+
// v2.14: delete auto-created branches (default true). Mirror
|
|
70
|
+
// the user's CLI flag via the dispatchOpts field below.
|
|
71
|
+
...(opts.cleanupBranches !== undefined
|
|
72
|
+
? { cleanupBranches: opts.cleanupBranches }
|
|
73
|
+
: {}),
|
|
74
|
+
...(opts.commitChanges ? { commitChanges: true } : {}),
|
|
75
|
+
onWorktreeEvent: (event) => {
|
|
76
|
+
// Surface worktree lifecycle in stderr (so it doesn't pollute
|
|
77
|
+
// the plan/results output). Cheap progress signal.
|
|
78
|
+
process.stderr.write(`forge orchestrator: ${event.kind} worktree ${event.path} (${event.branch})\n`);
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
process.stdout.write(`Plan (${result.plan.rationale ?? 'no rationale'}):\n`);
|
|
82
|
+
for (let i = 0; i < result.steps.length; i++) {
|
|
83
|
+
const s = result.steps[i];
|
|
84
|
+
const wtInfo = s.worktreePath
|
|
85
|
+
? ` worktree=${s.worktreeBranch}`
|
|
86
|
+
: '';
|
|
87
|
+
process.stdout.write(` ${i + 1}. [${s.step.specialist}] ${s.reason} (${s.durationMs}ms)${wtInfo}${s.error ? ` ERROR: ${s.error}` : ''}\n`);
|
|
88
|
+
if (s.finalText) {
|
|
89
|
+
const preview = s.finalText.length > 200 ? s.finalText.slice(0, 200) + '…' : s.finalText;
|
|
90
|
+
process.stdout.write(` → ${preview.replace(/\n/g, ' ')}\n`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const kept = result.steps.filter((s) => s.worktreeCommit && s.worktreeBranch);
|
|
94
|
+
if (kept.length > 0) {
|
|
95
|
+
process.stdout.write('\nBranches with committed work (review, then merge or delete):\n');
|
|
96
|
+
for (const s of kept) {
|
|
97
|
+
process.stdout.write(` ${s.worktreeBranch} (${s.changedFiles?.length ?? 0} file${s.changedFiles?.length === 1 ? '' : 's'})\n` +
|
|
98
|
+
` review: git diff HEAD...${s.worktreeBranch}\n` +
|
|
99
|
+
` merge: git merge --no-ff ${s.worktreeBranch}\n` +
|
|
100
|
+
` drop: git branch -D ${s.worktreeBranch}\n`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
process.stdout.write(`\ntotal: ${result.durationMs}ms, ${result.totalInputTokens} in / ${result.totalOutputTokens} out tokens` +
|
|
104
|
+
(result.costKnown ? `, $${result.totalCostUsd.toFixed(4)}` : '') +
|
|
105
|
+
'\n');
|
|
106
|
+
return 0;
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
process.stderr.write(`forge orchestrator: ${err.message}\n`);
|
|
110
|
+
return 1;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=orchestrator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/commands/orchestrator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/commands/plugin.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAQzD,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,mBAAmB,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA6ChG"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `forge plugin …` subcommand: list, show, install, remove plugin bundles.
|
|
3
|
+
* No AI provider required. Exit codes: 0 ok, 2 user error, 1 unexpected.
|
|
4
|
+
*/
|
|
5
|
+
import { discoverPlugins, installPlugin, removePlugin } from '@ikarmic/forge-core';
|
|
6
|
+
function counts(p) {
|
|
7
|
+
const hookCount = Object.values(p.hooks).reduce((n, entries) => n + (entries?.length ?? 0), 0);
|
|
8
|
+
const mcpCount = Object.keys(p.mcpServers).length;
|
|
9
|
+
return `skills: ${p.skillsDir ? 'yes' : 'no'}, hook entries: ${hookCount}, mcp servers: ${mcpCount}`;
|
|
10
|
+
}
|
|
11
|
+
export async function handlePluginCommand(cmd, cwd) {
|
|
12
|
+
const out = (s) => process.stdout.write(`${s}\n`);
|
|
13
|
+
const err = (s) => process.stderr.write(`${s}\n`);
|
|
14
|
+
try {
|
|
15
|
+
if (cmd.list) {
|
|
16
|
+
const plugins = await discoverPlugins(cwd);
|
|
17
|
+
if (plugins.length === 0)
|
|
18
|
+
out('(no plugins installed)');
|
|
19
|
+
for (const p of plugins)
|
|
20
|
+
out(`${p.name}${p.version ? `@${p.version}` : ''} [${p.scope}] ${counts(p)}${p.description ? `\n ${p.description}` : ''}`);
|
|
21
|
+
return 0;
|
|
22
|
+
}
|
|
23
|
+
if (cmd.show) {
|
|
24
|
+
const plugin = (await discoverPlugins(cwd)).find((p) => p.name === cmd.show.name);
|
|
25
|
+
if (!plugin) {
|
|
26
|
+
err(`forge plugin: "${cmd.show.name}" is not installed`);
|
|
27
|
+
return 2;
|
|
28
|
+
}
|
|
29
|
+
out(`${plugin.name}${plugin.version ? `@${plugin.version}` : ''} [${plugin.scope}]\n${plugin.root}\n${counts(plugin)}`);
|
|
30
|
+
for (const w of plugin.warnings)
|
|
31
|
+
out(`warning: ${w}`);
|
|
32
|
+
if (plugin.scope === 'project')
|
|
33
|
+
out('note: project plugins run hooks only after the project is trusted; their MCP servers are not started.');
|
|
34
|
+
return 0;
|
|
35
|
+
}
|
|
36
|
+
if (cmd.install) {
|
|
37
|
+
const plugin = await installPlugin(cmd.install.source, {
|
|
38
|
+
scope: cmd.install.project ? 'project' : 'global',
|
|
39
|
+
cwd,
|
|
40
|
+
overwrite: cmd.install.overwrite,
|
|
41
|
+
});
|
|
42
|
+
out(`installed ${plugin.name}${plugin.version ? `@${plugin.version}` : ''} → ${plugin.root}\n${counts(plugin)}`);
|
|
43
|
+
return 0;
|
|
44
|
+
}
|
|
45
|
+
if (cmd.remove) {
|
|
46
|
+
const removed = await removePlugin(cmd.remove.name, { scope: cmd.remove.project ? 'project' : 'global', cwd });
|
|
47
|
+
if (!removed) {
|
|
48
|
+
err(`forge plugin: "${cmd.remove.name}" is not installed in that scope`);
|
|
49
|
+
return 2;
|
|
50
|
+
}
|
|
51
|
+
out(`removed ${cmd.remove.name}`);
|
|
52
|
+
return 0;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
err(`forge plugin: ${e.message}`);
|
|
57
|
+
return 2;
|
|
58
|
+
}
|
|
59
|
+
err('forge plugin: expected one of list|show <name>|install <source>|remove <name>');
|
|
60
|
+
return 2;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/commands/plugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/commands/policy.ts"],"names":[],"mappings":"AAOA,wBAAgB,mBAAmB,IAAI,MAAM,CAa5C"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `forge policy`: show which organization policy (if any) applies on this machine.
|
|
3
|
+
*/
|
|
4
|
+
import process from 'node:process';
|
|
5
|
+
import { PolicyError, getOrgPolicy, managedPolicyPath } from '@ikarmic/forge-core';
|
|
6
|
+
export function handlePolicyCommand() {
|
|
7
|
+
try {
|
|
8
|
+
const loaded = getOrgPolicy();
|
|
9
|
+
if (!loaded) {
|
|
10
|
+
process.stdout.write(`No organization policy is active.\n(Looked for ${process.env.FORGE_POLICY_FILE ?? managedPolicyPath()})\n`);
|
|
11
|
+
return 0;
|
|
12
|
+
}
|
|
13
|
+
process.stdout.write(`Organization policy: ${loaded.source}\n\n${JSON.stringify(loaded.policy, null, 2)}\n`);
|
|
14
|
+
return 0;
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
process.stderr.write(`forge: ${err.message}\n`);
|
|
18
|
+
return err instanceof PolicyError ? 2 : 1;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/commands/policy.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAEnF,MAAM,UAAU,mBAAmB;IACjC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;QAC9B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,kDAAkD,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,iBAAiB,EAAE,KAAK,CAAC,CAAC;YAClI,OAAO,CAAC,CAAC;QACX,CAAC;QACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,wBAAwB,MAAM,CAAC,MAAM,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QAC7G,OAAO,CAAC,CAAC;IACX,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAW,GAAa,CAAC,OAAO,IAAI,CAAC,CAAC;QAC3D,OAAO,GAAG,YAAY,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5C,CAAC;AACH,CAAC"}
|