@zq-silk/yui 0.15.11 → 0.16.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.
Files changed (280) hide show
  1. package/ARCHITECTURE.md +11 -6
  2. package/ARCHITECTURE.zh-CN.md +8 -4
  3. package/README.md +13 -5
  4. package/dist/agentRun/agentRun.js +3 -0
  5. package/dist/artifacts/artifactCommitLock.js +16 -55
  6. package/dist/artifacts/taskArtifactRepository.js +3 -3
  7. package/dist/cli/agentConfigurationPicker.js +1 -1
  8. package/dist/cli/commandCatalog.js +92 -48
  9. package/dist/cli/completion.js +18 -18
  10. package/dist/cli/completionWizard.js +1 -1
  11. package/dist/cli/dynamicCompletion.js +1 -1
  12. package/dist/cli/interactionPolicy.js +11 -3
  13. package/dist/cli/invocationAuthority.js +64 -0
  14. package/dist/cli/managedDiagnostics.js +2 -2
  15. package/dist/cli/parseRepeatable.js +35 -0
  16. package/dist/cli/updatePorts.js +26 -5
  17. package/dist/cli.js +1303 -1235
  18. package/dist/commands/agentCommands.js +4 -4
  19. package/dist/commands/capabilityCommands.js +1 -1
  20. package/dist/commands/configCommands.js +6 -57
  21. package/dist/commands/configOverview.js +2 -2
  22. package/dist/commands/durableJobCommands.js +12 -6
  23. package/dist/commands/executionAuditCommands.js +10 -0
  24. package/dist/commands/globalRoleCommands.js +78 -29
  25. package/dist/commands/grantCommands.js +0 -3
  26. package/dist/commands/jobCommands.js +1 -4
  27. package/dist/commands/operatorCommands.js +3 -3
  28. package/dist/commands/projectCommands.js +45 -25
  29. package/dist/commands/resourcesCommands.js +10 -40
  30. package/dist/commands/roleConfiguration.js +2 -6
  31. package/dist/commands/taskActivationCommands.js +4 -8
  32. package/dist/commands/taskAgentCapabilities.js +9 -0
  33. package/dist/commands/taskCommandSupport.js +155 -0
  34. package/dist/commands/taskCommandTypes.js +1 -0
  35. package/dist/commands/taskCommands.js +355 -732
  36. package/dist/commands/taskCompletionGate.js +1 -1
  37. package/dist/commands/taskExecutionCommands.js +1 -1
  38. package/dist/commands/taskFactCommands.js +325 -0
  39. package/dist/commands/taskInputCommands.js +12 -42
  40. package/dist/commands/taskIntegrationCommands.js +20 -58
  41. package/dist/commands/taskNextActionCommand.js +7 -6
  42. package/dist/commands/taskPublicationAdoptCommand.js +127 -0
  43. package/dist/commands/taskPublicationCommands.js +12 -3
  44. package/dist/commands/taskPublicationVerifyCommand.js +24 -40
  45. package/dist/commands/taskRemoteDeliveryCommand.js +5 -86
  46. package/dist/commands/taskUpstreamCommands.js +19 -8
  47. package/dist/commands/workflowCommands.js +6 -1
  48. package/dist/completion/completionInstaller.js +26 -26
  49. package/dist/completion/completionState.js +26 -26
  50. package/dist/completion/fileCompletionManager.js +6 -11
  51. package/dist/config/configCatalog.js +0 -2
  52. package/dist/config/timeZone.js +14 -0
  53. package/dist/config/yuiConfig.js +0 -29
  54. package/dist/context/runContextPack.js +5 -3
  55. package/dist/context/taskCatalog.js +185 -0
  56. package/dist/context/taskContext.js +152 -151
  57. package/dist/context/wakeRunReferences.js +11 -0
  58. package/dist/controller/agentCapabilities.js +58 -0
  59. package/dist/controller/agentRuntimeObserver.js +6 -11
  60. package/dist/controller/clientRuntime.js +22 -14
  61. package/dist/controller/controller.js +20 -24
  62. package/dist/controller/fileSchedulerStoreAdapter.js +191 -225
  63. package/dist/controller/globalInputDelivery.js +13 -0
  64. package/dist/controller/jobClient.js +4 -4
  65. package/dist/controller/jobControl.js +60 -25
  66. package/dist/controller/jobSupervisor.js +4 -4
  67. package/dist/controller/providerRetryAdmission.js +100 -0
  68. package/dist/controller/providerRetryDelivery.js +218 -0
  69. package/dist/controller/runtime.js +85 -43
  70. package/dist/controller/runtimeEventProcessor.js +0 -5
  71. package/dist/controller/sessionOwnerReconciliation.js +5 -0
  72. package/dist/controller/taskAgentError.js +35 -0
  73. package/dist/coordination/workMailboxQueue.js +2 -24
  74. package/dist/core/controllerClient.js +2 -2
  75. package/dist/core/fileLockOwner.js +74 -0
  76. package/dist/decision/decision.js +17 -0
  77. package/dist/doctor/doctor.js +18 -9
  78. package/dist/event/taskEvent.js +12 -0
  79. package/dist/execution/workItemExecutionProjection.js +2 -2
  80. package/dist/executor/agentCapabilityConfig.js +43 -0
  81. package/dist/executor/agentConfigurationCatalog.js +49 -11
  82. package/dist/executor/agentExecutor.js +5 -8
  83. package/dist/executor/fileRoleLaunchPlanner.js +11 -53
  84. package/dist/executor/taskAgentCapabilities.js +64 -0
  85. package/dist/integration/deliveryObligation.js +1 -69
  86. package/dist/integration/gitIntegrationService.js +79 -90
  87. package/dist/integration/integrationAttempt.js +3 -14
  88. package/dist/integration/integrationSourceApplication.js +4 -12
  89. package/dist/integration/manifestTags.js +2 -2
  90. package/dist/job/durableJob.js +4 -25
  91. package/dist/job/jobAssignmentScope.js +22 -0
  92. package/dist/job/jobOperation.js +16 -0
  93. package/dist/job/jobRunner.js +2 -1
  94. package/dist/job/stepDirectory.js +15 -0
  95. package/dist/kernel/builtinCapabilities.js +15 -11
  96. package/dist/kernel/kernelPorts.js +1 -17
  97. package/dist/lifecycle/exactRunTerminalization.js +5 -10
  98. package/dist/message/globalProviderRetry.js +15 -0
  99. package/dist/message/inputControlResolution.js +3 -4
  100. package/dist/message/message.js +17 -20
  101. package/dist/message/messageContinuation.js +1 -1
  102. package/dist/milestone/milestone.js +11 -0
  103. package/dist/observability/executionAudit.js +19 -0
  104. package/dist/observability/orchestrationMetrics.js +24 -1
  105. package/dist/observability/runtimeIdentity.js +1 -17
  106. package/dist/output/agentConfigurationPresentation.js +2 -0
  107. package/dist/output/timePresentation.js +1 -14
  108. package/dist/plugins/pluginService.js +12 -4
  109. package/dist/release/releaseWorkflowPorts.js +45 -96
  110. package/dist/release/runtimeRelease.js +9 -15
  111. package/dist/repository/gitWorkspace.js +371 -105
  112. package/dist/repository/projectMaintenanceLock.js +98 -82
  113. package/dist/repository/taskBaseFreshness.js +1 -1
  114. package/dist/repository/taskWorkspaceCoordinator.js +82 -144
  115. package/dist/repository/taskWorkspacePreparer.js +113 -47
  116. package/dist/repository/workspaceCleanupInspection.js +187 -0
  117. package/dist/resources/autoResourceGc.js +4 -77
  118. package/dist/resources/liveReferences.js +7 -54
  119. package/dist/resources/resourceDiscovery.js +5 -118
  120. package/dist/resources/resourceGc.js +233 -181
  121. package/dist/resources/resourceRegistrar.js +5 -4
  122. package/dist/resources/resourceRegistry.js +3 -37
  123. package/dist/resources/resourceRegistryStore.js +13 -36
  124. package/dist/resources/sqliteResourceRegistry.js +43 -26
  125. package/dist/review/deltaRecheck.js +1 -1
  126. package/dist/review/reviewAcceptance.js +1 -1
  127. package/dist/review/reviewDecision.js +1 -1
  128. package/dist/review/reviewRound.js +8 -7
  129. package/dist/review/taskFinalReviewContractResolution.js +1 -1
  130. package/dist/runtime/acpProtocol.js +4 -51
  131. package/dist/runtime/acpSession.js +10 -75
  132. package/dist/runtime/acpSessionConfiguration.js +1 -8
  133. package/dist/runtime/agentEndpoint.js +3 -2
  134. package/dist/runtime/agentError.js +5 -3
  135. package/dist/runtime/agentFailureContext.js +43 -0
  136. package/dist/runtime/agentHost.js +42 -25
  137. package/dist/runtime/builtinAgentErrorMappers.js +91 -0
  138. package/dist/runtime/codexAppServerRuntime.js +34 -3
  139. package/dist/runtime/codexInteractiveHost.js +2 -2
  140. package/dist/runtime/index.js +0 -1
  141. package/dist/runtime/managedCaller.js +21 -1
  142. package/dist/runtime/providerControl.js +5 -1
  143. package/dist/runtime/providerErrors.js +38 -0
  144. package/dist/runtime/providerRetry.js +198 -0
  145. package/dist/runtime/providerRuntimeIdentity.js +28 -2
  146. package/dist/runtime/runtimeObservation.js +0 -5
  147. package/dist/runtime/runtimeSessionCandidate.js +2 -3
  148. package/dist/runtime/sessionOwnerIdentity.js +1 -1
  149. package/dist/runtime/sessionTokenMetrics.js +15 -5
  150. package/dist/runtime/structuredProviderHost.js +10 -43
  151. package/dist/runtime/taskUsageMetrics.js +275 -0
  152. package/dist/runtime/tmuxAdapters.js +6 -8
  153. package/dist/scheduler/activeRoleRunDelivery.js +19 -7
  154. package/dist/scheduler/leaderWakeupProcessor.js +24 -6
  155. package/dist/scheduler/operatorEvent.js +12 -20
  156. package/dist/scheduler/operatorInputNotificationProcessor.js +1 -1
  157. package/dist/scheduler/ports.js +5 -8
  158. package/dist/scheduler/roleRunLiveness.js +4 -4
  159. package/dist/scheduler/roleRunStall.js +16 -23
  160. package/dist/scheduler/taskExecutionProjection.js +49 -36
  161. package/dist/scheduler/taskObservabilityProjection.js +6 -45
  162. package/dist/scheduler/taskWake.js +5 -10
  163. package/dist/scheduler/wakeReason.js +2 -0
  164. package/dist/scheduler/wakeupQueue.js +2 -4
  165. package/dist/setup/setupCommand.js +1 -1
  166. package/dist/storage/contextRecords.js +106 -0
  167. package/dist/storage/currentTaskStore.js +1 -1
  168. package/dist/storage/homeLayout.js +13 -17
  169. package/dist/storage/migrations/agentFailureContext.js +22 -0
  170. package/dist/storage/migrations/currentInputContract.js +86 -0
  171. package/dist/storage/migrations/currentRuntimeContract.js +228 -0
  172. package/dist/storage/migrations/historicalVerificationPlan.js +35 -0
  173. package/dist/storage/migrations/integrationContinuation.js +5 -4
  174. package/dist/storage/migrations/narrowAgentFailureContext.js +65 -0
  175. package/dist/storage/migrations/notificationOnlyWakes.js +74 -0
  176. package/dist/storage/migrations/verificationPlanV1.js +162 -0
  177. package/dist/storage/migrations/verificationPolicy.js +74 -0
  178. package/dist/storage/migrations/workItemHistory.js +46 -0
  179. package/dist/storage/persistenceWorker.js +12 -4
  180. package/dist/storage/recordValidation.js +87 -0
  181. package/dist/storage/sqliteSchema.js +173 -1
  182. package/dist/storage/sqliteStore.js +172 -161
  183. package/dist/storage/storageSchema.js +2 -14
  184. package/dist/storage/storageVersions.js +1 -1
  185. package/dist/storage/storeRpc.js +16 -7
  186. package/dist/storage/taskCatalog.js +123 -0
  187. package/dist/storage/taskStore.js +5 -7
  188. package/dist/storage/upgrade/upgradeOrchestrator.js +25 -37
  189. package/dist/task/archiveDiagnostics.js +1 -0
  190. package/dist/task/archivePreflight.js +124 -0
  191. package/dist/task/completionReadiness.js +5 -24
  192. package/dist/task/draftPlan.js +0 -53
  193. package/dist/task/nextAction.js +7 -13
  194. package/dist/task/publicationAdoption.js +56 -0
  195. package/dist/task/publicationReference.js +10 -0
  196. package/dist/task/remoteDelivery.js +31 -16
  197. package/dist/task/remoteDeliveryService.js +89 -0
  198. package/dist/task/taskActivation.js +2 -25
  199. package/dist/task/taskActivationService.js +0 -2
  200. package/dist/task/taskRecordReference.js +0 -1
  201. package/dist/task/taskSubmission.js +3 -14
  202. package/dist/telemetry/sqliteTelemetryBatch.js +29 -0
  203. package/dist/telemetry/sqliteTelemetryStore.js +49 -49
  204. package/dist/telemetry/telemetryWiring.js +4 -3
  205. package/dist/tmux/tmuxManager.js +29 -20
  206. package/dist/verification/gateArtifact.js +15 -24
  207. package/dist/verification/gateArtifactStore.js +14 -7
  208. package/dist/verification/verificationGateService.js +29 -88
  209. package/dist/verification/verificationPlan.js +27 -72
  210. package/dist/web/assets/client/app.js +92 -17
  211. package/dist/web/assets/client/components.js +55 -13
  212. package/dist/web/assets/client/i18n.js +72 -4
  213. package/dist/web/assets/client/taskSurface.js +6 -5
  214. package/dist/web/assets/client/view.js +35 -7
  215. package/dist/web/assets/shell.js +6 -0
  216. package/dist/web/assets/styles/layout.js +7 -0
  217. package/dist/web/webServer.js +12 -3
  218. package/dist/web/webSnapshot.js +14 -85
  219. package/dist/web/webTaskSurface.js +17 -46
  220. package/dist/workItem/workItem.js +1 -12
  221. package/dist/workspace/cleanupInspection.js +63 -0
  222. package/dist/workspace/workItemChangeSetManager.js +110 -50
  223. package/docs/agent-result-consumption.md +4 -0
  224. package/docs/agent-result-consumption.zh-CN.md +3 -0
  225. package/docs/agent-runtime-drivers.md +7 -0
  226. package/docs/agent-runtime-drivers.zh-CN.md +5 -0
  227. package/docs/architecture/README.md +2 -0
  228. package/docs/architecture/README.zh-CN.md +3 -1
  229. package/docs/architecture/capabilities-and-resources.md +42 -5
  230. package/docs/architecture/capabilities-and-resources.zh-CN.md +33 -3
  231. package/docs/managed-turn-and-session-runtime.md +121 -1
  232. package/docs/managed-turn-and-session-runtime.zh-CN.md +96 -2
  233. package/docs/observability/README.md +62 -0
  234. package/docs/observability/README.zh-CN.md +47 -0
  235. package/docs/plugin-sdk.md +4 -2
  236. package/docs/project-refresh.md +77 -0
  237. package/docs/project-refresh.zh-CN.md +59 -0
  238. package/docs/provider-retry.md +70 -0
  239. package/docs/provider-runtime.md +3 -1
  240. package/docs/provider-runtime.zh-CN.md +4 -2
  241. package/docs/release-workflow.md +190 -7
  242. package/docs/release-workflow.zh-CN.md +139 -5
  243. package/docs/roles-and-configuration.md +29 -0
  244. package/docs/roles-and-configuration.zh-CN.md +21 -0
  245. package/docs/sqlite-control-plane-design.md +16 -3
  246. package/docs/sqlite-control-plane-design.zh-CN.md +13 -2
  247. package/docs/task-dag-semantics.md +3 -3
  248. package/docs/task-dag-semantics.zh-CN.md +2 -2
  249. package/docs/task-delivery.md +223 -17
  250. package/docs/task-delivery.zh-CN.md +171 -14
  251. package/docs/task-discovery.md +101 -0
  252. package/docs/task-discovery.zh-CN.md +85 -0
  253. package/docs/testing/verification-levels.md +161 -9
  254. package/docs/testing/verification-levels.zh-CN.md +116 -9
  255. package/i18n/README.zh-CN.md +13 -7
  256. package/package.json +1 -1
  257. package/skills/yui-leader/SKILL.md +5 -0
  258. package/skills/yui-leader/references/execution.md +3 -2
  259. package/skills/yui-leader/references/integration.md +9 -5
  260. package/skills/yui-leader/references/planning.md +9 -3
  261. package/skills/yui-operator/SKILL.md +24 -8
  262. package/skills/yui-reviewer/SKILL.md +4 -0
  263. package/skills/yui-runtime/SKILL.md +17 -2
  264. package/skills/yui-runtime/references/publication.md +26 -4
  265. package/skills/yui-runtime/references/recovery.md +71 -0
  266. package/dist/agent/agentRegistry.js +0 -10
  267. package/dist/agentRun/runIdentity.js +0 -22
  268. package/dist/commands/deliveryGuardPreflight.js +0 -30
  269. package/dist/commands/taskIntegrationQueueCommands.js +0 -226
  270. package/dist/commands/taskOverviewCommand.js +0 -376
  271. package/dist/completion/completionWizard.js +0 -125
  272. package/dist/context/dispatchContext.js +0 -110
  273. package/dist/context/wakeNotification.js +0 -144
  274. package/dist/integration/integrationCheckEvidenceReuse.js +0 -53
  275. package/dist/integration/integrationQueueEntry.js +0 -191
  276. package/dist/integration/integrationQueueService.js +0 -810
  277. package/dist/release/fakeReleasePorts.js +0 -55
  278. package/dist/runtime/sessionOwnerRegistry.js +0 -137
  279. package/dist/task/deliveryGuard.js +0 -226
  280. /package/dist/{commands/taskActor.js → task/taskAuthority.js} +0 -0
@@ -1,14 +1,14 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import { readdir, rename, rm } from "node:fs/promises";
3
3
  import { dirname, isAbsolute, join, relative, resolve } from "node:path";
4
- import { usageError } from "../errors/cliError.js";
4
+ import { CliError, usageError } from "../errors/cliError.js";
5
5
  import { defaultTableWidth, renderTable } from "../output/table.js";
6
6
  import { healCheckoutSwap, restoreCheckoutSwap, swapManagedCheckout } from "../repository/checkoutSwap.js";
7
- import { NodeGitWorkspace } from "../repository/gitWorkspace.js";
7
+ import { GitWorkspaceRefreshError, NodeGitWorkspace } from "../repository/gitWorkspace.js";
8
8
  import { acquireProjectMaintenanceLock } from "../repository/projectMaintenanceLock.js";
9
9
  import { addProjectKnowledge, addKnowledgeProposal, assertProjectActive, decideKnowledgeProposal, createProject, findKnowledgeProposal, findKnowledgeProposalByFingerprint, knowledgeEvidenceDigest, knowledgeProposalFingerprint, managedProjectPath, planKnowledgeAcceptance, retireProject, retireProjectKnowledge, resolveProject, updateProjectKnowledge, updateProjectMetadata, validateProject, validateProjectName } from "../repository/project.js";
10
10
  import { managedWorkspacesRoot } from "../storage/homeLayout.js";
11
- import { projectActor } from "./taskActor.js";
11
+ import { projectActor } from "../task/taskAuthority.js";
12
12
  export async function runProjectCommand(args, store, options = {}) {
13
13
  const [command, ...rest] = args;
14
14
  if (command === "add" || command === "clone") {
@@ -22,10 +22,14 @@ export async function runProjectCommand(args, store, options = {}) {
22
22
  }
23
23
  if (command === "refresh") {
24
24
  const refreshed = await refreshProject(rest, store, options);
25
+ const head = refreshed.changed
26
+ ? `Refreshed project ${refreshed.project.id}: ${refreshed.fromCommit} -> ${refreshed.toCommit}`
27
+ : `Project ${refreshed.project.id} HEAD is already current at ${refreshed.toCommit}`;
28
+ const tracking = refreshed.tracking;
25
29
  return {
26
- output: refreshed.changed
27
- ? `Refreshed project ${refreshed.project.id}: ${refreshed.fromCommit} -> ${refreshed.toCommit}\n`
28
- : `Project ${refreshed.project.id} is already current at ${refreshed.toCommit}\n`,
30
+ output: `${head}\n` + (tracking.status === "unmanaged"
31
+ ? `Tracking unmanaged: ${tracking.reason}\n`
32
+ : `Tracking ${tracking.status}: ${tracking.ref} at ${tracking.toCommit}\n`),
29
33
  data: refreshed
30
34
  };
31
35
  }
@@ -101,14 +105,23 @@ async function refreshProject(args, store, options) {
101
105
  // RFC Phase 1: hold the per-Project maintenance fence for the whole refresh
102
106
  // so Task workspace preparation and other maintenance cannot interleave
103
107
  // with the canonical branch/working-tree move.
104
- const releaseMaintenance = acquireProjectMaintenanceLock(store.rootDirectory(), project.id);
108
+ const releaseMaintenance = await acquireProjectMaintenanceLock(store.rootDirectory(), project.id, { signal: options.signal });
105
109
  try {
110
+ const current = requireUnchangedMaintenanceProject(store, project, "refresh");
106
111
  const refreshed = await (options.git ?? new NodeGitWorkspace()).refresh({
107
- repositoryPath: project.path,
108
- remoteUrl: project.remoteUrl,
109
- stableRef: project.stableBranch
112
+ repositoryPath: current.path,
113
+ remoteUrl: current.remoteUrl,
114
+ stableRef: current.stableBranch
110
115
  });
111
- return { project, ...refreshed };
116
+ return { project: current, ...refreshed };
117
+ }
118
+ catch (error) {
119
+ if (error instanceof GitWorkspaceRefreshError) {
120
+ throw new CliError("RUNTIME_ERROR", error.message, undefined, {
121
+ projectId: project.id, refresh: error.result
122
+ });
123
+ }
124
+ throw error;
112
125
  }
113
126
  finally {
114
127
  releaseMaintenance();
@@ -131,8 +144,9 @@ async function diagnoseProject(args, store, options) {
131
144
  };
132
145
  }
133
146
  const git = options.git ?? new NodeGitWorkspace();
134
- const releaseMaintenance = acquireProjectMaintenanceLock(store.rootDirectory(), project.id);
147
+ const releaseMaintenance = await acquireProjectMaintenanceLock(store.rootDirectory(), project.id, { signal: options.signal });
135
148
  try {
149
+ requireUnchangedMaintenanceProject(store, project, "diagnose");
136
150
  const current = await git.inspect(project.path, "HEAD");
137
151
  const remote = await git.resolveRemoteBaseline({
138
152
  repositoryPath: project.path,
@@ -307,13 +321,14 @@ async function migrateProject(args, store, options) {
307
321
  // Migration rewrites the Project's Git repository: hold the per-Project
308
322
  // maintenance fence so no rebuild/archive/cleanup (or a second migrate)
309
323
  // interleaves, and the Controller defers worktree preparation meanwhile.
310
- const releaseMaintenance = acquireProjectMaintenanceLock(store.rootDirectory(), project.id);
324
+ const releaseMaintenance = await acquireProjectMaintenanceLock(store.rootDirectory(), project.id, { signal: options.signal });
311
325
  try {
312
326
  // Re-read the Project under the fence. A concurrent migration may have
313
327
  // completed and switched the catalog to the Home-managed repo since the
314
328
  // record was resolved above; the stale snapshot must not drive any Git
315
329
  // effect (in particular it must not delete the now-canonical repo).
316
330
  const current = requireProject(store, project.id);
331
+ assertProjectActive(current, "migrate");
317
332
  if (current.ownership === "managed") {
318
333
  throw usageError(`Project is already Home-managed: ${project.id}.`);
319
334
  }
@@ -588,7 +603,7 @@ async function resetProject(args, store, options) {
588
603
  throw usageError(`Project reset requires matching stable and development branches: ${project.id}.`);
589
604
  }
590
605
  const git = options.git ?? new NodeGitWorkspace();
591
- const releaseMaintenance = acquireProjectMaintenanceLock(store.rootDirectory(), project.id);
606
+ const releaseMaintenance = await acquireProjectMaintenanceLock(store.rootDirectory(), project.id, { signal: options.signal });
592
607
  try {
593
608
  // Re-read under the fence so a concurrent catalog change can never drive
594
609
  // a destructive Git effect from a stale snapshot.
@@ -713,7 +728,7 @@ async function replaceProject(args, store, options) {
713
728
  + "Re-run with --discard-local to acknowledge that the checkout and any uncommitted state will be discarded.");
714
729
  }
715
730
  const git = options.git ?? new NodeGitWorkspace();
716
- const releaseMaintenance = acquireProjectMaintenanceLock(store.rootDirectory(), project.id);
731
+ const releaseMaintenance = await acquireProjectMaintenanceLock(store.rootDirectory(), project.id, { signal: options.signal });
717
732
  try {
718
733
  const current = requireProject(store, project.id);
719
734
  assertProjectActive(current, "replace");
@@ -922,8 +937,9 @@ async function deleteProjectCommand(args, store, options) {
922
937
  // every failure restores it, so the catalog never loses its recoverable
923
938
  // entry while a live checkout (or its failure) is still in play.
924
939
  const tombstone = join(store.rootDirectory(), "projects", `.delete-${project.id}`);
925
- const releaseMaintenance = acquireProjectMaintenanceLock(store.rootDirectory(), project.id);
940
+ const releaseMaintenance = await acquireProjectMaintenanceLock(store.rootDirectory(), project.id, { signal: options.signal });
926
941
  try {
942
+ requireUnchangedMaintenanceProject(store, project, "delete");
927
943
  // Heal a crashed earlier attempt before the prechecks turn.
928
944
  await healCheckoutSwap({ currentPath: project.path, backupPath: tombstone });
929
945
  if (existsSync(project.path)) {
@@ -1289,6 +1305,19 @@ function projectKnowledge(args, store, options) {
1289
1305
  ? "Project knowledge command is required."
1290
1306
  : `Unknown command: project knowledge ${command}`);
1291
1307
  }
1308
+ /** Waiting yields to catalog writers too; never apply stale Git/lifecycle inputs. */
1309
+ function requireUnchangedMaintenanceProject(store, expected, action) {
1310
+ const current = requireProject(store, expected.id);
1311
+ if (current.path !== expected.path
1312
+ || current.remoteUrl !== expected.remoteUrl
1313
+ || current.stableBranch !== expected.stableBranch
1314
+ || current.developmentBranch !== expected.developmentBranch
1315
+ || current.ownership !== expected.ownership
1316
+ || current.status !== expected.status) {
1317
+ throw new Error(`Project changed while waiting to ${action}: ${expected.id}; read current state before retrying.`);
1318
+ }
1319
+ return current;
1320
+ }
1292
1321
  function requireProject(store, reference) {
1293
1322
  const project = resolveProject(store.listProjects(), reference);
1294
1323
  if (project === null)
@@ -1468,9 +1497,6 @@ function proposeKnowledge(args, store, options) {
1468
1497
  * digest at proposal time, so a later Agent can verify the source record.
1469
1498
  */
1470
1499
  function requireProposalEvidence(store, parsed) {
1471
- if (store.getTask === undefined) {
1472
- throw usageError("Knowledge promotion requires Task evidence, which this store does not provide.");
1473
- }
1474
1500
  const task = store.getTask(parsed.task);
1475
1501
  if (task === null)
1476
1502
  throw usageError(`Task not found: ${parsed.task}.`);
@@ -1482,9 +1508,6 @@ function requireProposalEvidence(store, parsed) {
1482
1508
  };
1483
1509
  let evidence;
1484
1510
  if (parsed.decision !== undefined) {
1485
- if (store.getDecision === undefined) {
1486
- throw usageError("Knowledge promotion requires Decision evidence, which this store does not provide.");
1487
- }
1488
1511
  const decision = store.getDecision(task.id, parsed.decision);
1489
1512
  if (decision === null) {
1490
1513
  throw usageError(`Decision not found: ${parsed.decision} in Task ${task.id}.`);
@@ -1492,9 +1515,6 @@ function requireProposalEvidence(store, parsed) {
1492
1515
  evidence = `${decision.title}\n${decision.rationale}`;
1493
1516
  }
1494
1517
  else if (parsed.milestone !== undefined) {
1495
- if (store.getMilestone === undefined) {
1496
- throw usageError("Knowledge promotion requires Milestone evidence, which this store does not provide.");
1497
- }
1498
1518
  const milestone = store.getMilestone(task.id, parsed.milestone);
1499
1519
  if (milestone === null) {
1500
1520
  throw usageError(`Milestone not found: ${parsed.milestone} in Task ${task.id}.`);
@@ -7,12 +7,11 @@
7
7
  * every quarantined resource to its original path.
8
8
  */
9
9
  import { resolve } from "node:path";
10
+ import { resolveResourcesGcMode, resolveResourcesQuarantineTtlHours } from "../config/yuiConfig.js";
10
11
  import { usageError } from "../errors/cliError.js";
11
12
  import { defaultTableWidth, renderTable } from "../output/table.js";
12
- import { applyResourceGc, planResourceGc, purgeResourceQuarantine, restoreAllResourceGc } from "../resources/resourceGc.js";
13
- import { createResourceRegistryStore } from "../resources/resourceRegistryStore.js";
14
13
  import { resourceKindLabel, resourceOwnerLabel } from "../resources/resourceDiscovery.js";
15
- import { resolveResourcesGcMode, resolveResourcesQuarantineTtlHours } from "../config/yuiConfig.js";
14
+ import { applyResourceGc, planResourceGc, readResourceGcState, purgeResourceQuarantine, restoreAllResourceGc } from "../resources/resourceGc.js";
16
15
  export async function runResourcesCommand(args, store, options = {}) {
17
16
  const [command, ...rest] = args;
18
17
  if (command !== "gc") {
@@ -27,10 +26,7 @@ async function runGcCommand(args, store, options) {
27
26
  const now = options.now?.() ?? new Date();
28
27
  const home = resolve(store.rootDirectory());
29
28
  const mode = resolveGcMode(store);
30
- const projects = store.listProjects();
31
- const managedWorkspaces = collectManagedWorkspaces(store);
32
- const taskStatusById = collectTaskStatuses(store);
33
- const activeWorkspaceOwnerPaths = collectActiveWorkspaceOwnerPaths(store);
29
+ const { projects, managedWorkspaces, taskStatusById, activeWorkspaceOwnerPaths, sessionOwners } = readResourceGcState(store);
34
30
  if (action === "restore") {
35
31
  const result = await restoreAllResourceGc(home, { now });
36
32
  return {
@@ -46,7 +42,7 @@ async function runGcCommand(args, store, options) {
46
42
  data: { mode, action: "purge", skipped: true }
47
43
  };
48
44
  }
49
- const result = await purgeResourceQuarantine(home, { now, ttlHours, managedWorkspaces });
45
+ const result = await purgeResourceQuarantine(home, { now, ttlHours, managedWorkspaces }, store);
50
46
  return {
51
47
  output: renderPurgeResult(result),
52
48
  data: result
@@ -54,7 +50,7 @@ async function runGcCommand(args, store, options) {
54
50
  }
55
51
  const plan = await planResourceGc({
56
52
  home,
57
- registryStore: createResourceRegistryStore(home),
53
+ sessionOwners,
58
54
  projects,
59
55
  managedWorkspaces,
60
56
  taskStatusById,
@@ -66,7 +62,7 @@ async function runGcCommand(args, store, options) {
66
62
  if (action === "apply" && mode === "quarantine") {
67
63
  const result = await applyResourceGc({
68
64
  home,
69
- registryStore: createResourceRegistryStore(home),
65
+ sessionOwners,
70
66
  projects,
71
67
  managedWorkspaces,
72
68
  taskStatusById,
@@ -74,7 +70,7 @@ async function runGcCommand(args, store, options) {
74
70
  now,
75
71
  quarantineTtlHours: ttlHours,
76
72
  activeWorkspaceOwnerPaths
77
- }, plan);
73
+ }, plan, store);
78
74
  return {
79
75
  output: renderApplyResult(result),
80
76
  data: result
@@ -109,35 +105,6 @@ function parseTtlHours(args, store) {
109
105
  function resolveGcMode(store) {
110
106
  return resolveResourcesGcMode(store.getConfig().resourcesGcMode);
111
107
  }
112
- function collectManagedWorkspaces(store) {
113
- const workspaces = [];
114
- for (const task of store.listTasks()) {
115
- workspaces.push(...store.listManagedWorkspaces(task.id));
116
- }
117
- return workspaces;
118
- }
119
- function collectTaskStatuses(store) {
120
- const statuses = new Map();
121
- for (const task of store.listTasks()) {
122
- statuses.set(task.id, task.status);
123
- }
124
- return statuses;
125
- }
126
- /** Workspace paths claimed by active durable Jobs (AgentRuns). */
127
- function collectActiveWorkspaceOwnerPaths(store) {
128
- const paths = [];
129
- for (const task of store.listTasks()) {
130
- for (const run of store.listRuns(task.id)) {
131
- if (run.status !== "active")
132
- continue;
133
- const workspace = run.workspace;
134
- if (workspace === undefined)
135
- continue;
136
- paths.push(workspace.root, ...workspace.entries.map((entry) => entry.path));
137
- }
138
- }
139
- return paths;
140
- }
141
108
  function renderPlan(plan, action) {
142
109
  const lines = [];
143
110
  const modeNotice = plan.mode === "report" && action === "apply"
@@ -207,6 +174,9 @@ function renderApplyResult(result) {
207
174
  if (result.restored.length > 0) {
208
175
  lines.push(`Restored ${result.restored.length} resource(s) from quarantine.`);
209
176
  }
177
+ for (const record of result.planned.retained) {
178
+ lines.push(`Retained ${record.id} ${record.path}: ${record.blocker ?? "current ownership or live reference"}`);
179
+ }
210
180
  if (result.applied.length === 0 && result.failed.length === 0 && result.restored.length === 0) {
211
181
  lines.push("No releasable resources.");
212
182
  }
@@ -187,12 +187,8 @@ function permissionPatch(binding, parsed) {
187
187
  }
188
188
  const current = binding.config.permission;
189
189
  if (selected !== "configured" && !nativeOptions) {
190
- // Nothing about permission was named, so the binding keeps what it already
191
- // had. The fallback applies only to a binding that somehow carries no
192
- // permission at all, and it must be the adapter's own default rather than a
193
- // fixed `bypass`: ACP defaults to `default`, and defaulting it to bypass
194
- // here would widen authority the user never granted.
195
- return structuredClone(current ?? defaultRoleAgentConfig(binding.adapterId).permission);
190
+ // The validated binding always has its explicit permission strategy.
191
+ return structuredClone(current);
196
192
  }
197
193
  const permission = current?.strategy === "configured"
198
194
  ? structuredClone(current)
@@ -1,11 +1,11 @@
1
1
  import { createHash } from "node:crypto";
2
- import { usageError } from "../errors/cliError.js";
3
- import { currentManagedRuntime } from "../runtime/managedCaller.js";
4
2
  import { enqueueWork } from "../coordination/workMailboxQueue.js";
3
+ import { usageError } from "../errors/cliError.js";
5
4
  import { SYSTEM_LEADER_ROLE } from "../role/systemRoles.js";
5
+ import { currentManagedRuntime } from "../runtime/managedCaller.js";
6
6
  import { describeEnvironmentPlan } from "../task/taskActivation.js";
7
7
  import { cancelTaskActivation, requestTaskActivation, taskActivationOperationRef } from "../task/taskActivationService.js";
8
- import { taskLocalActor } from "./taskActor.js";
8
+ import { taskLocalActor } from "../task/taskAuthority.js";
9
9
  /**
10
10
  * Explicit Activation requests.
11
11
  *
@@ -52,10 +52,6 @@ function requestActivation(args, store, options) {
52
52
  actorId: caller.actorId,
53
53
  authorityRef: caller.authorityRef,
54
54
  environmentPlan,
55
- // The activation-request command is the explicit activation boundary, so
56
- // every request it records carries an explicit provable origin (task-32
57
- // §2.4). A develop submission records its own request with `submit-develop`.
58
- origin: "explicit",
59
55
  ...(caller.planningRunId === undefined ? {} : { callerRunId: caller.planningRunId })
60
56
  }, now));
61
57
  // An immediate request has nothing left to wait for, so ask the Controller to
@@ -65,7 +61,7 @@ function requestActivation(args, store, options) {
65
61
  store.transaction((tx) => {
66
62
  enqueueWork(tx, { kind: "task", taskId }, "activation-requested", now, [{ type: "task", id: taskId }]);
67
63
  });
68
- void options.runtime?.notifyMailboxChanged?.({ kind: "task", taskId });
64
+ void options.runtime?.notifyMailboxChanged({ kind: "task", taskId });
69
65
  }
70
66
  const request = result.request;
71
67
  const lines = [
@@ -0,0 +1,9 @@
1
+ import { exactPositionals, parseTail } from "./taskCommandSupport.js";
2
+ export function parseTaskAgentCapabilityQuery(args) {
3
+ const usage = "Usage: yui task role capabilities <task> <role> [--error <event-id>] [--refresh]";
4
+ const parsed = parseTail(args, new Set(["--error"]), usage, new Set(["--refresh"]));
5
+ exactPositionals(parsed.positionals, 2, usage);
6
+ const errorId = parsed.options.get("--error");
7
+ return { taskId: parsed.positionals[0], roleName: parsed.positionals[1],
8
+ ...(errorId === undefined ? {} : { errorId }), refresh: parsed.options.has("--refresh") };
9
+ }
@@ -0,0 +1,155 @@
1
+ import { taskNotFound, usageError } from "../errors/cliError.js";
2
+ import { createTaskEvent } from "../event/taskEvent.js";
3
+ import { formatTimestamp } from "../output/timePresentation.js";
4
+ import { SYSTEM_LEADER_ROLE as LEADER_ROLE } from "../role/systemRoles.js";
5
+ import { currentManagedRuntime } from "../runtime/managedCaller.js";
6
+ import { taskLocalActor as resolveTaskLocalActor } from "../task/taskAuthority.js";
7
+ export function recordTaskEvent(store, taskId, type, payload, now) {
8
+ return recordTaskEventRecord(store, taskId, type, payload, now);
9
+ }
10
+ export function leaderActionEventPayload(store, taskId, options) {
11
+ const caller = currentManagedRuntime(store, options.environment, taskId, "leader");
12
+ // A long-lived Session may be handling direct input while another request
13
+ // awaits admission. The Role's active pointer cannot prove command origin.
14
+ return caller === undefined ? {} : { leaderNativeSessionId: caller.nativeSessionId };
15
+ }
16
+ export function recordTaskEventRecord(store, taskId, type, payload, now) {
17
+ const event = createTaskEvent(store.nextEventId(taskId), taskId, type, payload, now);
18
+ store.saveEvent(taskId, event);
19
+ return event;
20
+ }
21
+ export function requireTask(store, taskId) {
22
+ const id = requiredText(taskId, "Task id");
23
+ const task = store.getTask(id);
24
+ if (task === null)
25
+ throw taskNotFound(id);
26
+ return task;
27
+ }
28
+ export function assertTaskOpen(task) {
29
+ if (task.status === "completed") {
30
+ throw usageError(`Task ${task.id} is completed; reopen it before continuing.`);
31
+ }
32
+ if (task.status === "archived")
33
+ throw usageError(`Task is archived: ${task.id}.`);
34
+ if (task.status === "cancelled")
35
+ throw usageError(`Task is retired: ${task.id}.`);
36
+ }
37
+ export function taskActor(store, options, taskId) {
38
+ return resolveTaskLocalActor(store, options.environment, taskId);
39
+ }
40
+ export function parseMultiValueTail(args, valueOptions, repeatOptions, usage, flagOptions = new Set()) {
41
+ const positionals = [];
42
+ const options = new Map();
43
+ const multiOptions = new Map();
44
+ for (let index = 0; index < args.length; index += 1) {
45
+ const value = args[index];
46
+ if (!value.startsWith("--")) {
47
+ positionals.push(value);
48
+ continue;
49
+ }
50
+ if (!valueOptions.has(value) && !repeatOptions.has(value) && !flagOptions.has(value)) {
51
+ throw usageError(`Unsupported option: ${value}.`, usage);
52
+ }
53
+ if (flagOptions.has(value)) {
54
+ if (options.has(value))
55
+ throw usageError(`Option may only be specified once: ${value}.`, usage);
56
+ options.set(value, "");
57
+ continue;
58
+ }
59
+ if (repeatOptions.has(value)) {
60
+ const optionValue = args[index + 1];
61
+ if (optionValue === undefined || optionValue.startsWith("--")) {
62
+ throw usageError(`${value} is required.`, usage);
63
+ }
64
+ const existing = multiOptions.get(value) ?? [];
65
+ multiOptions.set(value, [...existing, optionValue]);
66
+ index += 1;
67
+ continue;
68
+ }
69
+ if (options.has(value))
70
+ throw usageError(`Option may only be specified once: ${value}.`, usage);
71
+ const optionValue = args[index + 1];
72
+ if (optionValue === undefined || optionValue.startsWith("--")) {
73
+ throw usageError(`${value} is required.`, usage);
74
+ }
75
+ options.set(value, optionValue);
76
+ index += 1;
77
+ }
78
+ return { positionals, options, multiOptions };
79
+ }
80
+ export function parseTail(args, valueOptions, usage, flagOptions = new Set()) {
81
+ const positionals = [];
82
+ const options = new Map();
83
+ for (let index = 0; index < args.length; index += 1) {
84
+ const value = args[index];
85
+ if (!value.startsWith("--")) {
86
+ positionals.push(value);
87
+ continue;
88
+ }
89
+ if (!valueOptions.has(value) && !flagOptions.has(value)) {
90
+ throw usageError(`Unsupported option: ${value}.`, usage);
91
+ }
92
+ if (options.has(value))
93
+ throw usageError(`Option may only be specified once: ${value}.`, usage);
94
+ if (flagOptions.has(value)) {
95
+ options.set(value, "");
96
+ continue;
97
+ }
98
+ const optionValue = args[index + 1];
99
+ if (optionValue === undefined || optionValue.startsWith("--")) {
100
+ throw usageError(`${value} is required.`, usage);
101
+ }
102
+ options.set(value, optionValue);
103
+ index += 1;
104
+ }
105
+ return { positionals, options };
106
+ }
107
+ export function requiredOption(options, name) {
108
+ return requiredText(options.get(name), name);
109
+ }
110
+ export function optionalNonEmptyOption(options, name) {
111
+ if (!options.has(name))
112
+ return undefined;
113
+ return requiredText(options.get(name), name);
114
+ }
115
+ export function exactPositionals(values, count, usage) {
116
+ if (values.length !== count || values.some((value) => value.trim().length === 0)) {
117
+ throw usageError(usage);
118
+ }
119
+ }
120
+ export function requiredText(value, label) {
121
+ const normalized = value?.trim();
122
+ if (normalized === undefined || normalized.length === 0)
123
+ throw usageError(`${label} is required.`);
124
+ return normalized;
125
+ }
126
+ export function trimmed(value) {
127
+ const normalized = value?.trim();
128
+ return normalized === undefined || normalized.length === 0 ? undefined : normalized;
129
+ }
130
+ export function presentTime(value, timeZone) {
131
+ return formatTimestamp(value, timeZone);
132
+ }
133
+ export function output(value, data) {
134
+ return data === undefined
135
+ ? { kind: "output", output: value }
136
+ : { kind: "output", output: value, data };
137
+ }
138
+ export function clock(options) {
139
+ return options.now?.() ?? new Date();
140
+ }
141
+ export function taskMailbox(taskId) {
142
+ return { kind: "task", taskId };
143
+ }
144
+ export function roleMailbox(taskId, roleName) {
145
+ return { kind: "role", taskId, roleName };
146
+ }
147
+ export function leaderMailbox(taskId) {
148
+ return roleMailbox(taskId, LEADER_ROLE);
149
+ }
150
+ export function taskRef(id) {
151
+ return { type: "task", id };
152
+ }
153
+ export function notifyMailbox(runtime, target) {
154
+ void runtime?.notifyMailboxChanged(target);
155
+ }
@@ -0,0 +1 @@
1
+ export {};