@moretea-labs/forge 1.7.0 → 1.7.1
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/AGENTS.md +2 -0
- package/CHANGELOG.md +13 -0
- package/CLAUDE.md +2 -0
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/agents/openai.yaml +1 -1
- package/assets/partials-agents/02-operating-mode.partial.md +2 -0
- package/assets/plugin-registry.v1.json +3 -3
- package/assets/skill-version.json +2 -2
- package/assets/templates/helpers/check-architecture-sync.sh +17 -0
- package/assets/templates/helpers/inspect-project-state.ts +8 -6
- package/assets/templates/helpers/migrate-workflow-docs.ts +9 -7
- package/assets/templates/helpers/workflow-contract.ts +5 -1
- package/docs/architecture/CURRENT.md +12 -4
- package/docs/forge-plugin-management.md +1 -1
- package/docs/operations/controller-performance-and-502.md +19 -0
- package/docs/operations/homebrew.md +2 -2
- package/package.json +5 -2
- package/scripts/architecture-event.ts +2 -820
- package/scripts/architecture-queue.sh +2 -645
- package/scripts/archive-architecture-request.sh +2 -242
- package/scripts/archive-workflow.sh +1 -291
- package/scripts/benchmark-work-efficiency.ts +0 -0
- package/scripts/capability-config.ts +2 -392
- package/scripts/capability-resolver.ts +2 -503
- package/scripts/capture-plan.sh +1 -332
- package/scripts/check-agent-tooling.sh +2 -1531
- package/scripts/check-architecture-sync.sh +2 -302
- package/scripts/check-brain-manifest.sh +2 -253
- package/scripts/check-context-files.sh +2 -47
- package/scripts/check-deploy-sql-order.sh +2 -115
- package/scripts/check-runtime-architecture.mjs +243 -16
- package/scripts/check-skill-version.ts +3 -191
- package/scripts/check-source-duplication.mjs +61 -0
- package/scripts/check-stable-baseline.ts +0 -0
- package/scripts/check-task-sync.sh +2 -63
- package/scripts/check-task-workflow.sh +2 -1000
- package/scripts/codex-handoff-resume.sh +2 -267
- package/scripts/context-contract-sync.sh +2 -514
- package/scripts/contract-run.ts +2 -463
- package/scripts/contract-worktree.sh +1 -702
- package/scripts/ensure-task-workflow.sh +1 -1192
- package/scripts/inspect-project-state.ts +4 -279
- package/scripts/lib/project-init-lib.sh +7 -2
- package/scripts/lib/run-forge-helper.sh +19 -0
- package/scripts/lib/run-forge-helper.ts +26 -0
- package/scripts/migrate-project-template.sh +1 -33
- package/scripts/migrate-workflow-docs.ts +4 -412
- package/scripts/new-plan.sh +1 -180
- package/scripts/new-spec.sh +1 -47
- package/scripts/new-sprint.sh +1 -46
- package/scripts/plan-to-todo.sh +1 -771
- package/scripts/prepare-codex-handoff.sh +2 -201
- package/scripts/prepare-handoff.sh +1 -78
- package/scripts/refresh-current-status.sh +2 -467
- package/scripts/run-governed-gate.ts +3 -0
- package/scripts/select-agent-context-blocks.sh +2 -64
- package/scripts/ship-worktrees.sh +1 -531
- package/scripts/sprint-backlog.sh +1 -834
- package/scripts/stage-runtime-release.ts +2 -1
- package/scripts/summarize-failures.sh +2 -123
- package/scripts/switch-plan.sh +1 -150
- package/scripts/sync-brain-docs.sh +2 -379
- package/scripts/sync-generated-authority.mjs +175 -0
- package/scripts/verify-contract.sh +2 -593
- package/scripts/verify-sprint.sh +1 -500
- package/scripts/workflow-contract.ts +4 -201
- package/scripts/workstream-sync.sh +2 -261
- package/src/cli/agent-jobs/executor-health.ts +1 -1
- package/src/cli/commands/plugin.ts +12 -3
- package/src/cli/controller/check-runner.ts +7 -2
- package/src/cli/controller/context-pack.ts +46 -21
- package/src/cli/github/contracts.ts +16 -0
- package/src/cli/github/github.ts +2 -16
- package/src/cli/github/session.ts +2 -1
- package/src/cli/local-bridge/facade-api.ts +37 -47
- package/src/cli/local-bridge/server.ts +2 -2
- package/src/cli/mcp/legacy-tool-service.ts +10 -33
- package/src/cli/mcp/post-finalize-work-attribution.ts +150 -0
- package/src/cli/mcp/repository-tools.ts +85 -89
- package/src/cli/mcp/server.ts +57 -13
- package/src/cli/mcp/tool-contract.ts +14 -0
- package/src/cli/mcp/toolset.ts +2 -2
- package/src/cli/mcp/transports/http.ts +23 -0
- package/src/cli/repositories/command-classifier.ts +2 -2
- package/src/cli/repositories/command-executor.ts +24 -6
- package/src/cli/repositories/repository-snapshot.ts +5 -2
- package/src/cli/repositories/structured-git.ts +57 -3
- package/src/cli/repository/inspector.ts +11 -3
- package/src/runtime/context/generic-lsp-provider.ts +1 -1
- package/src/runtime/context/semantic-navigation-contract.ts +61 -0
- package/src/runtime/context/semantic-navigation.ts +9 -61
- package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +18 -25
- package/src/runtime/control-plane/execution/repository-work-attribution.ts +106 -0
- package/src/runtime/control-plane/execution/retained-work-resume.ts +203 -0
- package/src/runtime/control-plane/execution/work-completion-authority.ts +58 -0
- package/src/runtime/control-plane/execution/work-evidence-policy.ts +200 -0
- package/src/runtime/control-plane/execution/work-execution-support.ts +386 -0
- package/src/runtime/control-plane/execution/work-finalization-service.ts +1913 -0
- package/src/runtime/control-plane/execution/work-handle-authority.ts +96 -0
- package/src/runtime/control-plane/execution/work-handle-store.ts +1 -1
- package/src/runtime/control-plane/execution/work-operation-service.ts +468 -0
- package/src/runtime/control-plane/execution/work-path-scope.ts +37 -0
- package/src/runtime/control-plane/execution/work-preparation-service.ts +479 -0
- package/src/runtime/control-plane/execution/work-process-evidence.ts +129 -0
- package/src/runtime/control-plane/execution/work-task-receipt.ts +4 -43
- package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +13 -3
- package/src/runtime/control-plane/execution/work-verification-context.ts +56 -0
- package/src/runtime/control-plane/execution/work-verification-service.ts +388 -0
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +5 -1
- package/src/runtime/control-plane/facade/controller-round-relay.ts +164 -37
- package/src/runtime/control-plane/facade/controller-session-store.ts +183 -24
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +15 -1
- package/src/runtime/control-plane/facade/goal-workloop.ts +329 -148
- package/src/runtime/control-plane/facade/index.ts +2 -0
- package/src/runtime/control-plane/facade/plan-contract-store.ts +90 -22
- package/src/runtime/control-plane/facade/repository-work-admission.ts +147 -0
- package/src/runtime/control-plane/facade/requirement-authority.ts +83 -0
- package/src/runtime/control-plane/facade/types.ts +68 -5
- package/src/runtime/control-plane/facade/work-contract-store.ts +3 -209
- package/src/runtime/control-plane/facade/work-state-machine.ts +250 -0
- package/src/runtime/control-plane/global-scheduler/maintenance.ts +14 -7
- package/src/runtime/control-plane/global-scheduler/scheduler.ts +5 -1
- package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +13 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +15 -6
- package/src/runtime/control-plane/launcher/launch-reservation-store.ts +54 -5
- package/src/runtime/control-plane/launcher/thin-launcher.ts +56 -7
- package/src/runtime/control-plane/persistence/requirement-store.ts +0 -12
- package/src/runtime/control-plane/repo-actor/registry.ts +4 -2
- package/src/runtime/control-plane/routing/route-policy.ts +18 -6
- package/src/runtime/control-plane/routing/workspace-admission.ts +70 -0
- package/src/runtime/evidence/process-check-execution.ts +18 -0
- package/src/runtime/execution/jobs/child-reference.ts +6 -2
- package/src/runtime/execution/process-runtime/check-result.ts +53 -18
- package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +7 -1
- package/src/runtime/execution/process-runtime/command-facade.ts +39 -17
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +20 -3
- package/src/runtime/execution/process-runtime/persisted-check.ts +4 -1
- package/src/runtime/execution/process-runtime/runtime.ts +10 -0
- package/src/runtime/execution/process-runtime/types.ts +2 -12
- package/src/runtime/execution/work-activity.ts +21 -0
- package/src/runtime/execution/workers/executor.ts +18 -13
- package/src/runtime/gateway/mcp/execution-tools.ts +35 -2930
- package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +61 -0
- package/src/runtime/gateway/mcp/router.ts +2 -2
- package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +21 -2
- package/src/runtime/gateway/mcp/runtime-tools.ts +805 -1009
- package/src/runtime/plugins/app-store-connect-adapter.ts +93 -28
- package/src/runtime/plugins/browser-adapter.ts +256 -1083
- package/src/runtime/plugins/browser-handoff-host.ts +2 -25
- package/src/runtime/plugins/browser-handoff.ts +18 -3
- package/src/runtime/plugins/browser-macos-bridge.ts +121 -16
- package/src/runtime/plugins/browser-manifest-surface.ts +603 -0
- package/src/runtime/plugins/browser-native-session-service.ts +222 -0
- package/src/runtime/plugins/browser-runtime-contract.ts +2 -0
- package/src/runtime/plugins/browser-runtime.ts +10 -0
- package/src/runtime/plugins/browser-session-store.ts +121 -0
- package/src/runtime/plugins/browser-session-types.ts +98 -0
- package/src/runtime/plugins/desktop-operator-registration.ts +4 -4
- package/src/runtime/plugins/external-adapter.ts +92 -58
- package/src/runtime/plugins/macos-capability-broker.ts +0 -8
- package/src/runtime/plugins/store.ts +66 -9
- package/src/runtime/plugins/types.ts +3 -1
- package/src/runtime/recovery/maintenance-executor.ts +61 -25
- package/src/runtime/root/package-connector-service.ts +46 -4
- package/src/runtime/root/package-runtime-release.ts +1 -1
- package/src/runtime/root/package-runtime-service.ts +33 -2
- package/src/runtime/root/release-manifest.ts +137 -16
- package/src/runtime/root/release-materialize.ts +109 -35
- package/src/runtime/root/types.ts +10 -0
- package/src/runtime/standalone-recovery/core.ts +425 -194
- package/src/runtime/standalone-recovery/entry.ts +1 -1
- package/src/runtime/standalone-recovery/installer.ts +1 -1
- package/src/runtime/workflow/schedules/engine.ts +113 -87
- package/src/runtime/workflow/schedules/settlement.ts +26 -23
- package/src/runtime/workflow/schedules/store.ts +79 -10
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface GitHubRepositoryInfo {
|
|
2
|
+
nameWithOwner: string;
|
|
3
|
+
owner: string;
|
|
4
|
+
repo: string;
|
|
5
|
+
url: string;
|
|
6
|
+
defaultBranch: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface GitHubStatus {
|
|
10
|
+
available: boolean;
|
|
11
|
+
authenticated: boolean;
|
|
12
|
+
version?: string;
|
|
13
|
+
repository?: GitHubRepositoryInfo;
|
|
14
|
+
agentTaskSupported: boolean;
|
|
15
|
+
errors: string[];
|
|
16
|
+
}
|
package/src/cli/github/github.ts
CHANGED
|
@@ -7,22 +7,8 @@ import type { ControllerIssue, ControllerTask, GitHubIssueLink } from '../contro
|
|
|
7
7
|
import { readTaskRunEvidence } from '../controller/run-evidence';
|
|
8
8
|
import { resolveEffectiveTaskState, resolveIssueLifecycleStatus } from '../controller/task-status-resolver';
|
|
9
9
|
|
|
10
|
-
export
|
|
11
|
-
|
|
12
|
-
owner: string;
|
|
13
|
-
repo: string;
|
|
14
|
-
url: string;
|
|
15
|
-
defaultBranch: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface GitHubStatus {
|
|
19
|
-
available: boolean;
|
|
20
|
-
authenticated: boolean;
|
|
21
|
-
version?: string;
|
|
22
|
-
repository?: GitHubRepositoryInfo;
|
|
23
|
-
agentTaskSupported: boolean;
|
|
24
|
-
errors: string[];
|
|
25
|
-
}
|
|
10
|
+
export type { GitHubRepositoryInfo, GitHubStatus } from './contracts';
|
|
11
|
+
import type { GitHubRepositoryInfo, GitHubStatus } from './contracts';
|
|
26
12
|
|
|
27
13
|
export interface PublishIssueOptions {
|
|
28
14
|
repo?: string;
|
|
@@ -6,7 +6,8 @@ import {
|
|
|
6
6
|
classifyGitHubCopilotPreflight,
|
|
7
7
|
executorHealthCode,
|
|
8
8
|
} from '../agent-jobs/executor-health';
|
|
9
|
-
import { getGitHubStatus, resolveGitHubRepository
|
|
9
|
+
import { getGitHubStatus, resolveGitHubRepository } from './github';
|
|
10
|
+
import type { GitHubRepositoryInfo } from './contracts';
|
|
10
11
|
|
|
11
12
|
export interface GitHubAgentSession {
|
|
12
13
|
id: string;
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
persistControllerAccessMode,
|
|
11
11
|
resolveControllerAccessState,
|
|
12
12
|
} from '../mcp/access-mode';
|
|
13
|
-
import { listControllerChecks
|
|
13
|
+
import { listControllerChecks } from '../controller/check-runner';
|
|
14
14
|
import { createMcpToolContext, type MultiRepositoryMcpToolContext } from '../mcp/multi-repository';
|
|
15
15
|
import { readSchedulerHealthSnapshot } from '../../runtime/control-plane/global-scheduler/scheduler';
|
|
16
16
|
import { observeRuntimeStatus } from '../../runtime/root/status';
|
|
@@ -27,7 +27,6 @@ import {
|
|
|
27
27
|
buildFacadeResult,
|
|
28
28
|
buildSyncOperationDigest,
|
|
29
29
|
classifyUserFacingError,
|
|
30
|
-
classifyVerificationOutcome,
|
|
31
30
|
continueGoalWorkloop,
|
|
32
31
|
delegateToCodexCerebellum,
|
|
33
32
|
dismissHandoffItem,
|
|
@@ -44,7 +43,6 @@ import {
|
|
|
44
43
|
stopGoalWorkloop,
|
|
45
44
|
summarizeHandoffItem,
|
|
46
45
|
summarizeWorkContract,
|
|
47
|
-
verifyGoalWorkloop,
|
|
48
46
|
type ExecutionModeSelectionInput,
|
|
49
47
|
type FacadeResult,
|
|
50
48
|
type HandoffItem,
|
|
@@ -94,6 +92,7 @@ import type {
|
|
|
94
92
|
WorkSummaryViewModel,
|
|
95
93
|
} from './console-view-models';
|
|
96
94
|
import { listActiveOccurrences, listSchedules } from '../../runtime/workflow/schedules/store';
|
|
95
|
+
import { executeWorkVerification } from '../../runtime/control-plane/execution/work-verification-service';
|
|
97
96
|
|
|
98
97
|
export type ConsoleFacadeContext = {
|
|
99
98
|
controllerHome: string;
|
|
@@ -1042,6 +1041,9 @@ export function startConsoleWork(
|
|
|
1042
1041
|
requiresApproval?: boolean;
|
|
1043
1042
|
destructive?: boolean;
|
|
1044
1043
|
accessMode?: AccessMode;
|
|
1044
|
+
workspaceMode?: 'current' | 'isolated' | 'auto';
|
|
1045
|
+
requireWorktree?: boolean;
|
|
1046
|
+
directMainProhibited?: boolean;
|
|
1045
1047
|
approvalConfirmed?: boolean;
|
|
1046
1048
|
forceMode?: 'direct_control' | 'goal_workloop' | 'handoff_only';
|
|
1047
1049
|
checkIds?: string[];
|
|
@@ -1061,7 +1063,17 @@ export function startConsoleWork(
|
|
|
1061
1063
|
allowedPaths: input.allowedPaths,
|
|
1062
1064
|
forbiddenPaths: input.forbiddenPaths,
|
|
1063
1065
|
checks: input.checkIds,
|
|
1064
|
-
constraints: input.accessMode
|
|
1066
|
+
constraints: input.accessMode !== undefined
|
|
1067
|
+
|| input.workspaceMode !== undefined
|
|
1068
|
+
|| input.requireWorktree !== undefined
|
|
1069
|
+
|| input.directMainProhibited !== undefined
|
|
1070
|
+
? {
|
|
1071
|
+
...(input.accessMode !== undefined ? { accessMode: input.accessMode } : {}),
|
|
1072
|
+
...(input.workspaceMode !== undefined ? { workspaceMode: input.workspaceMode } : {}),
|
|
1073
|
+
...(input.requireWorktree !== undefined ? { requireWorktree: input.requireWorktree } : {}),
|
|
1074
|
+
...(input.directMainProhibited !== undefined ? { directMainProhibited: input.directMainProhibited } : {}),
|
|
1075
|
+
}
|
|
1076
|
+
: undefined,
|
|
1065
1077
|
modeInput: {
|
|
1066
1078
|
objective: input.objective,
|
|
1067
1079
|
expectedFiles: input.expectedFiles,
|
|
@@ -1092,51 +1104,24 @@ export function continueConsoleWork(ctx: ConsoleFacadeContext, workId: string, n
|
|
|
1092
1104
|
);
|
|
1093
1105
|
}
|
|
1094
1106
|
|
|
1095
|
-
export function verifyConsoleWork(
|
|
1107
|
+
export async function verifyConsoleWork(
|
|
1096
1108
|
ctx: ConsoleFacadeContext,
|
|
1097
1109
|
input: { workId: string; checkId?: string; simulate?: boolean; checkFailed?: boolean; infrastructureFailed?: boolean },
|
|
1098
|
-
): FacadeResult {
|
|
1099
|
-
const
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
}
|
|
1112
|
-
|
|
1113
|
-
return verifyGoalWorkloop(workloopCtx, {
|
|
1114
|
-
workId: input.workId,
|
|
1115
|
-
checkId: classified.normalizedCheckId ?? requested,
|
|
1116
|
-
checkFailed: input.checkFailed === true,
|
|
1117
|
-
infrastructureFailed: input.infrastructureFailed === true,
|
|
1118
|
-
});
|
|
1119
|
-
}
|
|
1120
|
-
try {
|
|
1121
|
-
const executed = runControllerCheck(ctx.repository.canonicalRoot, classified.normalizedCheckId!);
|
|
1122
|
-
return verifyGoalWorkloop(workloopCtx, {
|
|
1123
|
-
workId: input.workId,
|
|
1124
|
-
checkId: classified.normalizedCheckId!,
|
|
1125
|
-
infrastructureFailed: executed.timedOut === true,
|
|
1126
|
-
checkFailed: !executed.ok && !executed.timedOut,
|
|
1127
|
-
});
|
|
1128
|
-
} catch (error) {
|
|
1129
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1130
|
-
const facade = verifyGoalWorkloop(workloopCtx, {
|
|
1131
|
-
workId: input.workId,
|
|
1132
|
-
checkId: classified.normalizedCheckId ?? requested,
|
|
1133
|
-
infrastructureFailed: true,
|
|
1134
|
-
});
|
|
1135
|
-
return {
|
|
1136
|
-
...facade,
|
|
1137
|
-
warnings: [...facade.warnings, `环境执行检查失败:${message.slice(0, 160)}`],
|
|
1138
|
-
};
|
|
1139
|
-
}
|
|
1110
|
+
): Promise<FacadeResult> {
|
|
1111
|
+
const verification = await executeWorkVerification({
|
|
1112
|
+
controllerHome: ctx.controllerHome,
|
|
1113
|
+
repository: ctx.repository,
|
|
1114
|
+
workId: input.workId,
|
|
1115
|
+
checkId: input.checkId,
|
|
1116
|
+
interactiveWaitMs: 0,
|
|
1117
|
+
simulate: input.simulate
|
|
1118
|
+
? {
|
|
1119
|
+
checkFailed: input.checkFailed === true,
|
|
1120
|
+
infrastructureFailed: input.infrastructureFailed === true,
|
|
1121
|
+
}
|
|
1122
|
+
: undefined,
|
|
1123
|
+
});
|
|
1124
|
+
return verification.facade;
|
|
1140
1125
|
}
|
|
1141
1126
|
|
|
1142
1127
|
export function finalizeConsoleWork(ctx: ConsoleFacadeContext, workId: string): FacadeResult {
|
|
@@ -1276,6 +1261,11 @@ export function approveConsoleHandoff(ctx: ConsoleFacadeContext, handoffId: stri
|
|
|
1276
1261
|
requiresApproval: payload.requiresApproval === true,
|
|
1277
1262
|
destructive: payload.destructive === true,
|
|
1278
1263
|
accessMode: isAccessMode(payload.accessMode) ? payload.accessMode : undefined,
|
|
1264
|
+
workspaceMode: payload.workspaceMode === 'current' || payload.workspaceMode === 'isolated' || payload.workspaceMode === 'auto'
|
|
1265
|
+
? payload.workspaceMode
|
|
1266
|
+
: undefined,
|
|
1267
|
+
requireWorktree: typeof payload.requireWorktree === 'boolean' ? payload.requireWorktree : undefined,
|
|
1268
|
+
directMainProhibited: typeof payload.directMainProhibited === 'boolean' ? payload.directMainProhibited : undefined,
|
|
1279
1269
|
approvalConfirmed: true,
|
|
1280
1270
|
forceMode: 'goal_workloop',
|
|
1281
1271
|
checkIds: strings(payload.checkIds),
|
|
@@ -1575,12 +1575,12 @@ export async function startLocalBridgeServer(
|
|
|
1575
1575
|
}
|
|
1576
1576
|
});
|
|
1577
1577
|
|
|
1578
|
-
app.post("/api/console/work/verify", (request, response) => {
|
|
1578
|
+
app.post("/api/console/work/verify", async (request, response) => {
|
|
1579
1579
|
try {
|
|
1580
1580
|
const body = request.body && typeof request.body === "object" && !Array.isArray(request.body)
|
|
1581
1581
|
? request.body as Record<string, unknown>
|
|
1582
1582
|
: {};
|
|
1583
|
-
const result = verifyConsoleWork(consoleCtx(request), {
|
|
1583
|
+
const result = await verifyConsoleWork(consoleCtx(request), {
|
|
1584
1584
|
workId: queryString(body.workId) ?? "",
|
|
1585
1585
|
checkId: queryString(body.checkId),
|
|
1586
1586
|
simulate: body.simulate === true,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { CallToolResult
|
|
1
|
+
import type { CallToolResult, McpToolDefinition } from './tool-contract';
|
|
2
|
+
export type { CallToolResult, McpToolDefinition } from './tool-contract';
|
|
2
3
|
import { createHash } from "crypto";
|
|
3
4
|
import {
|
|
4
5
|
existsSync,
|
|
@@ -71,7 +72,8 @@ import {
|
|
|
71
72
|
import { normalizeCheckIds } from '../../runtime/control-plane/facade/check-normalization';
|
|
72
73
|
import { buildExecutionDiagnostics, buildRequirementBoard } from '../../runtime/control-plane/facade/requirement-board';
|
|
73
74
|
import { acceptVerifiedTaskFromControllerWork } from '../../runtime/control-plane/execution/work-task-receipt';
|
|
74
|
-
import {
|
|
75
|
+
import { getWorkContract } from '../../runtime/control-plane/facade/work-contract-store';
|
|
76
|
+
import { admitDirectEditWorkContract } from '../../runtime/control-plane/facade/repository-work-admission';
|
|
75
77
|
import { decideRoute } from '../../runtime/control-plane/routing/route-policy';
|
|
76
78
|
import { listCapabilityDescriptors, summarizeCapabilityGroups } from '../../runtime/control-plane/facade/capability-registry';
|
|
77
79
|
import {
|
|
@@ -149,6 +151,11 @@ import { hashMcpInput, tryWriteMcpAuditEntry } from "./audit";
|
|
|
149
151
|
import { loadMcpRuntimeState } from "./auth";
|
|
150
152
|
import { resolveLocalBridgeSurface, summarizeRecentJobs } from "../../runtime/shared/local-bridge-surface";
|
|
151
153
|
import { resolveRepoPreferredControllerHome } from "../repositories/controller-home";
|
|
154
|
+
import { resolveRepositorySelection } from '../repositories/registry';
|
|
155
|
+
import { executionIdentityForRepository } from '../../runtime/control-plane/execution/execution-identity';
|
|
156
|
+
import { runPersistedCheckViaProcessRuntime } from '../../runtime/gateway/mcp/persisted-check-process';
|
|
157
|
+
import { getProcessRecord } from '../../runtime/execution/process-runtime/store';
|
|
158
|
+
import { processCheckCompletionReceipt } from '../../runtime/execution/process-runtime/check-receipt';
|
|
152
159
|
import { normalizeMcpRelativePath, resolveMcpPath } from "./paths";
|
|
153
160
|
import { currentGitBranch, isForgeAdopted } from "./repo";
|
|
154
161
|
import { repositoryToolNames } from "./repository-tools";
|
|
@@ -173,16 +180,6 @@ export interface McpToolContext {
|
|
|
173
180
|
signal?: AbortSignal;
|
|
174
181
|
}
|
|
175
182
|
|
|
176
|
-
export interface McpToolDefinition {
|
|
177
|
-
name: string;
|
|
178
|
-
description: string;
|
|
179
|
-
inputSchema: Record<string, unknown>;
|
|
180
|
-
annotations?: Record<string, unknown>;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
export type CallToolResult = Omit<SdkCallToolResult, "content"> & {
|
|
184
|
-
content: Array<{ type: "text"; text: string }>;
|
|
185
|
-
};
|
|
186
183
|
|
|
187
184
|
const EMPTY_SCHEMA = { type: "object", additionalProperties: false };
|
|
188
185
|
|
|
@@ -4317,11 +4314,6 @@ export async function callMcpTool(
|
|
|
4317
4314
|
const checkIds = normalizedChecks.validCheckIds;
|
|
4318
4315
|
const checkResults: TaskVerification['checkResults'] = [];
|
|
4319
4316
|
if (checkIds.length > 0) {
|
|
4320
|
-
const { resolveRepositorySelection } = await import('../repositories/registry');
|
|
4321
|
-
const { executionIdentityForRepository } = await import('../../runtime/control-plane/execution/execution-identity');
|
|
4322
|
-
const { runPersistedCheckViaProcessRuntime } = await import('../../runtime/gateway/mcp/persisted-check-process');
|
|
4323
|
-
const { getProcessRecord } = await import('../../runtime/execution/process-runtime/store');
|
|
4324
|
-
const { processCheckCompletionReceipt } = await import('../../runtime/execution/process-runtime/check-receipt');
|
|
4325
4317
|
const controllerHome = resolveRepoPreferredControllerHome(ctx.repoRoot);
|
|
4326
4318
|
const repository = resolveRepositorySelection({
|
|
4327
4319
|
explicitPath: ctx.repoRoot,
|
|
@@ -4578,7 +4570,7 @@ export async function callMcpTool(
|
|
|
4578
4570
|
const existingWork = getWorkContract(workStore, workId);
|
|
4579
4571
|
if (requestedWorkId && !existingWork) return errorResult("WORK_NOT_FOUND", `WorkContract ${workId} not found`);
|
|
4580
4572
|
if (!existingWork) {
|
|
4581
|
-
|
|
4573
|
+
admitDirectEditWorkContract(workStore, {
|
|
4582
4574
|
workId,
|
|
4583
4575
|
repoId,
|
|
4584
4576
|
checkoutId: identity.checkoutId,
|
|
@@ -4586,28 +4578,13 @@ export async function callMcpTool(
|
|
|
4586
4578
|
controllerInstanceId: identity.controllerInstanceId,
|
|
4587
4579
|
baseRevision: git.head ?? undefined,
|
|
4588
4580
|
workspaceFingerprint: workspaceIdentity,
|
|
4589
|
-
routeDecisionFingerprint: routeDecision.inputFingerprint,
|
|
4590
4581
|
routeDecision,
|
|
4591
|
-
mode: "direct_control",
|
|
4592
4582
|
objective: purpose,
|
|
4593
|
-
acceptanceCriteria: [],
|
|
4594
|
-
constraints: { workspaceMode: "current", requireWorktree: false, requireHandoffOnAmbiguity: true },
|
|
4595
|
-
risk: "low",
|
|
4596
|
-
status: "running",
|
|
4597
|
-
phase: "implementation",
|
|
4598
4583
|
issueId: typeof args.issue_id === "string" ? args.issue_id : undefined,
|
|
4599
4584
|
taskId: typeof args.task_id === "string" ? args.task_id : undefined,
|
|
4600
|
-
scopeSummary: purpose,
|
|
4601
4585
|
allowedPaths,
|
|
4602
|
-
forbiddenPaths: [],
|
|
4603
4586
|
checks,
|
|
4604
4587
|
requestedBy: "chatgpt",
|
|
4605
|
-
evidenceRefs: [],
|
|
4606
|
-
handoffRefs: [],
|
|
4607
|
-
suggestedNextActions: [],
|
|
4608
|
-
policyDecisions: [],
|
|
4609
|
-
checkRefs: [],
|
|
4610
|
-
reconciliations: [],
|
|
4611
4588
|
});
|
|
4612
4589
|
}
|
|
4613
4590
|
const session = beginEditSession(ctx.repoRoot, {
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { classifyRepositoryCommand } from '../repositories/command-classifier';
|
|
2
|
+
import { resolveRepositorySelection } from '../repositories/registry';
|
|
3
|
+
import { executionIdentityForRepository } from '../../runtime/control-plane/execution/execution-identity';
|
|
4
|
+
import { getWorkContract } from '../../runtime/control-plane/facade/work-contract-store';
|
|
5
|
+
import { isTerminalWorkContractStatus } from '../../runtime/control-plane/facade/types';
|
|
6
|
+
import {
|
|
7
|
+
classifyRepositoryCommandRoute,
|
|
8
|
+
executeRepositoryCommandViaProcessRuntime,
|
|
9
|
+
} from '../../runtime/execution/process-runtime/command-facade';
|
|
10
|
+
import {
|
|
11
|
+
callRepositoryTool,
|
|
12
|
+
type RepositoryToolCallerContext,
|
|
13
|
+
} from './repository-tools';
|
|
14
|
+
import type { CallToolResult } from './tools';
|
|
15
|
+
|
|
16
|
+
function result(payload: Record<string, unknown>, isError = false): CallToolResult {
|
|
17
|
+
return {
|
|
18
|
+
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
19
|
+
structuredContent: payload,
|
|
20
|
+
...(isError ? { isError: true } : {}),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function optionalNumber(value: unknown): number | undefined {
|
|
25
|
+
if (typeof value === 'number' && Number.isFinite(value)) return value;
|
|
26
|
+
if (typeof value === 'string' && value.trim()) {
|
|
27
|
+
const parsed = Number(value);
|
|
28
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
29
|
+
}
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* A completed Work is historical attribution, never mutation authority.
|
|
35
|
+
*
|
|
36
|
+
* Finalize cleanup may remove the Work-owned checkout and release its Controller
|
|
37
|
+
* lease, but a Controller can still need to observe the repository immediately
|
|
38
|
+
* afterwards (for example `git status -sb`). Keep that observation attributed to
|
|
39
|
+
* the completed Work without reopening the Work lifecycle or writer lease.
|
|
40
|
+
*
|
|
41
|
+
* This path intentionally accepts only typed argv commands that the same command
|
|
42
|
+
* classifier used by Process Runtime proves readonly. Everything else falls
|
|
43
|
+
* through to the normal repository facade so active-Work ownership, terminal
|
|
44
|
+
* mutation fences, and completion-receipt remote-delivery rules stay authoritative.
|
|
45
|
+
*/
|
|
46
|
+
export async function callPostFinalizeWorkReadOnlyCommand(
|
|
47
|
+
controllerHome: string,
|
|
48
|
+
name: string,
|
|
49
|
+
args: Record<string, unknown>,
|
|
50
|
+
caller?: RepositoryToolCallerContext,
|
|
51
|
+
): Promise<CallToolResult | undefined> {
|
|
52
|
+
if (name !== 'repository_command_execute') return undefined;
|
|
53
|
+
if (typeof args.workspace_root === 'string' && args.workspace_root.trim()) return undefined;
|
|
54
|
+
|
|
55
|
+
const requestedWorkId = typeof args.work_id === 'string' ? args.work_id.trim() : '';
|
|
56
|
+
const principalId = caller?.principalId?.trim() ?? '';
|
|
57
|
+
const command = args.command;
|
|
58
|
+
if (!requestedWorkId || !principalId || !Array.isArray(command) || !command.every((entry) => typeof entry === 'string')) {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const repository = resolveRepositorySelection({
|
|
63
|
+
repoId: typeof args.repo_id === 'string' && args.repo_id.trim() ? args.repo_id.trim() : undefined,
|
|
64
|
+
controllerHome,
|
|
65
|
+
allowSoleRepository: true,
|
|
66
|
+
});
|
|
67
|
+
if (!repository) return undefined;
|
|
68
|
+
|
|
69
|
+
const work = getWorkContract({ controllerHome, repoId: repository.repoId }, requestedWorkId);
|
|
70
|
+
if (
|
|
71
|
+
!work
|
|
72
|
+
|| !isTerminalWorkContractStatus(work.status)
|
|
73
|
+
|| work.status !== 'completed'
|
|
74
|
+
|| !work.completionReceipt
|
|
75
|
+
|| work.completionReceipt.workId !== requestedWorkId
|
|
76
|
+
|| !work.principalId?.trim()
|
|
77
|
+
|| work.principalId.trim() !== principalId
|
|
78
|
+
) {
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const classification = classifyRepositoryCommand(command, repository.defaultBranch);
|
|
83
|
+
if (classification.risk !== 'readonly') return undefined;
|
|
84
|
+
const route = classifyRepositoryCommandRoute(command, {
|
|
85
|
+
defaultBranch: repository.defaultBranch,
|
|
86
|
+
timeoutMs: optionalNumber(args.timeout_ms),
|
|
87
|
+
});
|
|
88
|
+
if (route.route !== 'process_direct' || route.reason !== 'readonly_fast_path') return undefined;
|
|
89
|
+
|
|
90
|
+
const executionIdentity = executionIdentityForRepository(repository, { workId: requestedWorkId });
|
|
91
|
+
const execution = await executeRepositoryCommandViaProcessRuntime({
|
|
92
|
+
controllerHome,
|
|
93
|
+
repository,
|
|
94
|
+
command,
|
|
95
|
+
cwd: typeof args.cwd === 'string' ? args.cwd : undefined,
|
|
96
|
+
timeoutMs: optionalNumber(args.timeout_ms),
|
|
97
|
+
interactiveWaitMs: optionalNumber(args.interactive_wait_ms),
|
|
98
|
+
maxOutputBytes: optionalNumber(args.max_output_bytes),
|
|
99
|
+
requestId: typeof args.request_id === 'string' ? args.request_id : undefined,
|
|
100
|
+
workId: requestedWorkId,
|
|
101
|
+
executionIdentity,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
if (execution.route !== 'process_direct' || execution.process) {
|
|
105
|
+
return result({
|
|
106
|
+
accepted: false,
|
|
107
|
+
mode: 'reject',
|
|
108
|
+
path: 'post_finalize_readonly_route_mismatch',
|
|
109
|
+
route: 'reject',
|
|
110
|
+
repoId: repository.repoId,
|
|
111
|
+
checkoutId: repository.activeCheckoutId,
|
|
112
|
+
workId: requestedWorkId,
|
|
113
|
+
lifecycleClosed: true,
|
|
114
|
+
error: {
|
|
115
|
+
code: 'POST_FINALIZE_READONLY_ROUTE_MISMATCH',
|
|
116
|
+
message: 'Post-finalize Work attribution may execute only through the bounded readonly direct lane.',
|
|
117
|
+
},
|
|
118
|
+
}, true);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return result({
|
|
122
|
+
accepted: true,
|
|
123
|
+
mode: 'process_direct',
|
|
124
|
+
path: 'process_direct',
|
|
125
|
+
route: 'process_direct',
|
|
126
|
+
reason: 'post_finalize_work_readonly_followup',
|
|
127
|
+
repoId: repository.repoId,
|
|
128
|
+
checkoutId: repository.activeCheckoutId,
|
|
129
|
+
workId: requestedWorkId,
|
|
130
|
+
lifecycleClosed: true,
|
|
131
|
+
postFinalizeAttribution: 'readonly_followup',
|
|
132
|
+
completed: true,
|
|
133
|
+
ok: execution.ok === true,
|
|
134
|
+
exitCode: execution.exitCode,
|
|
135
|
+
stdout: execution.stdout,
|
|
136
|
+
stderr: execution.stderr,
|
|
137
|
+
durableSideEffects: execution.durableSideEffects,
|
|
138
|
+
next: 'Post-finalize readonly observation completed without reopening Work mutation authority or creating durable execution state.',
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export async function callRepositoryToolWithPostFinalizeAttribution(
|
|
143
|
+
controllerHome: string,
|
|
144
|
+
name: string,
|
|
145
|
+
args: Record<string, unknown>,
|
|
146
|
+
caller?: RepositoryToolCallerContext,
|
|
147
|
+
): Promise<CallToolResult | undefined> {
|
|
148
|
+
const followup = await callPostFinalizeWorkReadOnlyCommand(controllerHome, name, args, caller);
|
|
149
|
+
return followup ?? callRepositoryTool(controllerHome, name, args, caller);
|
|
150
|
+
}
|