@zq-silk/yui 0.14.0 → 0.14.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 (179) hide show
  1. package/ARCHITECTURE.md +64 -35
  2. package/README.md +258 -125
  3. package/dist/agent/argumentPolicy.js +2 -1
  4. package/dist/agent/managedRuntimeEnvironment.js +5 -8
  5. package/dist/cli/commandCatalog.js +74 -109
  6. package/dist/cli/helpRenderer.js +1 -2
  7. package/dist/cli/interactionCandidates.js +10 -0
  8. package/dist/cli/interactionPolicy.js +76 -37
  9. package/dist/cli/roleWizard.js +5 -6
  10. package/dist/cli/updateOrchestrator.js +10 -8
  11. package/dist/cli/updatePorts.js +17 -13
  12. package/dist/cli/upgradeCommand.js +2 -5
  13. package/dist/cli.js +268 -231
  14. package/dist/commands/agentCommands.js +13 -0
  15. package/dist/commands/configCommands.js +7 -19
  16. package/dist/commands/configOverview.js +3 -2
  17. package/dist/commands/durableJobCommands.js +1 -1
  18. package/dist/commands/executionAuditCommands.js +4 -9
  19. package/dist/commands/globalRoleCommands.js +17 -0
  20. package/dist/commands/profileCommands.js +200 -30
  21. package/dist/commands/sessionCommands.js +1 -1
  22. package/dist/commands/taskActor.js +29 -127
  23. package/dist/commands/taskChangeSetCommands.js +1 -3
  24. package/dist/commands/taskCommands.js +1771 -2107
  25. package/dist/commands/taskCompletionGate.js +27 -103
  26. package/dist/commands/taskContextCommand.js +47 -80
  27. package/dist/commands/taskExecutionCommands.js +9 -27
  28. package/dist/commands/taskInputCommands.js +10 -10
  29. package/dist/commands/taskIntegrationCommands.js +69 -61
  30. package/dist/commands/taskIntegrationQueueCommands.js +1 -1
  31. package/dist/commands/taskNextActionCommand.js +8 -29
  32. package/dist/commands/taskOverviewCommand.js +25 -3
  33. package/dist/commands/taskPublicationCommands.js +151 -85
  34. package/dist/commands/taskPublicationVerifyCommand.js +181 -0
  35. package/dist/commands/taskRemoteDeliveryCommand.js +134 -0
  36. package/dist/commands/taskRoleRuntimeStatus.js +5 -6
  37. package/dist/commands/taskUpstreamCommands.js +79 -95
  38. package/dist/config/configCatalog.js +1 -1
  39. package/dist/context/contextSnapshot.js +17 -2
  40. package/dist/context/sessionBootstrapManifest.js +18 -1
  41. package/dist/context/sourceTurnContext.js +30 -0
  42. package/dist/context/turnContextPack.js +107 -48
  43. package/dist/context/turnInputContract.js +11 -4
  44. package/dist/context/wakeNotification.js +84 -22
  45. package/dist/controller/agentRuntimeObserver.js +9 -12
  46. package/dist/controller/clientRuntime.js +13 -13
  47. package/dist/controller/controller.js +11 -11
  48. package/dist/controller/fileSchedulerStoreAdapter.js +262 -219
  49. package/dist/controller/jobControl.js +11 -10
  50. package/dist/controller/resourceInventory.js +6 -6
  51. package/dist/controller/resourceInventoryLinux.js +2 -2
  52. package/dist/controller/runtime.js +18 -61
  53. package/dist/controller/runtimeEventInbox.js +57 -34
  54. package/dist/controller/runtimeEventProcessor.js +36 -96
  55. package/dist/controller/runtimeHookTurnFence.js +33 -57
  56. package/dist/controller/runtimeLaunchCoordinator.js +44 -40
  57. package/dist/controller/runtimeObservationHook.js +18 -12
  58. package/dist/controller/sessionNotify.js +43 -28
  59. package/dist/controller/sessionOwnerReconciliation.js +21 -21
  60. package/dist/controller/structuredProviderObservation.js +13 -16
  61. package/dist/coordination/workMailboxQueue.js +132 -0
  62. package/dist/core/controllerServer.js +1 -0
  63. package/dist/domain/agentResultTransport.js +60 -0
  64. package/dist/execution/executionHealth.js +111 -118
  65. package/dist/execution/reviewMainTurn.js +161 -0
  66. package/dist/execution/workItemExecution.js +454 -0
  67. package/dist/execution/workItemExecutionProjection.js +309 -0
  68. package/dist/execution/workItemMainTurn.js +164 -0
  69. package/dist/executor/agentExecutor.js +19 -19
  70. package/dist/executor/executorRegistry.js +7 -28
  71. package/dist/executor/fileRoleLaunchPlanner.js +51 -83
  72. package/dist/external/githubPublicationVerifier.js +114 -0
  73. package/dist/external/gitlabPublicationVerifier.js +158 -0
  74. package/dist/external/pinnedCommandRunner.js +73 -0
  75. package/dist/integration/changeSetManifest.js +0 -3
  76. package/dist/integration/deliveryObligation.js +43 -6
  77. package/dist/integration/gitIntegrationService.js +284 -101
  78. package/dist/integration/integrationAttempt.js +64 -14
  79. package/dist/integration/integrationQueueEntry.js +5 -35
  80. package/dist/integration/integrationQueueService.js +65 -194
  81. package/dist/lifecycle/canonicalLifecycleEvent.js +16 -15
  82. package/dist/lifecycle/exactTurnTerminalization.js +100 -97
  83. package/dist/message/message.js +16 -0
  84. package/dist/observability/executionAudit.js +4 -25
  85. package/dist/observability/faultClassification.js +58 -70
  86. package/dist/observability/orchestrationMetrics.js +8 -50
  87. package/dist/profile/agentProfile.js +60 -15
  88. package/dist/profile/agentProfileRuntime.js +100 -0
  89. package/dist/release/releaseWorkflowPorts.js +5 -68
  90. package/dist/repository/executionLaneGitSnapshot.js +80 -0
  91. package/dist/repository/gitWorkspace.js +9 -67
  92. package/dist/repository/taskBaseFreshness.js +3 -1
  93. package/dist/repository/taskWorkspaceCoordinator.js +32 -4
  94. package/dist/repository/taskWorkspacePreparer.js +252 -411
  95. package/dist/resources/liveReferences.js +6 -55
  96. package/dist/resources/resourceDiscovery.js +1 -30
  97. package/dist/resources/resourceRegistrar.js +0 -23
  98. package/dist/review/deltaRecheck.js +8 -65
  99. package/dist/review/reviewAcceptance.js +22 -19
  100. package/dist/review/reviewConfig.js +0 -10
  101. package/dist/review/reviewDecision.js +2 -2
  102. package/dist/review/reviewRound.js +147 -273
  103. package/dist/review/reviewerAvailability.js +13 -23
  104. package/dist/role/role.js +3 -0
  105. package/dist/runtime/agentDriverObservation.js +1 -1
  106. package/dist/runtime/agentHost.js +51 -51
  107. package/dist/runtime/builtinAgentDrivers.js +9 -2
  108. package/dist/runtime/codexAppServerRuntime.js +23 -5
  109. package/dist/runtime/exactControlPlane.js +2 -267
  110. package/dist/runtime/firstProgressAdvisory.js +1 -1
  111. package/dist/runtime/index.js +1 -1
  112. package/dist/runtime/launchBroker.js +11 -11
  113. package/dist/runtime/lifecycleReservation.js +2 -2
  114. package/dist/runtime/managedCaller.js +111 -0
  115. package/dist/runtime/ports.js +16 -3
  116. package/dist/runtime/preallocatedNativeSession.js +2 -2
  117. package/dist/runtime/processExitObservation.js +3 -2
  118. package/dist/runtime/providerContinuationReconciliationService.js +1 -1
  119. package/dist/runtime/runtimeBinding.js +1 -1
  120. package/dist/runtime/runtimeObservation.js +33 -16
  121. package/dist/runtime/runtimeSessionCandidate.js +2 -2
  122. package/dist/runtime/runtimeStopReceipt.js +11 -11
  123. package/dist/runtime/sessionLaunchRequest.js +2 -2
  124. package/dist/runtime/sessionOwnerIdentity.js +9 -9
  125. package/dist/runtime/sessionOwnerRegistry.js +13 -13
  126. package/dist/runtime/sessionReconciliation.js +4 -4
  127. package/dist/runtime/sessionTerminationGuard.js +9 -9
  128. package/dist/runtime/sessionTokenMetrics.js +5 -7
  129. package/dist/runtime/structuredProviderHost.js +5 -5
  130. package/dist/runtime/taskRuntimeIsolation.js +24 -24
  131. package/dist/runtime/tmuxAdapters.js +32 -30
  132. package/dist/scheduler/activeRoleTurnDelivery.js +37 -15
  133. package/dist/scheduler/leaderWakeupProcessor.js +78 -55
  134. package/dist/scheduler/roleTurnLiveness.js +6 -6
  135. package/dist/scheduler/roleTurnStall.js +8 -9
  136. package/dist/scheduler/taskExecutionProjection.js +19 -41
  137. package/dist/scheduler/taskObservabilityProjection.js +75 -122
  138. package/dist/storage/sqliteSchema.js +1 -21
  139. package/dist/storage/sqliteStore.js +62 -47
  140. package/dist/storage/storageSchema.js +1 -8
  141. package/dist/storage/storageVersions.js +7 -4
  142. package/dist/storage/taskStore.js +8 -8
  143. package/dist/storage/upgrade/upgradeOrchestrator.js +112 -83
  144. package/dist/task/completionReadiness.js +17 -98
  145. package/dist/task/deliveryGuard.js +9 -11
  146. package/dist/task/draftPlan.js +142 -0
  147. package/dist/task/nextAction.js +179 -477
  148. package/dist/task/publicationVerification.js +1 -0
  149. package/dist/task/remoteDelivery.js +233 -0
  150. package/dist/task/task.js +108 -4
  151. package/dist/task/taskRecordReference.js +0 -1
  152. package/dist/turn/turn.js +109 -16
  153. package/dist/verification/verificationGateService.js +0 -26
  154. package/dist/web/assets/client/components.js +99 -121
  155. package/dist/web/assets/client/i18n.js +136 -58
  156. package/dist/web/assets/client/view.js +44 -0
  157. package/dist/web/assets/styles/cards.js +3 -15
  158. package/dist/web/assets/styles/widgets.js +4 -0
  159. package/dist/web/webSnapshot.js +29 -14
  160. package/dist/workItem/dependencyGate.js +34 -0
  161. package/dist/workItem/workItem.js +99 -266
  162. package/dist/workspace/workItemChangeSetManager.js +15 -59
  163. package/docs/task-local-identity.md +1 -1
  164. package/i18n/README.zh-CN.md +165 -59
  165. package/package.json +1 -1
  166. package/skills/yui-leader/SKILL.md +272 -782
  167. package/skills/yui-operator/SKILL.md +190 -365
  168. package/skills/yui-reviewer/SKILL.md +40 -33
  169. package/skills/yui-runtime/SKILL.md +27 -6
  170. package/skills/yui-worker/SKILL.md +19 -6
  171. package/dist/execution/candidateConvergence.js +0 -623
  172. package/dist/execution/executionGroup.js +0 -854
  173. package/dist/execution/resourceBroker.js +0 -426
  174. package/dist/executor/launchPlan.js +0 -16
  175. package/dist/review/reviewFinding.js +0 -240
  176. package/dist/review/reviewFindingLedger.js +0 -550
  177. package/dist/review/reviewOutcomeClassifier.js +0 -255
  178. package/dist/scheduler/resourceQueueProjection.js +0 -71
  179. package/dist/task/repairWave.js +0 -150
@@ -1,11 +1,6 @@
1
1
  import { usageError } from "../errors/cliError.js";
2
- import { activeRoleAgentBinding } from "../role/role.js";
3
- import { managedProviderTurnId } from "../runtime/providerRuntimeIdentity.js";
2
+ import { MANAGED_CALLER_KEY_ENV, currentManagedRuntime } from "../runtime/managedCaller.js";
4
3
  const LEADER_ROLE = "leader";
5
- const LEADER_ACTION_RUN_ENV = "YUI_LEADER_ACTION_TURN_ID";
6
- const LEADER_ACTION_RECEIPT_ENV = "YUI_LEADER_ACTION_RECEIPT_ID";
7
- /** rr13: Per-Session DurableJob caller key injected at native Session launch. */
8
- const JOB_CALLER_KEY_ENV = "YUI_JOB_CALLER_KEY";
9
4
  export function taskActor(environment, taskId) {
10
5
  const env = environment ?? {};
11
6
  if (env.YUI_SESSION_SCOPE === "task"
@@ -23,24 +18,23 @@ export function taskActor(environment, taskId) {
23
18
  }
24
19
  if (env.YUI_ROLE !== undefined
25
20
  || env.YUI_AGENT_ID !== undefined
26
- || env.YUI_TURN_ID !== undefined
27
- || env.YUI_NATIVE_SESSION_ID !== undefined) {
21
+ || env[MANAGED_CALLER_KEY_ENV] !== undefined) {
28
22
  throw usageError("Managed Agent identity is incomplete; refusing to infer user authority.");
29
23
  }
30
24
  return "user";
31
25
  }
32
26
  /**
33
27
  * Resolve authority for a recoverable Task-local mutation. A managed Leader
34
- * does not gain that authority from long-lived process environment alone: the
35
- * command must carry the exact current Turn assertion and it must still match
36
- * the durable active Turn, receipt, Role binding, native Session, and Home.
37
- * Plain-user and global-Operator behavior remains unchanged.
28
+ * does not gain that authority from long-lived process environment alone. Its
29
+ * process proves only that Yui launched it for this Task Role; whether it is
30
+ * still the current runtime, and which Turn is current, are read from durable
31
+ * state at command time. Plain-user and global-Operator behavior is unchanged.
38
32
  */
39
- export function taskLocalActor(store, environment, taskId, yuiHome) {
33
+ export function taskLocalActor(store, environment, taskId) {
40
34
  const actor = taskActor(environment, taskId);
41
35
  if (actor !== "leader")
42
36
  return actor;
43
- if (taskLeaderActionTurnId(store, taskId, environment, yuiHome) === undefined) {
37
+ if (taskLeaderActionTurnId(store, taskId, environment) === undefined) {
44
38
  throw usageError(`Task-local Leader authority requires the current Provider Turn: ${taskId}.`);
45
39
  }
46
40
  return actor;
@@ -56,8 +50,7 @@ export function projectActor(environment) {
56
50
  }
57
51
  if (env.YUI_ROLE !== undefined
58
52
  || env.YUI_AGENT_ID !== undefined
59
- || env.YUI_TURN_ID !== undefined
60
- || env.YUI_NATIVE_SESSION_ID !== undefined) {
53
+ || env[MANAGED_CALLER_KEY_ENV] !== undefined) {
61
54
  throw usageError("Managed Agent identity is incomplete; refusing to infer user authority.");
62
55
  }
63
56
  return "user";
@@ -67,10 +60,10 @@ export function projectActor(environment) {
67
60
  * the managed Session environment. The Controller verifies the Agent Session
68
61
  * and its scope; Role does not narrow Task control authority.
69
62
  *
70
- * rr12: The identity is now Controller-verified rather than self-reported:
71
- * - A managed Task Session (`YUI_SESSION_SCOPE=task`) returns `scope: "task"`
72
- * with its Role and Turn. For a Leader, the explicit current Turn id is
73
- * preferred over a possibly stale `YUI_TURN_ID`.
63
+ * The identity is Controller-verified rather than self-reported. A managed
64
+ * Task Session reports only its immutable self-identity (Task, Role, caller
65
+ * key); the Controller resolves the current Turn from durable state, so no
66
+ * Turn is ever carried across Turns in a long-lived process environment.
74
67
  *
75
68
  * rr13: A managed Task Session also carries `callerKey` — the
76
69
  * `YUI_JOB_CALLER_KEY` injected at its native Session launch. The Controller
@@ -80,7 +73,7 @@ export function projectActor(environment) {
80
73
  * managed global Agent carries its own durable Session identity.
81
74
  *
82
75
  * A managed Task Session may only start jobs for its own Task. An incomplete
83
- * managed identity (role/agent/Turn/Session vars without a scope) is rejected
76
+ * managed identity (role/agent/caller-key vars without a scope) is rejected
84
77
  * rather than silently downgraded to user authority.
85
78
  */
86
79
  export function resolveJobCaller(environment, taskId) {
@@ -93,25 +86,13 @@ export function resolveJobCaller(environment, taskId) {
93
86
  // rr13: Carry the per-Session caller key so the Controller can verify the
94
87
  // channel binding. Absent on a managed Session = fail-closed at the
95
88
  // Controller boundary.
96
- const callerKey = env[JOB_CALLER_KEY_ENV];
97
- if (role === LEADER_ROLE) {
98
- // Prefer the explicit current Turn over a possibly stale YUI_TURN_ID.
99
- const assertion = leaderActionAssertion(env);
100
- if (assertion !== undefined && assertion !== "invalid") {
101
- return {
102
- scope: "task",
103
- taskId,
104
- role,
105
- turnId: assertion.turnId,
106
- ...(callerKey === undefined ? {} : { callerKey })
107
- };
108
- }
109
- }
89
+ const callerKey = env[MANAGED_CALLER_KEY_ENV];
90
+ // The Turn is deliberately absent: the Controller reads the current Turn
91
+ // for this Task Role from durable state when it authorizes the request.
110
92
  return {
111
93
  scope: "task",
112
94
  taskId,
113
95
  role,
114
- ...(env.YUI_TURN_ID === undefined ? {} : { turnId: env.YUI_TURN_ID }),
115
96
  ...(callerKey === undefined ? {} : { callerKey })
116
97
  };
117
98
  }
@@ -121,107 +102,28 @@ export function resolveJobCaller(environment, taskId) {
121
102
  role: env.YUI_ROLE,
122
103
  agentId: env.YUI_AGENT_ID,
123
104
  adapterId: env.YUI_ADAPTER_ID,
124
- launchId: env.YUI_LAUNCH_ID,
105
+ runtimeGenerationId: env.YUI_RUNTIME_GENERATION_ID,
125
106
  nativeSessionId: env.YUI_NATIVE_SESSION_ID
126
107
  };
127
108
  }
128
109
  if (env.YUI_ROLE !== undefined
129
110
  || env.YUI_AGENT_ID !== undefined
130
- || env.YUI_TURN_ID !== undefined
131
- || env.YUI_NATIVE_SESSION_ID !== undefined) {
111
+ || env[MANAGED_CALLER_KEY_ENV] !== undefined) {
132
112
  throw usageError("Managed Agent identity is incomplete; refusing to infer user authority.");
133
113
  }
134
114
  return { scope: "user" };
135
115
  }
136
116
  /**
137
- * Resolve an exact current Task Leader Turn for event attribution.
117
+ * Resolve the current Task Leader Turn for event attribution and Task-local
118
+ * Leader authority.
138
119
  *
139
- * Task commands may be invoked by a managed process whose environment is
140
- * stale, incomplete, or copied from another Turn. A bare YUI_TURN_ID is never
141
- * enough: the active durable Turn, Role, in-flight receipt, native Session,
142
- * launch generation, and (when supplied) Home must all agree before an
143
- * allowlisted lifecycle event can buy a Leader action window. A fixed native
144
- * Session may keep an earlier Turn/launch in its process environment; in that
145
- * case the current Leader turn must explicitly carry the exact durable
146
- * Turn/receipt pair through the two command-only assertion variables below.
120
+ * A long-lived managed process cannot carry this: its environment is frozen at
121
+ * launch, so any Turn it holds is stale the moment Yui advances the Task. The
122
+ * Turn is therefore read from durable state, and the process only has to prove
123
+ * that it is still the current runtime of the Leader Role through its
124
+ * per-Session caller key. When the Role has no active Turn, or the process has
125
+ * been superseded, there is simply no Leader action window.
147
126
  */
148
- export function taskLeaderActionTurnId(store, taskId, environment, yuiHome) {
149
- const env = environment ?? {};
150
- if (env.YUI_SESSION_SCOPE !== "task" || env.YUI_ROLE !== LEADER_ROLE)
151
- return undefined;
152
- if (identity(env.YUI_TASK_ID) !== taskId)
153
- return undefined;
154
- const environmentAssertion = leaderActionAssertion(env);
155
- if (environmentAssertion === "invalid")
156
- return undefined;
157
- const explicitAssertion = environmentAssertion === undefined ? undefined : environmentAssertion;
158
- const observedTurnTurnId = managedProviderTurnId(store.getTaskRoleSessionSet(taskId, LEADER_ROLE)?.providerBinding?.turn) ?? undefined;
159
- const turnId = explicitAssertion?.turnId ?? observedTurnTurnId ?? identity(env.YUI_TURN_ID);
160
- const agentId = identity(env.YUI_AGENT_ID);
161
- const adapterId = identity(env.YUI_ADAPTER_ID);
162
- const launchId = identity(env.YUI_LAUNCH_ID);
163
- const home = identity(env.YUI_HOME);
164
- if (turnId === undefined
165
- || agentId === undefined
166
- || adapterId === undefined
167
- || launchId === undefined
168
- || home === undefined) {
169
- return undefined;
170
- }
171
- const storeHome = typeof store.rootDirectory === "function"
172
- ? store.rootDirectory()
173
- : undefined;
174
- if (yuiHome !== undefined && home !== yuiHome)
175
- return undefined;
176
- if (yuiHome === undefined && storeHome !== undefined && home !== storeHome)
177
- return undefined;
178
- const role = store.getRole(taskId, LEADER_ROLE);
179
- const run = store.getActiveTurn(taskId, LEADER_ROLE);
180
- const sessions = store.getTaskRoleSessionSet(taskId, LEADER_ROLE);
181
- if (role === null
182
- || run === null
183
- || run.status !== "active"
184
- || run.id !== turnId
185
- || run.taskId !== taskId
186
- || run.roleName !== LEADER_ROLE
187
- || run.effective.agentId !== agentId
188
- || run.effective.adapterId !== adapterId
189
- || role.activeAgentId !== agentId
190
- || activeRoleAgentBinding(role).adapterId !== adapterId
191
- || sessions === null
192
- || sessions.owner.scope !== "task"
193
- || sessions.owner.taskId !== taskId
194
- || sessions.owner.roleName !== LEADER_ROLE
195
- || sessions.activeAgentId !== agentId
196
- || managedProviderTurnId(sessions.providerBinding?.turn) !== turnId)
197
- return undefined;
198
- const session = sessions.sessions[agentId];
199
- if (session === undefined
200
- || identity(session.nativeSessionId) === undefined
201
- || identity(session.launchId) === undefined
202
- || session.status === "ended"
203
- || session.adapterId !== adapterId
204
- || (explicitAssertion === undefined && session.launchId !== launchId))
205
- return undefined;
206
- if (env.YUI_NATIVE_SESSION_ID !== undefined
207
- && env.YUI_NATIVE_SESSION_ID !== session.nativeSessionId)
208
- return undefined;
209
- return run.id;
210
- }
211
- function leaderActionAssertion(environment) {
212
- const turnId = environment[LEADER_ACTION_RUN_ENV];
213
- const receiptId = environment[LEADER_ACTION_RECEIPT_ENV];
214
- if (turnId === undefined && receiptId === undefined)
215
- return undefined;
216
- const normalizedTurnId = identity(turnId);
217
- const normalizedReceiptId = identity(receiptId);
218
- return normalizedTurnId === undefined || normalizedReceiptId === undefined
219
- ? "invalid"
220
- : { turnId: normalizedTurnId, receiptId: normalizedReceiptId };
221
- }
222
- function identity(value) {
223
- if (typeof value !== "string" || value.includes("\0"))
224
- return undefined;
225
- const normalized = value.trim();
226
- return normalized.length === 0 || normalized !== value ? undefined : normalized;
127
+ export function taskLeaderActionTurnId(store, taskId, environment) {
128
+ return currentManagedRuntime(store, environment, taskId, LEADER_ROLE)?.currentTurnId;
227
129
  }
@@ -46,8 +46,6 @@ function renderChangeSet(changeSet) {
46
46
  `Created: ${changeSet.createdAt}`
47
47
  ];
48
48
  const manifest = changeSet.manifest;
49
- lines.push("Manifest:", ` Tags: ${manifest.tags.join(", ")}`, ` Deleted paths: ${manifest.deletedPaths.length}`, ...manifest.deletedPaths.map((path) => ` ${path}`), ` Target: ${manifest.targetRef ?? "-"}`, ` Evidence: ${manifest.evidenceRefs.length === 0
50
- ? "-"
51
- : manifest.evidenceRefs.join(", ")}`);
49
+ lines.push("Manifest:", ` Tags: ${manifest.tags.join(", ")}`, ` Deleted paths: ${manifest.deletedPaths.length}`, ...manifest.deletedPaths.map((path) => ` ${path}`), ` Target: ${manifest.targetRef ?? "-"}`);
52
50
  return `${lines.join("\n")}\n`;
53
51
  }