ikarmic-forge 0.0.0-stage → 4.4.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 +58 -2
- package/dist/acp/server.d.ts +53 -0
- package/dist/acp/server.d.ts.map +1 -0
- package/dist/acp/server.js +235 -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 +747 -0
- package/dist/bin/forge.js.map +1 -0
- package/dist/chat-files.d.ts +37 -0
- package/dist/chat-files.d.ts.map +1 -0
- package/dist/chat-files.js +152 -0
- package/dist/chat-files.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/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 +13 -0
- package/dist/commands/spec.d.ts.map +1 -0
- package/dist/commands/spec.js +76 -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 +37 -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 +407 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +792 -0
- package/dist/options.js.map +1 -0
- package/dist/repl-commands.d.ts +53 -0
- package/dist/repl-commands.d.ts.map +1 -0
- package/dist/repl-commands.js +141 -0
- package/dist/repl-commands.js.map +1 -0
- package/dist/repl.d.ts +52 -0
- package/dist/repl.d.ts.map +1 -0
- package/dist/repl.js +1174 -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,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { loadForgeConfigFile as coreLoad, saveForgeConfigFile as coreSave } from '@ikarmic/forge-core';
|
|
3
|
+
import type { CredentialStore } from '@ikarmic/forge-core';
|
|
4
|
+
export interface ConfigWizardProps {
|
|
5
|
+
loadForgeConfigFile: typeof coreLoad;
|
|
6
|
+
saveForgeConfigFile: typeof coreSave;
|
|
7
|
+
credentialStore: CredentialStore;
|
|
8
|
+
onExit: () => void;
|
|
9
|
+
}
|
|
10
|
+
export declare function ConfigWizard(props: ConfigWizardProps): React.ReactElement;
|
|
11
|
+
/** Renders the wizard and resolves once the user finishes. */
|
|
12
|
+
export declare function runConfigWizard(deps: {
|
|
13
|
+
credentialStore: CredentialStore;
|
|
14
|
+
}): Promise<void>;
|
|
15
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAMnD,OAAO,EAOL,mBAAmB,IAAI,QAAQ,EAE/B,mBAAmB,IAAI,QAAQ,EAGhC,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,eAAe,EAA0E,MAAM,qBAAqB,CAAC;AAEnI,MAAM,WAAW,iBAAiB;IAChC,mBAAmB,EAAE,OAAO,QAAQ,CAAC;IACrC,mBAAmB,EAAE,OAAO,QAAQ,CAAC;IACrC,eAAe,EAAE,eAAe,CAAC;IACjC,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAID,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,KAAK,CAAC,YAAY,CA2NzE;AAED,8DAA8D;AAC9D,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAAE,eAAe,EAAE,eAAe,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAU/F"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import { Box, Text, render, useApp } from 'ink';
|
|
3
|
+
import SelectInput from 'ink-select-input';
|
|
4
|
+
import TextInput from 'ink-text-input';
|
|
5
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
6
|
+
import { BUILTIN_TOOLS, MODEL_CATALOG, SUPPORTED_PROVIDERS, exportSettings, importSettings, listSpecialists, loadForgeConfigFile as coreLoad, loadToolSandboxConfig, saveForgeConfigFile as coreSave, saveSpecialistsToConfig, saveToolSandboxConfig, } from '@ikarmic/forge-core';
|
|
7
|
+
export function ConfigWizard(props) {
|
|
8
|
+
const { exit } = useApp();
|
|
9
|
+
const [step, setStep] = useState('provider');
|
|
10
|
+
const [provider, setProvider] = useState(null);
|
|
11
|
+
const [keyInput, setKeyInput] = useState('');
|
|
12
|
+
const [agents, setAgents] = useState(() => [...listSpecialists()]);
|
|
13
|
+
const [agentError, setAgentError] = useState(null);
|
|
14
|
+
const [exportImportMsg, setExportImportMsg] = useState(null);
|
|
15
|
+
const [denyTools, setDenyTools] = useState([]);
|
|
16
|
+
const [permissionsMsg, setPermissionsMsg] = useState(null);
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
loadToolSandboxConfig(process.cwd(), { trustedProjectSettings: false }).then(({ sandbox }) => {
|
|
19
|
+
setDenyTools(sandbox.denyTools ?? []);
|
|
20
|
+
});
|
|
21
|
+
}, []);
|
|
22
|
+
if (step === 'provider') {
|
|
23
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
24
|
+
React.createElement(Text, { bold: true }, "Provider"),
|
|
25
|
+
React.createElement(SelectInput, { items: SUPPORTED_PROVIDERS.map((p) => ({ label: p, value: p })), onSelect: (item) => {
|
|
26
|
+
setProvider(item.value);
|
|
27
|
+
setStep('model');
|
|
28
|
+
} })));
|
|
29
|
+
}
|
|
30
|
+
if (step === 'model' && provider) {
|
|
31
|
+
const entries = MODEL_CATALOG[provider];
|
|
32
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
33
|
+
React.createElement(Text, { bold: true },
|
|
34
|
+
"Model (",
|
|
35
|
+
provider,
|
|
36
|
+
")"),
|
|
37
|
+
React.createElement(SelectInput, { items: entries.map((e) => ({ label: e.label, value: e.id })), onSelect: async (item) => {
|
|
38
|
+
await props.saveForgeConfigFile({ provider, model: item.value });
|
|
39
|
+
setStep('reasoningEffort');
|
|
40
|
+
} })));
|
|
41
|
+
}
|
|
42
|
+
if (step === 'reasoningEffort') {
|
|
43
|
+
const options = [
|
|
44
|
+
{ label: '(provider default)', value: '' },
|
|
45
|
+
{ label: 'None', value: 'none' },
|
|
46
|
+
{ label: 'Minimal', value: 'minimal' },
|
|
47
|
+
{ label: 'Low', value: 'low' },
|
|
48
|
+
{ label: 'Medium', value: 'medium' },
|
|
49
|
+
{ label: 'High', value: 'high' },
|
|
50
|
+
{ label: 'Extra high', value: 'xhigh' },
|
|
51
|
+
];
|
|
52
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
53
|
+
React.createElement(Text, { bold: true }, "Reasoning effort"),
|
|
54
|
+
React.createElement(SelectInput, { items: options, onSelect: async (item) => {
|
|
55
|
+
await props.saveForgeConfigFile({
|
|
56
|
+
...(item.value ? { reasoningEffort: item.value } : {}),
|
|
57
|
+
});
|
|
58
|
+
setStep('apiKey');
|
|
59
|
+
} })));
|
|
60
|
+
}
|
|
61
|
+
if (step === 'apiKey' && provider) {
|
|
62
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
63
|
+
React.createElement(Text, { bold: true },
|
|
64
|
+
"API key for ",
|
|
65
|
+
provider),
|
|
66
|
+
React.createElement(TextInput, { value: keyInput, onChange: setKeyInput, mask: "*", onSubmit: async (value) => {
|
|
67
|
+
if (value)
|
|
68
|
+
await props.credentialStore.set(provider, value);
|
|
69
|
+
setStep('agents');
|
|
70
|
+
} }),
|
|
71
|
+
React.createElement(Text, { color: "gray" }, "Press Enter to skip")));
|
|
72
|
+
}
|
|
73
|
+
if (step === 'agents') {
|
|
74
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
75
|
+
React.createElement(Text, { bold: true },
|
|
76
|
+
"Agents (",
|
|
77
|
+
agents.length,
|
|
78
|
+
" custom)"),
|
|
79
|
+
agents.map((a) => (React.createElement(Text, { key: a.id },
|
|
80
|
+
"- ",
|
|
81
|
+
a.id,
|
|
82
|
+
": ",
|
|
83
|
+
a.description))),
|
|
84
|
+
agentError && React.createElement(Text, { color: "red" }, agentError),
|
|
85
|
+
React.createElement(SelectInput, { items: [
|
|
86
|
+
{ label: 'Save and continue', value: 'save' },
|
|
87
|
+
{ label: 'Skip (no changes)', value: 'skip' },
|
|
88
|
+
], onSelect: async (item) => {
|
|
89
|
+
if (item.value === 'save') {
|
|
90
|
+
try {
|
|
91
|
+
await saveSpecialistsToConfig(agents);
|
|
92
|
+
setStep('permissions');
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
setAgentError(err.message);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
setStep('permissions');
|
|
100
|
+
}
|
|
101
|
+
} })));
|
|
102
|
+
}
|
|
103
|
+
if (step === 'permissions') {
|
|
104
|
+
const items = BUILTIN_TOOLS.map((t) => ({
|
|
105
|
+
label: (denyTools.includes(t.name) ? '[x] ' : '[ ] ') + t.name,
|
|
106
|
+
value: t.name,
|
|
107
|
+
}));
|
|
108
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
109
|
+
React.createElement(Text, { bold: true }, "Permissions: toggle tools to deny (Enter to toggle, select \"Done\" to save)"),
|
|
110
|
+
permissionsMsg && React.createElement(Text, { color: "green" }, permissionsMsg),
|
|
111
|
+
React.createElement(SelectInput, { items: [...items, { label: 'Done', value: '__done__' }], onSelect: async (item) => {
|
|
112
|
+
if (item.value === '__done__') {
|
|
113
|
+
const sandbox = denyTools.length > 0 ? { denyTools } : {};
|
|
114
|
+
await saveToolSandboxConfig(sandbox);
|
|
115
|
+
setPermissionsMsg('Saved.');
|
|
116
|
+
setStep('display');
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
setDenyTools((prev) => prev.includes(item.value) ? prev.filter((t) => t !== item.value) : [...prev, item.value]);
|
|
120
|
+
} })));
|
|
121
|
+
}
|
|
122
|
+
if (step === 'display') {
|
|
123
|
+
const options = [
|
|
124
|
+
{ label: 'Review first (expanded blocks, reasoning shown)', value: 'review' },
|
|
125
|
+
{ label: 'High autonomy (collapsed blocks, reasoning hidden)', value: 'autonomy' },
|
|
126
|
+
{ label: 'Continue without changing', value: 'skip' },
|
|
127
|
+
];
|
|
128
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
129
|
+
React.createElement(Text, { bold: true }, "Display"),
|
|
130
|
+
React.createElement(SelectInput, { items: options, onSelect: async (item) => {
|
|
131
|
+
if (item.value === 'review') {
|
|
132
|
+
await props.saveForgeConfigFile({ display: { detail: 'full', showReasoning: true } });
|
|
133
|
+
}
|
|
134
|
+
else if (item.value === 'autonomy') {
|
|
135
|
+
await props.saveForgeConfigFile({ display: { detail: 'compact', showReasoning: false } });
|
|
136
|
+
}
|
|
137
|
+
setStep('exportImport');
|
|
138
|
+
} })));
|
|
139
|
+
}
|
|
140
|
+
if (step === 'exportImport') {
|
|
141
|
+
const options = [
|
|
142
|
+
{ label: 'Export settings to ./forge-settings.json', value: 'export' },
|
|
143
|
+
{ label: 'Import settings from ./forge-settings.json', value: 'import' },
|
|
144
|
+
{ label: 'Done', value: 'done' },
|
|
145
|
+
];
|
|
146
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
147
|
+
React.createElement(Text, { bold: true }, "Export / Import"),
|
|
148
|
+
exportImportMsg && React.createElement(Text, { color: "green" }, exportImportMsg),
|
|
149
|
+
React.createElement(SelectInput, { items: options, onSelect: async (item) => {
|
|
150
|
+
if (item.value === 'export') {
|
|
151
|
+
const data = await exportSettings({});
|
|
152
|
+
await writeFile('./forge-settings.json', JSON.stringify(data, null, 2) + '\n', 'utf8');
|
|
153
|
+
setExportImportMsg('Exported to ./forge-settings.json');
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (item.value === 'import') {
|
|
157
|
+
try {
|
|
158
|
+
const raw = await readFile('./forge-settings.json', 'utf8');
|
|
159
|
+
await importSettings(JSON.parse(raw), {});
|
|
160
|
+
setExportImportMsg('Imported from ./forge-settings.json');
|
|
161
|
+
}
|
|
162
|
+
catch (err) {
|
|
163
|
+
setExportImportMsg('Import failed: ' + err.message);
|
|
164
|
+
}
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
setStep('done');
|
|
168
|
+
props.onExit();
|
|
169
|
+
exit();
|
|
170
|
+
} })));
|
|
171
|
+
}
|
|
172
|
+
return (React.createElement(Box, null,
|
|
173
|
+
React.createElement(Text, { color: "green" }, "Saved.")));
|
|
174
|
+
}
|
|
175
|
+
/** Renders the wizard and resolves once the user finishes. */
|
|
176
|
+
export async function runConfigWizard(deps) {
|
|
177
|
+
const { waitUntilExit } = render(React.createElement(ConfigWizard, { loadForgeConfigFile: coreLoad, saveForgeConfigFile: coreSave, credentialStore: deps.credentialStore, onExit: () => { } }));
|
|
178
|
+
await waitUntilExit();
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `forge diff <file1> <file2>` subcommand: print a unified diff between
|
|
3
|
+
* two files (or a file and stdin). Pure CLI surface over the
|
|
4
|
+
* {@link computeUnifiedDiff} core helper; no AI provider needed.
|
|
5
|
+
*
|
|
6
|
+
* Examples:
|
|
7
|
+
* forge diff before.txt after.txt
|
|
8
|
+
* forge diff --from-stdin package.json < updated-package.json
|
|
9
|
+
* forge diff --context 5 src/old.ts src/new.ts
|
|
10
|
+
*
|
|
11
|
+
* The output is pipe-friendly: same format as `git diff`, so it
|
|
12
|
+
* composes with `less`, `diff-so-fancy`, etc.
|
|
13
|
+
*/
|
|
14
|
+
export interface DiffCommandOptions {
|
|
15
|
+
fileA: string;
|
|
16
|
+
fileB?: string;
|
|
17
|
+
contextLines?: number;
|
|
18
|
+
fromStdin?: boolean;
|
|
19
|
+
/** When set, only print the one-line summary (no diff text). */
|
|
20
|
+
summaryOnly?: boolean;
|
|
21
|
+
cwd?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Run the `forge diff` subcommand. Resolves file paths relative to
|
|
25
|
+
* `cwd` and prints the unified diff (or summary) to stdout. Returns
|
|
26
|
+
* the shell exit code: 0 = files identical, 1 = files differ, 2 = error.
|
|
27
|
+
*/
|
|
28
|
+
export declare function handleDiffCommand(opts: DiffCommandOptions): number;
|
|
29
|
+
//# sourceMappingURL=diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/commands/diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAOH,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gEAAgE;IAChE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,kBAAkB,GAAG,MAAM,CA6ClE"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `forge diff <file1> <file2>` subcommand: print a unified diff between
|
|
3
|
+
* two files (or a file and stdin). Pure CLI surface over the
|
|
4
|
+
* {@link computeUnifiedDiff} core helper; no AI provider needed.
|
|
5
|
+
*
|
|
6
|
+
* Examples:
|
|
7
|
+
* forge diff before.txt after.txt
|
|
8
|
+
* forge diff --from-stdin package.json < updated-package.json
|
|
9
|
+
* forge diff --context 5 src/old.ts src/new.ts
|
|
10
|
+
*
|
|
11
|
+
* The output is pipe-friendly: same format as `git diff`, so it
|
|
12
|
+
* composes with `less`, `diff-so-fancy`, etc.
|
|
13
|
+
*/
|
|
14
|
+
import { readFileSync } from 'node:fs';
|
|
15
|
+
import process from 'node:process';
|
|
16
|
+
import { computeDiffSummary, computeUnifiedDiff } from '@ikarmic/forge-core';
|
|
17
|
+
/**
|
|
18
|
+
* Run the `forge diff` subcommand. Resolves file paths relative to
|
|
19
|
+
* `cwd` and prints the unified diff (or summary) to stdout. Returns
|
|
20
|
+
* the shell exit code: 0 = files identical, 1 = files differ, 2 = error.
|
|
21
|
+
*/
|
|
22
|
+
export function handleDiffCommand(opts) {
|
|
23
|
+
let before;
|
|
24
|
+
let after;
|
|
25
|
+
try {
|
|
26
|
+
before = readFileSync(resolvePath(opts.cwd ?? process.cwd(), opts.fileA), 'utf8');
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
process.stderr.write(`forge diff: failed to read ${opts.fileA}: ${err.message}\n`);
|
|
30
|
+
return 2;
|
|
31
|
+
}
|
|
32
|
+
if (opts.fromStdin) {
|
|
33
|
+
try {
|
|
34
|
+
after = readStdinSync();
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
process.stderr.write(`forge diff: failed to read stdin: ${err.message}\n`);
|
|
38
|
+
return 2;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
const fileB = opts.fileB;
|
|
43
|
+
if (!fileB) {
|
|
44
|
+
process.stderr.write('forge diff: missing <fileB> (or pass --from-stdin)\n');
|
|
45
|
+
return 2;
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
after = readFileSync(resolvePath(opts.cwd ?? process.cwd(), fileB), 'utf8');
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
process.stderr.write(`forge diff: failed to read ${fileB}: ${err.message}\n`);
|
|
52
|
+
return 2;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const diffOpts = {
|
|
56
|
+
filePath: opts.fileB ?? opts.fileA,
|
|
57
|
+
...(opts.contextLines !== undefined ? { contextLines: opts.contextLines } : {}),
|
|
58
|
+
};
|
|
59
|
+
const result = computeUnifiedDiff(before, after, diffOpts);
|
|
60
|
+
if (opts.summaryOnly) {
|
|
61
|
+
const summary = computeDiffSummary(before, after, diffOpts);
|
|
62
|
+
process.stdout.write(`${summary.summary}\n`);
|
|
63
|
+
}
|
|
64
|
+
else if (!result.unchanged) {
|
|
65
|
+
process.stdout.write(result.text);
|
|
66
|
+
if (!result.text.endsWith('\n'))
|
|
67
|
+
process.stdout.write('\n');
|
|
68
|
+
}
|
|
69
|
+
return result.unchanged ? 0 : 1;
|
|
70
|
+
}
|
|
71
|
+
function resolvePath(cwd, p) {
|
|
72
|
+
// Simple path resolver: accepts absolute paths as-is, otherwise
|
|
73
|
+
// joins with cwd. Node's path.resolve would also normalize `..` but
|
|
74
|
+
// we keep it minimal here. Also recognizes Windows UNC paths
|
|
75
|
+
// (`\\server\share\file`) as absolute.
|
|
76
|
+
if (p.startsWith('/') || p.startsWith('\\\\') || /^[a-zA-Z]:[\\/]/.test(p))
|
|
77
|
+
return p;
|
|
78
|
+
return `${cwd}/${p}`;
|
|
79
|
+
}
|
|
80
|
+
function readStdinSync() {
|
|
81
|
+
// Node 18+ exposes fs.readFileSync('/dev/stdin') as a synchronous
|
|
82
|
+
// stdin read. On Windows this falls back to reading 0 via `readFileSync`
|
|
83
|
+
// which works for short inputs. Errors (e.g. a known partial-read/EAGAIN
|
|
84
|
+
// behavior on non-regular-file descriptors for large piped input on
|
|
85
|
+
// Windows) propagate to the caller rather than being swallowed into ''
|
|
86
|
+
//: silently treating a read failure as empty stdin would make `forge
|
|
87
|
+
// diff --from-stdin` claim the whole file was deleted with no warning.
|
|
88
|
+
return readFileSync(0, 'utf8');
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/commands/diff.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
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 type { ParsedHookCommand } from '../options.js';
|
|
9
|
+
export declare function handleHookCommand(cmd: ParsedHookCommand, cwd: string): Promise<number>;
|
|
10
|
+
//# sourceMappingURL=hook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../../src/commands/hook.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEvD,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,iBAAiB,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAa5F"}
|
|
@@ -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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"}
|