@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.
Files changed (175) hide show
  1. package/AGENTS.md +2 -0
  2. package/CHANGELOG.md +13 -0
  3. package/CLAUDE.md +2 -0
  4. package/THIRD_PARTY_NOTICES.md +1 -1
  5. package/agents/openai.yaml +1 -1
  6. package/assets/partials-agents/02-operating-mode.partial.md +2 -0
  7. package/assets/plugin-registry.v1.json +3 -3
  8. package/assets/skill-version.json +2 -2
  9. package/assets/templates/helpers/check-architecture-sync.sh +17 -0
  10. package/assets/templates/helpers/inspect-project-state.ts +8 -6
  11. package/assets/templates/helpers/migrate-workflow-docs.ts +9 -7
  12. package/assets/templates/helpers/workflow-contract.ts +5 -1
  13. package/docs/architecture/CURRENT.md +12 -4
  14. package/docs/forge-plugin-management.md +1 -1
  15. package/docs/operations/controller-performance-and-502.md +19 -0
  16. package/docs/operations/homebrew.md +2 -2
  17. package/package.json +5 -2
  18. package/scripts/architecture-event.ts +2 -820
  19. package/scripts/architecture-queue.sh +2 -645
  20. package/scripts/archive-architecture-request.sh +2 -242
  21. package/scripts/archive-workflow.sh +1 -291
  22. package/scripts/benchmark-work-efficiency.ts +0 -0
  23. package/scripts/capability-config.ts +2 -392
  24. package/scripts/capability-resolver.ts +2 -503
  25. package/scripts/capture-plan.sh +1 -332
  26. package/scripts/check-agent-tooling.sh +2 -1531
  27. package/scripts/check-architecture-sync.sh +2 -302
  28. package/scripts/check-brain-manifest.sh +2 -253
  29. package/scripts/check-context-files.sh +2 -47
  30. package/scripts/check-deploy-sql-order.sh +2 -115
  31. package/scripts/check-runtime-architecture.mjs +243 -16
  32. package/scripts/check-skill-version.ts +3 -191
  33. package/scripts/check-source-duplication.mjs +61 -0
  34. package/scripts/check-stable-baseline.ts +0 -0
  35. package/scripts/check-task-sync.sh +2 -63
  36. package/scripts/check-task-workflow.sh +2 -1000
  37. package/scripts/codex-handoff-resume.sh +2 -267
  38. package/scripts/context-contract-sync.sh +2 -514
  39. package/scripts/contract-run.ts +2 -463
  40. package/scripts/contract-worktree.sh +1 -702
  41. package/scripts/ensure-task-workflow.sh +1 -1192
  42. package/scripts/inspect-project-state.ts +4 -279
  43. package/scripts/lib/project-init-lib.sh +7 -2
  44. package/scripts/lib/run-forge-helper.sh +19 -0
  45. package/scripts/lib/run-forge-helper.ts +26 -0
  46. package/scripts/migrate-project-template.sh +1 -33
  47. package/scripts/migrate-workflow-docs.ts +4 -412
  48. package/scripts/new-plan.sh +1 -180
  49. package/scripts/new-spec.sh +1 -47
  50. package/scripts/new-sprint.sh +1 -46
  51. package/scripts/plan-to-todo.sh +1 -771
  52. package/scripts/prepare-codex-handoff.sh +2 -201
  53. package/scripts/prepare-handoff.sh +1 -78
  54. package/scripts/refresh-current-status.sh +2 -467
  55. package/scripts/run-governed-gate.ts +3 -0
  56. package/scripts/select-agent-context-blocks.sh +2 -64
  57. package/scripts/ship-worktrees.sh +1 -531
  58. package/scripts/sprint-backlog.sh +1 -834
  59. package/scripts/stage-runtime-release.ts +2 -1
  60. package/scripts/summarize-failures.sh +2 -123
  61. package/scripts/switch-plan.sh +1 -150
  62. package/scripts/sync-brain-docs.sh +2 -379
  63. package/scripts/sync-generated-authority.mjs +175 -0
  64. package/scripts/verify-contract.sh +2 -593
  65. package/scripts/verify-sprint.sh +1 -500
  66. package/scripts/workflow-contract.ts +4 -201
  67. package/scripts/workstream-sync.sh +2 -261
  68. package/src/cli/agent-jobs/executor-health.ts +1 -1
  69. package/src/cli/commands/plugin.ts +12 -3
  70. package/src/cli/controller/check-runner.ts +7 -2
  71. package/src/cli/controller/context-pack.ts +46 -21
  72. package/src/cli/github/contracts.ts +16 -0
  73. package/src/cli/github/github.ts +2 -16
  74. package/src/cli/github/session.ts +2 -1
  75. package/src/cli/local-bridge/facade-api.ts +37 -47
  76. package/src/cli/local-bridge/server.ts +2 -2
  77. package/src/cli/mcp/legacy-tool-service.ts +10 -33
  78. package/src/cli/mcp/post-finalize-work-attribution.ts +150 -0
  79. package/src/cli/mcp/repository-tools.ts +85 -89
  80. package/src/cli/mcp/server.ts +57 -13
  81. package/src/cli/mcp/tool-contract.ts +14 -0
  82. package/src/cli/mcp/toolset.ts +2 -2
  83. package/src/cli/mcp/transports/http.ts +23 -0
  84. package/src/cli/repositories/command-classifier.ts +2 -2
  85. package/src/cli/repositories/command-executor.ts +24 -6
  86. package/src/cli/repositories/repository-snapshot.ts +5 -2
  87. package/src/cli/repositories/structured-git.ts +57 -3
  88. package/src/cli/repository/inspector.ts +11 -3
  89. package/src/runtime/context/generic-lsp-provider.ts +1 -1
  90. package/src/runtime/context/semantic-navigation-contract.ts +61 -0
  91. package/src/runtime/context/semantic-navigation.ts +9 -61
  92. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +18 -25
  93. package/src/runtime/control-plane/execution/repository-work-attribution.ts +106 -0
  94. package/src/runtime/control-plane/execution/retained-work-resume.ts +203 -0
  95. package/src/runtime/control-plane/execution/work-completion-authority.ts +58 -0
  96. package/src/runtime/control-plane/execution/work-evidence-policy.ts +200 -0
  97. package/src/runtime/control-plane/execution/work-execution-support.ts +386 -0
  98. package/src/runtime/control-plane/execution/work-finalization-service.ts +1913 -0
  99. package/src/runtime/control-plane/execution/work-handle-authority.ts +96 -0
  100. package/src/runtime/control-plane/execution/work-handle-store.ts +1 -1
  101. package/src/runtime/control-plane/execution/work-operation-service.ts +468 -0
  102. package/src/runtime/control-plane/execution/work-path-scope.ts +37 -0
  103. package/src/runtime/control-plane/execution/work-preparation-service.ts +479 -0
  104. package/src/runtime/control-plane/execution/work-process-evidence.ts +129 -0
  105. package/src/runtime/control-plane/execution/work-task-receipt.ts +4 -43
  106. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +13 -3
  107. package/src/runtime/control-plane/execution/work-verification-context.ts +56 -0
  108. package/src/runtime/control-plane/execution/work-verification-service.ts +388 -0
  109. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +5 -1
  110. package/src/runtime/control-plane/facade/controller-round-relay.ts +164 -37
  111. package/src/runtime/control-plane/facade/controller-session-store.ts +183 -24
  112. package/src/runtime/control-plane/facade/goal-workloop-access.ts +15 -1
  113. package/src/runtime/control-plane/facade/goal-workloop.ts +329 -148
  114. package/src/runtime/control-plane/facade/index.ts +2 -0
  115. package/src/runtime/control-plane/facade/plan-contract-store.ts +90 -22
  116. package/src/runtime/control-plane/facade/repository-work-admission.ts +147 -0
  117. package/src/runtime/control-plane/facade/requirement-authority.ts +83 -0
  118. package/src/runtime/control-plane/facade/types.ts +68 -5
  119. package/src/runtime/control-plane/facade/work-contract-store.ts +3 -209
  120. package/src/runtime/control-plane/facade/work-state-machine.ts +250 -0
  121. package/src/runtime/control-plane/global-scheduler/maintenance.ts +14 -7
  122. package/src/runtime/control-plane/global-scheduler/scheduler.ts +5 -1
  123. package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +13 -0
  124. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +15 -6
  125. package/src/runtime/control-plane/launcher/launch-reservation-store.ts +54 -5
  126. package/src/runtime/control-plane/launcher/thin-launcher.ts +56 -7
  127. package/src/runtime/control-plane/persistence/requirement-store.ts +0 -12
  128. package/src/runtime/control-plane/repo-actor/registry.ts +4 -2
  129. package/src/runtime/control-plane/routing/route-policy.ts +18 -6
  130. package/src/runtime/control-plane/routing/workspace-admission.ts +70 -0
  131. package/src/runtime/evidence/process-check-execution.ts +18 -0
  132. package/src/runtime/execution/jobs/child-reference.ts +6 -2
  133. package/src/runtime/execution/process-runtime/check-result.ts +53 -18
  134. package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +7 -1
  135. package/src/runtime/execution/process-runtime/command-facade.ts +39 -17
  136. package/src/runtime/execution/process-runtime/lightweight-managed.ts +20 -3
  137. package/src/runtime/execution/process-runtime/persisted-check.ts +4 -1
  138. package/src/runtime/execution/process-runtime/runtime.ts +10 -0
  139. package/src/runtime/execution/process-runtime/types.ts +2 -12
  140. package/src/runtime/execution/work-activity.ts +21 -0
  141. package/src/runtime/execution/workers/executor.ts +18 -13
  142. package/src/runtime/gateway/mcp/execution-tools.ts +35 -2930
  143. package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +61 -0
  144. package/src/runtime/gateway/mcp/router.ts +2 -2
  145. package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +21 -2
  146. package/src/runtime/gateway/mcp/runtime-tools.ts +805 -1009
  147. package/src/runtime/plugins/app-store-connect-adapter.ts +93 -28
  148. package/src/runtime/plugins/browser-adapter.ts +256 -1083
  149. package/src/runtime/plugins/browser-handoff-host.ts +2 -25
  150. package/src/runtime/plugins/browser-handoff.ts +18 -3
  151. package/src/runtime/plugins/browser-macos-bridge.ts +121 -16
  152. package/src/runtime/plugins/browser-manifest-surface.ts +603 -0
  153. package/src/runtime/plugins/browser-native-session-service.ts +222 -0
  154. package/src/runtime/plugins/browser-runtime-contract.ts +2 -0
  155. package/src/runtime/plugins/browser-runtime.ts +10 -0
  156. package/src/runtime/plugins/browser-session-store.ts +121 -0
  157. package/src/runtime/plugins/browser-session-types.ts +98 -0
  158. package/src/runtime/plugins/desktop-operator-registration.ts +4 -4
  159. package/src/runtime/plugins/external-adapter.ts +92 -58
  160. package/src/runtime/plugins/macos-capability-broker.ts +0 -8
  161. package/src/runtime/plugins/store.ts +66 -9
  162. package/src/runtime/plugins/types.ts +3 -1
  163. package/src/runtime/recovery/maintenance-executor.ts +61 -25
  164. package/src/runtime/root/package-connector-service.ts +46 -4
  165. package/src/runtime/root/package-runtime-release.ts +1 -1
  166. package/src/runtime/root/package-runtime-service.ts +33 -2
  167. package/src/runtime/root/release-manifest.ts +137 -16
  168. package/src/runtime/root/release-materialize.ts +109 -35
  169. package/src/runtime/root/types.ts +10 -0
  170. package/src/runtime/standalone-recovery/core.ts +425 -194
  171. package/src/runtime/standalone-recovery/entry.ts +1 -1
  172. package/src/runtime/standalone-recovery/installer.ts +1 -1
  173. package/src/runtime/workflow/schedules/engine.ts +113 -87
  174. package/src/runtime/workflow/schedules/settlement.ts +26 -23
  175. 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
+ }
@@ -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 interface GitHubRepositoryInfo {
11
- nameWithOwner: string;
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, type GitHubRepositoryInfo } from './github';
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, runControllerCheck } from '../controller/check-runner';
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 ? { accessMode: input.accessMode } : undefined,
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 checks = listControllerChecks(ctx.repository.canonicalRoot);
1100
- const workloopCtx = {
1101
- workStore: store(ctx),
1102
- handoffStore: store(ctx),
1103
- repoId: ctx.repository.repoId,
1104
- availableChecks: checks,
1105
- };
1106
- const work = getWorkContract(store(ctx), input.workId);
1107
- const requested = input.checkId || work?.checks[0] || checks[0]?.id || '';
1108
- const classified = classifyVerificationOutcome({ checkId: requested, available: checks });
1109
- if (classified.outcome === 'invalid_check_id') {
1110
- return verifyGoalWorkloop(workloopCtx, { workId: input.workId, checkId: requested });
1111
- }
1112
- if (input.simulate) {
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 as SdkCallToolResult } from '@modelcontextprotocol/sdk/types.js';
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 { createWorkContract, getWorkContract } from '../../runtime/control-plane/facade/work-contract-store';
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
- createWorkContract(workStore, {
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
+ }