@zq-silk/yui 0.6.0 → 0.6.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.
- package/README.md +5 -5
- package/dist/agent/managedRuntimeEnvironment.js +2 -1
- package/dist/cli/commandCatalog.js +251 -13
- package/dist/cli/updateOrchestrator.js +8 -0
- package/dist/cli/updatePorts.js +76 -22
- package/dist/cli.js +264 -20
- package/dist/commands/configCommands.js +83 -9
- package/dist/commands/controllerCommands.js +103 -0
- package/dist/commands/deliveryGuardPreflight.js +30 -0
- package/dist/commands/durableJobCommands.js +231 -0
- package/dist/commands/executionAuditCommands.js +193 -0
- package/dist/commands/grantCommands.js +374 -0
- package/dist/commands/projectCommands.js +119 -81
- package/dist/commands/releaseCommands.js +444 -0
- package/dist/commands/resourcesCommands.js +274 -0
- package/dist/commands/sessionCommands.js +104 -0
- package/dist/commands/taskActor.js +117 -0
- package/dist/commands/taskChangeSetCommands.js +60 -0
- package/dist/commands/taskCommands.js +618 -202
- package/dist/commands/taskCompletionGate.js +78 -1
- package/dist/commands/taskContextCommand.js +33 -6
- package/dist/commands/taskInputCommands.js +1 -1
- package/dist/commands/taskIntegrationCommands.js +136 -33
- package/dist/commands/taskIntegrationQueueCommands.js +228 -0
- package/dist/commands/taskNextActionCommand.js +100 -0
- package/dist/commands/taskOverlapCommands.js +120 -0
- package/dist/commands/taskOverviewCommand.js +36 -8
- package/dist/commands/telemetryCommands.js +330 -0
- package/dist/commands/workflowCommands.js +415 -0
- package/dist/config/yuiConfig.js +62 -0
- package/dist/controller/clientRuntime.js +42 -1
- package/dist/controller/controller.js +402 -56
- package/dist/controller/controllerMain.js +25 -2
- package/dist/controller/domainIdentity.js +16 -8
- package/dist/controller/fileSchedulerStoreAdapter.js +423 -31
- package/dist/controller/handoverCandidate.js +168 -0
- package/dist/controller/jobClient.js +102 -0
- package/dist/controller/jobControl.js +613 -0
- package/dist/controller/jobSupervisor.js +498 -0
- package/dist/controller/providerHookRunFence.js +34 -5
- package/dist/controller/resourceCleanupLinux.js +18 -9
- package/dist/controller/resourceInventoryLinux.js +90 -39
- package/dist/controller/runtime.js +165 -15
- package/dist/controller/runtimeEventInbox.js +234 -57
- package/dist/controller/runtimeEventProcessor.js +297 -58
- package/dist/controller/sessionOwnerReconciliation.js +321 -0
- package/dist/core/controllerServer.js +416 -27
- package/dist/core/controllerTelemetry.js +167 -0
- package/dist/doctor/doctor.js +113 -16
- package/dist/domain/validation.js +9 -0
- package/dist/execution/executionGroup.js +40 -3
- package/dist/executor/agentExecutor.js +6 -3
- package/dist/executor/effectiveLaunch.js +52 -0
- package/dist/executor/executorRegistry.js +50 -0
- package/dist/executor/fileRoleLaunchPlanner.js +61 -6
- package/dist/grant/capabilityGrant.js +282 -0
- package/dist/integration/changeSet.js +16 -3
- package/dist/integration/changeSetManifest.js +46 -0
- package/dist/integration/gitIntegrationService.js +528 -147
- package/dist/integration/integrationAttempt.js +54 -5
- package/dist/integration/integrationQueueEntry.js +221 -0
- package/dist/integration/integrationQueueService.js +955 -0
- package/dist/integration/manifestTags.js +99 -0
- package/dist/integration/overlapDiagnostics.js +211 -0
- package/dist/job/durableJob.js +449 -0
- package/dist/job/jobRunner.js +350 -0
- package/dist/lifecycle/exactRunTerminalization.js +24 -2
- package/dist/lifecycle/providerErrorClass.js +126 -0
- package/dist/message/message.js +16 -3
- package/dist/observability/executionAudit.js +545 -0
- package/dist/observability/faultClassification.js +160 -0
- package/dist/observability/runtimeIdentity.js +367 -0
- package/dist/release/fakeReleasePorts.js +55 -0
- package/dist/release/releaseHandover.js +475 -0
- package/dist/release/releaseIdempotencyStore.js +165 -0
- package/dist/release/releaseWorkflow.js +459 -0
- package/dist/release/releaseWorkflowEngine.js +688 -0
- package/dist/release/releaseWorkflowPorts.js +1720 -0
- package/dist/release/runtimeRelease.js +495 -0
- package/dist/release/workflowFileLock.js +218 -0
- package/dist/repository/gitWorkspace.js +177 -1
- package/dist/repository/projectMaintenanceLock.js +315 -0
- package/dist/repository/taskWorkspaceCoordinator.js +87 -17
- package/dist/repository/taskWorkspacePreparer.js +1091 -517
- package/dist/resources/autoResourceGc.js +116 -0
- package/dist/resources/liveReferences.js +574 -0
- package/dist/resources/resourceDiscovery.js +477 -0
- package/dist/resources/resourceGc.js +645 -0
- package/dist/resources/resourceRegistrar.js +256 -0
- package/dist/resources/resourceRegistry.js +150 -0
- package/dist/resources/resourceRegistryStore.js +41 -0
- package/dist/resources/resourceTypes.js +42 -0
- package/dist/resources/sqliteResourceRegistry.js +111 -0
- package/dist/review/reviewConfig.js +10 -0
- package/dist/review/reviewFinding.js +240 -0
- package/dist/review/reviewFindingLedger.js +545 -0
- package/dist/review/reviewOutcomeClassifier.js +61 -0
- package/dist/review/reviewRound.js +56 -4
- package/dist/run/agentRun.js +80 -4
- package/dist/run/providerRetry.js +84 -0
- package/dist/run/providerRetryConfig.js +63 -0
- package/dist/run/yieldReceipt.js +65 -0
- package/dist/runtime/exactControlPlane.js +79 -2
- package/dist/runtime/index.js +4 -0
- package/dist/runtime/sessionOwnerIdentity.js +269 -0
- package/dist/runtime/sessionOwnerRegistry.js +132 -0
- package/dist/runtime/sessionReconciliation.js +93 -0
- package/dist/runtime/sessionTerminationGuard.js +211 -0
- package/dist/runtime/taskRuntimeIsolation.js +13 -0
- package/dist/runtime/tmuxAdapters.js +34 -1
- package/dist/scheduler/actionability.js +155 -0
- package/dist/scheduler/activeRoleRunDelivery.js +14 -5
- package/dist/scheduler/activeTaskProgress.js +60 -0
- package/dist/scheduler/leaderWakeupProcessor.js +22 -11
- package/dist/scheduler/roleRunStall.js +135 -29
- package/dist/scheduler/taskExecutionProjection.js +11 -0
- package/dist/storage/compatibleTaskStore.js +112 -5
- package/dist/storage/migration/productionRegistry.js +736 -1
- package/dist/storage/sqliteSchema.js +264 -3
- package/dist/storage/sqliteStore.js +487 -13
- package/dist/storage/storeRpc.js +21 -0
- package/dist/storage/taskStore.js +974 -21
- package/dist/storage/upgrade/homeClassification.js +120 -2
- package/dist/storage/upgrade/migrationReceipt.js +67 -0
- package/dist/storage/upgrade/pseudoLayoutRepair.js +241 -0
- package/dist/storage/upgrade/recordVersions.js +10 -1
- package/dist/storage/upgrade/sqliteMigrationTarget.js +58 -6
- package/dist/storage/upgrade/sqliteRecordMigrationTarget.js +290 -0
- package/dist/storage/upgrade/sqliteStateMigration.js +258 -2
- package/dist/storage/upgrade/upgradeOrchestrator.js +482 -16
- package/dist/task/deliveryGuard.js +226 -0
- package/dist/task/nextAction.js +738 -0
- package/dist/task/repairWave.js +137 -0
- package/dist/task/taskRecordReference.js +6 -1
- package/dist/telemetry/sqliteTelemetryStore.js +387 -0
- package/dist/telemetry/telemetryCompaction.js +251 -0
- package/dist/telemetry/telemetryConfig.js +64 -0
- package/dist/telemetry/telemetryRouter.js +32 -0
- package/dist/telemetry/telemetryStore.js +19 -0
- package/dist/telemetry/telemetryWiring.js +33 -0
- package/dist/tmux/tmuxManager.js +20 -1
- package/dist/tmux/tmuxSocketEndpoint.js +20 -0
- package/dist/verification/gateArtifact.js +216 -0
- package/dist/verification/gateArtifactStore.js +87 -0
- package/dist/verification/verificationGateService.js +414 -0
- package/dist/verification/verificationPlan.js +308 -0
- package/dist/workspace/gitChangeSetCapture.js +12 -2
- package/dist/workspace/workItemChangeSetManager.js +60 -3
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +8 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { createTaskEvent } from "../event/taskEvent.js";
|
|
4
|
+
import { createSessionOwnerIdentity, discoverProviderRootByLaunchEnv, isLinuxProcessLive, listLaunchFencedProcesses, listOwnedProcessTree, readLinuxProcessIdentity, reconcileSessionOwners, terminateSessionOwners } from "../runtime/index.js";
|
|
5
|
+
import { tmuxSocketDirectory } from "../tmux/tmuxSocketEndpoint.js";
|
|
6
|
+
import { yuiTmuxServerName, yuiTmuxSessionName, yuiTmuxTarget } from "../tmux/tmuxManager.js";
|
|
7
|
+
/**
|
|
8
|
+
* Production I/O adapters for Issue 03 Session owner reconciliation. The pure
|
|
9
|
+
* logic lives in src/runtime; this module only binds it to the durable store,
|
|
10
|
+
* /proc, and the exact tmux namespace of one Home.
|
|
11
|
+
*/
|
|
12
|
+
export class SessionOwnerReconciliation {
|
|
13
|
+
#home;
|
|
14
|
+
#store;
|
|
15
|
+
#environment;
|
|
16
|
+
#tmux;
|
|
17
|
+
#onWarning;
|
|
18
|
+
constructor(deps) {
|
|
19
|
+
this.#home = deps.home;
|
|
20
|
+
this.#store = deps.store;
|
|
21
|
+
this.#environment = deps.environment ?? process.env;
|
|
22
|
+
this.#tmux = deps.tmux;
|
|
23
|
+
this.#onWarning = deps.onWarning ?? (() => undefined);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Persists the exact physical owner identity after a host created a new
|
|
27
|
+
* Provider process. The Provider root is attributed by the exact
|
|
28
|
+
* YUI_LAUNCH_ID environment fence; the tmux pane PID is only a weaker
|
|
29
|
+
* fallback when the fence cannot be read.
|
|
30
|
+
*/
|
|
31
|
+
recordHostOwner(input) {
|
|
32
|
+
const discovered = discoverProviderRootByLaunchEnv(input.launchId);
|
|
33
|
+
const fallback = discovered === undefined && input.panePid !== undefined
|
|
34
|
+
? readLinuxProcessIdentity(input.panePid)
|
|
35
|
+
: undefined;
|
|
36
|
+
const root = discovered ?? (fallback === undefined
|
|
37
|
+
? undefined
|
|
38
|
+
: { pid: fallback.pid, identity: fallback });
|
|
39
|
+
if (root === undefined) {
|
|
40
|
+
this.#onWarning(`Session owner identity could not attribute a Provider root for launch ${input.launchId}; `
|
|
41
|
+
+ "no owner record was written.");
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const owner = input.owner;
|
|
45
|
+
const taskId = owner.scope === "task" ? owner.taskId : undefined;
|
|
46
|
+
this.#store.saveSessionOwner(createSessionOwnerIdentity({
|
|
47
|
+
owner: {
|
|
48
|
+
scope: owner.scope,
|
|
49
|
+
...(taskId === undefined ? {} : { taskId }),
|
|
50
|
+
roleName: owner.roleName
|
|
51
|
+
},
|
|
52
|
+
agentId: input.agentId,
|
|
53
|
+
adapterId: input.adapterId,
|
|
54
|
+
launchId: input.launchId,
|
|
55
|
+
...(input.nativeSessionId === undefined
|
|
56
|
+
? {}
|
|
57
|
+
: { nativeSessionId: input.nativeSessionId }),
|
|
58
|
+
tmux: {
|
|
59
|
+
serverName: yuiTmuxServerName(this.#home),
|
|
60
|
+
socketPath: join(tmuxSocketDirectory(this.#environment), yuiTmuxServerName(this.#home)),
|
|
61
|
+
sessionName: owner.scope === "task"
|
|
62
|
+
? yuiTmuxSessionName(this.#home, owner.taskId)
|
|
63
|
+
: yuiTmuxSessionName(this.#home, "operator"),
|
|
64
|
+
windowName: owner.roleName,
|
|
65
|
+
...(input.panePid === undefined ? {} : { panePid: input.panePid })
|
|
66
|
+
},
|
|
67
|
+
providerRoot: {
|
|
68
|
+
pid: root.pid,
|
|
69
|
+
startIdentity: root.identity.startIdentity,
|
|
70
|
+
...(root.identity.processGroupId === undefined
|
|
71
|
+
? {}
|
|
72
|
+
: { processGroupId: root.identity.processGroupId }),
|
|
73
|
+
...(root.identity.processSessionId === undefined
|
|
74
|
+
? {}
|
|
75
|
+
: { processSessionId: root.identity.processSessionId }),
|
|
76
|
+
attribution: discovered === undefined ? "pane-pid" : "launch-env"
|
|
77
|
+
},
|
|
78
|
+
...(input.runtimeRoot === undefined ? {} : { runtimeRoot: input.runtimeRoot }),
|
|
79
|
+
recordedAt: new Date()
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
/** Read-only bidirectional reconciliation; never mutates physical state. */
|
|
83
|
+
report() {
|
|
84
|
+
return reconcileSessionOwners({
|
|
85
|
+
records: this.#store.listSessionOwners(),
|
|
86
|
+
durable: durableSessionFacts(this.#store),
|
|
87
|
+
taskStatus: (taskId) => this.#store.getTask(taskId)?.status,
|
|
88
|
+
observe: (record) => observeSessionOwnerPhysical(record),
|
|
89
|
+
inspectPane: (taskId, roleName) => {
|
|
90
|
+
if (this.#tmux === undefined || taskId === undefined)
|
|
91
|
+
return undefined;
|
|
92
|
+
try {
|
|
93
|
+
const pane = this.#tmux.inspectPane(taskId, roleName);
|
|
94
|
+
return { target: pane.target, dead: pane.dead };
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
lastStopOutcome: (taskId, roleName, launchId) => (lastSessionTerminationOutcome(this.#store, taskId, roleName, launchId)),
|
|
101
|
+
now: new Date()
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Stops one owner with physical exit proof. Removes the owner records only
|
|
106
|
+
* after every root is proven absent; a blocked result preserves them.
|
|
107
|
+
*/
|
|
108
|
+
async terminateOwner(owner, options = {}) {
|
|
109
|
+
const records = this.#store.listSessionOwnersForOwner(owner);
|
|
110
|
+
const ports = {
|
|
111
|
+
gracefulStop: async (target) => {
|
|
112
|
+
if (this.#tmux === undefined)
|
|
113
|
+
return false;
|
|
114
|
+
const hostId = target.scope === "task" ? target.taskId : "operator";
|
|
115
|
+
try {
|
|
116
|
+
this.#tmux.killRole(hostId, target.roleName);
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return this.#tmux.probeRoleStatus(hostId, target.roleName) === "exited";
|
|
120
|
+
}
|
|
121
|
+
return this.#tmux.probeRoleStatus(hostId, target.roleName) === "exited";
|
|
122
|
+
},
|
|
123
|
+
processIdentity: readLinuxProcessIdentity,
|
|
124
|
+
procEntryExists: (pid) => {
|
|
125
|
+
try {
|
|
126
|
+
return existsSync(`/proc/${pid}`);
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
listLaunchFencedProcesses: (launchId) => listLaunchFencedProcesses(launchId),
|
|
133
|
+
signalProcess: (pid, signal) => process.kill(pid, signal),
|
|
134
|
+
signalProcessGroup: (processGroupId, signal) => {
|
|
135
|
+
try {
|
|
136
|
+
process.kill(-processGroupId, signal);
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
if (error.code !== "ESRCH")
|
|
140
|
+
throw error;
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
sleep: (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)),
|
|
144
|
+
emit: (event) => this.#recordTerminationEvent(event),
|
|
145
|
+
now: () => new Date()
|
|
146
|
+
};
|
|
147
|
+
const result = await terminateSessionOwners(owner, records, ports, options);
|
|
148
|
+
if (result.outcome === "stop-confirmed") {
|
|
149
|
+
for (const record of result.confirmed) {
|
|
150
|
+
this.#store.removeSessionOwner(record.launchId);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
#recordTerminationEvent(event) {
|
|
156
|
+
const owner = event.owner;
|
|
157
|
+
if (owner.scope !== "task")
|
|
158
|
+
return;
|
|
159
|
+
try {
|
|
160
|
+
this.#store.saveEvent(owner.taskId, createTaskEvent(this.#store.nextEventId(owner.taskId), owner.taskId, "runtime.session-termination", {
|
|
161
|
+
roleName: owner.roleName,
|
|
162
|
+
launchId: event.launchId ?? "",
|
|
163
|
+
nativeSessionId: event.nativeSessionId ?? "",
|
|
164
|
+
outcome: event.stage,
|
|
165
|
+
...(event.detail === undefined ? {} : { detail: event.detail })
|
|
166
|
+
}, event.at));
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
this.#onWarning(`Session termination event could not be persisted: ${error instanceof Error ? error.message : String(error)}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/** Projects every durable Role session generation for reconciliation. */
|
|
174
|
+
export function durableSessionFacts(store) {
|
|
175
|
+
const facts = [];
|
|
176
|
+
for (const task of store.listTasks()) {
|
|
177
|
+
for (const set of store.listRoleSessionSets(task.id)) {
|
|
178
|
+
for (const [agentId, session] of Object.entries(set.sessions)) {
|
|
179
|
+
facts.push({
|
|
180
|
+
scope: "task",
|
|
181
|
+
taskId: task.id,
|
|
182
|
+
roleName: set.owner.roleName,
|
|
183
|
+
agentId,
|
|
184
|
+
adapterId: session.adapterId,
|
|
185
|
+
...(session.launchId === undefined ? {} : { launchId: session.launchId }),
|
|
186
|
+
...(session.nativeSessionId === undefined
|
|
187
|
+
? {}
|
|
188
|
+
: { nativeSessionId: session.nativeSessionId }),
|
|
189
|
+
status: session.status,
|
|
190
|
+
inHistory: false
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
for (const history of set.history ?? []) {
|
|
194
|
+
facts.push({
|
|
195
|
+
scope: "task",
|
|
196
|
+
taskId: task.id,
|
|
197
|
+
roleName: set.owner.roleName,
|
|
198
|
+
agentId: history.agentId,
|
|
199
|
+
adapterId: history.adapterId,
|
|
200
|
+
...(history.launchId === undefined ? {} : { launchId: history.launchId }),
|
|
201
|
+
...(history.nativeSessionId === undefined
|
|
202
|
+
? {}
|
|
203
|
+
: { nativeSessionId: history.nativeSessionId }),
|
|
204
|
+
status: history.status,
|
|
205
|
+
inHistory: true
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
for (const set of store.listGlobalRoleSessionSets()) {
|
|
211
|
+
for (const [agentId, session] of Object.entries(set.sessions)) {
|
|
212
|
+
facts.push({
|
|
213
|
+
scope: "global",
|
|
214
|
+
roleName: set.owner.roleName,
|
|
215
|
+
agentId,
|
|
216
|
+
adapterId: session.adapterId,
|
|
217
|
+
...(session.launchId === undefined ? {} : { launchId: session.launchId }),
|
|
218
|
+
...(session.nativeSessionId === undefined
|
|
219
|
+
? {}
|
|
220
|
+
: { nativeSessionId: session.nativeSessionId }),
|
|
221
|
+
status: session.status,
|
|
222
|
+
inHistory: false
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
const history = set.history;
|
|
226
|
+
for (const session of Object.values(history ?? {})) {
|
|
227
|
+
facts.push({
|
|
228
|
+
scope: "global",
|
|
229
|
+
roleName: set.owner.roleName,
|
|
230
|
+
agentId: session.agentId,
|
|
231
|
+
adapterId: session.adapterId,
|
|
232
|
+
...(session.launchId === undefined ? {} : { launchId: session.launchId }),
|
|
233
|
+
...(session.nativeSessionId === undefined
|
|
234
|
+
? {}
|
|
235
|
+
: { nativeSessionId: session.nativeSessionId }),
|
|
236
|
+
status: session.status,
|
|
237
|
+
inHistory: true
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return facts;
|
|
242
|
+
}
|
|
243
|
+
/** /proc observation for one owner record; undefined is a verification gap. */
|
|
244
|
+
export function observeSessionOwnerPhysical(record) {
|
|
245
|
+
const { pid, startIdentity } = record.providerRoot;
|
|
246
|
+
const current = readLinuxProcessIdentity(pid);
|
|
247
|
+
if (current === undefined) {
|
|
248
|
+
return {
|
|
249
|
+
alive: false,
|
|
250
|
+
identityConflict: false,
|
|
251
|
+
pid,
|
|
252
|
+
startIdentity,
|
|
253
|
+
rssBytes: 0,
|
|
254
|
+
ageMs: 0,
|
|
255
|
+
childCount: 0
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
if (current.startIdentity !== startIdentity) {
|
|
259
|
+
// PID reuse: the slot is live but it is a different process. Never kill.
|
|
260
|
+
return {
|
|
261
|
+
alive: false,
|
|
262
|
+
identityConflict: true,
|
|
263
|
+
pid,
|
|
264
|
+
startIdentity,
|
|
265
|
+
rssBytes: current.rssBytes,
|
|
266
|
+
ageMs: 0,
|
|
267
|
+
childCount: 0
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
if (current.state === "Z") {
|
|
271
|
+
// Zombie: the process has exited and only the unreaped task struct
|
|
272
|
+
// remains. It cannot execute or hold resources, so it is not alive.
|
|
273
|
+
return {
|
|
274
|
+
alive: false,
|
|
275
|
+
identityConflict: false,
|
|
276
|
+
pid,
|
|
277
|
+
startIdentity,
|
|
278
|
+
rssBytes: 0,
|
|
279
|
+
ageMs: 0,
|
|
280
|
+
childCount: 0
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
const tree = listOwnedProcessTree(pid, current.processGroupId);
|
|
284
|
+
return {
|
|
285
|
+
alive: true,
|
|
286
|
+
identityConflict: false,
|
|
287
|
+
pid,
|
|
288
|
+
startIdentity,
|
|
289
|
+
rssBytes: current.rssBytes,
|
|
290
|
+
ageMs: 0,
|
|
291
|
+
childCount: Math.max(0, tree.length - 1)
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
/** Reads the latest termination outcome recorded for one generation. */
|
|
295
|
+
export function lastSessionTerminationOutcome(store, taskId, roleName, launchId) {
|
|
296
|
+
if (taskId === undefined)
|
|
297
|
+
return undefined;
|
|
298
|
+
let latest;
|
|
299
|
+
for (const event of store.listEvents(taskId)) {
|
|
300
|
+
if (event.type !== "runtime.session-termination")
|
|
301
|
+
continue;
|
|
302
|
+
if (event.payload.roleName !== roleName)
|
|
303
|
+
continue;
|
|
304
|
+
if (launchId !== ""
|
|
305
|
+
&& event.payload.launchId !== undefined
|
|
306
|
+
&& event.payload.launchId !== ""
|
|
307
|
+
&& event.payload.launchId !== launchId) {
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
latest = event.payload.outcome;
|
|
311
|
+
}
|
|
312
|
+
return latest;
|
|
313
|
+
}
|
|
314
|
+
/** True when one owner record's Provider root is still the exact live process. */
|
|
315
|
+
export function ownerRootIsLive(record) {
|
|
316
|
+
return isLinuxProcessLive(record.providerRoot.pid, record.providerRoot.startIdentity);
|
|
317
|
+
}
|
|
318
|
+
/** Exact tmux target for one owner, for reports and diagnostics. */
|
|
319
|
+
export function ownerTmuxTarget(home, owner) {
|
|
320
|
+
return yuiTmuxTarget(home, owner.scope === "task" ? owner.taskId : "operator", owner.roleName);
|
|
321
|
+
}
|