@zq-silk/yui 0.6.16 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commandCatalog.js +3 -7
- package/dist/cli.js +12 -33
- package/dist/commands/executionAuditCommands.js +19 -0
- package/dist/commands/globalRoleCommands.js +70 -0
- package/dist/commands/taskActor.js +3 -2
- package/dist/commands/taskCommands.js +160 -41
- package/dist/commands/taskContextCommand.js +1 -1
- package/dist/commands/taskInputCommands.js +3 -2
- package/dist/commands/taskRoleRuntimeStatus.js +3 -3
- package/dist/context/contextSnapshot.js +228 -0
- package/dist/context/roleSessionContext.js +3 -1
- package/dist/context/runContextContract.js +162 -0
- package/dist/context/runContextPack.js +322 -0
- package/dist/context/sessionBootstrapManifest.js +81 -0
- package/dist/context/sessionProtocolIdentity.js +23 -0
- package/dist/controller/agentRuntimeObserver.js +6 -1
- package/dist/controller/controller.js +4 -3
- package/dist/controller/fileSchedulerStoreAdapter.js +446 -145
- package/dist/controller/jobControl.js +2 -1
- package/dist/controller/runtime.js +83 -0
- package/dist/controller/runtimeHookRunFence.js +6 -2
- package/dist/controller/sessionOwnerReconciliation.js +5 -0
- package/dist/coordination/workMailbox.js +25 -22
- package/dist/executor/agentAdapter.js +7 -2
- package/dist/executor/agentExecutor.js +23 -0
- package/dist/executor/effectiveLaunch.js +24 -0
- package/dist/executor/executorRegistry.js +7 -1
- package/dist/executor/fileRoleLaunchPlanner.js +73 -27
- package/dist/lifecycle/exactRunTerminalization.js +2 -3
- package/dist/lifecycle/providerErrorClass.js +8 -3
- package/dist/observability/executionAudit.js +87 -2
- package/dist/repository/taskWorkspacePreparer.js +2 -2
- package/dist/run/agentRun.js +101 -16
- package/dist/run/providerRetry.js +167 -56
- package/dist/run/providerRetryConfig.js +5 -1
- package/dist/run/runControlRequest.js +50 -0
- package/dist/runtime/agentDriver.js +47 -0
- package/dist/runtime/agentHost.js +327 -0
- package/dist/runtime/builtinAgentDrivers.js +23 -1
- package/dist/runtime/builtinTranscriptObserver.js +4 -0
- package/dist/runtime/builtinTranscriptUsage.js +2 -0
- package/dist/runtime/exactControlPlane.js +2 -2
- package/dist/runtime/globalProcessExitStore.js +38 -0
- package/dist/runtime/launchBroker.js +95 -0
- package/dist/runtime/processExitObservation.js +60 -0
- package/dist/runtime/runtimeBinding.js +6 -0
- package/dist/runtime/runtimeObservation.js +27 -6
- package/dist/runtime/runtimeProjection.js +6 -3
- package/dist/runtime/runtimeStopReceipt.js +42 -0
- package/dist/runtime/sessionTerminationGuard.js +13 -0
- package/dist/runtime/tmuxAdapters.js +203 -220
- package/dist/scheduler/activeRoleRunDelivery.js +24 -3
- package/dist/scheduler/leaderWakeupProcessor.js +18 -60
- package/dist/scheduler/roleRunLiveness.js +61 -27
- package/dist/storage/migration/productionRegistry.js +264 -0
- package/dist/storage/sqliteSchema.js +23 -2
- package/dist/storage/sqliteStore.js +48 -4
- package/dist/storage/taskStore.js +54 -5
- package/dist/storage/upgrade/recordVersions.js +3 -1
- package/dist/storage/upgrade/sqliteStateMigration.js +10 -0
- package/dist/task/taskRecordReference.js +1 -0
- package/dist/tmux/tmuxManager.js +15 -4
- package/dist/web/assets/client/components.js +1 -1
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +10 -5
- package/skills/yui-operator/SKILL.md +4 -0
- package/skills/yui-reviewer/SKILL.md +4 -0
- package/skills/yui-runtime/SKILL.md +61 -0
- package/skills/yui-worker/SKILL.md +82 -218
- package/dist/executor/managedClaudeRunner.js +0 -121
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export const RUNTIME_PROCESS_EXIT_SCHEMA_VERSION = 1;
|
|
2
|
+
export function validateRuntimeProcessExitObservation(observation) {
|
|
3
|
+
if (observation.schemaVersion !== RUNTIME_PROCESS_EXIT_SCHEMA_VERSION) {
|
|
4
|
+
throw new Error("Runtime process-exit observation version is invalid.");
|
|
5
|
+
}
|
|
6
|
+
identity(observation.observationId, "observationId");
|
|
7
|
+
identity(observation.hostInstanceId, "hostInstanceId");
|
|
8
|
+
optionalIdentity(observation.providerProcessInstanceId, "providerProcessInstanceId");
|
|
9
|
+
optionalIdentity(observation.taskId, "taskId");
|
|
10
|
+
identity(observation.roleName, "roleName");
|
|
11
|
+
optionalIdentity(observation.runId, "runId");
|
|
12
|
+
identity(observation.launchId, "launchId");
|
|
13
|
+
optionalIdentity(observation.nativeSessionId, "nativeSessionId");
|
|
14
|
+
if (observation.processKind !== "agent-host" && observation.processKind !== "provider-child") {
|
|
15
|
+
throw new Error("Runtime process kind is invalid.");
|
|
16
|
+
}
|
|
17
|
+
if (!Number.isSafeInteger(observation.hostSequence) || observation.hostSequence < 1) {
|
|
18
|
+
throw new Error("Runtime host sequence is invalid.");
|
|
19
|
+
}
|
|
20
|
+
if (observation.exitCode !== undefined
|
|
21
|
+
&& (!Number.isSafeInteger(observation.exitCode) || observation.exitCode < 0)) {
|
|
22
|
+
throw new Error("Runtime process exit code is invalid.");
|
|
23
|
+
}
|
|
24
|
+
optionalIdentity(observation.signal, "signal");
|
|
25
|
+
if (!Number.isFinite(Date.parse(observation.observedAt))) {
|
|
26
|
+
throw new Error("Runtime process observedAt is invalid.");
|
|
27
|
+
}
|
|
28
|
+
optionalIdentity(observation.stopReceiptId, "stopReceiptId");
|
|
29
|
+
optionalIdentity(observation.lastProviderEventId, "lastProviderEventId");
|
|
30
|
+
optionalIdentity(observation.diagnosticTailRef, "diagnosticTailRef");
|
|
31
|
+
return Object.freeze({ ...observation });
|
|
32
|
+
}
|
|
33
|
+
export function classifyRuntimeProcessExit(observation, input) {
|
|
34
|
+
validateRuntimeProcessExitObservation(observation);
|
|
35
|
+
if (observation.stopReceiptId !== undefined)
|
|
36
|
+
return "yui-requested-stop";
|
|
37
|
+
if (observation.processKind === "provider-child" && input.turnFailureObserved === true) {
|
|
38
|
+
return "provider-turn-failed";
|
|
39
|
+
}
|
|
40
|
+
if (observation.processKind === "provider-child"
|
|
41
|
+
&& input.childLifecycle === "per-turn"
|
|
42
|
+
&& observation.exitCode === 0
|
|
43
|
+
&& input.turnTerminalObserved === true) {
|
|
44
|
+
return "expected-per-turn-exit";
|
|
45
|
+
}
|
|
46
|
+
if ((observation.exitCode !== undefined && observation.exitCode !== 0)
|
|
47
|
+
|| observation.signal !== undefined) {
|
|
48
|
+
return "host-abnormal";
|
|
49
|
+
}
|
|
50
|
+
return "unknown";
|
|
51
|
+
}
|
|
52
|
+
function identity(value, label) {
|
|
53
|
+
if (typeof value !== "string" || value.trim().length === 0 || value.includes("\0")) {
|
|
54
|
+
throw new Error(`Runtime process ${label} is invalid.`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function optionalIdentity(value, label) {
|
|
58
|
+
if (value !== undefined)
|
|
59
|
+
identity(value, label);
|
|
60
|
+
}
|
|
@@ -10,6 +10,9 @@ export function createRuntimeBinding(input) {
|
|
|
10
10
|
if (initialPromptRunId !== undefined && hostCreated !== true) {
|
|
11
11
|
throw new TypeError("An initial prompt Run id requires a newly-created runtime host.");
|
|
12
12
|
}
|
|
13
|
+
const launchPromptUncertainRunId = input.launchPromptUncertainRunId === undefined
|
|
14
|
+
? undefined
|
|
15
|
+
: requireSafeIdentity(input.launchPromptUncertainRunId, "Uncertain launch prompt Run id");
|
|
13
16
|
return {
|
|
14
17
|
id: requireSafeIdentity(input.id, "Runtime binding id"),
|
|
15
18
|
launchId: requireSafeIdentity(input.launchId, "Launch id"),
|
|
@@ -19,6 +22,9 @@ export function createRuntimeBinding(input) {
|
|
|
19
22
|
hostRef: requireText(input.hostRef, "Session host reference"),
|
|
20
23
|
...(hostCreated === undefined ? {} : { hostCreated }),
|
|
21
24
|
...(initialPromptRunId === undefined ? {} : { initialPromptRunId }),
|
|
25
|
+
...(launchPromptUncertainRunId === undefined
|
|
26
|
+
? {}
|
|
27
|
+
: { launchPromptUncertainRunId }),
|
|
22
28
|
...(input.nativeSessionId === undefined
|
|
23
29
|
? {}
|
|
24
30
|
: { nativeSessionId: requireText(input.nativeSessionId, "Native session id") })
|
|
@@ -274,8 +274,12 @@ function normalizePayload(kind, input) {
|
|
|
274
274
|
if (!["model", "tool", "subagent", "provider", "resource"].includes(input.activity ?? "")) {
|
|
275
275
|
throw new Error("activity.observed requires an activity kind.");
|
|
276
276
|
}
|
|
277
|
-
if (input.usage !== undefined)
|
|
278
|
-
|
|
277
|
+
if (input.usage !== undefined) {
|
|
278
|
+
const usage = input.usage;
|
|
279
|
+
validateUsage(usage.semantics === undefined
|
|
280
|
+
? { ...usage, semantics: "cumulative-session" }
|
|
281
|
+
: usage);
|
|
282
|
+
}
|
|
279
283
|
}
|
|
280
284
|
if (kind === "observer.health") {
|
|
281
285
|
requireIdentity(input.sourceId, "Runtime observer source id");
|
|
@@ -339,7 +343,12 @@ function normalizePayload(kind, input) {
|
|
|
339
343
|
...(input.activityId === undefined
|
|
340
344
|
? {}
|
|
341
345
|
: { activityId: requireIdentity(input.activityId, "Runtime activity id") }),
|
|
342
|
-
...(input.usage === undefined
|
|
346
|
+
...(input.usage === undefined
|
|
347
|
+
? {}
|
|
348
|
+
: { usage: Object.freeze({
|
|
349
|
+
...input.usage,
|
|
350
|
+
semantics: input.usage.semantics ?? "cumulative-session"
|
|
351
|
+
}) }),
|
|
343
352
|
...(observerSource === undefined ? {} : { observerSource }),
|
|
344
353
|
...(input.sourceId === undefined
|
|
345
354
|
? {}
|
|
@@ -468,7 +477,10 @@ function normalizeFailure(input) {
|
|
|
468
477
|
: { lastOutput: requireText(input.lastOutput, "Runtime failure last output") }),
|
|
469
478
|
...(input.runTerminal === undefined
|
|
470
479
|
? {}
|
|
471
|
-
: { runTerminal: requireBoolean(input.runTerminal, "Runtime failure runTerminal") })
|
|
480
|
+
: { runTerminal: requireBoolean(input.runTerminal, "Runtime failure runTerminal") }),
|
|
481
|
+
...(input.retryAfterMs === undefined
|
|
482
|
+
? {}
|
|
483
|
+
: { retryAfterMs: requirePositiveMilliseconds(input.retryAfterMs) })
|
|
472
484
|
});
|
|
473
485
|
}
|
|
474
486
|
function requireBoolean(value, label) {
|
|
@@ -476,9 +488,18 @@ function requireBoolean(value, label) {
|
|
|
476
488
|
throw new Error(`${label} must be boolean.`);
|
|
477
489
|
return value;
|
|
478
490
|
}
|
|
491
|
+
function requirePositiveMilliseconds(value) {
|
|
492
|
+
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
493
|
+
throw new Error("Runtime failure retryAfterMs must be a positive safe integer.");
|
|
494
|
+
}
|
|
495
|
+
return value;
|
|
496
|
+
}
|
|
479
497
|
function validateUsage(input) {
|
|
480
|
-
|
|
481
|
-
|
|
498
|
+
if (!["cumulative-session", "request-context", "remaining-context"].includes(input.semantics)) {
|
|
499
|
+
throw new Error("Runtime usage semantics are invalid.");
|
|
500
|
+
}
|
|
501
|
+
for (const [name, value] of Object.entries(input).filter(([name]) => name !== "semantics")) {
|
|
502
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
482
503
|
throw new Error(`Runtime usage ${name} must be a non-negative safe integer.`);
|
|
483
504
|
}
|
|
484
505
|
}
|
|
@@ -489,10 +489,13 @@ function next(current, patch) {
|
|
|
489
489
|
});
|
|
490
490
|
}
|
|
491
491
|
function usageAdvanced(previous, current) {
|
|
492
|
+
if (current.semantics === "remaining-context")
|
|
493
|
+
return false;
|
|
494
|
+
if (current.semantics === "request-context")
|
|
495
|
+
return usageTotal(current) > 0;
|
|
492
496
|
// A first cumulative snapshot may contain history from a resumed native
|
|
493
|
-
// Session. It establishes
|
|
494
|
-
|
|
495
|
-
if (previous === undefined)
|
|
497
|
+
// Session. It establishes a baseline but cannot prove current progress.
|
|
498
|
+
if (previous === undefined || previous.semantics !== "cumulative-session")
|
|
496
499
|
return false;
|
|
497
500
|
return usageTotal(current) > usageTotal(previous);
|
|
498
501
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { chmodSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
|
+
export function writeRuntimeStopReceipt(home, launchId, requestedAt) {
|
|
5
|
+
const receipt = Object.freeze({
|
|
6
|
+
schemaVersion: 1,
|
|
7
|
+
receiptId: `runtime-stop-${createHash("sha256")
|
|
8
|
+
.update(`${launchId}\0${requestedAt.toISOString()}`)
|
|
9
|
+
.digest("hex")}`,
|
|
10
|
+
launchId,
|
|
11
|
+
requestedAt: requestedAt.toISOString()
|
|
12
|
+
});
|
|
13
|
+
const path = stopReceiptPath(home, launchId);
|
|
14
|
+
mkdirSync(resolve(join(home, "runtime", "stop-receipts")), { recursive: true, mode: 0o700 });
|
|
15
|
+
const temporary = `${path}.tmp-${process.pid}`;
|
|
16
|
+
writeFileSync(temporary, `${JSON.stringify(receipt)}\n`, { mode: 0o600 });
|
|
17
|
+
renameSync(temporary, path);
|
|
18
|
+
chmodSync(path, 0o600);
|
|
19
|
+
return receipt;
|
|
20
|
+
}
|
|
21
|
+
export function readRuntimeStopReceipt(home, launchId) {
|
|
22
|
+
try {
|
|
23
|
+
const value = JSON.parse(readFileSync(stopReceiptPath(home, launchId), "utf8"));
|
|
24
|
+
if (value.schemaVersion !== 1 || value.launchId !== launchId
|
|
25
|
+
|| typeof value.receiptId !== "string" || !Number.isFinite(Date.parse(value.requestedAt))) {
|
|
26
|
+
throw new Error("Runtime stop receipt is invalid.");
|
|
27
|
+
}
|
|
28
|
+
return Object.freeze({ ...value });
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
if (error.code === "ENOENT")
|
|
32
|
+
return null;
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export function removeRuntimeStopReceipt(home, launchId) {
|
|
37
|
+
rmSync(stopReceiptPath(home, launchId), { force: true });
|
|
38
|
+
}
|
|
39
|
+
function stopReceiptPath(home, launchId) {
|
|
40
|
+
const name = createHash("sha256").update(launchId).digest("hex");
|
|
41
|
+
return resolve(join(home, "runtime", "stop-receipts", `${name}.json`));
|
|
42
|
+
}
|
|
@@ -20,6 +20,19 @@ export async function terminateSessionOwners(owner, records, ports, options = {}
|
|
|
20
20
|
const pollMs = positiveDuration(options.pollMs, DEFAULT_TERMINATION_POLL_MS, "pollMs");
|
|
21
21
|
const now = ports.now();
|
|
22
22
|
ports.emit({ stage: "stop-requested", owner, at: now });
|
|
23
|
+
// Persist one exact launch receipt before any graceful stop can kill the
|
|
24
|
+
// Host. The owner-wide event remains for compatibility and summary display.
|
|
25
|
+
for (const record of records) {
|
|
26
|
+
ports.emit({
|
|
27
|
+
stage: "stop-requested",
|
|
28
|
+
owner,
|
|
29
|
+
launchId: record.launchId,
|
|
30
|
+
...(record.nativeSessionId === undefined
|
|
31
|
+
? {}
|
|
32
|
+
: { nativeSessionId: record.nativeSessionId }),
|
|
33
|
+
at: now
|
|
34
|
+
});
|
|
35
|
+
}
|
|
23
36
|
// A launch-fence scan is a point-in-time observation, not a durable owner
|
|
24
37
|
// inventory: /proc entries can disappear between the directory and
|
|
25
38
|
// environment reads. Retain every exact child identity observed during the
|