@zq-silk/yui 0.2.0 → 0.4.2

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 (208) hide show
  1. package/ARCHITECTURE.md +603 -133
  2. package/README.md +806 -31
  3. package/dist/agent/agent.js +2 -1
  4. package/dist/agent/argumentPolicy.js +3 -1
  5. package/dist/agent/launchEnvironment.js +106 -0
  6. package/dist/agent/managedRuntimeEnvironment.js +34 -0
  7. package/dist/brief/taskBrief.js +11 -1
  8. package/dist/cli/agentConfigurationPicker.js +287 -0
  9. package/dist/cli/commandCatalog.js +488 -60
  10. package/dist/cli/completion.js +146 -22
  11. package/dist/cli/helpRenderer.js +3 -1
  12. package/dist/cli/interactionCandidates.js +53 -15
  13. package/dist/cli/interactionPolicy.js +267 -30
  14. package/dist/cli/interactiveSelection.js +6 -2
  15. package/dist/cli/invocationRouter.js +5 -1
  16. package/dist/cli/operatorWizard.js +87 -0
  17. package/dist/cli/roleOptionCatalog.js +1 -0
  18. package/dist/cli/roleWizard.js +185 -21
  19. package/dist/cli/updateCommand.js +62 -19
  20. package/dist/cli/updateOrchestrator.js +539 -0
  21. package/dist/cli/updatePorts.js +1119 -0
  22. package/dist/cli/upgradeCommand.js +112 -0
  23. package/dist/cli.js +1420 -86
  24. package/dist/commands/agentCommands.js +146 -3
  25. package/dist/commands/configCommands.js +126 -0
  26. package/dist/commands/controllerCommands.js +365 -0
  27. package/dist/commands/globalRoleCommands.js +168 -126
  28. package/dist/commands/jobCommands.js +18 -8
  29. package/dist/commands/operatorCommands.js +159 -9
  30. package/dist/commands/profileCommands.js +203 -0
  31. package/dist/commands/projectCommands.js +650 -0
  32. package/dist/commands/roleConfiguration.js +85 -24
  33. package/dist/commands/roleRuntimeGuard.js +12 -0
  34. package/dist/commands/roleSkillValidation.js +47 -0
  35. package/dist/commands/taskActor.js +127 -0
  36. package/dist/commands/taskCommands.js +4201 -313
  37. package/dist/commands/taskCompletionGate.js +131 -0
  38. package/dist/commands/taskContextCommand.js +244 -30
  39. package/dist/commands/taskInputCommands.js +177 -59
  40. package/dist/commands/taskIntegrationCommands.js +303 -0
  41. package/dist/commands/taskOverviewCommand.js +363 -0
  42. package/dist/commands/taskRoleRuntimeStatus.js +125 -19
  43. package/dist/commands/textInput.js +15 -0
  44. package/dist/completion/completionInstaller.js +26 -22
  45. package/dist/config/yuiConfig.js +4 -3
  46. package/dist/context/dispatchContext.js +90 -38
  47. package/dist/context/roleSessionContext.js +119 -0
  48. package/dist/controller/claudeLifecycleHook.js +203 -0
  49. package/dist/controller/clientRuntime.js +408 -56
  50. package/dist/controller/codexLifecycleHook.js +108 -0
  51. package/dist/controller/controller.js +1089 -32
  52. package/dist/controller/domainIdentity.js +505 -0
  53. package/dist/controller/ephemeralResourceReaper.js +131 -0
  54. package/dist/controller/fileSchedulerStoreAdapter.js +2153 -103
  55. package/dist/controller/providerHookRunFence.js +127 -0
  56. package/dist/controller/resourceCleanupLinux.js +286 -0
  57. package/dist/controller/resourceInventory.js +531 -0
  58. package/dist/controller/resourceInventoryLinux.js +610 -0
  59. package/dist/controller/runtime.js +629 -10
  60. package/dist/controller/runtimeEventInbox.js +564 -0
  61. package/dist/controller/runtimeEventProcessor.js +248 -0
  62. package/dist/controller/runtimeLaunchCoordinator.js +477 -0
  63. package/dist/controller/sessionNotify.js +121 -78
  64. package/dist/coordination/deadlineScheduler.js +15 -0
  65. package/dist/coordination/mailboxScheduler.js +108 -0
  66. package/dist/coordination/workMailbox.js +329 -0
  67. package/dist/coordination/workMailboxQueue.js +86 -0
  68. package/dist/core/controllerClient.js +19 -5
  69. package/dist/core/controllerEndpoint.js +37 -0
  70. package/dist/core/controllerServer.js +218 -10
  71. package/dist/core/protocol.js +6 -2
  72. package/dist/decision/decision.js +2 -1
  73. package/dist/doctor/doctor.js +681 -32
  74. package/dist/domain/validation.js +53 -0
  75. package/dist/errors/cliError.js +5 -3
  76. package/dist/event/taskEvent.js +7 -3
  77. package/dist/execution/codexThreadNaming.js +160 -0
  78. package/dist/execution/executionGroup.js +579 -0
  79. package/dist/executor/agentAdapter.js +255 -40
  80. package/dist/executor/agentConfigurationCatalog.js +326 -0
  81. package/dist/executor/agentConfigurationProbe.js +506 -0
  82. package/dist/executor/agentExecutor.js +625 -10
  83. package/dist/executor/codexConfigConflict.js +290 -0
  84. package/dist/executor/effectiveLaunch.js +340 -0
  85. package/dist/executor/executorRegistry.js +238 -36
  86. package/dist/executor/fileRoleLaunchPlanner.js +550 -40
  87. package/dist/executor/turnCompletion.js +126 -0
  88. package/dist/input/inputRequest.js +30 -9
  89. package/dist/integration/changeSet.js +36 -0
  90. package/dist/integration/checkResult.js +24 -0
  91. package/dist/integration/gitIntegrationService.js +695 -0
  92. package/dist/integration/integrationAttempt.js +142 -0
  93. package/dist/interaction/operatorPresentation.js +96 -0
  94. package/dist/lifecycle/canonicalLifecycleEvent.js +342 -0
  95. package/dist/lifecycle/exactRunTerminalization.js +572 -0
  96. package/dist/lifecycle/providerLifecycleMapping.js +190 -0
  97. package/dist/lifecycle/taskRoleSessionReset.js +124 -0
  98. package/dist/message/message.js +23 -7
  99. package/dist/milestone/milestone.js +2 -1
  100. package/dist/operator/operatorSessionHistory.js +124 -0
  101. package/dist/output/agentConfigurationPresentation.js +43 -0
  102. package/dist/output/rolePresentation.js +34 -10
  103. package/dist/output/terminal.js +8 -0
  104. package/dist/output/timePresentation.js +55 -0
  105. package/dist/profile/agentProfile.js +128 -0
  106. package/dist/repository/gitWorkspace.js +578 -24
  107. package/dist/repository/project.js +213 -0
  108. package/dist/repository/taskWorkspaceCoordinator.js +392 -0
  109. package/dist/repository/taskWorkspacePreparer.js +1688 -191
  110. package/dist/review/reviewConfig.js +11 -0
  111. package/dist/review/reviewRound.js +399 -0
  112. package/dist/review/taskFinalReviewContract.js +90 -0
  113. package/dist/role/role.js +124 -23
  114. package/dist/run/agentRun.js +155 -12
  115. package/dist/run/runIdentity.js +82 -0
  116. package/dist/runtime/exactControlPlane.js +472 -0
  117. package/dist/runtime/index.js +8 -0
  118. package/dist/runtime/lifecycleReservation.js +38 -0
  119. package/dist/runtime/ports.js +11 -0
  120. package/dist/runtime/preallocatedNativeSession.js +13 -0
  121. package/dist/runtime/promptEnvelope.js +30 -0
  122. package/dist/runtime/runtimeBinding.js +31 -0
  123. package/dist/runtime/runtimeOwner.js +14 -0
  124. package/dist/runtime/sessionLaunchRequest.js +62 -0
  125. package/dist/runtime/sessionTitle.js +54 -0
  126. package/dist/runtime/taskRuntimeIsolation.js +643 -0
  127. package/dist/runtime/tmuxAdapters.js +315 -0
  128. package/dist/runtime/turnCompletion.js +3 -0
  129. package/dist/runtime/validation.js +23 -0
  130. package/dist/scheduler/activeRoleRunDelivery.js +342 -32
  131. package/dist/scheduler/activeTaskProgress.js +63 -0
  132. package/dist/scheduler/leaderFailure.js +2 -1
  133. package/dist/scheduler/leaderWakeupProcessor.js +307 -66
  134. package/dist/scheduler/operatorInputNotificationProcessor.js +109 -46
  135. package/dist/scheduler/operatorNotification.js +44 -2
  136. package/dist/scheduler/ports.js +28 -1
  137. package/dist/scheduler/roleRunLiveness.js +131 -25
  138. package/dist/scheduler/roleRunStall.js +951 -0
  139. package/dist/scheduler/taskExecutionProjection.js +544 -0
  140. package/dist/scheduler/wakeupQueue.js +3 -0
  141. package/dist/setup/setupCommand.js +302 -52
  142. package/dist/storage/compatibleTaskStore.js +102 -0
  143. package/dist/storage/migration/baseline.js +78 -0
  144. package/dist/storage/migration/classifier.js +51 -0
  145. package/dist/storage/migration/compatibleCodec.js +53 -0
  146. package/dist/storage/migration/engine.js +147 -0
  147. package/dist/storage/migration/index.js +33 -0
  148. package/dist/storage/migration/planner.js +154 -0
  149. package/dist/storage/migration/productionRegistry.js +486 -0
  150. package/dist/storage/migration/registry.js +169 -0
  151. package/dist/storage/migration/report.js +54 -0
  152. package/dist/storage/migration/types.js +31 -0
  153. package/dist/storage/storageSchema.js +147 -123
  154. package/dist/storage/storageVersions.js +11 -0
  155. package/dist/storage/taskStore.js +1793 -197
  156. package/dist/storage/upgrade/homeClassification.js +156 -0
  157. package/dist/storage/upgrade/homeMigrationTarget.js +595 -0
  158. package/dist/storage/upgrade/offlineUpgradeInventory.js +315 -0
  159. package/dist/storage/upgrade/productionMigrationRegistry.js +6 -0
  160. package/dist/storage/upgrade/recordVersionScan.js +176 -0
  161. package/dist/storage/upgrade/recordVersions.js +159 -0
  162. package/dist/storage/upgrade/switchProgress.js +80 -0
  163. package/dist/storage/upgrade/upgradeOrchestrator.js +948 -0
  164. package/dist/storage/upgrade/upgradeReceipt.js +161 -0
  165. package/dist/storage/upgradeCoordination.js +186 -0
  166. package/dist/storage/upgradeFence.js +366 -0
  167. package/dist/task/task.js +132 -26
  168. package/dist/task/taskRecordReference.js +66 -0
  169. package/dist/tmux/commandExecutor.js +75 -2
  170. package/dist/tmux/tmuxManager.js +747 -49
  171. package/dist/version.js +23 -0
  172. package/dist/web/assets/assetManifest.js +62 -0
  173. package/dist/web/assets/client/app.js +631 -0
  174. package/dist/web/assets/client/components.js +605 -0
  175. package/dist/web/assets/client/dom.js +14 -0
  176. package/dist/web/assets/client/format.js +28 -0
  177. package/dist/web/assets/client/i18n.js +494 -0
  178. package/dist/web/assets/client/markdown.js +114 -0
  179. package/dist/web/assets/client/theme.js +32 -0
  180. package/dist/web/assets/client/view.js +458 -0
  181. package/dist/web/assets/fontData.js +12 -0
  182. package/dist/web/assets/fonts.js +12 -0
  183. package/dist/web/assets/shell.js +114 -0
  184. package/dist/web/assets/styles/cards.js +135 -0
  185. package/dist/web/assets/styles/layout.js +47 -0
  186. package/dist/web/assets/styles/markdown.js +29 -0
  187. package/dist/web/assets/styles/responsive.js +39 -0
  188. package/dist/web/assets/styles/tokens.js +101 -0
  189. package/dist/web/assets/styles/widgets.js +147 -0
  190. package/dist/web/tmuxWebTerminal.js +158 -0
  191. package/dist/web/webServer.js +463 -0
  192. package/dist/web/webSnapshot.js +148 -0
  193. package/dist/workItem/workItem.js +642 -23
  194. package/dist/workspace/gitChangeSetCapture.js +86 -0
  195. package/dist/workspace/workItemChangeSetManager.js +445 -0
  196. package/dist/worktree/managedWorkspace.js +202 -0
  197. package/docs/task-local-identity.md +62 -0
  198. package/i18n/README.zh-CN.md +406 -31
  199. package/package.json +10 -2
  200. package/skills/yui-leader/SKILL.md +601 -39
  201. package/skills/yui-operator/SKILL.md +255 -34
  202. package/skills/yui-reviewer/SKILL.md +57 -0
  203. package/skills/yui-worker/SKILL.md +214 -17
  204. package/dist/commands/repositoryCommands.js +0 -86
  205. package/dist/operator/operatorContext.js +0 -66
  206. package/dist/repository/repository.js +0 -55
  207. package/dist/scheduler/archivedTaskRuntime.js +0 -12
  208. package/dist/worktree/roleWorkspace.js +0 -62
@@ -0,0 +1,131 @@
1
+ import { usageError } from "../errors/cliError.js";
2
+ import { GitIntegrationService } from "../integration/gitIntegrationService.js";
3
+ import { createIntegrationAttempt } from "../integration/integrationAttempt.js";
4
+ import { NodeGitWorkspace } from "../repository/gitWorkspace.js";
5
+ import { workspaceProjectEntry } from "../worktree/managedWorkspace.js";
6
+ /**
7
+ * Reconcile configured remote baselines before a Task completion attempt.
8
+ *
9
+ * Remote resolution and fetches happen from the Task's managed worktree. A
10
+ * moved remote is represented by a new Integration Attempt that reuses the
11
+ * already integrated ChangeSets, runs the existing Project checks, and lets
12
+ * the normal target CAS advance the Task branch. Stable Project checkouts
13
+ * are never refreshed or otherwise mutated here.
14
+ */
15
+ export async function reconcileTaskRemoteBaselines(taskId, store, home, options = {}) {
16
+ const task = store.getTask(taskId);
17
+ if (task === null)
18
+ throw usageError(`Task not found: ${taskId}.`);
19
+ // The delivery contract opts Project-backed Tasks into committed
20
+ // Integration evidence. Metadata-only Tasks retain their existing local
21
+ // completion semantics and have no remote baseline to reconcile here.
22
+ if (task.projectBindings.length === 0 || task.requireIntegration !== true)
23
+ return [];
24
+ const workspace = requireTaskWorkspace(store, task);
25
+ const git = options.git ?? new NodeGitWorkspace();
26
+ if (git.fetchRemoteHeadIntoWorktree === undefined
27
+ || git.mergeRemoteIntoWorktree === undefined) {
28
+ throw usageError(`Task ${task.id} cannot verify remote baselines: managed Git workspace support is unavailable.`);
29
+ }
30
+ const plans = [];
31
+ for (const binding of task.projectBindings) {
32
+ const project = store.getProject(binding.projectId);
33
+ if (project === null) {
34
+ throw usageError(`Project not found for Task ${task.id}: ${binding.projectId}.`);
35
+ }
36
+ if (project.remoteUrl === undefined)
37
+ continue;
38
+ const entry = workspaceProjectEntry(workspace, project.id);
39
+ if (entry === undefined || entry.access !== "write") {
40
+ throw usageError(`Task ${task.id} has no writable managed main workspace for remote Project ${project.id}.`);
41
+ }
42
+ const currentCommit = (await git.inspect(entry.path, "HEAD")).baseCommit;
43
+ const previousIntegration = latestCommittedIntegration(store, task.id, project.id);
44
+ // Let the existing exact-head Task-final gate report local post-
45
+ // Integration drift before attempting any network operation. This keeps
46
+ // completion read-only for an already-invalid candidate and preserves its
47
+ // precise recovery guidance.
48
+ if (previousIntegration !== undefined
49
+ && previousIntegration.candidateCommit !== currentCommit) {
50
+ continue;
51
+ }
52
+ const remote = await fetchRemote(git, entry, project);
53
+ if (remote.commit === currentCommit)
54
+ continue;
55
+ if (await git.isAncestor(entry.path, remote.commit, currentCommit))
56
+ continue;
57
+ if (previousIntegration === undefined) {
58
+ throw usageError(`Project ${project.id} remote target moved to ${remote.commit}, but no committed `
59
+ + "Integration can establish a safe Task baseline.");
60
+ }
61
+ if (previousIntegration.candidateCommit !== currentCommit) {
62
+ throw usageError(`Project ${project.id} Task head ${currentCommit} does not match its latest committed `
63
+ + `Integration ${previousIntegration.id}; settle that drift before remote reconciliation.`);
64
+ }
65
+ if (!await git.isClean(entry.path)) {
66
+ throw usageError(`Project ${project.id} managed Task workspace is dirty; commit or clean it before remote reconciliation.`);
67
+ }
68
+ plans.push({ project, entry, remote, currentCommit, previousIntegration });
69
+ }
70
+ const reconciled = [];
71
+ for (const plan of plans) {
72
+ const attempt = store.transaction((tx) => {
73
+ const created = createIntegrationAttempt({
74
+ id: tx.nextIntegrationAttemptId(task.id),
75
+ taskId: task.id,
76
+ projectId: plan.project.id,
77
+ targetRef: plan.entry.branch,
78
+ expectedHead: plan.currentCommit,
79
+ changeSetIds: plan.previousIntegration.changeSetIds,
80
+ checkCommands: plan.previousIntegration.checkCommands
81
+ }, options.now?.() ?? new Date());
82
+ tx.saveIntegrationAttempt(task.id, created);
83
+ return created;
84
+ });
85
+ const baseline = {
86
+ remoteUrl: plan.project.remoteUrl,
87
+ branch: plan.remote.branch
88
+ };
89
+ const result = await new GitIntegrationService(home, store, git, options.now ?? (() => new Date()), options.environment).integrate(task.id, attempt.id, { remoteBaseline: baseline });
90
+ if (result.status !== "committed" || result.attempt.candidateCommit === undefined) {
91
+ const detail = result.attempt.checks?.find(({ outcome }) => outcome === "failed")?.details
92
+ ?? result.attempt.conflict?.summary
93
+ ?? result.attempt.status;
94
+ throw usageError(`Remote baseline reconciliation failed for ${task.id}/${plan.project.id}: ${detail}`);
95
+ }
96
+ reconciled.push({
97
+ projectId: plan.project.id,
98
+ remote: plan.remote,
99
+ fromCommit: plan.currentCommit,
100
+ toCommit: result.attempt.candidateCommit,
101
+ integrationId: attempt.id
102
+ });
103
+ }
104
+ return reconciled;
105
+ }
106
+ async function fetchRemote(git, entry, project) {
107
+ try {
108
+ return await git.fetchRemoteHeadIntoWorktree({
109
+ repositoryPath: entry.path,
110
+ remoteUrl: project.remoteUrl,
111
+ branch: project.developmentBranch
112
+ });
113
+ }
114
+ catch (error) {
115
+ throw usageError(`Project ${project.id} remote target could not be resolved; completion is fail-closed: `
116
+ + `${error instanceof Error ? error.message : String(error)}`);
117
+ }
118
+ }
119
+ function requireTaskWorkspace(store, task) {
120
+ const workspace = store.getTaskWorkspace(task.id);
121
+ if (workspace === null || workspace.owner.type !== "task") {
122
+ throw usageError(`Task ${task.id} has no authoritative managed main workspace.`);
123
+ }
124
+ return workspace;
125
+ }
126
+ function latestCommittedIntegration(store, taskId, projectId) {
127
+ return store.listIntegrationAttempts(taskId)
128
+ .filter((attempt) => attempt.projectId === projectId && attempt.status === "committed")
129
+ .sort((left, right) => left.id.localeCompare(right.id, undefined, { numeric: true }))
130
+ .at(-1);
131
+ }
@@ -1,13 +1,18 @@
1
1
  import { taskNotFound, usageError } from "../errors/cliError.js";
2
2
  import { taskMessageAuthorLabel } from "../message/message.js";
3
+ import { formatTimestamp } from "../output/timePresentation.js";
4
+ import { isRoleRunStalled, latestStallProgressAt } from "../scheduler/roleRunStall.js";
5
+ import { buildTaskExecutionProjection } from "../scheduler/taskExecutionProjection.js";
6
+ import { inspectTaskRoleSessionRecovery } from "./taskRoleRuntimeStatus.js";
7
+ import { summarizeExecutionGroup } from "../execution/executionGroup.js";
8
+ import { currentWorkItemExecutionGroup } from "../workItem/workItem.js";
3
9
  const RECENT_RECORD_LIMIT = 5;
4
10
  const RELATED_RECORD_LIMIT = 5;
5
11
  const SUMMARY_TEXT_LIMIT = 400;
6
12
  const TERMINAL_WORK_ITEM_STATUSES = new Set([
7
13
  "completed",
8
14
  "failed",
9
- "cancelled",
10
- "superseded"
15
+ "retired"
11
16
  ]);
12
17
  export function runTaskContextCommand(args, store) {
13
18
  if (args.length !== 1 || args[0]?.trim().length === 0) {
@@ -19,29 +24,45 @@ export function runTaskContextCommand(args, store) {
19
24
  if (task === null)
20
25
  throw taskNotFound(taskId);
21
26
  const workItems = reader.listWorkItems(task.id);
22
- const workItemIds = new Set(workItems.map((item) => item.id));
23
27
  const inputRequests = reader.listInputRequests(task.id);
28
+ const roles = reader.listRoles(task.id);
29
+ const execution = buildTaskExecutionProjection(reader, task.id, task);
30
+ if (execution === null) {
31
+ throw new Error(`Task execution projection disappeared: ${task.id}.`);
32
+ }
33
+ const roleSessionSets = reader.listRoleSessionSets(task.id);
24
34
  return {
25
35
  task,
36
+ execution,
37
+ reviewConfig: reader.getReviewConfig(),
26
38
  brief: reader.getTaskBrief(task.id),
27
39
  activeDecisions: reader.listDecisions(task.id)
28
40
  .filter((decision) => decision.status === "active"),
29
41
  milestones: reader.listMilestones(task.id),
30
- roles: reader.listRoles(task.id),
42
+ roles,
43
+ managedWorkspaces: reader.listManagedWorkspaces(task.id),
44
+ roleSessionSets,
45
+ roleSessionRecoveries: roles.map((role) => (inspectTaskRoleSessionRecovery(task.id, role.name, reader))),
31
46
  workItems,
32
- runs: reader.listAgentRuns(task.id)
33
- .filter((run) => run.workItemId !== undefined && workItemIds.has(run.workItemId)),
47
+ agentRuns: chronological(reader.listAgentRuns(task.id)),
48
+ reviewRounds: chronological(reader.listReviewRounds(task.id)),
49
+ changeSets: chronological(reader.listChangeSets(task.id)),
50
+ integrations: chronological(reader.listIntegrationAttempts(task.id)),
34
51
  messages: reader.listMessages(task.id),
35
52
  openInputRequests: inputRequests.filter((request) => request.status === "open"),
36
53
  resolvedInputRequests: inputRequests.filter((request) => request.status !== "open"),
37
54
  events: reader.listEvents(task.id)
38
55
  };
39
56
  });
40
- const { task, brief, activeDecisions, milestones, roles, workItems, runs, messages, openInputRequests, resolvedInputRequests, events } = data;
57
+ const { task, execution, reviewConfig, brief, activeDecisions, milestones, roles, managedWorkspaces, roleSessionSets, roleSessionRecoveries, workItems, agentRuns, reviewRounds, changeSets, integrations, messages, openInputRequests, resolvedInputRequests, events } = data;
58
+ const timeZone = store.getConfig().timeZone;
41
59
  const displayedActiveDecisions = activeDecisions.slice(-RECENT_RECORD_LIMIT);
42
60
  const displayedWorkItems = currentAndRecentWorkItems(workItems);
43
61
  const displayedOpenInputRequests = openInputRequests.slice(-RECENT_RECORD_LIMIT);
44
62
  const displayedResolvedInputRequests = resolvedInputRequests.slice(-RECENT_RECORD_LIMIT);
63
+ const displayedExecutionCarriers = execution.monitoring === "active"
64
+ ? execution.activeRuns
65
+ : [];
45
66
  const lines = [
46
67
  `Task context: ${task.id}`,
47
68
  `Title: ${compactText(task.title)}`,
@@ -49,12 +70,41 @@ export function runTaskContextCommand(args, store) {
49
70
  ...(task.description === undefined ? [] : [`Description: ${compactText(task.description)}`]),
50
71
  ...(task.priority === undefined ? [] : [`Priority: ${task.priority}`]),
51
72
  ...(task.tags === undefined ? [] : [`Tags: ${task.tags.join(", ")}`]),
52
- ...(task.dueAt === undefined ? [] : [`Due: ${task.dueAt}`]),
73
+ ...(task.dueAt === undefined ? [] : [`Due: ${formatTimestamp(task.dueAt, timeZone)}`]),
53
74
  ...(task.completionSummary === undefined ? [] : [`Completion summary: ${task.completionSummary}`]),
75
+ ...(task.retirementSummary === undefined ? [] : [`Retirement summary: ${task.retirementSummary}`]),
76
+ ...(task.replacementTaskId === undefined ? [] : [`Replacement Task: ${task.replacementTaskId}`]),
54
77
  ...(task.archiveSummary === undefined ? [] : [`Archive summary: ${task.archiveSummary}`]),
55
- ...(task.repositoryId === undefined ? [] : [`Repository: ${task.repositoryId}`]),
56
- ...(task.baseRef === undefined ? [] : [`Base: ${task.baseRef}`]),
78
+ "Execution:",
79
+ ` Status: ${execution.status}`,
80
+ ` Owner/action: ${execution.owner}/${execution.action}`,
81
+ ` Monitoring: ${execution.monitoring}`,
82
+ ` Fail-closed: ${execution.failClosed ? "yes" : "no"}`,
83
+ ` Reason: ${execution.reason}`,
84
+ ` Attention: ${execution.attention.length === 0
85
+ ? "none"
86
+ : execution.attention.map(({ kind, owner }) => `${kind}/${owner}`).join(", ")}`,
87
+ ` Active execution carriers (${displayedExecutionCarriers.length}):`,
88
+ ...(displayedExecutionCarriers.length === 0
89
+ ? [" None."]
90
+ : displayedExecutionCarriers.map((run) => (` ${run.roleName}: ${run.id} [${run.status}; ${run.delivered ? "accepted" : "delivery-pending"}]`))),
91
+ ...(task.projectBindings.length === 0
92
+ ? []
93
+ : [
94
+ "Projects:",
95
+ ...task.projectBindings.map((binding) => (`- ${binding.directory}: ${binding.projectId} @ ${binding.baseRef}`))
96
+ ]),
57
97
  ...(task.cwd === undefined ? [] : [`Workspace: ${task.cwd}`]),
98
+ `Managed Workspaces (${managedWorkspaces.length}):`,
99
+ ...(managedWorkspaces.length === 0
100
+ ? [" None."]
101
+ : managedWorkspaces.map((workspace) => (` ${managedWorkspaceLabel(workspace)}: ${workspace.root} (${workspace.entries.filter(({ access }) => access === "write").length} writable / ${workspace.entries.length} Projects)`))),
102
+ `Completion evidence: ${task.requireIntegration
103
+ ? "WorkItem, ChangeSet, and committed Integration required"
104
+ : "delivery integration not required"}`,
105
+ `Global review: ${reviewConfig === null
106
+ ? "disabled"
107
+ : `${reviewConfig.roleName} (${reviewConfig.trigger})`}`,
58
108
  "",
59
109
  "Brief:",
60
110
  ...(brief === null
@@ -65,9 +115,12 @@ export function runTaskContextCommand(args, store) {
65
115
  ...(brief.boundaries.length === 0
66
116
  ? [" None."]
67
117
  : brief.boundaries.map((boundary) => ` - ${compactText(boundary)}`)),
118
+ ` Technical approach: ${brief.technicalApproach.length === 0
119
+ ? "Not defined."
120
+ : compactText(brief.technicalApproach)}`,
68
121
  ` Current focus: ${compactText(brief.currentFocus)}`,
69
122
  ` Leader summary: ${compactText(brief.leaderSummary)}`,
70
- ` Updated by ${brief.updatedBy} at ${brief.updatedAt}`
123
+ ` Updated by ${brief.updatedBy} at ${formatTimestamp(brief.updatedAt, timeZone)}`
71
124
  ]),
72
125
  "",
73
126
  `Active decisions (${displayedActiveDecisions.length}${activeDecisions.length > displayedActiveDecisions.length ? ` of ${activeDecisions.length}` : ""}):`,
@@ -79,55 +132,133 @@ export function runTaskContextCommand(args, store) {
79
132
  ])),
80
133
  "",
81
134
  ...recentSection("milestones", milestones, (milestone) => [
82
- ` ${milestone.id}: ${compactText(milestone.title)} (${milestone.createdAt})`,
135
+ ` ${milestone.id}: ${compactText(milestone.title)} (${formatTimestamp(milestone.createdAt, timeZone)})`,
83
136
  ` ${compactText(milestone.summary)}`
84
137
  ]),
85
138
  "",
86
- `Roles (${roles.length}):`,
139
+ `Task Roles (${roles.length}):`,
87
140
  ...(roles.length === 0
88
141
  ? [" None."]
89
- : roles.map((role) => (` ${role.name} [${role.status}] — Agent: ${role.activeAgentId}`))),
142
+ : roles.flatMap((role) => {
143
+ const binding = role.agentBindings[role.activeAgentId];
144
+ const activeRun = agentRuns.find((run) => (run.roleName === role.name && run.status === "active"));
145
+ const sessions = roleSessionSets.find((set) => set.owner.roleName === role.name);
146
+ const activeSession = sessions?.sessions[sessions.activeAgentId];
147
+ const effective = activeRun?.effective ?? activeSession?.effective;
148
+ const effectiveSource = activeRun === undefined ? "Session" : "Run";
149
+ const recovery = roleSessionRecoveries.find((entry) => entry.roleName === role.name);
150
+ const creation = [...events].reverse().find((event) => (event.type === "role.added" && event.payload.role === role.name));
151
+ return [
152
+ ` ${role.name} [${role.status}]: ${role.activeAgentId}/${binding.adapterId}`,
153
+ ` Desired: r${role.launchRevision}; Profile intent: ${role.defaultAccess}; Model: ${binding.config.model ?? "default"}; effort: ${binding.config.effort ?? "default"}; permission: ${binding.config.permission.strategy}`,
154
+ ` Effective: ${effective === undefined
155
+ ? "not started"
156
+ : `${effectiveSource} ${effective.agentId}/${effective.adapterId}; r${effective.sourceDesiredRevision}; Profile intent: ${effective.profileAccess}; permission: ${effective.permission.strategy}`}`,
157
+ ` Desired drift: ${effective === undefined
158
+ ? "-"
159
+ : effective.sourceDesiredRevision === role.launchRevision
160
+ ? "none"
161
+ : "pending next launch"}`,
162
+ ...(creation?.payload.runtimeSource === undefined
163
+ ? []
164
+ : [` Runtime source at creation: ${creation.payload.runtimeSource}`]),
165
+ ...(recovery === undefined ? [] : [
166
+ ` Runtime cleanup: ${recovery.runtimeCleanupPending ? "pending" : "none"}`,
167
+ ` Fresh launch: ${recovery.freshLaunchAllowed ? "allowed" : "blocked"}`
168
+ ])
169
+ ];
170
+ })),
90
171
  "",
91
172
  `Current and recent work items (${displayedWorkItems.length}${workItems.length > displayedWorkItems.length ? ` of ${workItems.length}` : ""}):`,
92
173
  ...(displayedWorkItems.length === 0
93
174
  ? [" None."]
94
175
  : displayedWorkItems.flatMap((item) => {
95
- const itemRuns = runs.filter((run) => run.workItemId === item.id);
176
+ const itemRuns = agentRuns.filter((run) => run.workItemId === item.id);
96
177
  const latestRun = itemRuns.at(-1);
97
178
  return [
98
- ` ${item.id} [${item.status}] ${item.assignee}: ${compactText(item.title)}`,
99
- ...(item.outcome === undefined
179
+ ` ${item.id} [${item.status}]: ${compactText(item.title)}`,
180
+ ` Objective: ${compactText(item.objective)}`,
181
+ ` Writable Projects: ${item.writeProjectIds.length === 0
182
+ ? "none"
183
+ : item.writeProjectIds.join(", ")}`,
184
+ ...(currentWorkItemExecutionGroup(item) === undefined
185
+ ? []
186
+ : renderExecutionGroup(currentWorkItemExecutionGroup(item))),
187
+ ...(item.acceptance.length === 0
188
+ ? []
189
+ : [` Acceptance: ${item.acceptance.map(compactText).join("; ")}`]),
190
+ ...(item.candidates.length === 0
100
191
  ? []
101
- : [` Outcome: ${compactText(item.outcome)}`]),
192
+ : item.candidates.flatMap((candidate) => [
193
+ ` Candidate ${candidate.sequence}: ${candidate.id}${item.status === "awaiting_acceptance" && candidate === item.candidates.at(-1) ? " [current]" : ""} (${candidate.source.type === "run" ? candidate.source.runId : "direct"})`,
194
+ ` Review policy: ${candidate.reviewPolicy === undefined ? "none" : `${candidate.reviewPolicy.roleName} (${candidate.reviewPolicy.trigger})`}`,
195
+ ` Task-final contract: ${candidate.taskFinalReviewContract === undefined
196
+ ? "none"
197
+ : `${candidate.taskFinalReviewContract.digest} via control ${candidate.taskFinalReviewContract.controlPlaneDigest}`}`,
198
+ ` Frozen Git: ${candidate.gitSnapshot === undefined
199
+ ? "unavailable"
200
+ : `${candidate.gitSnapshot.reviewBaseCommit} (${candidate.gitSnapshot.projects.length} Projects)`}`,
201
+ ` Summary: ${compactText(candidate.summary)}`
202
+ ])),
102
203
  ...(latestRun === undefined
103
- ? [" Runs: none."]
204
+ ? [" AgentRuns: none."]
104
205
  : [
105
- ` Runs: ${itemRuns.length}; latest ${latestRun.id} [${latestRun.status}] ${latestRun.roleName}`,
206
+ ` AgentRuns: ${itemRuns.length}; latest ${latestRun.id} [${latestRun.status}] ${latestRun.effective.agentId}/${latestRun.effective.adapterId} · effective r${latestRun.effective.sourceDesiredRevision}/${latestRun.effective.profileAccess}/${latestRun.effective.permission.strategy}`,
106
207
  ` Input: ${compactText(latestRun.input)}`,
107
208
  ...(latestRun.summary === undefined
108
209
  ? []
109
210
  : [` Summary: ${compactText(latestRun.summary)}`])
110
- ])
211
+ ]),
212
+ ...renderWorkItemReviews(reviewRounds.filter((round) => round.workItemId === item.id))
111
213
  ];
112
214
  })),
113
215
  "",
216
+ ...recentSection("AgentRuns", agentRuns, (run) => [
217
+ ` ${run.id} [${run.status}/${run.purpose}] ${run.roleName} via ${run.effective.agentId}/${run.effective.adapterId}`,
218
+ ` Effective: r${run.effective.sourceDesiredRevision}; Profile intent: ${run.effective.profileAccess}; permission: ${run.effective.permission.strategy}; model: ${run.effective.model ?? "default"}; effort: ${run.effective.effort ?? "default"}`,
219
+ ...(run.summary === undefined ? [] : [` Result: ${compactText(run.summary)}`])
220
+ ]),
221
+ "",
222
+ "Runtime health:",
223
+ ...(() => {
224
+ const stalled = agentRuns.filter((run) => (run.status === "active" && isRoleRunStalled(events, run.id)));
225
+ return stalled.length === 0
226
+ ? [" No needs-attention Runs."]
227
+ : stalled.flatMap((run) => [
228
+ ` ${run.id} [needs-attention] ${run.roleName}`,
229
+ ` Durable progress: ${formatTimestamp(latestStallProgressAt(events, run.id) ?? run.updatedAt, timeZone)}`,
230
+ ` Cause: ${latestStallKind(events, run.id)} with no new semantic Run evidence in the stall window`,
231
+ " Next: inspect Task context/Role status; no automatic retry or Session replacement was performed."
232
+ ]);
233
+ })(),
234
+ "",
235
+ `ChangeSets (${changeSets.length}):`,
236
+ ...(changeSets.length === 0
237
+ ? [" None."]
238
+ : changeSets.slice(-RECENT_RECORD_LIMIT).map((changeSet) => (` ${changeSet.id} [${changeSet.projectId}]: ${changeSet.baseCommit.slice(0, 12)}..${changeSet.headCommit.slice(0, 12)} (${changeSet.changedPaths.length} paths; WorkItem ${changeSet.workItemId})`))),
239
+ "",
240
+ `Integration Attempts (${integrations.length}):`,
241
+ ...(integrations.length === 0
242
+ ? [" None."]
243
+ : integrations.slice(-RECENT_RECORD_LIMIT).map((integration) => (` ${integration.id} [${integration.status}/${integration.projectId}] — ${integration.targetRef}; ${integration.changeSetIds.join(", ")}`))),
244
+ "",
114
245
  ...recentSection("messages", messages, (message) => [
115
- ` ${message.id} [${taskMessageAuthorLabel(message.author)}] ${message.createdAt}`,
246
+ ` ${message.id} [${taskMessageAuthorLabel(message.author)}] ${formatTimestamp(message.createdAt, timeZone)}`,
116
247
  ` ${compactText(message.body)}`
117
248
  ]),
118
249
  "",
119
250
  `Open input requests (${displayedOpenInputRequests.length}${openInputRequests.length > displayedOpenInputRequests.length ? ` of ${openInputRequests.length}` : ""}):`,
120
251
  ...(displayedOpenInputRequests.length === 0
121
252
  ? [" None."]
122
- : displayedOpenInputRequests.flatMap(renderOpenInputRequest)),
253
+ : displayedOpenInputRequests.flatMap((request) => renderOpenInputRequest(request, timeZone))),
123
254
  "",
124
255
  `Recent resolved input requests (${displayedResolvedInputRequests.length}${resolvedInputRequests.length > displayedResolvedInputRequests.length ? ` of ${resolvedInputRequests.length}` : ""}):`,
125
256
  ...(displayedResolvedInputRequests.length === 0
126
257
  ? [" None."]
127
- : displayedResolvedInputRequests.flatMap(renderResolvedInputRequest)),
258
+ : displayedResolvedInputRequests.flatMap((request) => renderResolvedInputRequest(request, timeZone))),
128
259
  "",
129
260
  ...recentSection("events", events, (event) => [
130
- ` ${event.id} ${event.type} (${event.createdAt})`,
261
+ ` ${event.id} ${event.type} (${formatTimestamp(event.createdAt, timeZone)})`,
131
262
  ...(Object.keys(event.payload).length === 0
132
263
  ? []
133
264
  : [` ${Object.entries(event.payload)
@@ -141,7 +272,43 @@ export function runTaskContextCommand(args, store) {
141
272
  data
142
273
  };
143
274
  }
144
- function renderResolvedInputRequest(request) {
275
+ function latestStallKind(events, runId) {
276
+ const event = [...events]
277
+ .filter((candidate) => candidate.type === "run.stalled" && candidate.payload.runId === runId)
278
+ .sort((left, right) => Date.parse(right.createdAt) - Date.parse(left.createdAt))[0];
279
+ return event?.payload.kind ?? "execution-stalled";
280
+ }
281
+ function renderWorkItemReviews(rounds) {
282
+ const latest = rounds.at(-1);
283
+ if (latest === undefined)
284
+ return [" ReviewRounds: none."];
285
+ return [
286
+ ` ReviewRounds: ${rounds.length}; latest ${latest.id} [${latest.status}] ${latest.scope === "task" ? "Task-final" : "WorkItem"} for ${latest.candidateId} via ${latest.reviewerRoleName} (${latest.requestedBy})`,
287
+ ` Review base: ${latest.reviewBaseCommit}`,
288
+ ...(latest.scope === "task"
289
+ ? [
290
+ ` Frozen integrated Task heads: ${latest.taskCandidate?.projects
291
+ .map(({ projectId, commit }) => `${projectId}@${commit}`).join(", ") ?? "unavailable"}`,
292
+ ` Task-final contract: ${latest.taskFinalReviewContract?.digest ?? "global policy"}`
293
+ ]
294
+ : []),
295
+ ` Review workspace: ${latest.workspace === undefined
296
+ ? "not prepared"
297
+ : `${latest.workspace.root} (${latest.workspace.entries.length} writable Projects)`}`,
298
+ ` Workspace disposition: ${latest.workspaceDisposition?.kind ?? "pending"}`,
299
+ ` Diagnostic evidence: ${latest.evidenceCommit ?? "none"}`,
300
+ ` Checks: ${latest.checks === undefined || latest.checks.length === 0
301
+ ? "none"
302
+ : latest.checks.map(({ name, outcome }) => `${name}=${outcome}`).join(", ")}`,
303
+ ...(latest.summary === undefined
304
+ ? []
305
+ : [` Review summary: ${compactText(latest.summary)}`]),
306
+ ...(latest.executionGroup === undefined
307
+ ? []
308
+ : renderExecutionGroup(latest.executionGroup).map((line) => ` ${line.trimStart()}`))
309
+ ];
310
+ }
311
+ function renderResolvedInputRequest(request, timeZone) {
145
312
  if (request.status === "open")
146
313
  return [];
147
314
  return [
@@ -150,15 +317,15 @@ function renderResolvedInputRequest(request) {
150
317
  ...(request.status === "answered"
151
318
  ? [
152
319
  ` Answer: ${compactText(request.resolution.answer.text)}`,
153
- ` Answered by ${request.resolution.answeredBy} at ${request.resolution.answeredAt}`
320
+ ` Answered by ${request.resolution.answeredBy} at ${formatTimestamp(request.resolution.answeredAt, timeZone)}`
154
321
  ]
155
322
  : [
156
323
  ` Cancelled: ${compactText(request.cancellation.reason)}`,
157
- ` Cancelled at: ${request.cancellation.cancelledAt}`
324
+ ` Cancelled at: ${formatTimestamp(request.cancellation.cancelledAt, timeZone)}`
158
325
  ])
159
326
  ];
160
327
  }
161
- function renderOpenInputRequest(request) {
328
+ function renderOpenInputRequest(request, timeZone) {
162
329
  const choices = request.choices.slice(0, RELATED_RECORD_LIMIT);
163
330
  const blockedRefs = request.blockedRefs.slice(0, RELATED_RECORD_LIMIT);
164
331
  const recommendedChoiceKey = request.policy.kind === "recommended"
@@ -179,7 +346,7 @@ function renderOpenInputRequest(request) {
179
346
  ...(request.policy.kind === "recommended"
180
347
  ? [
181
348
  ` Recommended choice: ${request.policy.recommendedChoiceKey}: ${compactText(recommendedChoice?.label ?? request.policy.recommendedChoiceKey)}`,
182
- ` Timeout at: ${request.policy.timeoutAt}`
349
+ ` Timeout at: ${formatTimestamp(request.policy.timeoutAt, timeZone)}`
183
350
  ]
184
351
  : []),
185
352
  ...(request.blockedRefs.length === 0
@@ -207,9 +374,56 @@ function currentAndRecentWorkItems(records) {
207
374
  const selected = new Set([...current, ...recentTerminal]);
208
375
  return records.filter((record) => selected.has(record));
209
376
  }
377
+ function chronological(records) {
378
+ return [...records].sort((left, right) => (Date.parse(left.createdAt) - Date.parse(right.createdAt)
379
+ || left.id.localeCompare(right.id)));
380
+ }
210
381
  function compactText(value) {
211
382
  const oneLine = value.replace(/\s+/g, " ").trim();
212
383
  return oneLine.length <= SUMMARY_TEXT_LIMIT
213
384
  ? oneLine
214
385
  : `${oneLine.slice(0, SUMMARY_TEXT_LIMIT - 3)}...`;
215
386
  }
387
+ function managedWorkspaceLabel(workspace) {
388
+ switch (workspace.owner.type) {
389
+ case "task":
390
+ return "task";
391
+ case "work-item":
392
+ return `work-item ${workspace.owner.workItemId}`;
393
+ case "review-round":
394
+ return `review-round ${workspace.owner.reviewRoundId}`;
395
+ case "integration-attempt":
396
+ return `integration-attempt ${workspace.owner.integrationAttemptId}`;
397
+ case "execution-lane":
398
+ return `execution-lane ${workspace.owner.executionGroupId}/${workspace.owner.executionLaneId}`;
399
+ }
400
+ }
401
+ function renderExecutionGroup(group) {
402
+ const summary = summarizeExecutionGroup(group);
403
+ return [
404
+ ` Execution Group ${summary.groupId} [${summary.purpose}/${summary.strategy.mode}]: ${summary.activeLaneCount} active / ${summary.terminalLaneCount} terminal; ${summary.failedLaneCount} failed`,
405
+ ...summary.laneSummaries.flatMap((lane) => [
406
+ ` Lane ${lane.laneId} (#${lane.ordinal}, ${lane.roleName}) [${lane.status}]${lane.summary === undefined ? "" : `: ${compactText(lane.summary)}`}`,
407
+ ...(lane.report === undefined ? [] : [` Report: ${compactText(lane.report)}`]),
408
+ ...(lane.checks === undefined || lane.checks.length === 0
409
+ ? []
410
+ : [` Checks: ${lane.checks.map(({ name, outcome }) => `${name}:${outcome}`).join(", ")}`]),
411
+ ...(lane.findings === undefined || lane.findings.length === 0
412
+ ? []
413
+ : [` Findings: ${lane.findings.map(({ id, severity, status }) => `${id}:${severity}/${status}`).join(", ")}`]),
414
+ ...(lane.evidence === undefined || lane.evidence.length === 0
415
+ ? []
416
+ : [` Evidence: ${lane.evidence.length} item(s)`]),
417
+ ...(lane.evidenceCommit === undefined
418
+ ? []
419
+ : [` Evidence commit: ${lane.evidenceCommit}`]),
420
+ ...(lane.decision === undefined ? [] : [` Decision: ${lane.decision}`])
421
+ ]),
422
+ ...(summary.openHighPriorityFindingIds.length === 0
423
+ ? []
424
+ : [` Open high findings: ${summary.openHighPriorityFindingIds.join(", ")}`]),
425
+ ...(summary.resolution === undefined
426
+ ? []
427
+ : [` Resolution: ${summary.resolution.decision} — ${compactText(summary.resolution.summary)}`])
428
+ ];
429
+ }