march-cli 0.1.34 → 0.1.36
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/package.json +12 -1
- package/src/agent/code-search/cache.mjs +133 -0
- package/src/agent/code-search/chunk-rules.mjs +107 -0
- package/src/agent/code-search/chunker.mjs +125 -0
- package/src/agent/code-search/engine.mjs +109 -0
- package/src/agent/code-search/languages.mjs +25 -0
- package/src/agent/code-search/parser-pool.mjs +29 -0
- package/src/agent/code-search/rerank.mjs +43 -0
- package/src/agent/code-search/retrieval/bm25.mjs +47 -0
- package/src/agent/code-search/retrieval/fusion.mjs +18 -0
- package/src/agent/code-search/retrieval/model2vec.mjs +96 -0
- package/src/agent/code-search/retrieval/safetensors.mjs +49 -0
- package/src/agent/code-search/retrieval/vector.mjs +107 -0
- package/src/agent/code-search/retrieval/wordpiece.mjs +82 -0
- package/src/agent/code-search/scanner.mjs +84 -0
- package/src/agent/code-search/tokenize.mjs +16 -0
- package/src/agent/code-search/tool.mjs +75 -0
- package/src/agent/lifecycle/runner-lifecycle.mjs +16 -0
- package/src/agent/lifecycle/runtime-restart-tool.mjs +22 -0
- package/src/agent/runner/provider-quota-runtime.mjs +38 -0
- package/src/agent/runner.mjs +14 -14
- package/src/agent/runtime/remote-runner-client.mjs +9 -15
- package/src/agent/runtime/runner-ipc-target.mjs +10 -22
- package/src/agent/runtime/runner-process-client.mjs +101 -24
- package/src/agent/runtime/runner-runtime-host.mjs +2 -0
- package/src/agent/runtime/state/runner-state.mjs +81 -0
- package/src/agent/runtime/ui-event-bridge.mjs +2 -0
- package/src/agent/session/session-options.mjs +2 -1
- package/src/agent/tools.mjs +6 -1
- package/src/cli/args.mjs +14 -3
- package/src/cli/commands/catalog/visible-commands.mjs +5 -0
- package/src/cli/commands/help-command.mjs +1 -7
- package/src/cli/commands/registry/slash-command-registry.mjs +296 -0
- package/src/cli/commands/status-command.mjs +61 -35
- package/src/cli/input/autocomplete.mjs +2 -25
- package/src/cli/repl-loop.mjs +24 -41
- package/src/cli/slash-commands.mjs +19 -185
- package/src/cli/startup/app-runtime.mjs +201 -0
- package/src/cli/startup/configured-command.mjs +9 -0
- package/src/cli/startup/early-command.mjs +29 -0
- package/src/cli/turn/turn-input-preparer.mjs +41 -0
- package/src/context/system-core/base.md +5 -0
- package/src/main.mjs +47 -242
- package/src/provider/quota/codex.mjs +278 -0
- package/src/provider/quota/index.mjs +46 -0
- package/src/provider/quota/transport-observer.mjs +99 -0
- package/src/web-ui/command.mjs +112 -0
- package/src/web-ui/index.html +12 -0
- package/src/web-ui/runtime-host.mjs +188 -0
- package/src/web-ui/server.mjs +140 -0
- package/src/web-ui/session-manager.mjs +111 -0
- package/src/web-ui/src/App.tsx +7 -0
- package/src/web-ui/src/components/AppShell.tsx +48 -0
- package/src/web-ui/src/components/Composer.tsx +47 -0
- package/src/web-ui/src/components/FileExplorer.tsx +46 -0
- package/src/web-ui/src/components/RightSidebar.tsx +115 -0
- package/src/web-ui/src/components/SessionTimeline.tsx +31 -0
- package/src/web-ui/src/components/timeline/TimelineBlocks.tsx +109 -0
- package/src/web-ui/src/components/timeline/TimelineList.tsx +14 -0
- package/src/web-ui/src/fileTreeAdapter.ts +51 -0
- package/src/web-ui/src/main.tsx +11 -0
- package/src/web-ui/src/mockData.ts +87 -0
- package/src/web-ui/src/model.ts +82 -0
- package/src/web-ui/src/runtime/client.ts +81 -0
- package/src/web-ui/src/runtime/runtimeTimeline.ts +88 -0
- package/src/web-ui/src/runtime/useWebRuntime.ts +144 -0
- package/src/web-ui/src/styles/shell.css +166 -0
- package/src/web-ui/src/styles/tokens.css +116 -0
- package/src/web-ui/src/timelineAdapter.ts +43 -0
- package/src/web-ui/src/vite-env.d.ts +1 -0
- package/src/web-ui/tsconfig.json +20 -0
- package/src/web-ui/vite.config.mjs +11 -0
package/src/agent/runner.mjs
CHANGED
|
@@ -26,6 +26,8 @@ import { appendFastVariants, createFastModelEntry, fromFastEntryModel, isFastPro
|
|
|
26
26
|
import { registerSuperGrokProvider } from "../supergrok/provider.mjs";
|
|
27
27
|
import { registerCustomProviders } from "../provider/custom-provider.mjs";
|
|
28
28
|
import { injectHostedTools } from "../provider/hosted-tools.mjs";
|
|
29
|
+
import { createRunnerLifecycle } from "./lifecycle/runner-lifecycle.mjs";
|
|
30
|
+
import { createRunnerProviderQuotaRuntime } from "./runner/provider-quota-runtime.mjs";
|
|
29
31
|
export { MARCH_BASE_TOOL_NAMES, installModelPayloadDumper };
|
|
30
32
|
export { createDefaultSessionManager, resolveRunnerSessionManager } from "./runner/runner-init.mjs";
|
|
31
33
|
export { getRunnerSessionStats, syncEngineSessionState } from "./runner/runner-session-state.mjs";
|
|
@@ -58,6 +60,7 @@ export async function createRunner({ cwd, modelId = null, provider = null, provi
|
|
|
58
60
|
const resolvedSessionManager = resolveRunnerSessionManager(cwd, sessionManager);
|
|
59
61
|
const sessionBinding = createSessionBinding(null);
|
|
60
62
|
let currentModelCallKind = "model", currentTurnId = null, currentPromptForContext = "";
|
|
63
|
+
const lifecycle = createRunnerLifecycle();
|
|
61
64
|
let currentTurnContextMode = "rebuild";
|
|
62
65
|
let nextTurnContextMode = "rebuild";
|
|
63
66
|
let lastNotificationResult = null, runtimeHost = null, lifecycleAdapter = null;
|
|
@@ -70,7 +73,7 @@ export async function createRunner({ cwd, modelId = null, provider = null, provi
|
|
|
70
73
|
sessionManager: resolvedSessionManager, sessionBinding, engine, ui: runtimeUi,
|
|
71
74
|
projectMarchDir,
|
|
72
75
|
memoryTools, memoryStore, shellRuntime, lspService, mcpTools, webTools,
|
|
73
|
-
permissionController, extensionPaths, hostedTools,
|
|
76
|
+
lifecycle, permissionController, extensionPaths, hostedTools,
|
|
74
77
|
onRebind: (session) => {
|
|
75
78
|
installModelPayloadDumper(session, modelContextDumper, () => currentModelCallKind, onLoggedModelPayload, injectMarchSystemContext);
|
|
76
79
|
syncEngineSessionState(engine, session);
|
|
@@ -82,7 +85,7 @@ export async function createRunner({ cwd, modelId = null, provider = null, provi
|
|
|
82
85
|
} else {
|
|
83
86
|
const sessionOptions = resolveRunnerSessionOptions({
|
|
84
87
|
cwd, stateRoot, provider, modelId, modelRegistry, engine, ui: runtimeUi,
|
|
85
|
-
memoryTools, shellRuntime, lspService, mcpTools, webTools, permissionController,
|
|
88
|
+
memoryTools, shellRuntime, lspService, mcpTools, webTools, lifecycle, permissionController,
|
|
86
89
|
authStorage: resolvedAuth, projectMarchDir,
|
|
87
90
|
getCurrentModel: () => sessionBinding.get()?.model ?? selectedModel,
|
|
88
91
|
});
|
|
@@ -105,6 +108,8 @@ export async function createRunner({ cwd, modelId = null, provider = null, provi
|
|
|
105
108
|
if (serviceTier === "priority" && selectedModel && isFastProvider(selectedModel.provider)) {
|
|
106
109
|
_currentFastEntry = createFastModelEntry(selectedModel).model;
|
|
107
110
|
}
|
|
111
|
+
const providerQuotaRuntime = createRunnerProviderQuotaRuntime({ authStorage: resolvedAuth, ui: runtimeUi,
|
|
112
|
+
getCurrentModel: () => _currentFastEntry ?? sessionBinding.get().model });
|
|
108
113
|
return {
|
|
109
114
|
engine,
|
|
110
115
|
get session() { return sessionBinding.get(); },
|
|
@@ -115,6 +120,7 @@ export async function createRunner({ cwd, modelId = null, provider = null, provi
|
|
|
115
120
|
const contextMode = nextTurnContextMode;
|
|
116
121
|
currentTurnContextMode = contextMode;
|
|
117
122
|
nextTurnContextMode = "rebuild";
|
|
123
|
+
lifecycle.clearPendingAction();
|
|
118
124
|
const turnStartedAt = Date.now();
|
|
119
125
|
const codexTransportStatsBefore = getCodexTransportDebugSnapshot(sessionBinding.get());
|
|
120
126
|
const turnLog = beginLoggedTurn({ logger, engine, modelId, provider, contextMode, userMessage, userRecallHints, startedAt: turnStartedAt }); currentTurnId = turnLog.turnId;
|
|
@@ -135,6 +141,8 @@ export async function createRunner({ cwd, modelId = null, provider = null, provi
|
|
|
135
141
|
draft: result?.draft ?? "",
|
|
136
142
|
durationMs: Date.now() - turnStartedAt,
|
|
137
143
|
}, (notificationResult) => { lastNotificationResult = notificationResult; });
|
|
144
|
+
const lifecycleAction = lifecycle.takePendingAction();
|
|
145
|
+
if (lifecycleAction) result.lifecycleAction = lifecycleAction;
|
|
138
146
|
turnLog.endSuccess(result);
|
|
139
147
|
return result;
|
|
140
148
|
} catch (err) {
|
|
@@ -171,6 +179,7 @@ export async function createRunner({ cwd, modelId = null, provider = null, provi
|
|
|
171
179
|
return result;
|
|
172
180
|
},
|
|
173
181
|
getCurrentModel() { return _currentFastEntry ?? sessionBinding.get().model; },
|
|
182
|
+
...providerQuotaRuntime,
|
|
174
183
|
async setModel(model) {
|
|
175
184
|
const activeSession = sessionBinding.get();
|
|
176
185
|
const { baseId, isFast } = fromFastEntryModel(model);
|
|
@@ -186,21 +195,11 @@ export async function createRunner({ cwd, modelId = null, provider = null, provi
|
|
|
186
195
|
return model;
|
|
187
196
|
},
|
|
188
197
|
getScopedModels() { return appendFastVariants(sessionBinding.get().scopedModels); },
|
|
189
|
-
getConfiguredProviders() {
|
|
190
|
-
const configured = Object.values(providers ?? {}).map((profile) => profile?.type).filter(Boolean);
|
|
191
|
-
const available = (modelRegistry.getAvailable?.() ?? []).map((model) => model.provider);
|
|
192
|
-
return [...new Set([...configured, ...available])];
|
|
193
|
-
},
|
|
198
|
+
getConfiguredProviders() { return [...new Set([...Object.values(providers ?? {}).map((profile) => profile?.type).filter(Boolean), ...(modelRegistry.getAvailable?.() ?? []).map((model) => model.provider)])]; },
|
|
194
199
|
getSessionStats() { return getRunnerSessionStats(sessionBinding.get(), runtimeHost); },
|
|
195
200
|
getLastNotificationResult() { return lastNotificationResult; },
|
|
196
201
|
async notifyTest({ title = "March", message = "If you see this, March runtime notifications work." } = {}) {
|
|
197
|
-
lastNotificationResult = await notifyTurnEndBestEffort(turnNotifier, {
|
|
198
|
-
status: "success",
|
|
199
|
-
sessionName: engine.sessionName,
|
|
200
|
-
title,
|
|
201
|
-
message,
|
|
202
|
-
durationMs: 0,
|
|
203
|
-
});
|
|
202
|
+
lastNotificationResult = await notifyTurnEndBestEffort(turnNotifier, { status: "success", sessionName: engine.sessionName, title, message, durationMs: 0 });
|
|
204
203
|
return lastNotificationResult;
|
|
205
204
|
},
|
|
206
205
|
estimateContextTokens(userMessage = "") {
|
|
@@ -254,6 +253,7 @@ export async function createRunner({ cwd, modelId = null, provider = null, provi
|
|
|
254
253
|
() => shellRuntime?.dispose?.() ?? shellRuntime?.killAll?.(),
|
|
255
254
|
() => lspService.dispose(),
|
|
256
255
|
() => mcpClientManager?.disconnectAll?.(),
|
|
256
|
+
() => providerQuotaRuntime.disposeProviderQuotaRuntime(),
|
|
257
257
|
() => detachRuntimeUi(),
|
|
258
258
|
]);
|
|
259
259
|
},
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
+
import { createRunnerEngineStateFacade } from "./state/runner-state.mjs";
|
|
2
|
+
|
|
1
3
|
export function createRemoteRunnerClient(peer, { initialState = null } = {}) {
|
|
2
4
|
let state = initialState;
|
|
5
|
+
const engineFacade = createRunnerEngineStateFacade({
|
|
6
|
+
getState: () => state,
|
|
7
|
+
setState: (nextState) => { state = nextState; },
|
|
8
|
+
});
|
|
3
9
|
|
|
4
10
|
const client = {
|
|
5
|
-
get engine() { return
|
|
11
|
+
get engine() { return engineFacade; },
|
|
6
12
|
get runtimeState() { return state; },
|
|
7
13
|
async init(options = {}) {
|
|
8
14
|
state = await peer.call("init", options);
|
|
@@ -20,6 +26,8 @@ export function createRemoteRunnerClient(peer, { initialState = null } = {}) {
|
|
|
20
26
|
getScopedModels: () => state?.scopedModels ?? [],
|
|
21
27
|
getConfiguredProviders: () => state?.configuredProviders ?? [],
|
|
22
28
|
getSessionStats: () => state?.sessionStats ?? null,
|
|
29
|
+
getCachedProviderQuotaSnapshot: () => state?.providerQuota ?? null,
|
|
30
|
+
async getProviderQuotaSnapshot(options = {}) { return applyResultWithState(await peer.call("getProviderQuotaSnapshot", options)); },
|
|
23
31
|
async refreshState() { return refreshState(); },
|
|
24
32
|
getLastNotificationResult: () => peer.call("getLastNotificationResult"),
|
|
25
33
|
notifyTest: (options) => peer.call("notifyTest", options),
|
|
@@ -56,18 +64,4 @@ export function createRemoteRunnerClient(peer, { initialState = null } = {}) {
|
|
|
56
64
|
return response;
|
|
57
65
|
}
|
|
58
66
|
|
|
59
|
-
function createEngineFacade() {
|
|
60
|
-
const engine = state?.engine ?? {};
|
|
61
|
-
return {
|
|
62
|
-
...engine,
|
|
63
|
-
hasRenderedPendingAssistantRecallHints: () => true,
|
|
64
|
-
takePendingAssistantRecallHints: () => [],
|
|
65
|
-
peekPendingAssistantRecallHints: () => [],
|
|
66
|
-
markPendingAssistantRecallHintsRendered: () => {},
|
|
67
|
-
getRecentRecallMemoryIds: () => [],
|
|
68
|
-
restoreSession: () => {
|
|
69
|
-
throw new Error("remote runner session restore is not available");
|
|
70
|
-
},
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
67
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { createRunnerStateSnapshot } from "./state/runner-state.mjs";
|
|
2
|
+
|
|
1
3
|
export function createRunnerIpcTarget({ createRunnerImpl, runnerOptions = {} } = {}) {
|
|
2
4
|
if (typeof createRunnerImpl !== "function") throw new Error("createRunnerImpl is required");
|
|
3
5
|
|
|
@@ -35,6 +37,13 @@ export function createRunnerIpcTarget({ createRunnerImpl, runnerOptions = {} } =
|
|
|
35
37
|
getSessionStats() {
|
|
36
38
|
return getRunner().getSessionStats();
|
|
37
39
|
},
|
|
40
|
+
async getProviderQuotaSnapshot(options = {}) {
|
|
41
|
+
const result = await getRunner().getProviderQuotaSnapshot(options);
|
|
42
|
+
return { result, state: getRunnerState(runner) };
|
|
43
|
+
},
|
|
44
|
+
getCachedProviderQuotaSnapshot() {
|
|
45
|
+
return getRunner().getCachedProviderQuotaSnapshot?.() ?? null;
|
|
46
|
+
},
|
|
38
47
|
getState() {
|
|
39
48
|
return getRunnerState(getRunner());
|
|
40
49
|
},
|
|
@@ -100,26 +109,5 @@ export function createRunnerIpcTarget({ createRunnerImpl, runnerOptions = {} } =
|
|
|
100
109
|
}
|
|
101
110
|
|
|
102
111
|
export function getRunnerState(runner) {
|
|
103
|
-
|
|
104
|
-
const scopedModels = runner.getScopedModels?.() ?? [];
|
|
105
|
-
const thinkingLevel = runner.getThinkingLevel?.() ?? runner.engine?.thinkingLevel ?? null;
|
|
106
|
-
return {
|
|
107
|
-
engine: {
|
|
108
|
-
cwd: runner.engine?.cwd ?? null,
|
|
109
|
-
modelId: runner.engine?.modelId ?? currentModel?.id ?? null,
|
|
110
|
-
provider: runner.engine?.provider ?? currentModel?.provider ?? null,
|
|
111
|
-
thinkingLevel,
|
|
112
|
-
sessionName: runner.engine?.sessionName ?? "",
|
|
113
|
-
turns: runner.engine?.turns ?? [],
|
|
114
|
-
},
|
|
115
|
-
currentModel,
|
|
116
|
-
scopedModels,
|
|
117
|
-
configuredProviders: runner.getConfiguredProviders?.() ?? [],
|
|
118
|
-
availableThinkingLevels: runner.getAvailableThinkingLevels?.() ?? [],
|
|
119
|
-
canSwitchPiSession: runner.canSwitchPiSession?.() ?? false,
|
|
120
|
-
sessionStats: runner.getSessionStats?.() ?? null,
|
|
121
|
-
lspStatus: runner.getLspStatus?.() ?? null,
|
|
122
|
-
extensionDiagnostics: runner.getExtensionDiagnostics?.() ?? [],
|
|
123
|
-
extensionLifecycleState: runner.getExtensionLifecycleState?.() ?? null,
|
|
124
|
-
};
|
|
112
|
+
return createRunnerStateSnapshot(runner);
|
|
125
113
|
}
|
|
@@ -14,34 +14,111 @@ export async function createRunnerProcessClient({
|
|
|
14
14
|
forkImpl = fork,
|
|
15
15
|
timeoutMs = 0,
|
|
16
16
|
} = {}) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
let active = await startRuntime();
|
|
18
|
+
let disposed = false;
|
|
19
|
+
const localProps = new Map();
|
|
20
|
+
|
|
21
|
+
const runner = new Proxy({}, {
|
|
22
|
+
get(_target, prop) {
|
|
23
|
+
if (prop === "restartRuntime") return restartRuntime;
|
|
24
|
+
if (prop === "dispose") return dispose;
|
|
25
|
+
if (localProps.has(prop)) return localProps.get(prop);
|
|
26
|
+
const value = active.runner[prop];
|
|
27
|
+
return typeof value === "function" ? value.bind(active.runner) : value;
|
|
28
|
+
},
|
|
29
|
+
set(_target, prop, value) {
|
|
30
|
+
localProps.set(prop, value);
|
|
31
|
+
return true;
|
|
32
|
+
},
|
|
33
|
+
has(_target, prop) {
|
|
34
|
+
return prop === "restartRuntime" || prop === "dispose" || localProps.has(prop) || prop in active.runner;
|
|
25
35
|
},
|
|
26
|
-
timeoutMs,
|
|
27
36
|
});
|
|
28
|
-
const runner = createRemoteRunnerClient(peer);
|
|
29
|
-
try {
|
|
30
|
-
await runner.init(runnerOptions);
|
|
31
|
-
} catch (error) {
|
|
32
|
-
peer.dispose();
|
|
33
|
-
child.kill?.();
|
|
34
|
-
throw error;
|
|
35
|
-
}
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
return { runner, get child() { return active.child; }, dispose };
|
|
39
|
+
|
|
40
|
+
async function startRuntime() {
|
|
41
|
+
const child = forkImpl(entry, [], {
|
|
42
|
+
stdio: ["ignore", "inherit", "inherit", "ipc"],
|
|
43
|
+
});
|
|
44
|
+
const peer = createProcessRuntimeIpcPeer({
|
|
45
|
+
processLike: child,
|
|
46
|
+
target: {
|
|
47
|
+
...createRuntimeUiEventTarget(ui),
|
|
48
|
+
modelPayload: (event) => onModelPayload?.(event),
|
|
49
|
+
},
|
|
50
|
+
timeoutMs,
|
|
51
|
+
});
|
|
52
|
+
const remoteRunner = createRemoteRunnerClient(peer);
|
|
39
53
|
try {
|
|
40
|
-
await
|
|
41
|
-
}
|
|
54
|
+
await waitForRuntimeInit({ child, initPromise: remoteRunner.init(runnerOptions) });
|
|
55
|
+
} catch (error) {
|
|
56
|
+
peer.dispose();
|
|
42
57
|
child.kill?.();
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
runner: remoteRunner,
|
|
62
|
+
child,
|
|
63
|
+
async dispose() {
|
|
64
|
+
try {
|
|
65
|
+
await remoteRunner.dispose();
|
|
66
|
+
} finally {
|
|
67
|
+
child.kill?.();
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async function restartRuntime({ restoreSession = true } = {}) {
|
|
74
|
+
if (disposed) throw new Error("runtime runner is already disposed");
|
|
75
|
+
const previousState = await refreshRunnerState(active.runner);
|
|
76
|
+
const previousSessionFile = previousState?.sessionStats?.sessionFile ?? previousState?.sessionStats?.sessionPath ?? null;
|
|
77
|
+
const previousActive = active;
|
|
78
|
+
await previousActive.dispose();
|
|
79
|
+
active = await startRuntime();
|
|
80
|
+
|
|
81
|
+
// Rebind the same persisted pi session after the fresh child imports updated source.
|
|
82
|
+
if (restoreSession && previousSessionFile && active.runner.canSwitchPiSession?.()) {
|
|
83
|
+
await active.runner.switchPiSession(previousSessionFile, previousState?.engine ?? null);
|
|
43
84
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
85
|
+
return await refreshRunnerState(active.runner);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async function dispose() {
|
|
89
|
+
if (disposed) return;
|
|
90
|
+
disposed = true;
|
|
91
|
+
await active.dispose();
|
|
92
|
+
}
|
|
47
93
|
}
|
|
94
|
+
|
|
95
|
+
async function refreshRunnerState(runner) {
|
|
96
|
+
if (typeof runner.refreshState === "function") return await runner.refreshState();
|
|
97
|
+
return runner.runtimeState ?? null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function waitForRuntimeInit({ child, initPromise }) {
|
|
101
|
+
return new Promise((resolve, reject) => {
|
|
102
|
+
let settled = false;
|
|
103
|
+
const cleanup = () => {
|
|
104
|
+
child.off?.("exit", onExit);
|
|
105
|
+
child.off?.("error", onError);
|
|
106
|
+
};
|
|
107
|
+
const finish = (fn, value) => {
|
|
108
|
+
if (settled) return;
|
|
109
|
+
settled = true;
|
|
110
|
+
cleanup();
|
|
111
|
+
fn(value);
|
|
112
|
+
};
|
|
113
|
+
const onExit = (code, signal) => {
|
|
114
|
+
const codeText = code == null ? "" : ` with code ${code}`;
|
|
115
|
+
const signalText = signal ? ` (${signal})` : "";
|
|
116
|
+
finish(reject, new Error(`Runtime process exited during startup${codeText}${signalText}`));
|
|
117
|
+
};
|
|
118
|
+
const onError = (error) => finish(reject, error);
|
|
119
|
+
|
|
120
|
+
child.once?.("exit", onExit);
|
|
121
|
+
child.once?.("error", onError);
|
|
122
|
+
initPromise.then((value) => finish(resolve, value), (error) => finish(reject, error));
|
|
123
|
+
});
|
|
124
|
+
}
|
|
@@ -24,6 +24,7 @@ export async function createRunnerRuntimeHost({
|
|
|
24
24
|
lspService = null,
|
|
25
25
|
mcpTools = [],
|
|
26
26
|
webTools = [],
|
|
27
|
+
lifecycle = null,
|
|
27
28
|
permissionController = null,
|
|
28
29
|
extensionPaths = [],
|
|
29
30
|
hostedTools = {},
|
|
@@ -59,6 +60,7 @@ export async function createRunnerRuntimeHost({
|
|
|
59
60
|
lspService,
|
|
60
61
|
mcpTools,
|
|
61
62
|
webTools,
|
|
63
|
+
lifecycle,
|
|
62
64
|
permissionController,
|
|
63
65
|
authStorage,
|
|
64
66
|
projectMarchDir,
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export function createRunnerStateSnapshot(runner) {
|
|
2
|
+
const currentModel = runner.getCurrentModel?.() ?? null;
|
|
3
|
+
const scopedModels = runner.getScopedModels?.() ?? [];
|
|
4
|
+
const thinkingLevel = runner.getThinkingLevel?.() ?? runner.engine?.thinkingLevel ?? null;
|
|
5
|
+
const engine = runner.engine ?? {};
|
|
6
|
+
return {
|
|
7
|
+
engine: {
|
|
8
|
+
cwd: engine.cwd ?? null,
|
|
9
|
+
modelId: engine.modelId ?? currentModel?.id ?? null,
|
|
10
|
+
provider: engine.provider ?? currentModel?.provider ?? null,
|
|
11
|
+
thinkingLevel,
|
|
12
|
+
sessionName: engine.sessionName ?? "",
|
|
13
|
+
remoteMemorySources: engine.remoteMemorySources ?? [],
|
|
14
|
+
turns: engine.turns ?? [],
|
|
15
|
+
pendingAssistantRecallHints: engine.peekPendingAssistantRecallHints?.() ?? engine.pendingAssistantRecallHints ?? [],
|
|
16
|
+
pendingAssistantRecallHintsRendered: engine.hasRenderedPendingAssistantRecallHints?.() ?? engine.pendingAssistantRecallHintsRendered ?? false,
|
|
17
|
+
recentRecallMemoryIds: [...(engine.getRecentRecallMemoryIds?.() ?? [])],
|
|
18
|
+
},
|
|
19
|
+
currentModel,
|
|
20
|
+
scopedModels,
|
|
21
|
+
configuredProviders: runner.getConfiguredProviders?.() ?? [],
|
|
22
|
+
availableThinkingLevels: runner.getAvailableThinkingLevels?.() ?? [],
|
|
23
|
+
canSwitchPiSession: runner.canSwitchPiSession?.() ?? false,
|
|
24
|
+
sessionStats: runner.getSessionStats?.() ?? null,
|
|
25
|
+
providerQuota: runner.getCachedProviderQuotaSnapshot?.() ?? null,
|
|
26
|
+
lspStatus: runner.getLspStatus?.() ?? null,
|
|
27
|
+
extensionDiagnostics: runner.getExtensionDiagnostics?.() ?? [],
|
|
28
|
+
extensionLifecycleState: runner.getExtensionLifecycleState?.() ?? null,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function createRunnerEngineStateFacade({ getState, setState }) {
|
|
33
|
+
return {
|
|
34
|
+
get cwd() { return engineState(getState()).cwd ?? null; },
|
|
35
|
+
get modelId() { return engineState(getState()).modelId ?? null; },
|
|
36
|
+
get provider() { return engineState(getState()).provider ?? null; },
|
|
37
|
+
get thinkingLevel() { return engineState(getState()).thinkingLevel ?? null; },
|
|
38
|
+
get sessionName() { return engineState(getState()).sessionName ?? ""; },
|
|
39
|
+
get remoteMemorySources() { return engineState(getState()).remoteMemorySources ?? []; },
|
|
40
|
+
get turns() { return engineState(getState()).turns ?? []; },
|
|
41
|
+
peekPendingAssistantRecallHints() {
|
|
42
|
+
return engineState(getState()).pendingAssistantRecallHints ?? [];
|
|
43
|
+
},
|
|
44
|
+
hasRenderedPendingAssistantRecallHints() {
|
|
45
|
+
return Boolean(engineState(getState()).pendingAssistantRecallHintsRendered);
|
|
46
|
+
},
|
|
47
|
+
markPendingAssistantRecallHintsRendered() {
|
|
48
|
+
updateEngineState(getState, setState, (engine) => {
|
|
49
|
+
if ((engine.pendingAssistantRecallHints ?? []).length > 0) {
|
|
50
|
+
engine.pendingAssistantRecallHintsRendered = true;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
takePendingAssistantRecallHints() {
|
|
55
|
+
const hints = engineState(getState()).pendingAssistantRecallHints ?? [];
|
|
56
|
+
updateEngineState(getState, setState, (engine) => {
|
|
57
|
+
engine.pendingAssistantRecallHints = [];
|
|
58
|
+
engine.pendingAssistantRecallHintsRendered = false;
|
|
59
|
+
});
|
|
60
|
+
return hints;
|
|
61
|
+
},
|
|
62
|
+
getRecentRecallMemoryIds() {
|
|
63
|
+
return engineState(getState()).recentRecallMemoryIds ?? [];
|
|
64
|
+
},
|
|
65
|
+
restoreSession() {
|
|
66
|
+
throw new Error("remote runner session restore is not available");
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function engineState(state) {
|
|
72
|
+
return state?.engine ?? {};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function updateEngineState(getState, setState, update) {
|
|
76
|
+
const state = getState();
|
|
77
|
+
if (!state) return;
|
|
78
|
+
const engine = { ...(state.engine ?? {}) };
|
|
79
|
+
update(engine);
|
|
80
|
+
setState({ ...state, engine });
|
|
81
|
+
}
|
|
@@ -51,6 +51,7 @@ export function createRuntimeUiClient(eventBus) {
|
|
|
51
51
|
status: (text) => eventBus.emit({ type: "status", text }),
|
|
52
52
|
debugLines: (lines) => eventBus.emit({ type: "debug_lines", lines }),
|
|
53
53
|
recall: ({ source, hints }) => eventBus.emit({ type: "recall", source, hints }),
|
|
54
|
+
providerQuotaSnapshot: (snapshot) => eventBus.emit({ type: "provider_quota_snapshot", snapshot }),
|
|
54
55
|
editDiff: (path, diffLines) => eventBus.emit({ type: "edit_diff", path, diffLines }),
|
|
55
56
|
requestPermission: (request) => eventBus.request({ type: "permission_request", ...request }),
|
|
56
57
|
};
|
|
@@ -72,6 +73,7 @@ export function dispatchRuntimeUiEvent(ui, event) {
|
|
|
72
73
|
case "status": return ui.status?.(event.text);
|
|
73
74
|
case "debug_lines": return writeDebugLines(ui, event.lines);
|
|
74
75
|
case "recall": return ui.recall?.({ source: event.source, hints: event.hints });
|
|
76
|
+
case "provider_quota_snapshot": return ui.providerQuotaSnapshot?.(event.snapshot);
|
|
75
77
|
case "edit_diff": return ui.editDiff?.(event.path, event.diffLines);
|
|
76
78
|
case "permission_request": return ui.requestPermission?.({ toolName: event.toolName, params: event.params, category: event.category });
|
|
77
79
|
default: return undefined;
|
|
@@ -14,6 +14,7 @@ export function resolveRunnerSessionOptions({
|
|
|
14
14
|
lspService = null,
|
|
15
15
|
mcpTools = [],
|
|
16
16
|
webTools = [],
|
|
17
|
+
lifecycle = null,
|
|
17
18
|
permissionController = null,
|
|
18
19
|
authStorage = null,
|
|
19
20
|
projectMarchDir = null,
|
|
@@ -30,7 +31,7 @@ export function resolveRunnerSessionOptions({
|
|
|
30
31
|
?? (provider && modelId ? getModel(provider, modelId) : null);
|
|
31
32
|
if (!model) throw new Error(`Model not found: ${provider}/${modelId}`);
|
|
32
33
|
|
|
33
|
-
const customTools = createMarchCustomTools({ cwd, engine, ui, memoryTools, shellRuntime, lspService, mcpTools, webTools, permissionController, authStorage, projectMarchDir, stateRoot, getCurrentModel: () => getCurrentModel?.() ?? model });
|
|
34
|
+
const customTools = createMarchCustomTools({ cwd, engine, ui, memoryTools, shellRuntime, lspService, mcpTools, webTools, lifecycle, permissionController, authStorage, projectMarchDir, stateRoot, getCurrentModel: () => getCurrentModel?.() ?? model });
|
|
34
35
|
const customToolNames = customTools.map((tool) => tool.name);
|
|
35
36
|
const tools = [
|
|
36
37
|
...customToolNames.filter((name) => name === "read"),
|
package/src/agent/tools.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createCommandExecTool } from "./command-exec-tool.mjs";
|
|
2
|
+
import { createCodeSearchTool } from "./code-search/tool.mjs";
|
|
2
3
|
import { createContextStatsTool } from "./context-stats-tool.mjs";
|
|
3
4
|
import { createEditFileTool } from "./file-edit-tool.mjs";
|
|
4
5
|
import { createReadFileTool } from "./file-tools/read-file-tool.mjs";
|
|
@@ -11,9 +12,11 @@ import { createShellTools } from "../shell/tools.mjs";
|
|
|
11
12
|
import { initImageGen } from "../image-gen/index.mjs";
|
|
12
13
|
import { createSuperGrokTool } from "../supergrok/tool.mjs";
|
|
13
14
|
import { createBrowserTools } from "../browser/tools/index.mjs";
|
|
15
|
+
import { createRuntimeRestartTool } from "./lifecycle/runtime-restart-tool.mjs";
|
|
14
16
|
|
|
15
|
-
export function createMarchCustomTools({ cwd, engine, ui, memoryTools = [], shellRuntime = null, lspService = null, mcpTools = [], webTools = [], permissionController = null, authStorage = null, projectMarchDir = null, stateRoot = null, getCurrentModel = null }) {
|
|
17
|
+
export function createMarchCustomTools({ cwd, engine, ui, memoryTools = [], shellRuntime = null, lspService = null, mcpTools = [], webTools = [], lifecycle = null, permissionController = null, authStorage = null, projectMarchDir = null, stateRoot = null, getCurrentModel = null }) {
|
|
16
18
|
const commandExecTool = createCommandExecTool({ cwd });
|
|
19
|
+
const codeSearchTool = createCodeSearchTool({ engine, stateRoot });
|
|
17
20
|
const contextStatsTool = createContextStatsTool({ engine });
|
|
18
21
|
const editFileTool = createEditFileTool({ engine, ui, lspService });
|
|
19
22
|
const readFileTool = createReadFileTool({ engine });
|
|
@@ -29,12 +32,14 @@ export function createMarchCustomTools({ cwd, engine, ui, memoryTools = [], shel
|
|
|
29
32
|
screenTool,
|
|
30
33
|
listWindowsTool,
|
|
31
34
|
contextStatsTool,
|
|
35
|
+
codeSearchTool,
|
|
32
36
|
commandExecTool,
|
|
33
37
|
editFileTool,
|
|
34
38
|
...createShellTools(shellRuntime),
|
|
35
39
|
...memoryTools,
|
|
36
40
|
...mcpTools,
|
|
37
41
|
...webTools,
|
|
42
|
+
...(lifecycle ? [createRuntimeRestartTool({ lifecycle })] : []),
|
|
38
43
|
...createBrowserTools({ stateRoot }),
|
|
39
44
|
...(authStorage ? [createSuperGrokTool({ authStorage, projectMarchDir })] : []),
|
|
40
45
|
...(authStorage ? initImageGen({ authStorage, projectMarchDir }) : []),
|
package/src/cli/args.mjs
CHANGED
|
@@ -20,15 +20,18 @@ export function parseCliArgs(argv) {
|
|
|
20
20
|
"permission-mode": { type: "string" },
|
|
21
21
|
host: { type: "string" },
|
|
22
22
|
port: { type: "string" },
|
|
23
|
+
"api-port": { type: "string" },
|
|
23
24
|
name: { type: "string" },
|
|
24
25
|
token: { type: "string" },
|
|
25
26
|
foreground: { type: "boolean" },
|
|
27
|
+
workspace: { type: "string" },
|
|
28
|
+
dev: { type: "boolean" },
|
|
26
29
|
help: { type: "boolean", short: "h" },
|
|
27
30
|
},
|
|
28
31
|
allowPositionals: true,
|
|
29
32
|
});
|
|
30
33
|
|
|
31
|
-
const commandName = ["login", "provider", "websearch", "memory", "browser", "gateway"].includes(positionals[0]) ? positionals[0] : null;
|
|
34
|
+
const commandName = ["login", "provider", "web", "websearch", "memory", "browser", "gateway"].includes(positionals[0]) ? positionals[0] : null;
|
|
32
35
|
|
|
33
36
|
return {
|
|
34
37
|
command: commandName ? { name: commandName, args: positionals.slice(1) } : null,
|
|
@@ -47,9 +50,12 @@ export function parseCliArgs(argv) {
|
|
|
47
50
|
permissionMode: values["permission-mode"] ?? "bypassPermissions",
|
|
48
51
|
host: values.host ?? null,
|
|
49
52
|
port: values.port ?? null,
|
|
53
|
+
apiPort: values["api-port"] ?? null,
|
|
50
54
|
name: values.name ?? null,
|
|
51
55
|
token: values.token ?? null,
|
|
52
56
|
foreground: values.foreground ?? false,
|
|
57
|
+
workspace: values.workspace ?? null,
|
|
58
|
+
dev: values.dev ?? false,
|
|
53
59
|
help: values.help ?? false,
|
|
54
60
|
prompt: commandName ? "" : positionals.join(" "),
|
|
55
61
|
};
|
|
@@ -65,6 +71,8 @@ Usage:
|
|
|
65
71
|
march provider --config Configure provider credentials
|
|
66
72
|
march provider share [id] Share a provider profile
|
|
67
73
|
march provider accept <token>
|
|
74
|
+
march web [path] Start the local Web UI session manager
|
|
75
|
+
march web --dev Start Web UI with Vite hot reload
|
|
68
76
|
march websearch --config Configure web search credentials
|
|
69
77
|
march memory serve [folder]
|
|
70
78
|
march memory add <url>
|
|
@@ -92,8 +100,11 @@ Options:
|
|
|
92
100
|
--permission-mode <mode> Permission mode: default, bypassPermissions, dontAsk (default: bypassPermissions)
|
|
93
101
|
-e, --extension <path>
|
|
94
102
|
Load a pi extension path in the default runtime host (repeatable)
|
|
95
|
-
--host <host> With memory serve, bind host (default: 127.0.0.1)
|
|
96
|
-
--port <port> With memory serve, bind port
|
|
103
|
+
--host <host> With memory serve/web, bind host (default: 127.0.0.1)
|
|
104
|
+
--port <port> With memory serve/web, bind port
|
|
105
|
+
--api-port <port> With web --dev, bind API backend port
|
|
106
|
+
--workspace <path> With web, open an initial workspace session
|
|
107
|
+
--dev With web, use Vite dev server and proxy /api
|
|
97
108
|
--name <name> With memory serve/add, remote memory source name
|
|
98
109
|
--foreground With memory serve, run server in current process
|
|
99
110
|
-h, --help Show this help
|
|
@@ -1,7 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
return [
|
|
3
|
-
"Commands: /new, /exit, /help, /hotkeys, /templates, /do, /discuss, /mode, /export jsonl, /export html, /export gist <jsonl|html>, /settings, /extensions, /providers, /providers <name>, /model, /models, /session, /status, /shell, /shell spawn [name], /save, /name, /copy",
|
|
4
|
-
"Sessions: /session opens previous sessions and restores the selected one.",
|
|
5
|
-
"Shortcuts: Tab = toggle Do/Discuss, Esc = abort turn, Ctrl+C = abort turn / press twice to exit when idle, Ctrl+O = toggle tool output, Alt+S = shell pane, Alt+N = next shell, Alt+K/J = shell scroll, PageUp/PageDown = output scroll, Ctrl+G = external editor, Shift+Tab = thinking selector, Ctrl+T = thinking selector, Ctrl+L = model selector",
|
|
6
|
-
];
|
|
7
|
-
}
|
|
1
|
+
export { formatHelpLines } from "./registry/slash-command-registry.mjs";
|