march-cli 0.1.37 → 0.1.39
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 +1 -1
- package/src/agent/runner/runner-utils.mjs +20 -0
- package/src/agent/runner.mjs +16 -17
- package/src/agent/runtime/remote-ui-client.mjs +0 -1
- package/src/agent/runtime/runner-process-client.mjs +2 -0
- package/src/agent/runtime/runner-process-factory.mjs +3 -4
- package/src/agent/runtime/runner-runtime-host.mjs +0 -2
- package/src/agent/runtime/ui-event-bridge.mjs +0 -2
- package/src/agent/session/session-options.mjs +1 -2
- package/src/agent/tools.mjs +2 -23
- package/src/agent/turn/turn-runner.mjs +4 -4
- package/src/cli/args.mjs +3 -3
- package/src/cli/commands/mode-command.mjs +1 -0
- package/src/cli/commands/registry/slash-command-registry.mjs +4 -3
- package/src/cli/fallback-ui.mjs +0 -2
- package/src/cli/input/mode-state.mjs +1 -1
- package/src/cli/repl-commands.mjs +1 -1
- package/src/cli/repl-loop.mjs +67 -19
- package/src/cli/session/pi-session-switch-command.mjs +11 -11
- package/src/cli/session/session-list-command.mjs +1 -1
- package/src/cli/session/session-source-command.mjs +0 -76
- package/src/cli/startup/app-runtime.mjs +103 -4
- package/src/cli/startup/create-runtime-runner.mjs +2 -1
- package/src/cli/startup/startup-session.mjs +3 -13
- package/src/cli/ui.mjs +0 -6
- package/src/cli/workspace/command.mjs +121 -0
- package/src/cli/workspace/output-router.mjs +127 -0
- package/src/cli/workspace/project-runtime.mjs +94 -0
- package/src/cli/workspace/runtime-session-state.mjs +9 -0
- package/src/config/features.mjs +0 -1
- package/src/extensions/lifecycle-adapter.mjs +3 -3
- package/src/main.mjs +11 -1
- package/src/notification/desktop-notifier.mjs +16 -8
- package/src/session/sidecar-sync.mjs +3 -17
- package/src/session/sidecar.mjs +40 -41
- package/src/session/state/march-session-state.mjs +175 -0
- package/src/session/state/march-session-sync.mjs +20 -0
- package/src/session/state/march-session-ui-state.mjs +60 -0
- package/src/web-ui/dist/assets/index-BQtl1uQs.css +1 -0
- package/src/web-ui/dist/assets/index-DrlJis_D.js +1845 -0
- package/src/web-ui/dist/index.html +13 -0
- package/src/web-ui/runtime-host.mjs +1 -2
- package/src/web-ui/src/components/timeline/TimelineBlocks.tsx +2 -10
- package/src/web-ui/src/mockData.ts +1 -8
- package/src/web-ui/src/model.ts +0 -2
- package/src/web-ui/src/runtime/client.ts +0 -1
- package/src/web-ui/src/runtime/runtimeTimeline.ts +1 -3
- package/src/web-ui/src/styles/shell.css +1 -2
- package/src/web-ui/src/timelineAdapter.ts +1 -2
- package/src/workspace/project-id.mjs +14 -0
- package/src/workspace/project-registry.mjs +74 -0
- package/src/workspace/session-index.mjs +102 -0
- package/src/workspace/supervisor.mjs +178 -0
- package/src/agent/pi-session/pi-session-sidecar-failure.mjs +0 -10
- package/src/cli/permissions.mjs +0 -103
- package/src/cli/session/session-switch-command.mjs +0 -1
- package/src/cli/tui/permission-request-ui.mjs +0 -18
- package/src/session/persist.mjs +0 -1
package/package.json
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
import { installCodexTransportCompression } from "./codex-transport-compression.mjs";
|
|
2
|
+
import { installCodexWebSocketEventDebug } from "./codex-websocket-event-debug.mjs";
|
|
3
|
+
import { installCodexLargeContextGuard } from "./codex-large-context-guard.mjs";
|
|
4
|
+
|
|
5
|
+
export function installRunnerProcessGuards() {
|
|
6
|
+
installCodexLargeContextGuard();
|
|
7
|
+
installCodexTransportCompression();
|
|
8
|
+
installCodexWebSocketEventDebug();
|
|
9
|
+
}
|
|
10
|
+
|
|
1
11
|
export function providerContextToPayload(providerContext) {
|
|
2
12
|
return {
|
|
3
13
|
messages: [
|
|
@@ -22,3 +32,13 @@ export function notifyTurnEndDetached(turnNotifier, event, onResult = () => {})
|
|
|
22
32
|
pending.then(onResult, () => {});
|
|
23
33
|
return pending;
|
|
24
34
|
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
export function buildNotificationActivation({ notificationContext, sessionStats }) {
|
|
38
|
+
if (!notificationContext?.projectId) return null;
|
|
39
|
+
return {
|
|
40
|
+
type: "workspace-session",
|
|
41
|
+
projectId: notificationContext.projectId,
|
|
42
|
+
sessionId: sessionStats?.sessionId ?? null,
|
|
43
|
+
};
|
|
44
|
+
}
|
package/src/agent/runner.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { createAgentSession, ModelRegistry, SettingsManager } from "@earendil-wo
|
|
|
2
2
|
import { createMarchAuthStorage } from "../auth/storage.mjs";
|
|
3
3
|
import { ContextEngine } from "../context/engine.mjs";
|
|
4
4
|
import { createMarchLifecycleAdapter } from "../extensions/lifecycle-adapter.mjs";
|
|
5
|
-
import {
|
|
5
|
+
import { syncMarchSessionState } from "../session/state/march-session-sync.mjs";
|
|
6
6
|
import { LspService } from "../lsp/service.mjs";
|
|
7
7
|
import { formatLspServiceEvent } from "../lsp/status-message.mjs";
|
|
8
8
|
import { estimateProviderPayloadTokens, installModelPayloadDumper, replaceProviderContextMessages } from "./model-payload-dumper.mjs";
|
|
@@ -11,11 +11,9 @@ import { runRunnerCleanup } from "./runner/runner-cleanup.mjs";
|
|
|
11
11
|
import { createRunnerRuntimeHost } from "./runtime/runner-runtime-host.mjs";
|
|
12
12
|
import { createRuntimeUiBridge } from "./runtime/ui-event-bridge.mjs";
|
|
13
13
|
import { getRunnerSessionStats, syncEngineSessionState } from "./runner/runner-session-state.mjs";
|
|
14
|
-
import { notifyTurnEndBestEffort, notifyTurnEndDetached, providerContextToPayload } from "./runner/runner-utils.mjs";
|
|
14
|
+
import { buildNotificationActivation, installRunnerProcessGuards, notifyTurnEndBestEffort, notifyTurnEndDetached, providerContextToPayload } from "./runner/runner-utils.mjs";
|
|
15
15
|
import { dumpCodexTransportDebug, getCodexTransportDebugSnapshot } from "./runner/codex-transport-debug.mjs";
|
|
16
|
-
import {
|
|
17
|
-
import { installCodexTransportCompression } from "./runner/codex-transport-compression.mjs";
|
|
18
|
-
import { applyCodexLargeContextGuardToPayload, installCodexLargeContextGuard } from "./runner/codex-large-context-guard.mjs";
|
|
16
|
+
import { applyCodexLargeContextGuardToPayload } from "./runner/codex-large-context-guard.mjs";
|
|
19
17
|
import { resolveRunnerSessionOptions } from "./session/session-options.mjs";
|
|
20
18
|
import { createSessionBinding } from "./session/session-binding.mjs";
|
|
21
19
|
import { maybeAutoNameSession } from "./session/session-auto-name.mjs";
|
|
@@ -32,10 +30,8 @@ import { appendRunnerTurnHistory, createRunnerHistoryStore } from "../history/ru
|
|
|
32
30
|
export { MARCH_BASE_TOOL_NAMES, installModelPayloadDumper };
|
|
33
31
|
export { createDefaultSessionManager, resolveRunnerSessionManager } from "./runner/runner-init.mjs";
|
|
34
32
|
export { getRunnerSessionStats, syncEngineSessionState } from "./runner/runner-session-state.mjs";
|
|
35
|
-
export async function createRunner({ cwd, modelId = null, provider = null, providers = {}, stateRoot, ui, memoryRoot = null, profilePaths = null, memoryStore = null, memoryTools = [], remoteMemorySources = [], shellRuntime = null, mcpTools = [], mcpInjections = [], mcpClientManager = null, webTools = [], namespace = "", sessionManager = null, useRuntimeHost = false, projectMarchDir = null,
|
|
36
|
-
|
|
37
|
-
installCodexTransportCompression();
|
|
38
|
-
installCodexWebSocketEventDebug();
|
|
33
|
+
export async function createRunner({ cwd, modelId = null, provider = null, providers = {}, stateRoot, ui, memoryRoot = null, profilePaths = null, memoryStore = null, memoryTools = [], remoteMemorySources = [], shellRuntime = null, mcpTools = [], mcpInjections = [], mcpClientManager = null, webTools = [], namespace = "", sessionManager = null, useRuntimeHost = false, projectMarchDir = null, syncMarchSessionState: syncMarchSessionStateEnabled = false, syncPiSidecar = syncMarchSessionStateEnabled, extensionPaths = [], lifecycleHooks = [], lifecycleDiagnostics = [], authStorage = null, modelContextDumper = null, turnNotifier = null, logger = null, onModelPayload = null, onLspStatusChange = null, createAgentSessionImpl = createAgentSession, createAgentSessionRuntimeImpl, createRuntimeServices, createRuntimeSessionFromServices, maxTurns, trimBatch, serviceTier = null, hostedTools = {}, notificationContext = null }) {
|
|
34
|
+
installRunnerProcessGuards();
|
|
39
35
|
if (!useRuntimeHost && extensionPaths.length > 0) throw new Error("--extension requires the default pi runtime host path");
|
|
40
36
|
const authConfig = authStorage ? { authStorage, hasAuth: true } : createMarchAuthStorage({ provider: provider ?? "deepseek", providers, cwd });
|
|
41
37
|
if (!authConfig.hasAuth) throw new Error("No providers configured. Run: march provider --config");
|
|
@@ -71,7 +67,7 @@ export async function createRunner({ cwd, modelId = null, provider = null, provi
|
|
|
71
67
|
sessionManager: resolvedSessionManager, sessionBinding, engine, ui: runtimeUi,
|
|
72
68
|
projectMarchDir,
|
|
73
69
|
memoryTools, memoryStore, historyStore, shellRuntime, lspService, mcpTools, webTools,
|
|
74
|
-
lifecycle,
|
|
70
|
+
lifecycle, extensionPaths, hostedTools,
|
|
75
71
|
onRebind: (session) => {
|
|
76
72
|
installModelPayloadDumper(session, modelContextDumper, () => currentModelCallKind, onLoggedModelPayload, injectMarchSystemContext);
|
|
77
73
|
syncEngineSessionState(engine, session);
|
|
@@ -83,7 +79,7 @@ export async function createRunner({ cwd, modelId = null, provider = null, provi
|
|
|
83
79
|
} else {
|
|
84
80
|
const sessionOptions = resolveRunnerSessionOptions({
|
|
85
81
|
cwd, stateRoot, provider, modelId, modelRegistry, engine, ui: runtimeUi,
|
|
86
|
-
memoryTools, historyStore, shellRuntime, lspService, mcpTools, webTools, lifecycle,
|
|
82
|
+
memoryTools, historyStore, shellRuntime, lspService, mcpTools, webTools, lifecycle,
|
|
87
83
|
authStorage: resolvedAuth, projectMarchDir,
|
|
88
84
|
getCurrentModel: () => sessionBinding.get()?.model ?? selectedModel,
|
|
89
85
|
});
|
|
@@ -129,7 +125,7 @@ export async function createRunner({ cwd, modelId = null, provider = null, provi
|
|
|
129
125
|
setModelCallKind: (kind) => { currentModelCallKind = kind; },
|
|
130
126
|
logger: turnLog.logger,
|
|
131
127
|
setPhase: turnLog.setPhase,
|
|
132
|
-
|
|
128
|
+
syncCurrentMarchSessionState,
|
|
133
129
|
autoNameSession,
|
|
134
130
|
contextMode,
|
|
135
131
|
recordHistory: (turn) => appendRunnerTurnHistory({ store: historyStore, turn, sessionStats: getRunnerSessionStats(sessionBinding.get(), runtimeHost), modelId: engine.modelId, provider: engine.provider }),
|
|
@@ -139,6 +135,7 @@ export async function createRunner({ cwd, modelId = null, provider = null, provi
|
|
|
139
135
|
sessionName: engine.sessionName,
|
|
140
136
|
draft: result?.draft ?? "",
|
|
141
137
|
durationMs: Date.now() - turnStartedAt,
|
|
138
|
+
activation: buildNotificationActivation({ notificationContext, sessionStats: getRunnerSessionStats(sessionBinding.get(), runtimeHost) }),
|
|
142
139
|
}, (notificationResult) => { lastNotificationResult = notificationResult; });
|
|
143
140
|
const lifecycleAction = lifecycle.takePendingAction();
|
|
144
141
|
if (lifecycleAction) result.lifecycleAction = lifecycleAction;
|
|
@@ -150,6 +147,7 @@ export async function createRunner({ cwd, modelId = null, provider = null, provi
|
|
|
150
147
|
sessionName: engine.sessionName,
|
|
151
148
|
errorMessage: err?.message ?? String(err),
|
|
152
149
|
durationMs: Date.now() - turnStartedAt,
|
|
150
|
+
activation: buildNotificationActivation({ notificationContext, sessionStats: getRunnerSessionStats(sessionBinding.get(), runtimeHost) }),
|
|
153
151
|
}, (notificationResult) => { lastNotificationResult = notificationResult; });
|
|
154
152
|
turnLog.endError(err);
|
|
155
153
|
throw err;
|
|
@@ -208,14 +206,14 @@ export async function createRunner({ cwd, modelId = null, provider = null, provi
|
|
|
208
206
|
const activeSession = sessionBinding.get();
|
|
209
207
|
activeSession.setSessionName?.(name);
|
|
210
208
|
engine.setSessionName(name);
|
|
211
|
-
|
|
209
|
+
syncCurrentMarchSessionState();
|
|
212
210
|
return engine.sessionName;
|
|
213
211
|
},
|
|
214
212
|
canSwitchPiSession() { return Boolean(runtimeHost); },
|
|
215
213
|
async startNewSession() {
|
|
216
214
|
if (!runtimeHost) throw new Error("pi runtime host is not enabled");
|
|
217
215
|
nextTurnContextMode = "rebuild";
|
|
218
|
-
|
|
216
|
+
syncCurrentMarchSessionState();
|
|
219
217
|
const result = await runtimeHost.newSession();
|
|
220
218
|
if (result?.cancelled) return { cancelled: true };
|
|
221
219
|
engine.restoreSession({}, [], { replace: true });
|
|
@@ -257,9 +255,10 @@ export async function createRunner({ cwd, modelId = null, provider = null, provi
|
|
|
257
255
|
]);
|
|
258
256
|
},
|
|
259
257
|
};
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
258
|
+
return runner;
|
|
259
|
+
function syncCurrentMarchSessionState() {
|
|
260
|
+
return syncMarchSessionState({
|
|
261
|
+
enabled: syncPiSidecar || syncMarchSessionStateEnabled, projectMarchDir, engine,
|
|
263
262
|
sessionStats: getRunnerSessionStats(sessionBinding.get(), runtimeHost),
|
|
264
263
|
});
|
|
265
264
|
}
|
|
@@ -15,6 +15,5 @@ export function createRemoteRuntimeUiClient(peer) {
|
|
|
15
15
|
debugLines: (lines) => peer.notify("uiEvent", { type: "debug_lines", lines }),
|
|
16
16
|
recall: ({ source, hints }) => peer.notify("uiEvent", { type: "recall", source, hints }),
|
|
17
17
|
editDiff: (path, diffLines) => peer.notify("uiEvent", { type: "edit_diff", path, diffLines }),
|
|
18
|
-
requestPermission: (request) => peer.call("uiRequest", { type: "permission_request", ...request }),
|
|
19
18
|
};
|
|
20
19
|
}
|
|
@@ -11,6 +11,7 @@ export async function createRunnerProcessClient({
|
|
|
11
11
|
ui,
|
|
12
12
|
onModelPayload = null,
|
|
13
13
|
onLspStatusChange = null,
|
|
14
|
+
onNotificationActivation = null,
|
|
14
15
|
entry = fileURLToPath(DEFAULT_ENTRY),
|
|
15
16
|
forkImpl = fork,
|
|
16
17
|
timeoutMs = 0,
|
|
@@ -51,6 +52,7 @@ export async function createRunnerProcessClient({
|
|
|
51
52
|
await active?.runner?.refreshState?.();
|
|
52
53
|
onLspStatusChange?.(event);
|
|
53
54
|
},
|
|
55
|
+
notificationActivation: (activation) => onNotificationActivation?.(activation),
|
|
54
56
|
},
|
|
55
57
|
timeoutMs,
|
|
56
58
|
});
|
|
@@ -8,7 +8,6 @@ import { createMarkdownMemoryTools } from "../../memory/markdown-tools.mjs";
|
|
|
8
8
|
import { normalizeRemoteMemorySources } from "../../memory/remote/config.mjs";
|
|
9
9
|
import { initializeMcp } from "../../mcp/index.mjs";
|
|
10
10
|
import { createWebToolsFromConfig } from "../../web/tools.mjs";
|
|
11
|
-
import { createPermissionController } from "../../cli/permissions.mjs";
|
|
12
11
|
import { resolvePiSessionManager } from "../../session/pi-manager.mjs";
|
|
13
12
|
import { createModelContextDumper } from "../../debug/model-context-dumper.mjs";
|
|
14
13
|
import { createLogger, installProcessLogHandlers } from "../../debug/logger.mjs";
|
|
@@ -23,7 +22,6 @@ const DEFAULT_DEPS = {
|
|
|
23
22
|
createMarkdownMemoryTools,
|
|
24
23
|
initializeMcp,
|
|
25
24
|
createWebToolsFromConfig,
|
|
26
|
-
createPermissionController,
|
|
27
25
|
resolvePiSessionManager,
|
|
28
26
|
createModelContextDumper,
|
|
29
27
|
createMarchAuthStorage,
|
|
@@ -74,7 +72,7 @@ export async function createIsolatedRunner(options = {}, deps = {}) {
|
|
|
74
72
|
enabled: true,
|
|
75
73
|
}),
|
|
76
74
|
useRuntimeHost: true,
|
|
77
|
-
|
|
75
|
+
syncMarchSessionState: true,
|
|
78
76
|
lifecycleHooks: options.lifecycleHooks ?? [],
|
|
79
77
|
lifecycleDiagnostics: options.lifecycleDiagnostics ?? [],
|
|
80
78
|
authStorage: d.createMarchAuthStorage({
|
|
@@ -85,11 +83,12 @@ export async function createIsolatedRunner(options = {}, deps = {}) {
|
|
|
85
83
|
maxTurns: options.config?.maxTurns ?? undefined,
|
|
86
84
|
trimBatch: options.config?.trimBatch ?? undefined,
|
|
87
85
|
hostedTools: options.config?.hostedTools,
|
|
88
|
-
|
|
86
|
+
notificationContext: options.notificationContext,
|
|
89
87
|
modelContextDumper: d.createModelContextDumper(options.modelContextDumper ?? { enabled: false }),
|
|
90
88
|
turnNotifier: d.createDesktopTurnNotifier({
|
|
91
89
|
enabled: Boolean(options.config?.notifications?.turnEnd),
|
|
92
90
|
config: options.config?.notifications,
|
|
91
|
+
onActivation: (activation) => d.peer.notify("notificationActivation", activation),
|
|
93
92
|
}),
|
|
94
93
|
logger,
|
|
95
94
|
onModelPayload: (event) => d.peer.notify("modelPayload", pickModelPayloadEvent(event)),
|
|
@@ -26,7 +26,6 @@ export async function createRunnerRuntimeHost({
|
|
|
26
26
|
mcpTools = [],
|
|
27
27
|
webTools = [],
|
|
28
28
|
lifecycle = null,
|
|
29
|
-
permissionController = null,
|
|
30
29
|
extensionPaths = [],
|
|
31
30
|
hostedTools = {},
|
|
32
31
|
onRebind = null,
|
|
@@ -63,7 +62,6 @@ export async function createRunnerRuntimeHost({
|
|
|
63
62
|
mcpTools,
|
|
64
63
|
webTools,
|
|
65
64
|
lifecycle,
|
|
66
|
-
permissionController,
|
|
67
65
|
authStorage,
|
|
68
66
|
projectMarchDir,
|
|
69
67
|
hostedTools,
|
|
@@ -53,7 +53,6 @@ export function createRuntimeUiClient(eventBus) {
|
|
|
53
53
|
recall: ({ source, hints }) => eventBus.emit({ type: "recall", source, hints }),
|
|
54
54
|
providerQuotaSnapshot: (snapshot) => eventBus.emit({ type: "provider_quota_snapshot", snapshot }),
|
|
55
55
|
editDiff: (path, diffLines) => eventBus.emit({ type: "edit_diff", path, diffLines }),
|
|
56
|
-
requestPermission: (request) => eventBus.request({ type: "permission_request", ...request }),
|
|
57
56
|
};
|
|
58
57
|
}
|
|
59
58
|
|
|
@@ -75,7 +74,6 @@ export function dispatchRuntimeUiEvent(ui, event) {
|
|
|
75
74
|
case "recall": return ui.recall?.({ source: event.source, hints: event.hints });
|
|
76
75
|
case "provider_quota_snapshot": return ui.providerQuotaSnapshot?.(event.snapshot);
|
|
77
76
|
case "edit_diff": return ui.editDiff?.(event.path, event.diffLines);
|
|
78
|
-
case "permission_request": return ui.requestPermission?.({ toolName: event.toolName, params: event.params, category: event.category });
|
|
79
77
|
default: return undefined;
|
|
80
78
|
}
|
|
81
79
|
}
|
|
@@ -16,7 +16,6 @@ export function resolveRunnerSessionOptions({
|
|
|
16
16
|
mcpTools = [],
|
|
17
17
|
webTools = [],
|
|
18
18
|
lifecycle = null,
|
|
19
|
-
permissionController = null,
|
|
20
19
|
authStorage = null,
|
|
21
20
|
projectMarchDir = null,
|
|
22
21
|
stateRoot = null,
|
|
@@ -32,7 +31,7 @@ export function resolveRunnerSessionOptions({
|
|
|
32
31
|
?? (provider && modelId ? getModel(provider, modelId) : null);
|
|
33
32
|
if (!model) throw new Error(`Model not found: ${provider}/${modelId}`);
|
|
34
33
|
|
|
35
|
-
const customTools = createMarchCustomTools({ cwd, engine, ui, memoryTools, historyStore, shellRuntime, lspService, mcpTools, webTools, lifecycle,
|
|
34
|
+
const customTools = createMarchCustomTools({ cwd, engine, ui, memoryTools, historyStore, shellRuntime, lspService, mcpTools, webTools, lifecycle, authStorage, projectMarchDir, stateRoot, getCurrentModel: () => getCurrentModel?.() ?? model });
|
|
36
35
|
const customToolNames = customTools.map((tool) => tool.name);
|
|
37
36
|
const tools = [
|
|
38
37
|
...customToolNames.filter((name) => name === "read"),
|
package/src/agent/tools.mjs
CHANGED
|
@@ -7,7 +7,6 @@ import { createReadImageTool } from "./file-tools/read-image-tool.mjs";
|
|
|
7
7
|
import { createSendBinaryTool } from "./output/send-binary-tool.mjs";
|
|
8
8
|
import { createScreenTool } from "./screen-tools/screen-tool.mjs";
|
|
9
9
|
import { createListWindowsTool } from "./screen-tools/list-windows-tool.mjs";
|
|
10
|
-
import { toolText } from "./tool-result.mjs";
|
|
11
10
|
import { createShellTools } from "../shell/tools.mjs";
|
|
12
11
|
import { initImageGen } from "../image-gen/index.mjs";
|
|
13
12
|
import { createSuperGrokTool } from "../supergrok/tool.mjs";
|
|
@@ -15,7 +14,7 @@ import { createBrowserTools } from "../browser/tools/index.mjs";
|
|
|
15
14
|
import { createRuntimeRestartTool } from "./lifecycle/runtime-restart-tool.mjs";
|
|
16
15
|
import { createHistorySearchTool } from "../history/tool.mjs";
|
|
17
16
|
|
|
18
|
-
export function createMarchCustomTools({ cwd, engine, ui, memoryTools = [], historyStore = null, shellRuntime = null, lspService = null, mcpTools = [], webTools = [], lifecycle = null,
|
|
17
|
+
export function createMarchCustomTools({ cwd, engine, ui, memoryTools = [], historyStore = null, shellRuntime = null, lspService = null, mcpTools = [], webTools = [], lifecycle = null, authStorage = null, projectMarchDir = null, stateRoot = null, getCurrentModel = null }) {
|
|
19
18
|
const commandExecTool = createCommandExecTool({ cwd });
|
|
20
19
|
const codeSearchTool = createCodeSearchTool({ engine, stateRoot });
|
|
21
20
|
const contextStatsTool = createContextStatsTool({ engine });
|
|
@@ -47,25 +46,5 @@ export function createMarchCustomTools({ cwd, engine, ui, memoryTools = [], hist
|
|
|
47
46
|
...(authStorage ? [createSuperGrokTool({ authStorage, projectMarchDir })] : []),
|
|
48
47
|
...(authStorage ? initImageGen({ authStorage, projectMarchDir }) : []),
|
|
49
48
|
];
|
|
50
|
-
|
|
51
|
-
if (!permissionController) return tools;
|
|
52
|
-
|
|
53
|
-
return tools.map((tool) => {
|
|
54
|
-
const execute = tool.execute;
|
|
55
|
-
if (!execute) return tool;
|
|
56
|
-
const wrapped = async (toolCallId, params, signal, onUpdate) => {
|
|
57
|
-
const decision = await permissionController.requestApproval(
|
|
58
|
-
tool.name,
|
|
59
|
-
params,
|
|
60
|
-
ui.requestPermission
|
|
61
|
-
? (ctx) => ui.requestPermission(ctx)
|
|
62
|
-
: null,
|
|
63
|
-
);
|
|
64
|
-
if (decision.behavior === "deny") {
|
|
65
|
-
return toolText(`Permission denied: ${decision.message}`, { error: true, permissionDenied: true });
|
|
66
|
-
}
|
|
67
|
-
return execute(toolCallId, params, signal, onUpdate);
|
|
68
|
-
};
|
|
69
|
-
return { ...tool, execute: wrapped };
|
|
70
|
-
});
|
|
49
|
+
return tools;
|
|
71
50
|
}
|
|
@@ -14,7 +14,7 @@ export async function runRunnerTurn({
|
|
|
14
14
|
setModelCallKind,
|
|
15
15
|
logger = null,
|
|
16
16
|
setPhase = null,
|
|
17
|
-
|
|
17
|
+
syncCurrentMarchSessionState,
|
|
18
18
|
autoNameSession,
|
|
19
19
|
contextMode = "rebuild",
|
|
20
20
|
recordHistory = null,
|
|
@@ -79,7 +79,7 @@ export async function runRunnerTurn({
|
|
|
79
79
|
ui,
|
|
80
80
|
turnState,
|
|
81
81
|
midTurnRecallHints,
|
|
82
|
-
|
|
82
|
+
syncCurrentMarchSessionState,
|
|
83
83
|
autoNameSession,
|
|
84
84
|
recordHistory,
|
|
85
85
|
});
|
|
@@ -129,7 +129,7 @@ function logSessionEvent(logger, event) {
|
|
|
129
129
|
});
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
function finalizeTurn({ prompt, userMessage, userRecallHints, currentProject, memoryStore, engine, ui, turnState, midTurnRecallHints,
|
|
132
|
+
function finalizeTurn({ prompt, userMessage, userRecallHints, currentProject, memoryStore, engine, ui, turnState, midTurnRecallHints, syncCurrentMarchSessionState, autoNameSession, recordHistory }) {
|
|
133
133
|
closeAssistantReply({ ui, state: turnState });
|
|
134
134
|
const assistantRecallHints = flushAssistantRecall({ memoryStore, engine, turnState, currentProject });
|
|
135
135
|
engine.setPendingAssistantRecallHints?.(assistantRecallHints);
|
|
@@ -145,7 +145,7 @@ function finalizeTurn({ prompt, userMessage, userRecallHints, currentProject, me
|
|
|
145
145
|
recordHistory?.({ ...turn, thinking: assistantThinkingText(turnState), toolCalls: turnState.toolCalls });
|
|
146
146
|
|
|
147
147
|
autoNameSession?.();
|
|
148
|
-
|
|
148
|
+
syncCurrentMarchSessionState();
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
function flushAssistantRecall({ memoryStore, engine, turnState, currentProject }) {
|
package/src/cli/args.mjs
CHANGED
|
@@ -17,7 +17,6 @@ export function parseCliArgs(argv) {
|
|
|
17
17
|
"pi-runtime-host": { type: "boolean" },
|
|
18
18
|
"shell-runtime": { type: "boolean" },
|
|
19
19
|
"no-shell-runtime": { type: "boolean" },
|
|
20
|
-
"permission-mode": { type: "string" },
|
|
21
20
|
host: { type: "string" },
|
|
22
21
|
port: { type: "string" },
|
|
23
22
|
"api-port": { type: "string" },
|
|
@@ -27,6 +26,7 @@ export function parseCliArgs(argv) {
|
|
|
27
26
|
workspace: { type: "string" },
|
|
28
27
|
dev: { type: "boolean" },
|
|
29
28
|
help: { type: "boolean", short: "h" },
|
|
29
|
+
version: { type: "boolean", short: "v" },
|
|
30
30
|
},
|
|
31
31
|
allowPositionals: true,
|
|
32
32
|
});
|
|
@@ -47,7 +47,6 @@ export function parseCliArgs(argv) {
|
|
|
47
47
|
piSessions: values["pi-sessions"] ?? false,
|
|
48
48
|
piRuntimeHost: values["pi-runtime-host"] ?? false,
|
|
49
49
|
shellRuntime: values["no-shell-runtime"] ? false : true,
|
|
50
|
-
permissionMode: values["permission-mode"] ?? "bypassPermissions",
|
|
51
50
|
host: values.host ?? null,
|
|
52
51
|
port: values.port ?? null,
|
|
53
52
|
apiPort: values["api-port"] ?? null,
|
|
@@ -57,6 +56,7 @@ export function parseCliArgs(argv) {
|
|
|
57
56
|
workspace: values.workspace ?? null,
|
|
58
57
|
dev: values.dev ?? false,
|
|
59
58
|
help: values.help ?? false,
|
|
59
|
+
version: values.version ?? false,
|
|
60
60
|
prompt: commandName ? "" : positionals.join(" "),
|
|
61
61
|
};
|
|
62
62
|
}
|
|
@@ -97,7 +97,6 @@ Options:
|
|
|
97
97
|
--pi-runtime-host Force pi AgentSessionRuntime host path
|
|
98
98
|
--shell-runtime Enable interactive PTY shell tools (default)
|
|
99
99
|
--no-shell-runtime Disable interactive PTY shell tools and shell pane
|
|
100
|
-
--permission-mode <mode> Permission mode: default, bypassPermissions, dontAsk (default: bypassPermissions)
|
|
101
100
|
-e, --extension <path>
|
|
102
101
|
Load a pi extension path in the default runtime host (repeatable)
|
|
103
102
|
--host <host> With memory serve/web, bind host (default: 127.0.0.1)
|
|
@@ -108,5 +107,6 @@ Options:
|
|
|
108
107
|
--name <name> With memory serve/add, remote memory source name
|
|
109
108
|
--foreground With memory serve, run server in current process
|
|
110
109
|
-h, --help Show this help
|
|
110
|
+
-v, --version Show the March CLI version
|
|
111
111
|
`);
|
|
112
112
|
}
|
|
@@ -12,6 +12,7 @@ import { handleSessionNameCommand, parseSessionNameCommand } from "../../session
|
|
|
12
12
|
import { handleShellCommand, parseShellCommand } from "../../shell/shell-command.mjs";
|
|
13
13
|
import { handleProviderCommand, parseProviderCommand } from "../provider-command.mjs";
|
|
14
14
|
import { handleModeCommand, parseModeCommand } from "../mode-command.mjs";
|
|
15
|
+
import { WORKSPACE_SLASH_COMMANDS } from "../../workspace/command.mjs";
|
|
15
16
|
|
|
16
17
|
export const SLASH_COMMANDS = [
|
|
17
18
|
exactCommand({
|
|
@@ -94,6 +95,7 @@ export const SLASH_COMMANDS = [
|
|
|
94
95
|
parse: parseThinkingCommand,
|
|
95
96
|
run: async (ctx, command) => writeLines(ctx.ui, await handleThinkingCommand(command, { runner: ctx.runner, ui: ctx.ui })),
|
|
96
97
|
}),
|
|
98
|
+
...WORKSPACE_SLASH_COMMANDS,
|
|
97
99
|
exactCommand({
|
|
98
100
|
name: "status",
|
|
99
101
|
description: "Show runtime status",
|
|
@@ -225,10 +227,9 @@ function parsedCommand({ names, metadata, parse, run }) {
|
|
|
225
227
|
function sessionSourceCommand() {
|
|
226
228
|
return {
|
|
227
229
|
metadata: [
|
|
228
|
-
{ name: "session", description: "Open previous session selector" },
|
|
229
230
|
{ name: "save", description: "Show auto-save status" },
|
|
230
231
|
],
|
|
231
|
-
match: (trimmed) =>
|
|
232
|
+
match: (trimmed) => trimmed === "/save" ? { parsed: { trimmed } } : null,
|
|
232
233
|
run: async (ctx, { trimmed }) => handleSessionSourceCommand(trimmed, ctx),
|
|
233
234
|
};
|
|
234
235
|
}
|
|
@@ -282,7 +283,7 @@ function writeLines(ui, lines) {
|
|
|
282
283
|
export function formatHelpLines() {
|
|
283
284
|
return [
|
|
284
285
|
`Commands: ${getHelpCommandSyntaxes().join(", ")}`,
|
|
285
|
-
"Sessions: /session opens
|
|
286
|
+
"Sessions: /session opens the workspace session selector.",
|
|
286
287
|
"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",
|
|
287
288
|
];
|
|
288
289
|
}
|
package/src/cli/fallback-ui.mjs
CHANGED
|
@@ -48,7 +48,6 @@ export function createJsonUI() {
|
|
|
48
48
|
editDiff: (path, diffLines) => {
|
|
49
49
|
stdout.write(JSON.stringify({ type: "edit_diff", path, diff: diffLines }) + "\n");
|
|
50
50
|
},
|
|
51
|
-
requestPermission: async () => true,
|
|
52
51
|
setEscapeHandler: () => {},
|
|
53
52
|
setCtrlCHandler: () => {},
|
|
54
53
|
setShiftTabHandler: () => {},
|
|
@@ -137,7 +136,6 @@ export function createPlainUI() {
|
|
|
137
136
|
else stdout.write(`${dim(` ${d.text}`)}\n`);
|
|
138
137
|
}
|
|
139
138
|
},
|
|
140
|
-
requestPermission: async () => true,
|
|
141
139
|
setEscapeHandler: () => {},
|
|
142
140
|
setCtrlCHandler: () => {},
|
|
143
141
|
setShiftTabHandler: () => {},
|
|
@@ -34,7 +34,7 @@ export function formatModeReminder(mode = MODES.DO) {
|
|
|
34
34
|
"</mode>";
|
|
35
35
|
}
|
|
36
36
|
return "<mode>\n" +
|
|
37
|
-
"You are in do mode. You may implement changes when the user asks for execution, following normal
|
|
37
|
+
"You are in do mode. You may implement changes when the user asks for execution, following normal project rules.\n" +
|
|
38
38
|
"</mode>";
|
|
39
39
|
}
|
|
40
40
|
|
|
@@ -57,7 +57,7 @@ export function formatHotkeysPanel(keybindings = DEFAULT_KEYBINDINGS, diagnostic
|
|
|
57
57
|
...formatKeybindingDiagnostics(diagnostics),
|
|
58
58
|
"Input prefixes:",
|
|
59
59
|
" / Slash command autocomplete",
|
|
60
|
-
" /session
|
|
60
|
+
" /session Open workspace session selector",
|
|
61
61
|
" /thinking Choose or list/set thinking level",
|
|
62
62
|
" @ File path autocomplete",
|
|
63
63
|
" ! cmd Run local shell command without sending to the model",
|
package/src/cli/repl-loop.mjs
CHANGED
|
@@ -37,6 +37,10 @@ export async function runInteractiveRepl({
|
|
|
37
37
|
runner,
|
|
38
38
|
memoryStore,
|
|
39
39
|
currentProject,
|
|
40
|
+
currentProjectInfo = null,
|
|
41
|
+
workspaceSupervisor = null,
|
|
42
|
+
workspaceOutputRouter = null,
|
|
43
|
+
stateRoot = null,
|
|
40
44
|
sessionState,
|
|
41
45
|
sessionsRoot,
|
|
42
46
|
projectMarchDir,
|
|
@@ -58,7 +62,8 @@ export async function runInteractiveRepl({
|
|
|
58
62
|
let trimmed = line.trim();
|
|
59
63
|
if (!trimmed) continue;
|
|
60
64
|
|
|
61
|
-
const
|
|
65
|
+
const active = getActiveRuntime({ workspaceSupervisor, cwd, runner, memoryStore, currentProject, currentProjectInfo, sessionState, sessionsRoot, projectMarchDir, extensionPaths, keybindingConfig, promptTemplateConfig });
|
|
66
|
+
const handledInline = handleInlineCommand(trimmed, { cwd: active.cwd, ui, lastInlineShellCommand });
|
|
62
67
|
if (handledInline.type === "handled") {
|
|
63
68
|
lastInlineShellCommand = handledInline.lastInlineShellCommand;
|
|
64
69
|
continue;
|
|
@@ -67,45 +72,70 @@ export async function runInteractiveRepl({
|
|
|
67
72
|
|
|
68
73
|
const slashResult = await handleSlashCommand(trimmed, {
|
|
69
74
|
ui,
|
|
70
|
-
runner,
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
runner: active.runner,
|
|
76
|
+
workspaceSupervisor,
|
|
77
|
+
workspaceOutputRouter,
|
|
78
|
+
sessionState: active.sessionState,
|
|
79
|
+
sessionsRoot: active.sessionsRoot,
|
|
80
|
+
projectMarchDir: active.projectMarchDir,
|
|
74
81
|
sessionSource,
|
|
75
|
-
extensionPaths,
|
|
76
|
-
keybindings: keybindingConfig.keybindings,
|
|
77
|
-
keybindingDiagnostics: keybindingConfig.diagnostics,
|
|
78
|
-
promptTemplates: promptTemplateConfig.templates,
|
|
79
|
-
promptTemplateDiagnostics: promptTemplateConfig.diagnostics,
|
|
82
|
+
extensionPaths: active.extensionPaths,
|
|
83
|
+
keybindings: active.keybindingConfig.keybindings,
|
|
84
|
+
keybindingDiagnostics: active.keybindingConfig.diagnostics,
|
|
85
|
+
promptTemplates: active.promptTemplateConfig.templates,
|
|
86
|
+
promptTemplateDiagnostics: active.promptTemplateConfig.diagnostics,
|
|
80
87
|
modeState,
|
|
81
88
|
renderStartupBanner,
|
|
82
89
|
configHomeDir,
|
|
90
|
+
stateRoot,
|
|
91
|
+
currentProjectId: active.project?.projectId ?? null,
|
|
83
92
|
});
|
|
84
93
|
if (slashResult.exit) break;
|
|
85
94
|
if (slashResult.handled) {
|
|
86
|
-
|
|
95
|
+
const refreshedActive = getActiveRuntime({ workspaceSupervisor, cwd, runner, memoryStore, currentProject, currentProjectInfo, sessionState, sessionsRoot, projectMarchDir, extensionPaths, keybindingConfig, promptTemplateConfig });
|
|
96
|
+
refreshStatusBar(contextTokenRefreshOptions(slashResult, refreshedActive.runner));
|
|
87
97
|
continue;
|
|
88
98
|
}
|
|
89
99
|
|
|
90
|
-
const
|
|
100
|
+
const turnActive = getActiveRuntime({ workspaceSupervisor, cwd, runner, memoryStore, currentProject, currentProjectInfo, sessionState, sessionsRoot, projectMarchDir, extensionPaths, keybindingConfig, promptTemplateConfig });
|
|
101
|
+
const templateResult = expandPromptTemplate(trimmed, turnActive.promptTemplateConfig.templates);
|
|
91
102
|
if (templateResult.type === "template") {
|
|
92
103
|
ui.writeln(brightBlack(`● template: ${templateResult.name}`));
|
|
93
104
|
trimmed = templateResult.prompt;
|
|
94
105
|
}
|
|
95
106
|
|
|
96
|
-
|
|
107
|
+
if (turnActive.turnTask) {
|
|
108
|
+
ui.writeln("This session is still running. Use /session to start or inspect another session.");
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
startReplTurn({
|
|
113
|
+
runtime: turnActive,
|
|
97
114
|
prompt: trimmed,
|
|
98
|
-
runner,
|
|
99
|
-
memoryStore,
|
|
100
|
-
currentProject,
|
|
101
115
|
ui,
|
|
102
116
|
refreshStatusBar,
|
|
103
117
|
setTurnRunning,
|
|
118
|
+
workspaceSupervisor,
|
|
104
119
|
modeState,
|
|
105
120
|
});
|
|
106
121
|
}
|
|
107
122
|
}
|
|
108
123
|
|
|
124
|
+
export function getActiveRuntime({ workspaceSupervisor, cwd, runner, memoryStore, currentProject, currentProjectInfo, sessionState, sessionsRoot, projectMarchDir, extensionPaths, keybindingConfig, promptTemplateConfig }) {
|
|
125
|
+
return workspaceSupervisor?.getActive?.() ?? {
|
|
126
|
+
project: currentProjectInfo,
|
|
127
|
+
cwd,
|
|
128
|
+
runner,
|
|
129
|
+
memoryStore,
|
|
130
|
+
currentProject,
|
|
131
|
+
sessionState,
|
|
132
|
+
sessionsRoot,
|
|
133
|
+
projectMarchDir,
|
|
134
|
+
extensionPaths,
|
|
135
|
+
keybindingConfig,
|
|
136
|
+
promptTemplateConfig,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
109
139
|
export function contextTokenRefreshOptions(slashResult, runner) {
|
|
110
140
|
if (!slashResult?.refreshContextTokens) return undefined;
|
|
111
141
|
if (typeof runner.estimateContextTokens !== "function") return undefined;
|
|
@@ -127,6 +157,27 @@ function handleInlineCommand(trimmed, { cwd, ui, lastInlineShellCommand }) {
|
|
|
127
157
|
return { type: "none" };
|
|
128
158
|
}
|
|
129
159
|
|
|
160
|
+
function startReplTurn({ runtime, prompt, ui, refreshStatusBar, setTurnRunning, workspaceSupervisor = null, modeState = null }) {
|
|
161
|
+
const turnUi = runtime.ui ?? ui;
|
|
162
|
+
const task = runReplTurn({
|
|
163
|
+
prompt,
|
|
164
|
+
runner: runtime.runner,
|
|
165
|
+
memoryStore: runtime.memoryStore,
|
|
166
|
+
currentProject: runtime.currentProject,
|
|
167
|
+
ui: turnUi,
|
|
168
|
+
refreshStatusBar,
|
|
169
|
+
setTurnRunning,
|
|
170
|
+
modeState,
|
|
171
|
+
}).finally(() => {
|
|
172
|
+
if (runtime.turnTask === task) runtime.turnTask = null;
|
|
173
|
+
const hasRunningTurn = Boolean(workspaceSupervisor?.hasRunningTurn?.());
|
|
174
|
+
setTurnRunning(hasRunningTurn);
|
|
175
|
+
if (!hasRunningTurn) refreshStatusBar.stopWorking?.();
|
|
176
|
+
refreshStatusBar();
|
|
177
|
+
});
|
|
178
|
+
runtime.turnTask = task;
|
|
179
|
+
}
|
|
180
|
+
|
|
130
181
|
async function runReplTurn({ prompt, runner, memoryStore, currentProject, ui, refreshStatusBar, setTurnRunning, modeState = null }) {
|
|
131
182
|
memoryStore.beginTurn();
|
|
132
183
|
try {
|
|
@@ -143,10 +194,7 @@ async function runReplTurn({ prompt, runner, memoryStore, currentProject, ui, re
|
|
|
143
194
|
} catch (err) {
|
|
144
195
|
ui.writeln(`Error: ${err.message}`);
|
|
145
196
|
} finally {
|
|
146
|
-
setTurnRunning(false);
|
|
147
|
-
refreshStatusBar.stopWorking?.();
|
|
148
197
|
memoryStore.endTurn();
|
|
149
|
-
refreshStatusBar();
|
|
150
198
|
}
|
|
151
199
|
}
|
|
152
200
|
|