@sortedyuan/maybecode 0.3.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +166 -55
- package/README.zh-CN.md +267 -0
- package/dist/application.d.ts +40 -34
- package/dist/application.d.ts.map +1 -1
- package/dist/application.js +290 -170
- package/dist/application.js.map +1 -1
- package/dist/args.d.ts +2 -2
- package/dist/args.d.ts.map +1 -1
- package/dist/args.js +50 -27
- package/dist/args.js.map +1 -1
- package/dist/bin.js +82 -71
- package/dist/bin.js.map +4 -4
- package/dist/cli/chunk-3IORPKBL.js +3572 -0
- package/dist/cli/chunk-3IORPKBL.js.map +7 -0
- package/dist/cli/{chunk-LVTRXPDS.js → chunk-4B2Z6KW7.js} +1547 -1536
- package/dist/cli/chunk-4B2Z6KW7.js.map +7 -0
- package/dist/cli/{chunk-JT6VBKOM.js → chunk-4WG6JIJJ.js} +127 -33
- package/dist/cli/{chunk-JT6VBKOM.js.map → chunk-4WG6JIJJ.js.map} +3 -3
- package/dist/cli/{chunk-K5JWPNSY.js → chunk-5SLWALZK.js} +3521 -16164
- package/dist/cli/chunk-5SLWALZK.js.map +7 -0
- package/dist/cli/chunk-MNBYXL5Y.js +132 -0
- package/dist/cli/chunk-MNBYXL5Y.js.map +7 -0
- package/dist/cli/{chunk-F4XRPLUM.js → chunk-SLWLUEHQ.js} +226 -86
- package/dist/cli/chunk-SLWLUEHQ.js.map +7 -0
- package/dist/cli/chunk-UQDZ55LQ.js +199 -0
- package/dist/cli/chunk-UQDZ55LQ.js.map +7 -0
- package/dist/cli/{chunk-7ISOHFS7.js → chunk-WMSG5ZTR.js} +717 -388
- package/dist/cli/chunk-WMSG5ZTR.js.map +7 -0
- package/dist/cli/chunk-WVIRS76R.js +4057 -0
- package/dist/cli/chunk-WVIRS76R.js.map +7 -0
- package/dist/cli/{chunk-HOU5ITUK.js → chunk-XTEMRAQW.js} +1 -1
- package/dist/cli/chunk-XTEMRAQW.js.map +7 -0
- package/dist/cli/chunk-Z3BOPBVU.js +91 -0
- package/dist/cli/chunk-Z3BOPBVU.js.map +7 -0
- package/dist/cli/{configured-WHY3GGAJ.js → configured-ACNM6TRQ.js} +10 -9
- package/dist/cli/{file-type-R2T7TBHI.js → file-type-HLHPV7WC.js} +817 -13
- package/dist/cli/file-type-HLHPV7WC.js.map +7 -0
- package/dist/cli/mcp-auth-XD5U7WCV.js +74 -0
- package/dist/cli/mcp-auth-XD5U7WCV.js.map +7 -0
- package/dist/cli/onboarding-WQWCPYEO.js +530 -0
- package/dist/cli/onboarding-WQWCPYEO.js.map +7 -0
- package/dist/cli/onboarding-check-HRRI5OJ7.js +32 -0
- package/dist/cli/onboarding-check-HRRI5OJ7.js.map +7 -0
- package/dist/cli/{retained-tui-VJ3VX4R3.js → retained-tui-QF5VMYLC.js} +788 -332
- package/dist/cli/retained-tui-QF5VMYLC.js.map +7 -0
- package/dist/cli/{sixel-LWTCM76G.js → sixel-ISZ4FZ3U.js} +37 -37
- package/dist/cli/{sixel-LWTCM76G.js.map → sixel-ISZ4FZ3U.js.map} +1 -1
- package/dist/cli/{team-T7G7PPNN.js → team-O2I5BXHM.js} +7 -6
- package/dist/cli/{team-v2-JGBBQ7FR.js → team-v2-YYO2G7DJ.js} +816 -390
- package/dist/cli/team-v2-YYO2G7DJ.js.map +7 -0
- package/dist/cli/{web-server-FOMNPY7Q.js → web-server-SXMH6FGA.js} +55 -19
- package/dist/cli/web-server-SXMH6FGA.js.map +7 -0
- package/dist/cli/{web-ui-COB6PKC5.js → web-ui-UWQUFE4W.js} +7 -6
- package/dist/config-schema.json +337 -0
- package/dist/configured.d.ts +18 -11
- package/dist/configured.d.ts.map +1 -1
- package/dist/configured.js +213 -390
- package/dist/configured.js.map +1 -1
- package/dist/controller.d.ts +19 -18
- package/dist/controller.d.ts.map +1 -1
- package/dist/delegation-commands.d.ts +1 -1
- package/dist/delegation-commands.d.ts.map +1 -1
- package/dist/delegation-commands.js +8 -8
- package/dist/delegation-commands.js.map +1 -1
- package/dist/errors.d.ts +2 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +2 -1
- package/dist/errors.js.map +1 -1
- package/dist/events.d.ts +8 -6
- package/dist/events.d.ts.map +1 -1
- package/dist/fork-picker.d.ts.map +1 -1
- package/dist/fork-picker.js +19 -5
- package/dist/fork-picker.js.map +1 -1
- package/dist/git-request.d.ts +6 -6
- package/dist/git-request.d.ts.map +1 -1
- package/dist/git-request.js +28 -15
- package/dist/git-request.js.map +1 -1
- package/dist/goal-commands.d.ts +1 -1
- package/dist/goal-commands.d.ts.map +1 -1
- package/dist/goal-commands.js +12 -5
- package/dist/goal-commands.js.map +1 -1
- package/dist/index.d.ts +5 -37
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -36
- package/dist/index.js.map +1 -1
- package/dist/instructions.d.ts +2 -7
- package/dist/instructions.d.ts.map +1 -1
- package/dist/instructions.js +7 -15
- package/dist/instructions.js.map +1 -1
- package/dist/keymap.d.ts +2 -2
- package/dist/keymap.d.ts.map +1 -1
- package/dist/keymap.js +2 -2
- package/dist/keymap.js.map +1 -1
- package/dist/maybecode-config.schema.json +1765 -0
- package/dist/mcp-auth.d.ts +1 -1
- package/dist/mcp-auth.d.ts.map +1 -1
- package/dist/mcp-auth.js +11 -8
- package/dist/mcp-auth.js.map +1 -1
- package/dist/mcp-commands.d.ts.map +1 -1
- package/dist/mcp-commands.js +18 -4
- package/dist/mcp-commands.js.map +1 -1
- package/dist/mcp-interaction-ui.d.ts.map +1 -1
- package/dist/mcp-interaction-ui.js +11 -4
- package/dist/mcp-interaction-ui.js.map +1 -1
- package/dist/media-history.d.ts +1 -1
- package/dist/media-history.d.ts.map +1 -1
- package/dist/media-history.js +8 -2
- package/dist/media-history.js.map +1 -1
- package/dist/model-picker.d.ts.map +1 -1
- package/dist/model-picker.js +10 -11
- package/dist/model-picker.js.map +1 -1
- package/dist/model-transition.d.ts +11 -0
- package/dist/model-transition.d.ts.map +1 -0
- package/dist/model-transition.js +48 -0
- package/dist/model-transition.js.map +1 -0
- package/dist/model.d.ts +2 -2
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +8 -4
- package/dist/model.js.map +1 -1
- package/dist/onboarding-check.d.ts +3 -0
- package/dist/onboarding-check.d.ts.map +1 -0
- package/dist/onboarding-check.js +22 -0
- package/dist/onboarding-check.js.map +1 -0
- package/dist/onboarding.d.ts +6 -0
- package/dist/onboarding.d.ts.map +1 -0
- package/dist/onboarding.js +463 -0
- package/dist/onboarding.js.map +1 -0
- package/dist/plugins/application.d.ts +6 -4
- package/dist/plugins/application.d.ts.map +1 -1
- package/dist/plugins/application.js +106 -52
- package/dist/plugins/application.js.map +1 -1
- package/dist/plugins/instructions.d.ts +1 -1
- package/dist/plugins/instructions.d.ts.map +1 -1
- package/dist/plugins/instructions.js +24 -11
- package/dist/plugins/instructions.js.map +1 -1
- package/dist/plugins/resources.d.ts +2 -2
- package/dist/plugins/resources.d.ts.map +1 -1
- package/dist/plugins/resources.js +22 -12
- package/dist/plugins/resources.js.map +1 -1
- package/dist/policy.d.ts +1 -1
- package/dist/policy.d.ts.map +1 -1
- package/dist/policy.js +59 -11
- package/dist/policy.js.map +1 -1
- package/dist/run.d.ts +2 -0
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +38 -33
- package/dist/run.js.map +1 -1
- package/dist/runtime-instructions.d.ts +1 -1
- package/dist/runtime-instructions.d.ts.map +1 -1
- package/dist/runtime-instructions.js +15 -7
- package/dist/runtime-instructions.js.map +1 -1
- package/dist/session-navigation.d.ts +6 -0
- package/dist/session-navigation.d.ts.map +1 -0
- package/dist/session-navigation.js +64 -0
- package/dist/session-navigation.js.map +1 -0
- package/dist/session-picker.d.ts +1 -1
- package/dist/session-picker.d.ts.map +1 -1
- package/dist/session-picker.js +23 -32
- package/dist/session-picker.js.map +1 -1
- package/dist/settings.d.ts +718 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +14 -0
- package/dist/settings.js.map +1 -0
- package/dist/skills.d.ts +1 -1
- package/dist/skills.d.ts.map +1 -1
- package/dist/skills.js +10 -12
- package/dist/skills.js.map +1 -1
- package/dist/slash-commands.d.ts +2 -2
- package/dist/slash-commands.d.ts.map +1 -1
- package/dist/slash-commands.js +149 -67
- package/dist/slash-commands.js.map +1 -1
- package/dist/team-execution.d.ts +10 -0
- package/dist/team-execution.d.ts.map +1 -0
- package/dist/team-execution.js +29 -0
- package/dist/team-execution.js.map +1 -0
- package/dist/team-patches.d.ts.map +1 -1
- package/dist/team-patches.js +149 -52
- package/dist/team-patches.js.map +1 -1
- package/dist/team-plan.d.ts +2 -2
- package/dist/team-plan.d.ts.map +1 -1
- package/dist/team-plan.js +115 -34
- package/dist/team-plan.js.map +1 -1
- package/dist/team-recovery.d.ts +1 -1
- package/dist/team-recovery.d.ts.map +1 -1
- package/dist/team-recovery.js +40 -10
- package/dist/team-recovery.js.map +1 -1
- package/dist/team-v2.d.ts.map +1 -1
- package/dist/team-v2.js +335 -104
- package/dist/team-v2.js.map +1 -1
- package/dist/team-verification.d.ts +4 -2
- package/dist/team-verification.d.ts.map +1 -1
- package/dist/team-verification.js +300 -97
- package/dist/team-verification.js.map +1 -1
- package/dist/team.d.ts +2 -2
- package/dist/team.d.ts.map +1 -1
- package/dist/team.js +172 -62
- package/dist/team.js.map +1 -1
- package/dist/terminal-web.d.ts +1 -0
- package/dist/terminal-web.d.ts.map +1 -1
- package/dist/terminal-web.js +28 -10
- package/dist/terminal-web.js.map +1 -1
- package/dist/ui/actions.d.ts.map +1 -1
- package/dist/ui/actions.js.map +1 -1
- package/dist/ui/retained-tui.d.ts.map +1 -1
- package/dist/ui/retained-tui.js +231 -173
- package/dist/ui/retained-tui.js.map +1 -1
- package/dist/ui/{prototype-view.d.ts → terminal-view.d.ts} +7 -7
- package/dist/ui/terminal-view.d.ts.map +1 -0
- package/dist/ui/{prototype-view.js → terminal-view.js} +185 -98
- package/dist/ui/terminal-view.js.map +1 -0
- package/dist/web-commands.d.ts.map +1 -1
- package/dist/web-commands.js +160 -57
- package/dist/web-commands.js.map +1 -1
- package/dist/web-extension.d.ts.map +1 -1
- package/dist/web-extension.js +14 -4
- package/dist/web-extension.js.map +1 -1
- package/dist/web-server.d.ts.map +1 -1
- package/dist/web-server.js +2 -1
- package/dist/web-server.js.map +1 -1
- package/dist/web-ui.d.ts.map +1 -1
- package/dist/web-ui.js +167 -40
- package/dist/web-ui.js.map +1 -1
- package/dist/workspace-configuration.d.ts +7 -0
- package/dist/workspace-configuration.d.ts.map +1 -0
- package/dist/workspace-configuration.js +134 -0
- package/dist/workspace-configuration.js.map +1 -0
- package/dist/workspace-state.d.ts +20 -0
- package/dist/workspace-state.d.ts.map +1 -0
- package/dist/workspace-state.js +2 -0
- package/dist/workspace-state.js.map +1 -0
- package/dist/workspace.d.ts +26 -43
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +261 -323
- package/dist/workspace.js.map +1 -1
- package/package.json +21 -31
- package/dist/cli/chunk-7ISOHFS7.js.map +0 -7
- package/dist/cli/chunk-F4XRPLUM.js.map +0 -7
- package/dist/cli/chunk-H7SNBFO4.js +0 -5522
- package/dist/cli/chunk-H7SNBFO4.js.map +0 -7
- package/dist/cli/chunk-HOU5ITUK.js.map +0 -7
- package/dist/cli/chunk-K5JWPNSY.js.map +0 -7
- package/dist/cli/chunk-LVTRXPDS.js.map +0 -7
- package/dist/cli/chunk-VAZMCNBB.js +0 -686
- package/dist/cli/chunk-VAZMCNBB.js.map +0 -7
- package/dist/cli/chunk-WOFEI42C.js +0 -7820
- package/dist/cli/chunk-WOFEI42C.js.map +0 -7
- package/dist/cli/file-type-R2T7TBHI.js.map +0 -7
- package/dist/cli/mcp-auth-UNRHSIKJ.js +0 -63
- package/dist/cli/mcp-auth-UNRHSIKJ.js.map +0 -7
- package/dist/cli/retained-tui-VJ3VX4R3.js.map +0 -7
- package/dist/cli/team-v2-JGBBQ7FR.js.map +0 -7
- package/dist/cli/tui-SA74DKMA.js +0 -1705
- package/dist/cli/tui-SA74DKMA.js.map +0 -7
- package/dist/cli/web-server-FOMNPY7Q.js.map +0 -7
- package/dist/delegation.d.ts +0 -2
- package/dist/delegation.d.ts.map +0 -1
- package/dist/delegation.js +0 -2
- package/dist/delegation.js.map +0 -1
- package/dist/history-memory.d.ts +0 -2
- package/dist/history-memory.d.ts.map +0 -1
- package/dist/history-memory.js +0 -2
- package/dist/history-memory.js.map +0 -1
- package/dist/subagent-budget.d.ts +0 -2
- package/dist/subagent-budget.d.ts.map +0 -1
- package/dist/subagent-budget.js +0 -2
- package/dist/subagent-budget.js.map +0 -1
- package/dist/subagent-files.d.ts +0 -2
- package/dist/subagent-files.d.ts.map +0 -1
- package/dist/subagent-files.js +0 -2
- package/dist/subagent-files.js.map +0 -1
- package/dist/subagent-host.d.ts +0 -2
- package/dist/subagent-host.d.ts.map +0 -1
- package/dist/subagent-host.js +0 -2
- package/dist/subagent-host.js.map +0 -1
- package/dist/subagent-instructions.d.ts +0 -2
- package/dist/subagent-instructions.d.ts.map +0 -1
- package/dist/subagent-instructions.js +0 -2
- package/dist/subagent-instructions.js.map +0 -1
- package/dist/subagents.d.ts +0 -2
- package/dist/subagents.d.ts.map +0 -1
- package/dist/subagents.js +0 -2
- package/dist/subagents.js.map +0 -1
- package/dist/summarizer.d.ts +0 -2
- package/dist/summarizer.d.ts.map +0 -1
- package/dist/summarizer.js +0 -2
- package/dist/summarizer.js.map +0 -1
- package/dist/tui.d.ts +0 -7
- package/dist/tui.d.ts.map +0 -1
- package/dist/tui.js +0 -1109
- package/dist/tui.js.map +0 -1
- package/dist/ui/prototype-view.d.ts.map +0 -1
- package/dist/ui/prototype-view.js.map +0 -1
- /package/dist/cli/{configured-WHY3GGAJ.js.map → configured-ACNM6TRQ.js.map} +0 -0
- /package/dist/cli/{team-T7G7PPNN.js.map → team-O2I5BXHM.js.map} +0 -0
- /package/dist/cli/{web-ui-COB6PKC5.js.map → web-ui-UWQUFE4W.js.map} +0 -0
package/dist/workspace.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { isAbsolute, relative, resolve } from "node:path";
|
|
2
1
|
import { randomUUID } from "node:crypto";
|
|
3
2
|
import { mediaHistory } from "./media-history.js";
|
|
4
|
-
import { MaybeCodeUsageError } from "./errors.js";
|
|
5
3
|
import { parsePermissionMode } from "./policy.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { AsyncEventQueue, RunCancelledError, isStreamingMayEvent, } from "@sortedyuan/core";
|
|
4
|
+
import { observabilityService } from "@sortedyuan/observability/plugin";
|
|
5
|
+
import { GitCheckpointError, GitWorkspaceConflictError, } from "@sortedyuan/may/application/git-workspace";
|
|
6
|
+
import { AsyncEventQueue, RunCancelledError, isStreamingMayEvent, omitUndefined, } from "@sortedyuan/may/core";
|
|
10
7
|
import { mcpResourceToUserMessage, mcpPromptToUserMessage, mcpTaskToUserMessage, } from "@sortedyuan/mcp";
|
|
11
|
-
import {
|
|
8
|
+
import { GOAL_STATE_KEY } from "@sortedyuan/may/goals";
|
|
9
|
+
import { openWorkspaceConfiguration } from "./workspace-configuration.js";
|
|
10
|
+
import { unknownReasoningEffort, withModelConfiguration } from "./model-transition.js";
|
|
11
|
+
import { workspaceForkPoints } from "./session-navigation.js";
|
|
12
12
|
/** MaybeCode model policy around the reusable multi-session workspace. */
|
|
13
13
|
export class MaybeCodeWorkspace {
|
|
14
14
|
events;
|
|
@@ -16,7 +16,7 @@ export class MaybeCodeWorkspace {
|
|
|
16
16
|
state;
|
|
17
17
|
eventQueue = new AsyncEventQueue({
|
|
18
18
|
maxBufferedValues: 1024,
|
|
19
|
-
isDroppable: (event) => event.type === "mcp.resource.updated" || event.type === "run.event" && isStreamingMayEvent(event.event),
|
|
19
|
+
isDroppable: (event) => event.type === "mcp.resource.updated" || (event.type === "run.event" && isStreamingMayEvent(event.event)),
|
|
20
20
|
});
|
|
21
21
|
managerEventRelay;
|
|
22
22
|
mcpEventRelays = new Set();
|
|
@@ -43,79 +43,7 @@ export class MaybeCodeWorkspace {
|
|
|
43
43
|
this.connectMcpEvents();
|
|
44
44
|
}
|
|
45
45
|
static async open(options) {
|
|
46
|
-
|
|
47
|
-
throw new TypeError("delegationNotifications must be boolean");
|
|
48
|
-
}
|
|
49
|
-
const state = {
|
|
50
|
-
rootWorkspace: resolve(options.workspace),
|
|
51
|
-
git: new Map(),
|
|
52
|
-
createdSessions: new Map(),
|
|
53
|
-
options: withoutSelection({
|
|
54
|
-
...options,
|
|
55
|
-
permissionMode: parsePermissionMode(options.permissionMode ?? "default"),
|
|
56
|
-
workspace: resolve(options.workspace),
|
|
57
|
-
}),
|
|
58
|
-
};
|
|
59
|
-
if (state.options.git !== false)
|
|
60
|
-
state.git.set(state.rootWorkspace, await ProjectGitWorkspace.open({
|
|
61
|
-
...state.options.git, workspace: state.rootWorkspace, deferInitialization: true,
|
|
62
|
-
excludedPaths: [...(state.options.git?.excludedPaths ?? []), ...workspaceStoragePaths(state.options, state.rootWorkspace)],
|
|
63
|
-
}));
|
|
64
|
-
const manager = await AgentWorkspace.open({
|
|
65
|
-
workspace: state.options.workspace,
|
|
66
|
-
store: state.options.store,
|
|
67
|
-
catalog: state.options.catalog,
|
|
68
|
-
workspacePaths: async () => [state.rootWorkspace, ...((await state.git.get(state.rootWorkspace)?.listWorktrees()) ?? [])
|
|
69
|
-
.filter(tree => tree.status !== "deleted").map(tree => tree.workspace)],
|
|
70
|
-
openApplication: async (selection) => {
|
|
71
|
-
const workspace = selection.workspace ?? state.options.workspace;
|
|
72
|
-
if (workspace !== state.options.workspace && (state.options.tools || state.options.additionalTools || state.options.toolSource) && !state.options.configureWorkspace) {
|
|
73
|
-
throw new Error("Custom workspace tools require configureWorkspace before creating or opening a worktree");
|
|
74
|
-
}
|
|
75
|
-
const configured = await state.options.configureWorkspace?.(workspace);
|
|
76
|
-
let gitWorkspace = state.git.get(workspace);
|
|
77
|
-
if (state.options.git !== false && !gitWorkspace) {
|
|
78
|
-
gitWorkspace = await ProjectGitWorkspace.open({ ...state.options.git, workspace, deferInitialization: true,
|
|
79
|
-
excludedPaths: [...(state.options.git?.excludedPaths ?? []), ...workspaceStoragePaths(state.options, workspace)] });
|
|
80
|
-
state.git.set(workspace, gitWorkspace);
|
|
81
|
-
}
|
|
82
|
-
let nextOptions = { ...state.options, ...configured, workspace,
|
|
83
|
-
modelRuntimeOptions: state.options.modelRuntimeOptions ?? configuredModelOptions(state.options, state.options.modelInfo?.profile) };
|
|
84
|
-
if (selection.fork) {
|
|
85
|
-
if (!state.options.store.inspect)
|
|
86
|
-
throw new Error("Historical model selection requires read-only Session inspection");
|
|
87
|
-
const history = await state.options.store.inspect(selection.fork.sessionId);
|
|
88
|
-
const event = [...history].reverse().find(item => item.seq <= selection.fork.positionSeq && item.type === "state.updated" && item.key === "maybecode.model");
|
|
89
|
-
if (event?.type === "state.updated") {
|
|
90
|
-
const saved = readHistoricalModel(event.value);
|
|
91
|
-
if (saved.profile && nextOptions.createModelConfiguration) {
|
|
92
|
-
const configuration = await nextOptions.createModelConfiguration(saved.profile, saved.runtimeOptions);
|
|
93
|
-
assertHistoricalModel(saved, configuration.modelInfo);
|
|
94
|
-
nextOptions = withModelConfiguration(nextOptions, configuration, saved.runtimeOptions);
|
|
95
|
-
}
|
|
96
|
-
else {
|
|
97
|
-
assertHistoricalModel(saved, nextOptions.modelInfo);
|
|
98
|
-
nextOptions = { ...nextOptions, modelRuntimeOptions: saved.runtimeOptions };
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
const app = await MaybeCodeApplication.open({ ...applicationOptions(nextOptions, state),
|
|
103
|
-
...(gitWorkspace ? { gitWorkspace } : {}),
|
|
104
|
-
...(selection.fork ? { fork: selection.fork } : {}),
|
|
105
|
-
...(selection.metadata ? { sessionMetadata: selection.metadata } : {}),
|
|
106
|
-
...(selection.sessionId ? { sessionId: selection.sessionId } : {}), resume: selection.resume });
|
|
107
|
-
state.options = nextOptions;
|
|
108
|
-
if (!selection.resume && !selection.fork)
|
|
109
|
-
state.createdSessions.set(app.sessionId, workspace);
|
|
110
|
-
return app;
|
|
111
|
-
},
|
|
112
|
-
...(options.sessionId === undefined
|
|
113
|
-
? {}
|
|
114
|
-
: { sessionId: options.sessionId }),
|
|
115
|
-
...(options.autoResume === undefined
|
|
116
|
-
? {}
|
|
117
|
-
: { autoResume: options.autoResume }),
|
|
118
|
-
});
|
|
46
|
+
const { state, manager } = await openWorkspaceConfiguration(options);
|
|
119
47
|
const product = new MaybeCodeWorkspace(state, manager);
|
|
120
48
|
await product.syncWorktreeProcess();
|
|
121
49
|
return product;
|
|
@@ -123,86 +51,85 @@ export class MaybeCodeWorkspace {
|
|
|
123
51
|
get sessionId() {
|
|
124
52
|
return this.manager.sessionId;
|
|
125
53
|
}
|
|
126
|
-
get workspace() {
|
|
127
|
-
|
|
54
|
+
get workspace() {
|
|
55
|
+
return this.manager.workspace;
|
|
56
|
+
}
|
|
57
|
+
/** Application of the active Session; a Session change replaces it. */
|
|
58
|
+
get application() {
|
|
59
|
+
return this.manager.activeApplication;
|
|
60
|
+
}
|
|
61
|
+
/** Run a state change on the Session queue of the active application. */
|
|
62
|
+
transition(action, options) {
|
|
63
|
+
return this.manager.runStateTransition(action, options);
|
|
64
|
+
}
|
|
65
|
+
get git() {
|
|
66
|
+
return this.state.git.get(this.workspace);
|
|
67
|
+
}
|
|
128
68
|
async getWorkspaceGit() {
|
|
129
69
|
if (!this.git)
|
|
130
70
|
return { path: this.workspace, status: "disabled", autoCommit: false };
|
|
131
71
|
try {
|
|
132
72
|
const status = await this.git.summary();
|
|
133
|
-
return {
|
|
134
|
-
|
|
135
|
-
|
|
73
|
+
return {
|
|
74
|
+
path: this.workspace,
|
|
75
|
+
status: status.state === "unborn" || (status.state === "unmanaged" && status.autoCommit && !status.readOnly)
|
|
76
|
+
? "initializing"
|
|
77
|
+
: status.state === "unmanaged"
|
|
78
|
+
? "disabled"
|
|
79
|
+
: "ready",
|
|
80
|
+
autoCommit: status.autoCommit && !status.readOnly,
|
|
81
|
+
detached: status.detached,
|
|
82
|
+
...(status.branch ? { branch: status.branch } : {}),
|
|
83
|
+
...(status.commit ? { commit: status.commit } : {}),
|
|
84
|
+
};
|
|
136
85
|
}
|
|
137
86
|
catch (error) {
|
|
138
|
-
return {
|
|
87
|
+
return {
|
|
88
|
+
path: this.workspace,
|
|
89
|
+
status: "error",
|
|
90
|
+
autoCommit: this.git.autoCommit,
|
|
91
|
+
error: error instanceof Error ? error.message : String(error),
|
|
92
|
+
};
|
|
139
93
|
}
|
|
140
94
|
}
|
|
141
95
|
async getForkPoints(sessionId) {
|
|
142
|
-
|
|
143
|
-
const checkpoints = await this.git?.checkpoints() ?? [];
|
|
144
|
-
const sessions = await this.listSessions();
|
|
145
|
-
const worktrees = await this.git?.listWorktrees() ?? [];
|
|
146
|
-
const checkpointFor = (sourceId, runId) => {
|
|
147
|
-
const seen = new Set();
|
|
148
|
-
while (!seen.has(sourceId)) {
|
|
149
|
-
seen.add(sourceId);
|
|
150
|
-
const checkpoint = [...checkpoints].reverse().find(item => item.sessionId === sourceId && (item.runId === runId || item.runIds?.includes(runId)));
|
|
151
|
-
if (checkpoint)
|
|
152
|
-
return checkpoint;
|
|
153
|
-
const source = nodes.find(node => node.sessionId === sourceId)?.fork;
|
|
154
|
-
if (!source)
|
|
155
|
-
return undefined;
|
|
156
|
-
sourceId = source.sessionId;
|
|
157
|
-
}
|
|
158
|
-
throw new Error("Session branch lineage contains a cycle");
|
|
159
|
-
};
|
|
160
|
-
return nodes.flatMap(node => {
|
|
161
|
-
if (sessionId && node.sessionId !== sessionId)
|
|
162
|
-
return [];
|
|
163
|
-
const workspace = sessions.find(session => session.id === node.sessionId)?.workspace;
|
|
164
|
-
const worktree = worktrees.find(tree => tree.workspace === workspace);
|
|
165
|
-
const workspaceReady = worktree === undefined || worktree.status === "ready";
|
|
166
|
-
return node.positions.map((position, index) => {
|
|
167
|
-
const checkpoint = checkpointFor(node.sessionId, position.runId);
|
|
168
|
-
const completeRequest = checkpoint?.runIds?.length ? checkpoint.runId === position.runId : true;
|
|
169
|
-
const parent = index ? node.positions[index - 1] : undefined;
|
|
170
|
-
return { id: `${node.sessionId}:${position.positionSeq}`, sessionId: node.sessionId, runId: position.runId,
|
|
171
|
-
createdAt: position.timestamp, userPreview: position.request, assistantPreview: position.response,
|
|
172
|
-
available: position.available && completeRequest && workspaceReady,
|
|
173
|
-
...(!workspaceReady ? { reason: "The managed worktree did not finish initialization; inspect its diagnostic" } :
|
|
174
|
-
!completeRequest ? { reason: "The selected Run belongs to an unfinished part of this request" } : position.reason ? { reason: position.reason } : {}),
|
|
175
|
-
...(parent ? { parentPointId: `${node.sessionId}:${parent.positionSeq}` } : node.fork ? { parentPointId: `${node.fork.sessionId}:${node.fork.positionSeq}` } : {}),
|
|
176
|
-
...(checkpoint?.commit ? { commit: checkpoint.commit } : {}), ...(checkpoint?.branch ? { branch: checkpoint.branch } : {}),
|
|
177
|
-
worktreeAvailable: position.available && completeRequest && workspaceReady && this.git?.readOnly !== true && checkpoint?.commit !== undefined && ["committed", "unchanged"].includes(checkpoint.status) };
|
|
178
|
-
});
|
|
179
|
-
});
|
|
96
|
+
return workspaceForkPoints(this.manager, () => this.git, () => this.listSessions(), sessionId);
|
|
180
97
|
}
|
|
181
98
|
async forkSession(pointId, mode) {
|
|
182
99
|
return this.runWorkspaceOperation(() => this.forkWorkspaceSession(pointId, mode));
|
|
183
100
|
}
|
|
184
101
|
async forkWorkspaceSession(pointId, mode) {
|
|
185
|
-
const point = (await this.getForkPoints()).find(item => item.id === pointId);
|
|
102
|
+
const point = (await this.getForkPoints()).find((item) => item.id === pointId);
|
|
186
103
|
if (!point?.available)
|
|
187
104
|
throw new Error(point?.reason ?? "Session history position is unavailable");
|
|
188
105
|
const positionSeq = Number(point.id.slice(point.sessionId.length + 1));
|
|
189
106
|
const git = this.git;
|
|
190
107
|
const checkpoint = await this.checkpointForRun(point.sessionId, point.runId);
|
|
191
|
-
const sourceWorkspace = (await this.listSessions()).find(session => session.id === point.sessionId)?.workspace;
|
|
108
|
+
const sourceWorkspace = (await this.listSessions()).find((session) => session.id === point.sessionId)?.workspace;
|
|
192
109
|
if (!sourceWorkspace)
|
|
193
110
|
throw new Error("Source Session workspace is unavailable");
|
|
194
111
|
let tree;
|
|
195
112
|
if (mode === "worktree") {
|
|
196
113
|
if (!git || !checkpoint?.commit || !point.worktreeAvailable)
|
|
197
114
|
throw new Error("Selected reply has no complete Git checkpoint");
|
|
198
|
-
tree = await git.createWorktree({
|
|
115
|
+
tree = await git.createWorktree({
|
|
116
|
+
sessionId: point.sessionId,
|
|
117
|
+
historyPosition: positionSeq,
|
|
118
|
+
checkpointId: checkpoint.id,
|
|
119
|
+
});
|
|
199
120
|
}
|
|
200
121
|
let sessionId;
|
|
201
122
|
try {
|
|
202
123
|
sessionId = await this.manager.forkSession(point.sessionId, positionSeq, {
|
|
203
124
|
...(tree ? { workspace: tree.workspace } : {}),
|
|
204
|
-
metadata: {
|
|
205
|
-
|
|
125
|
+
metadata: {
|
|
126
|
+
workspaceFork: {
|
|
127
|
+
mode,
|
|
128
|
+
sourceWorkspace,
|
|
129
|
+
sourceCommit: point.commit ?? null,
|
|
130
|
+
...(tree ? { worktreeId: tree.id } : { currentFiles: true }),
|
|
131
|
+
},
|
|
132
|
+
},
|
|
206
133
|
});
|
|
207
134
|
if (tree)
|
|
208
135
|
await git.attachWorktreeSession(tree.id, sessionId);
|
|
@@ -218,7 +145,7 @@ export class MaybeCodeWorkspace {
|
|
|
218
145
|
}
|
|
219
146
|
async getCheckpoints(sessionId = this.sessionId) {
|
|
220
147
|
const points = await this.getForkPoints(sessionId);
|
|
221
|
-
const checkpoints = await this.git?.checkpoints() ?? [];
|
|
148
|
+
const checkpoints = (await this.git?.checkpoints()) ?? [];
|
|
222
149
|
const sourceIds = [sessionId];
|
|
223
150
|
while (true) {
|
|
224
151
|
const created = (await this.manager.readSessionHistory(sourceIds[sourceIds.length - 1]))[0];
|
|
@@ -227,21 +154,31 @@ export class MaybeCodeWorkspace {
|
|
|
227
154
|
if (sourceIds.includes(created.fork.sessionId))
|
|
228
155
|
throw new Error("Session branch lineage contains a cycle");
|
|
229
156
|
sourceIds.push(created.fork.sessionId);
|
|
230
|
-
if (!(await this.listSessions()).some(session => session.id === created.fork.sessionId))
|
|
157
|
+
if (!(await this.listSessions()).some((session) => session.id === created.fork.sessionId))
|
|
231
158
|
break;
|
|
232
159
|
}
|
|
233
|
-
return points.map(point => {
|
|
160
|
+
return points.map((point) => {
|
|
234
161
|
let checkpoint;
|
|
235
162
|
for (const sourceId of sourceIds) {
|
|
236
|
-
checkpoint = [...checkpoints]
|
|
163
|
+
checkpoint = [...checkpoints]
|
|
164
|
+
.reverse()
|
|
165
|
+
.find((item) => item.sessionId === sourceId && (item.runId === point.runId || item.runIds?.includes(point.runId)));
|
|
237
166
|
if (checkpoint)
|
|
238
167
|
break;
|
|
239
168
|
}
|
|
240
|
-
return {
|
|
241
|
-
|
|
169
|
+
return {
|
|
170
|
+
runId: point.runId,
|
|
171
|
+
pointId: point.id,
|
|
172
|
+
...(checkpoint?.fromCommit ? { startCommit: checkpoint.fromCommit } : {}),
|
|
173
|
+
...(checkpoint?.commit ? { endCommit: checkpoint.commit } : {}),
|
|
242
174
|
...(checkpoint?.branch ? { branch: checkpoint.branch } : {}),
|
|
243
|
-
status: checkpoint?.status === "failed"
|
|
244
|
-
|
|
175
|
+
status: checkpoint?.status === "failed"
|
|
176
|
+
? "failed"
|
|
177
|
+
: !checkpoint || checkpoint.status === "uncommitted"
|
|
178
|
+
? "unavailable"
|
|
179
|
+
: "saved",
|
|
180
|
+
...(checkpoint?.error ? { error: checkpoint.error } : {}),
|
|
181
|
+
};
|
|
245
182
|
});
|
|
246
183
|
}
|
|
247
184
|
async checkpointForRun(sessionId, runId) {
|
|
@@ -261,20 +198,28 @@ export class MaybeCodeWorkspace {
|
|
|
261
198
|
throw new Error("Session branch lineage contains a cycle");
|
|
262
199
|
}
|
|
263
200
|
async getWorktrees() {
|
|
264
|
-
return ((await this.git?.listWorktrees()) ?? [])
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
201
|
+
return ((await this.git?.listWorktrees()) ?? [])
|
|
202
|
+
.filter((tree) => tree.status !== "deleted")
|
|
203
|
+
.map((tree) => ({
|
|
204
|
+
id: tree.id,
|
|
205
|
+
path: tree.workspace,
|
|
206
|
+
branch: tree.branch,
|
|
207
|
+
sourceSessionId: tree.sourceSessionId,
|
|
208
|
+
pointId: `${tree.sourceSessionId}:${tree.historyPosition}`,
|
|
209
|
+
commit: tree.commit,
|
|
210
|
+
sessionIds: tree.sessions,
|
|
211
|
+
status: tree.status === "failed" ? "error" : tree.status === "creating" ? "creating" : "ready",
|
|
212
|
+
...(tree.error ? { error: tree.error } : {}),
|
|
268
213
|
}));
|
|
269
214
|
}
|
|
270
215
|
async openWorktree(id) {
|
|
271
216
|
return this.runWorkspaceOperation(() => this.openWorkspaceWorktree(id));
|
|
272
217
|
}
|
|
273
218
|
async openWorkspaceWorktree(id) {
|
|
274
|
-
const tree = (await this.getWorktrees()).find(item => item.id === id);
|
|
219
|
+
const tree = (await this.getWorktrees()).find((item) => item.id === id);
|
|
275
220
|
if (!tree || tree.status !== "ready")
|
|
276
221
|
throw new Error("Managed worktree is unavailable");
|
|
277
|
-
const session = (await this.listSessions()).find(item => tree.sessionIds.includes(item.id));
|
|
222
|
+
const session = (await this.listSessions()).find((item) => tree.sessionIds.includes(item.id));
|
|
278
223
|
if (!session)
|
|
279
224
|
throw new Error("Worktree has no available Session");
|
|
280
225
|
await this.resumeWorkspaceSession(session.id);
|
|
@@ -284,13 +229,13 @@ export class MaybeCodeWorkspace {
|
|
|
284
229
|
}
|
|
285
230
|
async deleteWorkspaceWorktree(id) {
|
|
286
231
|
const git = this.requireGit();
|
|
287
|
-
const tree = (await git.listWorktrees()).find(item => item.id === id);
|
|
232
|
+
const tree = (await git.listWorktrees()).find((item) => item.id === id);
|
|
288
233
|
if (!tree)
|
|
289
234
|
throw new Error("Managed worktree is unavailable");
|
|
290
235
|
if (tree.workspace === this.workspace)
|
|
291
236
|
throw new Error("Switch to another workspace before deleting this worktree");
|
|
292
237
|
for (const sessionId of tree.sessions) {
|
|
293
|
-
if ((await this.listSessions()).some(session => session.id === sessionId))
|
|
238
|
+
if ((await this.listSessions()).some((session) => session.id === sessionId))
|
|
294
239
|
throw new Error("Delete or move associated Sessions before deleting this worktree");
|
|
295
240
|
await git.attachWorktreeSession(id, sessionId, false);
|
|
296
241
|
}
|
|
@@ -318,11 +263,24 @@ export class MaybeCodeWorkspace {
|
|
|
318
263
|
if (!from)
|
|
319
264
|
throw new Error("Git comparison has no available initial version");
|
|
320
265
|
const diff = await git.diff({ from, ...(to ? { to } : {}) });
|
|
321
|
-
const files = diff.files.map(file => ({
|
|
266
|
+
const files = diff.files.map((file) => ({
|
|
267
|
+
path: file.path,
|
|
268
|
+
...(file.previousPath ? { previousPath: file.previousPath } : {}),
|
|
322
269
|
status: file.status === "typechanged" || file.status === "unknown" ? "modified" : file.status,
|
|
323
|
-
binary: file.binary,
|
|
324
|
-
|
|
325
|
-
|
|
270
|
+
binary: file.binary,
|
|
271
|
+
additions: file.insertions,
|
|
272
|
+
deletions: file.deletions,
|
|
273
|
+
patch: file.patch,
|
|
274
|
+
}));
|
|
275
|
+
return {
|
|
276
|
+
scope: query.scope,
|
|
277
|
+
title: query.scope === "run" ? "本轮文件变化" : query.scope === "session" ? "Session 文件变化" : "当前工作区文件变化",
|
|
278
|
+
from: diff.from,
|
|
279
|
+
...(diff.to ? { to: diff.to } : {}),
|
|
280
|
+
...(query.runId ? { runId: query.runId } : {}),
|
|
281
|
+
uncommitted: !diff.to,
|
|
282
|
+
files,
|
|
283
|
+
};
|
|
326
284
|
}
|
|
327
285
|
async previewRestore(runId, paths) {
|
|
328
286
|
return this.runWorkspaceOperation(() => this.previewWorkspaceRestore(runId, paths));
|
|
@@ -338,21 +296,38 @@ export class MaybeCodeWorkspace {
|
|
|
338
296
|
const previewId = randomUUID();
|
|
339
297
|
this.restorePreviews.clear();
|
|
340
298
|
this.restorePreviews.set(previewId, { sessionId: this.sessionId, preview });
|
|
341
|
-
return {
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
299
|
+
return {
|
|
300
|
+
previewId,
|
|
301
|
+
diff: {
|
|
302
|
+
scope: "run",
|
|
303
|
+
runId,
|
|
304
|
+
title: "文件恢复预览",
|
|
305
|
+
to: preview.commit,
|
|
306
|
+
uncommitted: true,
|
|
307
|
+
restorePreviewId: previewId,
|
|
308
|
+
files: preview.files.map((file) => ({
|
|
309
|
+
path: file.path,
|
|
310
|
+
status: file.targetMode === undefined ? "deleted" : file.beforeFingerprint === undefined ? "added" : "modified",
|
|
311
|
+
binary: file.binary,
|
|
312
|
+
additions: 0,
|
|
313
|
+
deletions: 0,
|
|
314
|
+
patch: file.patch,
|
|
315
|
+
})),
|
|
316
|
+
},
|
|
317
|
+
};
|
|
346
318
|
}
|
|
347
319
|
async restoreFiles(previewId) {
|
|
348
|
-
return this.runWorkspaceOperation(() => this.
|
|
320
|
+
return this.runWorkspaceOperation(() => this.transition(() => this.restoreWorkspaceFiles(previewId)));
|
|
349
321
|
}
|
|
350
322
|
async restoreWorkspaceFiles(previewId) {
|
|
351
323
|
const saved = this.restorePreviews.get(previewId);
|
|
352
324
|
if (!saved || saved.sessionId !== this.sessionId || saved.preview.workspace !== this.workspace)
|
|
353
325
|
throw new Error("File restore preview is no longer available");
|
|
354
326
|
try {
|
|
355
|
-
const checkpoint = await this.requireGit().restore(saved.preview, {
|
|
327
|
+
const checkpoint = await this.requireGit().restore(saved.preview, {
|
|
328
|
+
sessionId: this.sessionId,
|
|
329
|
+
commitMessage: "Restore selected files from a session checkpoint",
|
|
330
|
+
});
|
|
356
331
|
this.restorePreviews.delete(previewId);
|
|
357
332
|
this.eventQueue.push({ type: "workspace.git.changed", checkpoint });
|
|
358
333
|
}
|
|
@@ -369,7 +344,7 @@ export class MaybeCodeWorkspace {
|
|
|
369
344
|
}
|
|
370
345
|
assertWorkspaceIdle() {
|
|
371
346
|
this.throwIfClosed();
|
|
372
|
-
if (this.isRunning || this.getGoal()?.status === "active" || this.getMcpInteractions().length)
|
|
347
|
+
if (this.isRunning || this.application.getGoal()?.status === "active" || this.getMcpInteractions().length)
|
|
373
348
|
throw new Error("Finish the active operation before changing the workspace");
|
|
374
349
|
}
|
|
375
350
|
assertNoWorkspaceOperation() {
|
|
@@ -382,24 +357,28 @@ export class MaybeCodeWorkspace {
|
|
|
382
357
|
this.assertWorkspaceIdle();
|
|
383
358
|
else
|
|
384
359
|
this.assertNoWorkspaceOperation();
|
|
385
|
-
if (this.getGoal()?.status === "active")
|
|
360
|
+
if (this.application.getGoal()?.status === "active")
|
|
386
361
|
throw new GitWorkspaceConflictError("Pause or finish the active Goal before changing the workspace");
|
|
387
362
|
const previousSessionId = this.sessionId;
|
|
388
363
|
const previousOptions = this.state.options;
|
|
389
|
-
const operation = Promise.resolve()
|
|
364
|
+
const operation = Promise.resolve()
|
|
365
|
+
.then(work)
|
|
366
|
+
.catch((error) => {
|
|
390
367
|
if (this.sessionId === previousSessionId)
|
|
391
368
|
this.state.options = previousOptions;
|
|
392
369
|
throw error;
|
|
393
370
|
});
|
|
394
371
|
this.workspaceOperation = operation;
|
|
395
|
-
return operation.finally(() => {
|
|
396
|
-
this.workspaceOperation
|
|
372
|
+
return operation.finally(() => {
|
|
373
|
+
if (this.workspaceOperation === operation)
|
|
374
|
+
this.workspaceOperation = undefined;
|
|
375
|
+
});
|
|
397
376
|
}
|
|
398
377
|
async syncWorktreeProcess() {
|
|
399
378
|
const git = this.state.git.get(this.state.rootWorkspace);
|
|
400
379
|
if (!git || git.readOnly)
|
|
401
380
|
return;
|
|
402
|
-
const tree = (await git.listWorktrees()).find(item => item.workspace === this.workspace && item.status === "ready");
|
|
381
|
+
const tree = (await git.listWorktrees()).find((item) => item.workspace === this.workspace && item.status === "ready");
|
|
403
382
|
if (this.worktreeProcessId && this.worktreeProcessId !== tree?.id)
|
|
404
383
|
await git.trackWorktreeProcess(this.worktreeProcessId, process.pid, false);
|
|
405
384
|
this.worktreeProcessId = tree?.id;
|
|
@@ -424,10 +403,10 @@ export class MaybeCodeWorkspace {
|
|
|
424
403
|
this.assertNoWorkspaceOperation();
|
|
425
404
|
this.throwIfClosed();
|
|
426
405
|
parsePermissionMode(mode);
|
|
427
|
-
await this.
|
|
406
|
+
await this.transition(() => {
|
|
428
407
|
if (mode === this.permissionMode)
|
|
429
408
|
return;
|
|
430
|
-
if (this.isRunning || this.getGoal()?.status === "active" || this.getMcpInteractions().length > 0) {
|
|
409
|
+
if (this.isRunning || this.application.getGoal()?.status === "active" || this.getMcpInteractions().length > 0) {
|
|
431
410
|
throw new Error("Pause or cancel the current operation before changing permission mode");
|
|
432
411
|
}
|
|
433
412
|
this.state.options = { ...this.state.options, permissionMode: mode };
|
|
@@ -435,48 +414,37 @@ export class MaybeCodeWorkspace {
|
|
|
435
414
|
}, { activeOperationMessage: "Pause or cancel the current operation before changing permission mode" });
|
|
436
415
|
}
|
|
437
416
|
get isRunning() {
|
|
438
|
-
return this.workspaceOperation !== undefined ||
|
|
417
|
+
return (this.workspaceOperation !== undefined ||
|
|
418
|
+
this.manager.isRunning ||
|
|
419
|
+
this.mcpOperationController !== undefined ||
|
|
420
|
+
this.pendingInputs.size > 0 ||
|
|
421
|
+
this.pendingSteering > 0);
|
|
439
422
|
}
|
|
440
|
-
get instructions() {
|
|
441
|
-
return this.manager.activeApplication.instructions;
|
|
442
|
-
}
|
|
443
|
-
listSkills() {
|
|
444
|
-
const skills = this.manager.activeApplication.skills;
|
|
445
|
-
const active = new Map(skills?.listActive().map((item) => [item.name, item]));
|
|
446
|
-
const all = new Map(skills?.registry.list().map((item) => [item.name, item]));
|
|
447
|
-
for (const [name, item] of active)
|
|
448
|
-
all.set(name, item);
|
|
449
|
-
return [...all.values()].map((item) => ({ ...item, active: active.has(item.name) }));
|
|
450
|
-
}
|
|
451
|
-
getSkillDiagnostics() { return this.manager.activeApplication.skills?.registry.diagnostics ?? []; }
|
|
452
423
|
readSkill(name) {
|
|
453
424
|
this.assertNoWorkspaceOperation();
|
|
454
|
-
return this.
|
|
455
|
-
if (!
|
|
425
|
+
return this.transition(async ({ agent }) => {
|
|
426
|
+
if (!agent.skills)
|
|
456
427
|
throw new Error("Skills are disabled");
|
|
457
|
-
return
|
|
428
|
+
return agent.skills.listActive().find((item) => item.name === name) ?? agent.skills.registry.load(name);
|
|
458
429
|
}, { requireIdle: false });
|
|
459
430
|
}
|
|
460
431
|
activateSkill(name) {
|
|
461
432
|
this.assertNoWorkspaceOperation();
|
|
462
|
-
return this.
|
|
433
|
+
return this.transition((app) => app.activateSkill(name));
|
|
463
434
|
}
|
|
464
435
|
submitSkill(name, input) {
|
|
465
436
|
this.assertNoWorkspaceOperation();
|
|
466
437
|
return this.manager.submitPrepared(async () => {
|
|
467
|
-
await this.
|
|
438
|
+
await this.application.activateSkill(name);
|
|
468
439
|
return { input: `Use the ${name} skill for this task:\n${input}` };
|
|
469
440
|
});
|
|
470
441
|
}
|
|
471
|
-
get modelInfo() {
|
|
472
|
-
return this.manager.activeApplication.modelInfo;
|
|
473
|
-
}
|
|
474
442
|
async getMcpStatus() {
|
|
475
443
|
this.throwIfClosed();
|
|
476
444
|
return this.mcp?.status() ?? [];
|
|
477
445
|
}
|
|
478
446
|
get mcp() {
|
|
479
|
-
return this.
|
|
447
|
+
return this.application.mcp ?? this.state.options.mcp;
|
|
480
448
|
}
|
|
481
449
|
getMcpInteractions() {
|
|
482
450
|
const interactions = this.mcp?.interactions;
|
|
@@ -495,13 +463,15 @@ export class MaybeCodeWorkspace {
|
|
|
495
463
|
const request = this.getMcpInteractions().find((entry) => entry.id === id);
|
|
496
464
|
return request === undefined ? false : this.mcp.interactions.respond(id, request.owner, response);
|
|
497
465
|
}
|
|
498
|
-
mcpOwner() {
|
|
466
|
+
mcpOwner() {
|
|
467
|
+
return { workspaceId: this.workspace, sessionId: this.sessionId };
|
|
468
|
+
}
|
|
499
469
|
/** 活动请求的子 Session 保留自己的 MCP 身份与授权记录。 */
|
|
500
470
|
delegatedSessions() {
|
|
501
|
-
return this.
|
|
471
|
+
return this.application.ownedDelegatedSessions();
|
|
502
472
|
}
|
|
503
473
|
ownsSession(sessionId) {
|
|
504
|
-
return sessionId === this.sessionId || this.
|
|
474
|
+
return sessionId === this.sessionId || this.application.ownsSession(sessionId);
|
|
505
475
|
}
|
|
506
476
|
async refreshMcp(serverId) {
|
|
507
477
|
this.assertNoWorkspaceOperation();
|
|
@@ -528,45 +498,52 @@ export class MaybeCodeWorkspace {
|
|
|
528
498
|
return this.mcp?.listTasks?.(this.mcpOwner()) ?? Promise.resolve([]);
|
|
529
499
|
}
|
|
530
500
|
getMcpTask(serverId, id, options = {}) {
|
|
531
|
-
return this.mcpOperation((signal) => this.
|
|
501
|
+
return this.mcpOperation((signal) => this.transition(() => this.mcpMethod("getTask")(serverId, id, { ...options, signal, owner: this.mcpOwner() })), options.signal);
|
|
532
502
|
}
|
|
533
503
|
updateMcpTask(serverId, id, options = {}) {
|
|
534
|
-
return this.mcpOperation((signal) => this.
|
|
504
|
+
return this.mcpOperation((signal) => this.transition(() => this.mcpMethod("updateTask")(serverId, id, { ...options, signal, owner: this.mcpOwner() })), options.signal);
|
|
535
505
|
}
|
|
536
506
|
waitMcpTask(serverId, id, options = {}) {
|
|
537
|
-
return this.mcpOperation((signal) => this.
|
|
507
|
+
return this.mcpOperation((signal) => this.transition(() => this.mcpMethod("waitTask")(serverId, id, { ...options, signal, owner: this.mcpOwner() })), options.signal);
|
|
538
508
|
}
|
|
539
509
|
cancelMcpTask(serverId, id, options = {}) {
|
|
540
|
-
return this.mcpOperation((signal) => this.
|
|
510
|
+
return this.mcpOperation((signal) => this.transition(() => this.mcpMethod("cancelTask")(serverId, id, { ...options, signal, owner: this.mcpOwner() })), options.signal);
|
|
541
511
|
}
|
|
542
512
|
forgetMcpTask(serverId, id) {
|
|
543
|
-
return this.mcpOperation(() => this.
|
|
513
|
+
return this.mcpOperation(() => this.transition(() => this.mcpMethod("forgetTask")(serverId, id, this.mcpOwner())));
|
|
544
514
|
}
|
|
545
515
|
submitMcpTask(serverId, id, instruction) {
|
|
546
516
|
return this.mcpOperation((signal) => this.manager.submitPrepared(async () => ({
|
|
547
|
-
input: mcpTaskToUserMessage(await this.mcpMethod("getTask")(serverId, id, { signal, owner: this.mcpOwner() }), instruction),
|
|
517
|
+
input: mcpTaskToUserMessage(await this.mcpMethod("getTask")(serverId, id, { signal, owner: this.mcpOwner() }), instruction),
|
|
518
|
+
signal,
|
|
548
519
|
})));
|
|
549
520
|
}
|
|
550
521
|
readMcpResource(serverId, uri, options = {}) {
|
|
551
|
-
return this.mcpOperation((signal) => this.
|
|
522
|
+
return this.mcpOperation((signal) => this.transition(() => this.mcpMethod("readResource")(serverId, uri, { ...options, signal, owner: this.mcpOwner() })), options.signal);
|
|
552
523
|
}
|
|
553
524
|
readMcpResourceTemplate(serverId, template, variables, options = {}) {
|
|
554
|
-
return this.mcpOperation((signal) => this.
|
|
525
|
+
return this.mcpOperation((signal) => this.transition(() => this.mcpMethod("readResourceTemplate")(serverId, template, variables, {
|
|
526
|
+
...options,
|
|
527
|
+
signal,
|
|
528
|
+
owner: this.mcpOwner(),
|
|
529
|
+
})), options.signal);
|
|
555
530
|
}
|
|
556
531
|
getMcpPrompt(serverId, name, args, options = {}) {
|
|
557
|
-
return this.mcpOperation((signal) => this.
|
|
532
|
+
return this.mcpOperation((signal) => this.transition(() => this.mcpMethod("getPrompt")(serverId, name, args, { ...options, signal, owner: this.mcpOwner() })), options.signal);
|
|
558
533
|
}
|
|
559
534
|
completeMcp(serverId, params, options = {}) {
|
|
560
|
-
return this.mcpOperation((signal) => this.
|
|
535
|
+
return this.mcpOperation((signal) => this.transition(() => this.mcpMethod("complete")(serverId, params, { ...options, signal, owner: this.mcpOwner() })), options.signal);
|
|
561
536
|
}
|
|
562
537
|
submitMcpResource(serverId, uri, instruction) {
|
|
563
538
|
return this.mcpOperation((signal) => this.manager.submitPrepared(async () => ({
|
|
564
|
-
input: mcpResourceToUserMessage(await this.mcpMethod("readResource")(serverId, uri, { signal, owner: this.mcpOwner() }), instruction),
|
|
539
|
+
input: mcpResourceToUserMessage(await this.mcpMethod("readResource")(serverId, uri, { signal, owner: this.mcpOwner() }), instruction),
|
|
540
|
+
signal,
|
|
565
541
|
})));
|
|
566
542
|
}
|
|
567
543
|
submitMcpPrompt(serverId, name, args) {
|
|
568
544
|
return this.mcpOperation((signal) => this.manager.submitPrepared(async () => ({
|
|
569
|
-
input: mcpPromptToUserMessage(await this.mcpMethod("getPrompt")(serverId, name, args, { signal, owner: this.mcpOwner() })),
|
|
545
|
+
input: mcpPromptToUserMessage(await this.mcpMethod("getPrompt")(serverId, name, args, { signal, owner: this.mcpOwner() })),
|
|
546
|
+
signal,
|
|
570
547
|
})));
|
|
571
548
|
}
|
|
572
549
|
watchMcpResource(serverId, uri) {
|
|
@@ -577,7 +554,7 @@ export class MaybeCodeWorkspace {
|
|
|
577
554
|
return this.mcpWatches.get(key);
|
|
578
555
|
const watch = await this.mcpMethod("subscribeResource")(serverId, uri, { signal, owner: this.mcpOwner() });
|
|
579
556
|
this.mcpWatches.set(key, watch);
|
|
580
|
-
|
|
557
|
+
this.trackMcpRelay((async () => {
|
|
581
558
|
for await (const event of watch.events) {
|
|
582
559
|
if (!this.closed && owner.workspaceId === this.workspace && owner.sessionId === this.sessionId)
|
|
583
560
|
this.eventQueue.push({ type: "mcp.resource.updated", serverId, uri: event.uri });
|
|
@@ -587,7 +564,7 @@ export class MaybeCodeWorkspace {
|
|
|
587
564
|
this.mcpWatches.delete(key);
|
|
588
565
|
if (!this.closed && owner.workspaceId === this.workspace && owner.sessionId === this.sessionId)
|
|
589
566
|
this.eventQueue.push({ type: "mcp.resource.watch-closed", serverId, uri, reason });
|
|
590
|
-
})();
|
|
567
|
+
})());
|
|
591
568
|
return watch;
|
|
592
569
|
});
|
|
593
570
|
}
|
|
@@ -607,7 +584,11 @@ export class MaybeCodeWorkspace {
|
|
|
607
584
|
throw new Error("Cannot start an MCP user operation while another operation is active");
|
|
608
585
|
const controller = new AbortController();
|
|
609
586
|
this.mcpOperationController = controller;
|
|
610
|
-
const signal = AbortSignal.any([
|
|
587
|
+
const signal = AbortSignal.any([
|
|
588
|
+
controller.signal,
|
|
589
|
+
this.mcpLifetime.signal,
|
|
590
|
+
...(external === undefined ? [] : [external]),
|
|
591
|
+
]);
|
|
611
592
|
try {
|
|
612
593
|
signal.throwIfAborted();
|
|
613
594
|
return await work(signal);
|
|
@@ -622,7 +603,10 @@ export class MaybeCodeWorkspace {
|
|
|
622
603
|
const controller = new AbortController();
|
|
623
604
|
this.pendingInputs.add(controller);
|
|
624
605
|
try {
|
|
625
|
-
return await this.manager.submit({
|
|
606
|
+
return await this.manager.submit({
|
|
607
|
+
...options,
|
|
608
|
+
signal: options.signal === undefined ? controller.signal : AbortSignal.any([controller.signal, options.signal]),
|
|
609
|
+
});
|
|
626
610
|
}
|
|
627
611
|
finally {
|
|
628
612
|
this.pendingInputs.delete(controller);
|
|
@@ -633,7 +617,7 @@ export class MaybeCodeWorkspace {
|
|
|
633
617
|
const epoch = this.inputEpoch;
|
|
634
618
|
this.pendingSteering++;
|
|
635
619
|
try {
|
|
636
|
-
return await this.
|
|
620
|
+
return await this.transition((app) => {
|
|
637
621
|
if (epoch !== this.inputEpoch)
|
|
638
622
|
throw new RunCancelledError("Input cancelled before acceptance");
|
|
639
623
|
return app.steer(options);
|
|
@@ -643,15 +627,20 @@ export class MaybeCodeWorkspace {
|
|
|
643
627
|
this.pendingSteering--;
|
|
644
628
|
}
|
|
645
629
|
}
|
|
646
|
-
listSteeringInputs() { return this.manager.activeApplication.listSteeringInputs(); }
|
|
647
|
-
getGoal() { return this.manager.activeApplication.getGoal(); }
|
|
648
630
|
startGoal(objective, budget) {
|
|
649
631
|
this.assertNoWorkspaceOperation();
|
|
650
|
-
return this.
|
|
632
|
+
return this.transition((app) => app.startGoal(objective, budget));
|
|
633
|
+
}
|
|
634
|
+
resumeGoal() {
|
|
635
|
+
this.assertNoWorkspaceOperation();
|
|
636
|
+
return this.transition((app) => app.resumeGoal());
|
|
637
|
+
}
|
|
638
|
+
pauseGoal() {
|
|
639
|
+
return this.transition((app) => app.pauseGoal(), { requireIdle: false });
|
|
640
|
+
}
|
|
641
|
+
cancelGoal() {
|
|
642
|
+
return this.transition((app) => app.cancelGoal(), { requireIdle: false });
|
|
651
643
|
}
|
|
652
|
-
resumeGoal() { this.assertNoWorkspaceOperation(); return this.manager.runStateTransition(app => app.resumeGoal()); }
|
|
653
|
-
pauseGoal() { return this.manager.runStateTransition(app => app.pauseGoal(), { requireIdle: false }); }
|
|
654
|
-
cancelGoal() { return this.manager.runStateTransition(app => app.cancelGoal(), { requireIdle: false }); }
|
|
655
644
|
retry() {
|
|
656
645
|
this.assertNoWorkspaceOperation();
|
|
657
646
|
return this.manager.retry();
|
|
@@ -667,15 +656,24 @@ export class MaybeCodeWorkspace {
|
|
|
667
656
|
resolveApproval(requestId, decision, options) {
|
|
668
657
|
return this.manager.resolveApproval(requestId, decision, options);
|
|
669
658
|
}
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
659
|
+
listPermissionRules(scopeId) {
|
|
660
|
+
return this.manager.listPermissionRules(scopeId);
|
|
661
|
+
}
|
|
662
|
+
createPermissionRule(check, options) {
|
|
663
|
+
return this.manager.createPermissionRule(check, options);
|
|
664
|
+
}
|
|
665
|
+
createPermissionRuleFrom(id, options) {
|
|
666
|
+
return this.transition((app) => app.createPermissionRuleFrom(id, options));
|
|
667
|
+
}
|
|
668
|
+
revokePermissionRule(id) {
|
|
669
|
+
return this.manager.revokePermissionRule(id);
|
|
670
|
+
}
|
|
675
671
|
listSessions() {
|
|
676
672
|
return this.manager.listSessions();
|
|
677
673
|
}
|
|
678
|
-
async readSessionHistory(sessionId) {
|
|
674
|
+
async readSessionHistory(sessionId) {
|
|
675
|
+
return mediaHistory(await this.manager.readSessionHistory(sessionId));
|
|
676
|
+
}
|
|
679
677
|
async newSession() {
|
|
680
678
|
return this.runWorkspaceOperation(() => this.newWorkspaceSession(), false);
|
|
681
679
|
}
|
|
@@ -719,7 +717,7 @@ export class MaybeCodeWorkspace {
|
|
|
719
717
|
const selected = (this.state.options.modelProfiles ?? []).find((candidate) => candidate.name === profile);
|
|
720
718
|
if (selected === undefined)
|
|
721
719
|
throw new Error(`Unknown model profile "${profile}"`);
|
|
722
|
-
const result = await this.
|
|
720
|
+
const result = await this.transition(async (current) => {
|
|
723
721
|
if (current.modelInfo?.profile === profile && !current.modelUpdateFailed) {
|
|
724
722
|
this.manager.emit({ type: "model.changed", model: current.modelInfo });
|
|
725
723
|
return current.modelInfo;
|
|
@@ -738,7 +736,7 @@ export class MaybeCodeWorkspace {
|
|
|
738
736
|
this.assertModelChangeAllowed();
|
|
739
737
|
await current.updateModel({
|
|
740
738
|
...configuration,
|
|
741
|
-
...(
|
|
739
|
+
...omitUndefined({ modelRuntimeOptions: nextOptions.modelRuntimeOptions }),
|
|
742
740
|
});
|
|
743
741
|
this.state.options = nextOptions;
|
|
744
742
|
this.manager.emit({ type: "model.changed", model: current.modelInfo });
|
|
@@ -757,7 +755,7 @@ export class MaybeCodeWorkspace {
|
|
|
757
755
|
setDefaultModel(profile) {
|
|
758
756
|
this.assertNoWorkspaceOperation();
|
|
759
757
|
this.throwIfClosed();
|
|
760
|
-
return this.
|
|
758
|
+
return this.transition(async () => {
|
|
761
759
|
const profiles = this.state.options.modelProfiles ?? [];
|
|
762
760
|
if (!profiles.some((candidate) => candidate.name === profile)) {
|
|
763
761
|
throw new Error(`Unknown model profile "${profile}"`);
|
|
@@ -779,7 +777,7 @@ export class MaybeCodeWorkspace {
|
|
|
779
777
|
}
|
|
780
778
|
async getReasoningEffort() {
|
|
781
779
|
this.throwIfClosed();
|
|
782
|
-
const profile = this.modelInfo?.profile;
|
|
780
|
+
const profile = this.application.modelInfo?.profile;
|
|
783
781
|
if (profile === undefined)
|
|
784
782
|
return unknownReasoningEffort();
|
|
785
783
|
const resolveCapabilities = this.state.options.resolveModelCapabilities;
|
|
@@ -793,45 +791,42 @@ export class MaybeCodeWorkspace {
|
|
|
793
791
|
const overridden = typeof override === "string" && (override !== configured || requested === override);
|
|
794
792
|
const effectiveEffort = typeof override === "string"
|
|
795
793
|
? override
|
|
796
|
-
: configured ?? (capabilities.status === "known"
|
|
797
|
-
? capabilities.defaultEffort
|
|
798
|
-
: undefined);
|
|
794
|
+
: (configured ?? (capabilities.status === "known" ? capabilities.defaultEffort : undefined));
|
|
799
795
|
return {
|
|
800
796
|
status: capabilities.status,
|
|
801
797
|
source: capabilities.source,
|
|
802
|
-
efforts: capabilities.status === "known"
|
|
803
|
-
|
|
804
|
-
:
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
? { defaultEffort: capabilities.defaultEffort }
|
|
808
|
-
: {}),
|
|
809
|
-
...(effectiveEffort === undefined ? {} : { effectiveEffort }),
|
|
798
|
+
efforts: capabilities.status === "known" ? [...capabilities.efforts] : [],
|
|
799
|
+
...omitUndefined({
|
|
800
|
+
defaultEffort: capabilities.status === "known" ? capabilities.defaultEffort : undefined,
|
|
801
|
+
effectiveEffort,
|
|
802
|
+
}),
|
|
810
803
|
overridden,
|
|
811
804
|
};
|
|
812
805
|
}
|
|
813
|
-
async getModelCapabilities(profile = this.modelInfo?.profile, refresh = false) {
|
|
806
|
+
async getModelCapabilities(profile = this.application.modelInfo?.profile, refresh = false) {
|
|
814
807
|
if (profile === undefined || this.state.options.resolveModelCapabilities === undefined) {
|
|
815
808
|
throw new Error("The active workspace does not provide model capability discovery");
|
|
816
809
|
}
|
|
817
|
-
if (!(this.state.options.modelProfiles ?? []).some(model => model.name === profile)) {
|
|
810
|
+
if (!(this.state.options.modelProfiles ?? []).some((model) => model.name === profile)) {
|
|
818
811
|
throw new Error(`Unknown model profile: ${profile}`);
|
|
819
812
|
}
|
|
820
813
|
return this.state.options.resolveModelCapabilities(profile, { refresh });
|
|
821
814
|
}
|
|
822
815
|
get modelCapabilitiesAvailable() {
|
|
823
|
-
return this.modelInfo?.profile !== undefined && this.state.options.resolveModelCapabilities !== undefined;
|
|
816
|
+
return (this.application.modelInfo?.profile !== undefined && this.state.options.resolveModelCapabilities !== undefined);
|
|
824
817
|
}
|
|
825
818
|
getTelemetry(query = {}) {
|
|
826
819
|
const sessionId = query.sessionId ?? this.sessionId;
|
|
827
820
|
if (!this.ownsSession(sessionId))
|
|
828
821
|
throw new Error("Telemetry session does not belong to this workspace");
|
|
829
|
-
return this.
|
|
822
|
+
return this.application.agent
|
|
823
|
+
.getOptionalService(observabilityService)
|
|
824
|
+
?.diagnostics?.getDiagnostics({ ...query, sessionId });
|
|
830
825
|
}
|
|
831
826
|
async setReasoningEffort(effort) {
|
|
832
827
|
this.assertNoWorkspaceOperation();
|
|
833
828
|
this.throwIfClosed();
|
|
834
|
-
await this.
|
|
829
|
+
await this.transition(async (current) => {
|
|
835
830
|
this.assertModelChangeAllowed();
|
|
836
831
|
const profile = current.modelInfo?.profile;
|
|
837
832
|
if (profile === undefined) {
|
|
@@ -859,7 +854,7 @@ export class MaybeCodeWorkspace {
|
|
|
859
854
|
this.assertModelChangeAllowed();
|
|
860
855
|
await current.updateModel({
|
|
861
856
|
...configuration,
|
|
862
|
-
...(
|
|
857
|
+
...omitUndefined({ modelRuntimeOptions: nextOptions.modelRuntimeOptions }),
|
|
863
858
|
});
|
|
864
859
|
this.state.options = nextOptions;
|
|
865
860
|
if (effort === undefined)
|
|
@@ -874,20 +869,16 @@ export class MaybeCodeWorkspace {
|
|
|
874
869
|
async history() {
|
|
875
870
|
return mediaHistory(await this.manager.history());
|
|
876
871
|
}
|
|
877
|
-
listRecoveries() {
|
|
878
|
-
|
|
879
|
-
listDelegationRequests() {
|
|
880
|
-
return this.manager.activeApplication.listDelegationRequests();
|
|
872
|
+
listRecoveries() {
|
|
873
|
+
return this.manager.listRecoveries();
|
|
881
874
|
}
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
delegationToolRecords(taskId) {
|
|
886
|
-
return this.manager.activeApplication.delegationToolRecords(taskId);
|
|
875
|
+
resolveRecovery(id, finding) {
|
|
876
|
+
this.assertNoWorkspaceOperation();
|
|
877
|
+
return this.manager.resolveRecovery(id, finding);
|
|
887
878
|
}
|
|
888
879
|
resolveDelegationRecovery(requestId, taskId, finding, outcome) {
|
|
889
880
|
this.assertNoWorkspaceOperation();
|
|
890
|
-
return this.
|
|
881
|
+
return this.application.resolveDelegationRecovery(requestId, taskId, finding, outcome);
|
|
891
882
|
}
|
|
892
883
|
queryHistory(query) {
|
|
893
884
|
return this.manager.queryHistory(query);
|
|
@@ -900,7 +891,7 @@ export class MaybeCodeWorkspace {
|
|
|
900
891
|
return this.manager.compactContext(strategy);
|
|
901
892
|
}
|
|
902
893
|
close() {
|
|
903
|
-
return this.closing ??= this.closeOnce();
|
|
894
|
+
return (this.closing ??= this.closeOnce());
|
|
904
895
|
}
|
|
905
896
|
async closeOnce() {
|
|
906
897
|
this.closed = true;
|
|
@@ -918,7 +909,9 @@ export class MaybeCodeWorkspace {
|
|
|
918
909
|
}
|
|
919
910
|
if (this.worktreeProcessId) {
|
|
920
911
|
try {
|
|
921
|
-
await this.state.git
|
|
912
|
+
await this.state.git
|
|
913
|
+
.get(this.state.rootWorkspace)
|
|
914
|
+
.trackWorktreeProcess(this.worktreeProcessId, process.pid, false);
|
|
922
915
|
}
|
|
923
916
|
catch (error) {
|
|
924
917
|
failures.push(error);
|
|
@@ -930,7 +923,7 @@ export class MaybeCodeWorkspace {
|
|
|
930
923
|
catch (error) {
|
|
931
924
|
failures.push(error);
|
|
932
925
|
}
|
|
933
|
-
await watchesClosing;
|
|
926
|
+
failures.push(...(await watchesClosing).flatMap((result) => (result.status === "rejected" ? [result.reason] : [])));
|
|
934
927
|
try {
|
|
935
928
|
await this.disconnectMcpEvents();
|
|
936
929
|
await Promise.all([this.managerEventRelay, ...this.mcpEventRelays]);
|
|
@@ -950,9 +943,12 @@ export class MaybeCodeWorkspace {
|
|
|
950
943
|
const { store, catalog } = this.state.options;
|
|
951
944
|
for (const [sessionId, workspace] of this.state.createdSessions) {
|
|
952
945
|
const history = await store.read(sessionId);
|
|
953
|
-
if (history.some(event => event.type === "input.submitted" ||
|
|
954
|
-
event.type === "input.steering.queued" ||
|
|
955
|
-
event.type === "
|
|
946
|
+
if (history.some((event) => event.type === "input.submitted" ||
|
|
947
|
+
event.type === "input.steering.queued" ||
|
|
948
|
+
event.type === "run.started" ||
|
|
949
|
+
event.type === "assistant.completed" ||
|
|
950
|
+
(event.type === "session.created" && event.fork !== undefined) ||
|
|
951
|
+
(event.type === "state.updated" && event.key === GOAL_STATE_KEY)))
|
|
956
952
|
continue;
|
|
957
953
|
if (!store.delete || !catalog.remove)
|
|
958
954
|
throw new Error("Empty Session cleanup requires store and catalog deletion support");
|
|
@@ -1006,85 +1002,27 @@ export class MaybeCodeWorkspace {
|
|
|
1006
1002
|
const iterators = [...this.mcpEventIterators];
|
|
1007
1003
|
this.mcpEventIterators.clear();
|
|
1008
1004
|
this.observedMcp = undefined;
|
|
1009
|
-
const results = await Promise.allSettled(iterators.map(async (iterator) => {
|
|
1010
|
-
|
|
1005
|
+
const results = await Promise.allSettled(iterators.map(async (iterator) => {
|
|
1006
|
+
await iterator.return?.();
|
|
1007
|
+
}));
|
|
1008
|
+
const errors = results.flatMap((result) => (result.status === "rejected" ? [result.reason] : []));
|
|
1011
1009
|
if (errors.length)
|
|
1012
1010
|
throw new AggregateError(errors, "MCP event streams failed to close");
|
|
1013
1011
|
}
|
|
1014
1012
|
trackMcpRelay(operation) {
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1013
|
+
const task = operation.then(() => {
|
|
1014
|
+
this.mcpEventRelays.delete(task);
|
|
1015
|
+
}, (error) => {
|
|
1016
|
+
this.mcpEventRelays.delete(task);
|
|
1018
1017
|
this.mcpRelayErrors.push(error);
|
|
1019
1018
|
if (!this.closed)
|
|
1020
1019
|
this.cancel("MCP event forwarding failed");
|
|
1021
1020
|
});
|
|
1021
|
+
this.mcpEventRelays.add(task);
|
|
1022
1022
|
}
|
|
1023
1023
|
throwIfClosed() {
|
|
1024
1024
|
if (this.closed)
|
|
1025
1025
|
throw new Error("MaybeCode workspace is closed");
|
|
1026
1026
|
}
|
|
1027
1027
|
}
|
|
1028
|
-
function withoutSelection(options) {
|
|
1029
|
-
const { sessionId: _sessionId, autoResume: _autoResume, ...base } = options;
|
|
1030
|
-
return base;
|
|
1031
|
-
}
|
|
1032
|
-
function workspaceStoragePaths(options, workspace) {
|
|
1033
|
-
const store = options.store;
|
|
1034
|
-
const catalog = options.catalog;
|
|
1035
|
-
return [store.directory, catalog.path, resolve(workspace, ".may", "permission-rules.json"),
|
|
1036
|
-
resolve(workspace, ".may", "permission-rules.json.lock")].filter((value) => {
|
|
1037
|
-
if (typeof value !== "string")
|
|
1038
|
-
return false;
|
|
1039
|
-
const path = relative(workspace, resolve(value));
|
|
1040
|
-
return path !== "" && path !== ".." && !path.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) && !isAbsolute(path);
|
|
1041
|
-
});
|
|
1042
|
-
}
|
|
1043
|
-
function applicationOptions(options, state) {
|
|
1044
|
-
const { permissionMode: _permissionMode, delegationNotifications: _delegationNotifications, catalog: _catalog, modelProfiles: _modelProfiles, createModelConfiguration: _createModelConfiguration, resolveModelCapabilities: _resolveModelCapabilities, persistDefaultModel: _persistDefaultModel, closeOwnedResources: _closeOwnedResources, mcp: _mcp, git: _git, configureWorkspace: _configureWorkspace, ...application } = options;
|
|
1045
|
-
return { ...application, permissionModeSource: () => state.options.permissionMode ?? "default" };
|
|
1046
|
-
}
|
|
1047
|
-
function unknownReasoningEffort() {
|
|
1048
|
-
return {
|
|
1049
|
-
status: "unknown",
|
|
1050
|
-
source: "unknown",
|
|
1051
|
-
efforts: [],
|
|
1052
|
-
overridden: false,
|
|
1053
|
-
};
|
|
1054
|
-
}
|
|
1055
|
-
function withModelConfiguration(options, configuration, runtimeOptions) {
|
|
1056
|
-
const { model: _model, modelInfo: _modelInfo, contextBudget: _contextBudget, ...unchanged } = options;
|
|
1057
|
-
return {
|
|
1058
|
-
...unchanged,
|
|
1059
|
-
model: configuration.model,
|
|
1060
|
-
modelInfo: configuration.modelInfo,
|
|
1061
|
-
modelRuntimeOptions: runtimeOptions ?? configuredModelOptions(options, configuration.modelInfo.profile),
|
|
1062
|
-
...(configuration.contextBudget === undefined
|
|
1063
|
-
? {}
|
|
1064
|
-
: { contextBudget: configuration.contextBudget }),
|
|
1065
|
-
};
|
|
1066
|
-
}
|
|
1067
|
-
function configuredModelOptions(options, profile) {
|
|
1068
|
-
const effort = options.modelProfiles?.find(item => item.name === profile)?.reasoningEffort;
|
|
1069
|
-
return effort === undefined ? {} : { reasoningEffort: effort };
|
|
1070
|
-
}
|
|
1071
|
-
function readHistoricalModel(value) {
|
|
1072
|
-
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
1073
|
-
throw new MaybeCodeUsageError("Historical model identity is invalid");
|
|
1074
|
-
const saved = value;
|
|
1075
|
-
for (const key of ["provider", "model"])
|
|
1076
|
-
if (typeof saved[key] !== "string" || !saved[key])
|
|
1077
|
-
throw new MaybeCodeUsageError(`Historical model ${key} is invalid`);
|
|
1078
|
-
for (const key of ["profile", "adapter"])
|
|
1079
|
-
if (saved[key] !== undefined && typeof saved[key] !== "string")
|
|
1080
|
-
throw new MaybeCodeUsageError(`Historical model ${key} is invalid`);
|
|
1081
|
-
if (!saved.runtimeOptions || typeof saved.runtimeOptions !== "object" || Array.isArray(saved.runtimeOptions))
|
|
1082
|
-
throw new MaybeCodeUsageError("Historical model options are invalid");
|
|
1083
|
-
return saved;
|
|
1084
|
-
}
|
|
1085
|
-
function assertHistoricalModel(saved, current) {
|
|
1086
|
-
if (!current || saved.provider !== current.provider || saved.model !== current.model || saved.adapter !== current.adapter) {
|
|
1087
|
-
throw new MaybeCodeUsageError("The selected history position requires its original provider, model and adapter configuration");
|
|
1088
|
-
}
|
|
1089
|
-
}
|
|
1090
1028
|
//# sourceMappingURL=workspace.js.map
|