@zq-silk/yui 0.6.16 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/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 +39 -2
- 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
|
@@ -27,7 +27,7 @@ export const SQLITE_LAYOUT_VERSION = 7;
|
|
|
27
27
|
/** The aggregate version of the normalized SQLite schema. */
|
|
28
28
|
export const SQLITE_AGGREGATE_VERSION = 1;
|
|
29
29
|
/** The current schema migration version. */
|
|
30
|
-
export const SQLITE_SCHEMA_VERSION =
|
|
30
|
+
export const SQLITE_SCHEMA_VERSION = 17;
|
|
31
31
|
/** Telemetry retention bounds (§4.4). Open question 3 in §11; defaults from the design. */
|
|
32
32
|
export const TELEMETRY_KEEP_PER_GENERATION = 200;
|
|
33
33
|
export const TELEMETRY_RUN_CAP = 50_000;
|
|
@@ -911,6 +911,25 @@ CREATE TABLE IF NOT EXISTS task_wakes (
|
|
|
911
911
|
);
|
|
912
912
|
CREATE INDEX IF NOT EXISTS idx_task_wakes_seq ON task_wakes(task_id, seq);
|
|
913
913
|
`;
|
|
914
|
+
/** Migration 17: immutable, Task-scoped ContextSnapshot records. */
|
|
915
|
+
const MIGRATION_17_SQL = `
|
|
916
|
+
CREATE TABLE IF NOT EXISTS context_snapshots (
|
|
917
|
+
task_id TEXT NOT NULL,
|
|
918
|
+
snapshot_id TEXT NOT NULL,
|
|
919
|
+
scope TEXT NOT NULL CHECK (scope IN ('task','workitem','stage')),
|
|
920
|
+
scope_ref TEXT,
|
|
921
|
+
sequence INTEGER NOT NULL CHECK (sequence > 0),
|
|
922
|
+
digest TEXT NOT NULL CHECK (length(digest) = 64),
|
|
923
|
+
payload TEXT NOT NULL,
|
|
924
|
+
frozen_at TEXT NOT NULL,
|
|
925
|
+
PRIMARY KEY (task_id, snapshot_id),
|
|
926
|
+
FOREIGN KEY (task_id) REFERENCES tasks_catalog(task_id) ON DELETE CASCADE,
|
|
927
|
+
CHECK ((scope = 'task' AND scope_ref IS NULL) OR (scope <> 'task' AND scope_ref IS NOT NULL))
|
|
928
|
+
);
|
|
929
|
+
|
|
930
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_context_snapshots_scope_sequence
|
|
931
|
+
ON context_snapshots(task_id, scope, COALESCE(scope_ref, ''), sequence);
|
|
932
|
+
`;
|
|
914
933
|
const MIGRATIONS = [
|
|
915
934
|
{ version: 1, axis: "layout", sql: MIGRATION_1_SQL },
|
|
916
935
|
{ version: 2, axis: "record", recordKind: "durableJob+capability-grant+release-workflow", sql: MIGRATION_2_SQL },
|
|
@@ -927,7 +946,8 @@ const MIGRATIONS = [
|
|
|
927
946
|
{ version: 13, axis: "layout", sql: MIGRATION_13_SQL },
|
|
928
947
|
{ version: 14, axis: "record", recordKind: "workMailbox", sql: MIGRATION_14_SQL },
|
|
929
948
|
{ version: 15, axis: "record", recordKind: "publicationReference", sql: MIGRATION_15_SQL },
|
|
930
|
-
{ version: 16, axis: "record", recordKind: "taskWake", sql: MIGRATION_16_SQL }
|
|
949
|
+
{ version: 16, axis: "record", recordKind: "taskWake", sql: MIGRATION_16_SQL },
|
|
950
|
+
{ version: 17, axis: "record", recordKind: "contextSnapshot", sql: MIGRATION_17_SQL }
|
|
931
951
|
];
|
|
932
952
|
/** Current hot-path indexes whose absence would invalidate a current Home. */
|
|
933
953
|
const REQUIRED_SCHEMA_INDEXES = [
|
|
@@ -1169,6 +1189,7 @@ export const SQLITE_SCHEMA_TABLES = [
|
|
|
1169
1189
|
"role_session_sets",
|
|
1170
1190
|
"work_items",
|
|
1171
1191
|
"work_item_candidates",
|
|
1192
|
+
"context_snapshots",
|
|
1172
1193
|
"agent_runs",
|
|
1173
1194
|
"active_runs",
|
|
1174
1195
|
"review_rounds",
|
|
@@ -39,6 +39,7 @@ import { join } from "node:path";
|
|
|
39
39
|
import { isDeepStrictEqual } from "node:util";
|
|
40
40
|
import Database from "better-sqlite3";
|
|
41
41
|
import { consumePendingBatch, mailboxTargetKey, pendingLane, validateWorkMailbox } from "../coordination/workMailbox.js";
|
|
42
|
+
import { validateContextSnapshot } from "../context/contextSnapshot.js";
|
|
42
43
|
import { compareRuntimeSessionCandidates, projectRuntimeSessionCandidate } from "../runtime/runtimeSessionCandidate.js";
|
|
43
44
|
import { validateReviewFinding } from "../review/reviewFinding.js";
|
|
44
45
|
import { reviewFindingLedgerMode } from "../review/reviewFindingLedger.js";
|
|
@@ -1418,6 +1419,37 @@ export class SqliteTaskStore {
|
|
|
1418
1419
|
return Object.freeze({ retained, deleted: toDelete.length });
|
|
1419
1420
|
});
|
|
1420
1421
|
}
|
|
1422
|
+
// -- context snapshots ------------------------------------------------------
|
|
1423
|
+
nextContextSnapshotId(taskId) {
|
|
1424
|
+
return this.#nextTaskRecordId(taskId, "contextSnapshot");
|
|
1425
|
+
}
|
|
1426
|
+
getContextSnapshot(taskId, snapshotId) {
|
|
1427
|
+
return this.#getPayload("context_snapshots", "task_id = ? AND snapshot_id = ?", [taskId, snapshotId]);
|
|
1428
|
+
}
|
|
1429
|
+
listContextSnapshots(taskId) {
|
|
1430
|
+
return this.#sortById(this.#listPayload("context_snapshots", "task_id = ?", [taskId]), (snapshot) => snapshot.id);
|
|
1431
|
+
}
|
|
1432
|
+
saveContextSnapshot(snapshot) {
|
|
1433
|
+
const stored = validateContextSnapshot(snapshot);
|
|
1434
|
+
this.#requireTask(stored.taskId);
|
|
1435
|
+
const existing = this.getContextSnapshot(stored.taskId, stored.id);
|
|
1436
|
+
if (existing !== null) {
|
|
1437
|
+
if (!isDeepStrictEqual(existing, stored)) {
|
|
1438
|
+
throw new StorageRecordError(`Context Snapshot is immutable: ${stored.id}.`);
|
|
1439
|
+
}
|
|
1440
|
+
return;
|
|
1441
|
+
}
|
|
1442
|
+
const duplicate = this.#db.prepare(`SELECT snapshot_id FROM context_snapshots
|
|
1443
|
+
WHERE task_id = ? AND scope = ? AND COALESCE(scope_ref, '') = COALESCE(?, '') AND sequence = ?`).get(stored.taskId, stored.scope, stored.scopeRef ?? null, stored.sequence);
|
|
1444
|
+
if (duplicate !== undefined) {
|
|
1445
|
+
throw new StorageRecordError(`Context Snapshot sequence already exists: ${stored.taskId}/${stored.scope}/${stored.sequence}.`);
|
|
1446
|
+
}
|
|
1447
|
+
this.#mutate(() => {
|
|
1448
|
+
this.#db.prepare(`INSERT INTO context_snapshots
|
|
1449
|
+
(task_id, snapshot_id, scope, scope_ref, sequence, digest, payload, frozen_at)
|
|
1450
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(stored.taskId, stored.id, stored.scope, stored.scopeRef ?? null, stored.sequence, stored.digest, this.#json(stored), stored.frozenAt);
|
|
1451
|
+
});
|
|
1452
|
+
}
|
|
1421
1453
|
// -- agent runs -------------------------------------------------------------
|
|
1422
1454
|
nextAgentRunId(taskId) { return this.#nextTaskRecordId(taskId, "agentRun"); }
|
|
1423
1455
|
peekNextAgentRunId(taskId) { return this.#peekTaskRecordId(taskId, "agentRun"); }
|
|
@@ -1451,13 +1483,18 @@ export class SqliteTaskStore {
|
|
|
1451
1483
|
? ""
|
|
1452
1484
|
: ` AND tc.task_id IN (${selectedTaskIds.map(() => "?").join(", ")})`;
|
|
1453
1485
|
const rows = this.#db.prepare(`SELECT DISTINCT ar.task_id AS taskId, ar.run_id AS runId, ar.role_name AS roleName,
|
|
1454
|
-
json_extract(ar.payload, '$.providerRetry.
|
|
1486
|
+
json_extract(ar.payload, '$.providerRetry.state') AS state,
|
|
1487
|
+
CASE json_extract(ar.payload, '$.providerRetry.state')
|
|
1488
|
+
WHEN 'scheduled' THEN json_extract(ar.payload, '$.providerRetry.nextAttemptAt')
|
|
1489
|
+
ELSE json_extract(ar.payload, '$.providerRetry.episodeDeadlineAt')
|
|
1490
|
+
END AS dueAt
|
|
1455
1491
|
FROM tasks_catalog tc INDEXED BY idx_tasks_active
|
|
1456
1492
|
JOIN active_runs ap ON ap.task_id = tc.task_id
|
|
1457
1493
|
JOIN agent_runs ar ON ar.task_id = ap.task_id AND ar.run_id = ap.run_id
|
|
1458
1494
|
WHERE tc.is_active = 1
|
|
1459
1495
|
AND ar.status = 'active'
|
|
1460
|
-
AND json_extract(ar.payload, '$.providerRetry.
|
|
1496
|
+
AND json_extract(ar.payload, '$.providerRetry.state') IN
|
|
1497
|
+
('scheduled', 'dispatching', 'awaiting-progress')${taskPredicate}`).all(...(selectedTaskIds ?? []));
|
|
1461
1498
|
return rows.sort((left, right) => (numericCompare(left.taskId, right.taskId)
|
|
1462
1499
|
|| numericCompare(left.roleName, right.roleName)
|
|
1463
1500
|
|| numericCompare(left.runId, right.runId)));
|
|
@@ -9,10 +9,12 @@ import { publicationExternalKey, validatePublicationReference } from "../task/pu
|
|
|
9
9
|
import { reconciliationIntervalMilliseconds, resolveLeaderNextActionMode, resolveResourcesGcAutoQuarantine, resolveResourcesGcMode } from "../config/yuiConfig.js";
|
|
10
10
|
import { resolveTimeZone } from "../output/timePresentation.js";
|
|
11
11
|
import { mailboxBatches, consumePendingBatch, mailboxHasWork, mailboxTargetKey, pendingLane, validateWorkMailbox } from "../coordination/workMailbox.js";
|
|
12
|
+
import { validateContextSnapshot } from "../context/contextSnapshot.js";
|
|
12
13
|
import { validateInputRequest } from "../input/inputRequest.js";
|
|
13
14
|
import { validateRoleSessionSet } from "../executor/agentExecutor.js";
|
|
14
15
|
import { validateTaskMessage } from "../message/message.js";
|
|
15
|
-
import { validateAgentRun } from "../run/agentRun.js";
|
|
16
|
+
import { agentRunDeliveryReceiptId, validateAgentRun } from "../run/agentRun.js";
|
|
17
|
+
import { providerRetryWakeAt } from "../run/providerRetry.js";
|
|
16
18
|
import { compareRuntimeSessionCandidates, projectRuntimeSessionCandidate } from "../runtime/runtimeSessionCandidate.js";
|
|
17
19
|
import { FileSessionOwnerRegistry } from "../runtime/sessionOwnerRegistry.js";
|
|
18
20
|
import { validateReviewConfig } from "../review/reviewConfig.js";
|
|
@@ -31,7 +33,7 @@ import { CURRENT_LEADER_FAILURE_SCHEMA_VERSION } from "../scheduler/leaderFailur
|
|
|
31
33
|
import { CURRENT_OPERATOR_NOTIFICATION_SCHEMA_VERSION } from "../scheduler/operatorNotification.js";
|
|
32
34
|
import { CURRENT_TASK_WAKE_SCHEMA_VERSION, validateTaskWake } from "../scheduler/taskWake.js";
|
|
33
35
|
import { validateTask } from "../task/task.js";
|
|
34
|
-
import {
|
|
36
|
+
import { TASK_RECORD_ID_PREFIXES, validateTaskRecordReference } from "../task/taskRecordReference.js";
|
|
35
37
|
import { workItemExecutionGroupById, validateWorkItem } from "../workItem/workItem.js";
|
|
36
38
|
import { isExecutionGroupTransition, validateExecutionGroup } from "../execution/executionGroup.js";
|
|
37
39
|
import { managedWorkspaceKey, validateManagedWorkspace } from "../worktree/managedWorkspace.js";
|
|
@@ -60,6 +62,7 @@ export const CURRENT_GLOBAL_ROLE_SCHEMA_VERSION = 3;
|
|
|
60
62
|
export const CURRENT_GLOBAL_ROLE_SESSION_SET_SCHEMA_VERSION = 3;
|
|
61
63
|
export const CURRENT_TASK_SCHEMA_VERSION = 4;
|
|
62
64
|
export const CURRENT_TASK_BRIEF_SCHEMA_VERSION = 2;
|
|
65
|
+
export const CURRENT_CONTEXT_SNAPSHOT_SCHEMA_VERSION = 1;
|
|
63
66
|
export const CURRENT_TASK_ROLE_SCHEMA_VERSION = 3;
|
|
64
67
|
export const CURRENT_MANAGED_WORKSPACE_SCHEMA_VERSION = 2;
|
|
65
68
|
export const CURRENT_WORK_ITEM_SCHEMA_VERSION = 9;
|
|
@@ -120,7 +123,7 @@ export const CURRENT_TASK_ROLE_SESSION_SET_SCHEMA_VERSION = 5;
|
|
|
120
123
|
* actionability fields. All are optional, so the v6→v7 migration is a
|
|
121
124
|
* version-only rewrite.
|
|
122
125
|
*/
|
|
123
|
-
export const CURRENT_AGENT_RUN_SCHEMA_VERSION =
|
|
126
|
+
export const CURRENT_AGENT_RUN_SCHEMA_VERSION = 9;
|
|
124
127
|
export const CURRENT_INTEGRATION_QUEUE_SCHEMA_VERSION = 1;
|
|
125
128
|
export class FileTaskStore {
|
|
126
129
|
rootDir;
|
|
@@ -904,6 +907,38 @@ export class FileTaskStore {
|
|
|
904
907
|
task.workItems[stored.id] = stored;
|
|
905
908
|
});
|
|
906
909
|
}
|
|
910
|
+
nextContextSnapshotId(taskId) {
|
|
911
|
+
return this.#nextTaskRecordId(taskId, "contextSnapshot");
|
|
912
|
+
}
|
|
913
|
+
getContextSnapshot(taskId, id) {
|
|
914
|
+
return optional(this.#state().tasks[taskId]?.contextSnapshots[id]);
|
|
915
|
+
}
|
|
916
|
+
listContextSnapshots(taskId) {
|
|
917
|
+
return values(this.#requireTask(taskId).contextSnapshots, "id");
|
|
918
|
+
}
|
|
919
|
+
saveContextSnapshot(snapshot) {
|
|
920
|
+
const stored = identified(snapshot, CURRENT_CONTEXT_SNAPSHOT_SCHEMA_VERSION, "id", snapshot.id, "Context Snapshot");
|
|
921
|
+
validateContextSnapshot(stored);
|
|
922
|
+
const aggregate = this.#requireTaskForWrite(stored.taskId);
|
|
923
|
+
const existing = aggregate.contextSnapshots[stored.id];
|
|
924
|
+
if (existing !== undefined) {
|
|
925
|
+
if (!isDeepStrictEqual(existing, stored)) {
|
|
926
|
+
throw new StorageRecordError(`Context Snapshot is immutable: ${stored.id}.`);
|
|
927
|
+
}
|
|
928
|
+
return;
|
|
929
|
+
}
|
|
930
|
+
const duplicateSequence = Object.values(aggregate.contextSnapshots).find((candidate) => (candidate.scope === stored.scope
|
|
931
|
+
&& candidate.scopeRef === stored.scopeRef
|
|
932
|
+
&& candidate.sequence === stored.sequence));
|
|
933
|
+
if (duplicateSequence !== undefined) {
|
|
934
|
+
throw new StorageRecordError(`Context Snapshot sequence already exists: ${stored.taskId}/${stored.scope}/${stored.sequence}.`);
|
|
935
|
+
}
|
|
936
|
+
this.#mutate((state) => {
|
|
937
|
+
const task = state.tasks[stored.taskId];
|
|
938
|
+
observeTaskRecordId(task, "contextSnapshot", stored.id);
|
|
939
|
+
task.contextSnapshots[stored.id] = stored;
|
|
940
|
+
});
|
|
941
|
+
}
|
|
907
942
|
nextAgentRunId(taskId) {
|
|
908
943
|
return this.#nextTaskRecordId(taskId, "agentRun");
|
|
909
944
|
}
|
|
@@ -926,7 +961,9 @@ export class FileTaskStore {
|
|
|
926
961
|
if (task.status !== "active")
|
|
927
962
|
continue;
|
|
928
963
|
for (const run of this.listAgentRuns(task.id)) {
|
|
929
|
-
if (run.status === "active"
|
|
964
|
+
if (run.status === "active"
|
|
965
|
+
&& run.providerRetry !== undefined
|
|
966
|
+
&& providerRetryWakeAt(run.providerRetry) !== null) {
|
|
930
967
|
throw new StorageRecordError("Provider retry in place requires the SQLite backend; run `yui update` to migrate this Home.");
|
|
931
968
|
}
|
|
932
969
|
}
|
|
@@ -1920,6 +1957,7 @@ function emptyStoredTask(task) {
|
|
|
1920
1957
|
roleSessionSets: {},
|
|
1921
1958
|
jobCallerKeyHashes: {},
|
|
1922
1959
|
workItems: {},
|
|
1960
|
+
contextSnapshots: {},
|
|
1923
1961
|
agentRuns: {},
|
|
1924
1962
|
reviewRounds: {},
|
|
1925
1963
|
activeRuns: {},
|
|
@@ -1939,6 +1977,7 @@ function emptyStoredTask(task) {
|
|
|
1939
1977
|
function emptyTaskIdHighWaterMarks() {
|
|
1940
1978
|
return {
|
|
1941
1979
|
workItem: 0,
|
|
1980
|
+
contextSnapshot: 0,
|
|
1942
1981
|
agentRun: 0,
|
|
1943
1982
|
reviewRound: 0,
|
|
1944
1983
|
reviewFinding: 0,
|
|
@@ -2137,6 +2176,7 @@ function parseStoredTask(value, taskId) {
|
|
|
2137
2176
|
"roleSessionSets",
|
|
2138
2177
|
"jobCallerKeyHashes",
|
|
2139
2178
|
"workItems",
|
|
2179
|
+
"contextSnapshots",
|
|
2140
2180
|
"agentRuns",
|
|
2141
2181
|
"reviewRounds",
|
|
2142
2182
|
"activeRuns",
|
|
@@ -2226,6 +2266,14 @@ function parseStoredTask(value, taskId) {
|
|
|
2226
2266
|
validateWorkItem(item);
|
|
2227
2267
|
return item;
|
|
2228
2268
|
}, "workItems");
|
|
2269
|
+
parseMap(aggregate.contextSnapshots, (record, key) => {
|
|
2270
|
+
const snapshot = identified(record, CURRENT_CONTEXT_SNAPSHOT_SCHEMA_VERSION, "id", key, "Context Snapshot");
|
|
2271
|
+
if (snapshot.taskId !== taskId) {
|
|
2272
|
+
throw new StorageRecordError(`Context Snapshot belongs to another Task: ${snapshot.taskId}.`);
|
|
2273
|
+
}
|
|
2274
|
+
validateContextSnapshot(snapshot);
|
|
2275
|
+
return snapshot;
|
|
2276
|
+
}, "contextSnapshots");
|
|
2229
2277
|
parseMap(aggregate.agentRuns, (record, key) => {
|
|
2230
2278
|
const run = identified(record, CURRENT_AGENT_RUN_SCHEMA_VERSION, "id", key, "Agent run");
|
|
2231
2279
|
if (run.taskId !== taskId) {
|
|
@@ -2357,6 +2405,7 @@ function parseStoredTask(value, taskId) {
|
|
|
2357
2405
|
function validateTaskIdHighWaterCoverage(aggregate, taskId) {
|
|
2358
2406
|
const records = {
|
|
2359
2407
|
workItem: aggregate.workItems,
|
|
2408
|
+
contextSnapshot: aggregate.contextSnapshots,
|
|
2360
2409
|
agentRun: aggregate.agentRuns,
|
|
2361
2410
|
reviewRound: aggregate.reviewRounds,
|
|
2362
2411
|
// Issue 06 dbonly: review findings are SQLite-native; the file aggregate
|
|
@@ -3230,7 +3279,7 @@ function validateCanonicalTaskReferences(state, aggregate) {
|
|
|
3230
3279
|
if (sessions.inFlight !== null) {
|
|
3231
3280
|
const run = aggregate.agentRuns[sessions.inFlight.runId];
|
|
3232
3281
|
if (run === undefined || run.roleName !== roleName
|
|
3233
|
-
|| sessions.inFlight.receiptId !==
|
|
3282
|
+
|| sessions.inFlight.receiptId !== agentRunDeliveryReceiptId(run)) {
|
|
3234
3283
|
throw new StorageRecordError(`Task Role in-flight Run is invalid: ${taskId}/${roleName}.`);
|
|
3235
3284
|
}
|
|
3236
3285
|
}
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* transform in the production migration graph.
|
|
17
17
|
*/
|
|
18
18
|
import { CURRENT_AGGREGATE_SCHEMA_VERSION, CURRENT_STORAGE_LAYOUT_VERSION } from "../storageVersions.js";
|
|
19
|
-
import { CURRENT_AGENT_RUN_SCHEMA_VERSION, CURRENT_ACTIVE_RUN_POINTER_SCHEMA_VERSION, CURRENT_AGENT_PROFILE_SCHEMA_VERSION, CURRENT_CAPABILITY_GRANT_SCHEMA_VERSION, CURRENT_CONFIG_SCHEMA_VERSION, CURRENT_CONFIGURED_AGENT_SCHEMA_VERSION, CURRENT_CHANGE_SET_SCHEMA_VERSION, CURRENT_DECISION_SCHEMA_VERSION, CURRENT_EVENT_SCHEMA_VERSION, CURRENT_GLOBAL_ROLE_SCHEMA_VERSION, CURRENT_GLOBAL_ROLE_SESSION_SET_SCHEMA_VERSION, CURRENT_INPUT_REQUEST_SCHEMA_VERSION, CURRENT_INTEGRATION_ATTEMPT_SCHEMA_VERSION, CURRENT_INTEGRATION_QUEUE_SCHEMA_VERSION, CURRENT_MANAGED_WORKSPACE_SCHEMA_VERSION, CURRENT_MESSAGE_SCHEMA_VERSION, CURRENT_MILESTONE_SCHEMA_VERSION, CURRENT_PUBLICATION_REFERENCE_SCHEMA_VERSION, CURRENT_PROJECT_SCHEMA_VERSION, CURRENT_RELEASE_WORKFLOW_SCHEMA_VERSION, CURRENT_REVIEW_ROUND_SCHEMA_VERSION, CURRENT_STORED_TASK_SCHEMA_VERSION, CURRENT_TASK_BRIEF_SCHEMA_VERSION, CURRENT_TASK_ROLE_SCHEMA_VERSION, CURRENT_TASK_ROLE_SESSION_SET_SCHEMA_VERSION, CURRENT_TASK_SCHEMA_VERSION, CURRENT_WORK_ITEM_SCHEMA_VERSION, CURRENT_WORK_MAILBOX_SCHEMA_VERSION } from "../taskStore.js";
|
|
19
|
+
import { CURRENT_AGENT_RUN_SCHEMA_VERSION, CURRENT_ACTIVE_RUN_POINTER_SCHEMA_VERSION, CURRENT_AGENT_PROFILE_SCHEMA_VERSION, CURRENT_CAPABILITY_GRANT_SCHEMA_VERSION, CURRENT_CONFIG_SCHEMA_VERSION, CURRENT_CONFIGURED_AGENT_SCHEMA_VERSION, CURRENT_CHANGE_SET_SCHEMA_VERSION, CURRENT_CONTEXT_SNAPSHOT_SCHEMA_VERSION, CURRENT_DECISION_SCHEMA_VERSION, CURRENT_EVENT_SCHEMA_VERSION, CURRENT_GLOBAL_ROLE_SCHEMA_VERSION, CURRENT_GLOBAL_ROLE_SESSION_SET_SCHEMA_VERSION, CURRENT_INPUT_REQUEST_SCHEMA_VERSION, CURRENT_INTEGRATION_ATTEMPT_SCHEMA_VERSION, CURRENT_INTEGRATION_QUEUE_SCHEMA_VERSION, CURRENT_MANAGED_WORKSPACE_SCHEMA_VERSION, CURRENT_MESSAGE_SCHEMA_VERSION, CURRENT_MILESTONE_SCHEMA_VERSION, CURRENT_PUBLICATION_REFERENCE_SCHEMA_VERSION, CURRENT_PROJECT_SCHEMA_VERSION, CURRENT_RELEASE_WORKFLOW_SCHEMA_VERSION, CURRENT_REVIEW_ROUND_SCHEMA_VERSION, CURRENT_STORED_TASK_SCHEMA_VERSION, CURRENT_TASK_BRIEF_SCHEMA_VERSION, CURRENT_TASK_ROLE_SCHEMA_VERSION, CURRENT_TASK_ROLE_SESSION_SET_SCHEMA_VERSION, CURRENT_TASK_SCHEMA_VERSION, CURRENT_WORK_ITEM_SCHEMA_VERSION, CURRENT_WORK_MAILBOX_SCHEMA_VERSION } from "../taskStore.js";
|
|
20
20
|
import { CURRENT_LEADER_FAILURE_SCHEMA_VERSION } from "../../scheduler/leaderFailure.js";
|
|
21
21
|
import { CURRENT_OPERATOR_NOTIFICATION_SCHEMA_VERSION } from "../../scheduler/operatorNotification.js";
|
|
22
22
|
import { CURRENT_TASK_WAKE_SCHEMA_VERSION } from "../../scheduler/taskWake.js";
|
|
@@ -44,6 +44,7 @@ const EXPECTED_DIRECT_RECORD_LOCATORS = Object.freeze({
|
|
|
44
44
|
managedWorkspace: "state.json#/tasks/*/managedWorkspaces",
|
|
45
45
|
taskRoleSessionSet: "state.json#/tasks/*/roleSessionSets",
|
|
46
46
|
workItem: "state.json#/tasks/*/workItems",
|
|
47
|
+
contextSnapshot: "state.json#/tasks/*/contextSnapshots",
|
|
47
48
|
agentRun: "state.json#/tasks/*/agentRuns",
|
|
48
49
|
reviewRound: "state.json#/tasks/*/reviewRounds",
|
|
49
50
|
changeSet: "state.json#/tasks/*/changeSets",
|
|
@@ -99,6 +100,7 @@ function getCurrentRecordDescriptors() {
|
|
|
99
100
|
managedWorkspace: descriptor(CURRENT_MANAGED_WORKSPACE_SCHEMA_VERSION, "state.json#/tasks/*/managedWorkspaces"),
|
|
100
101
|
taskRoleSessionSet: descriptor(CURRENT_TASK_ROLE_SESSION_SET_SCHEMA_VERSION, "state.json#/tasks/*/roleSessionSets"),
|
|
101
102
|
workItem: descriptor(CURRENT_WORK_ITEM_SCHEMA_VERSION, "state.json#/tasks/*/workItems"),
|
|
103
|
+
contextSnapshot: descriptor(CURRENT_CONTEXT_SNAPSHOT_SCHEMA_VERSION, "state.json#/tasks/*/contextSnapshots"),
|
|
102
104
|
agentRun: descriptor(CURRENT_AGENT_RUN_SCHEMA_VERSION, "state.json#/tasks/*/agentRuns"),
|
|
103
105
|
reviewRound: descriptor(CURRENT_REVIEW_ROUND_SCHEMA_VERSION, "state.json#/tasks/*/reviewRounds"),
|
|
104
106
|
changeSet: descriptor(CURRENT_CHANGE_SET_SCHEMA_VERSION, "state.json#/tasks/*/changeSets"),
|
|
@@ -176,6 +176,7 @@ function asStoredTask(value) {
|
|
|
176
176
|
managedWorkspaces: asObjectMap(record.managedWorkspaces),
|
|
177
177
|
roleSessionSets: asObjectMap(record.roleSessionSets),
|
|
178
178
|
workItems: asObjectMap(record.workItems),
|
|
179
|
+
contextSnapshots: asObjectMap(record.contextSnapshots),
|
|
179
180
|
agentRuns: asObjectMap(record.agentRuns),
|
|
180
181
|
reviewRounds: asObjectMap(record.reviewRounds),
|
|
181
182
|
changeSets: asObjectMap(record.changeSets),
|
|
@@ -271,6 +272,9 @@ export function populateSqliteFromState(home, state, databaseFilename) {
|
|
|
271
272
|
for (const item of Object.values(stored.workItems)) {
|
|
272
273
|
store.saveWorkItem(taskId, item);
|
|
273
274
|
}
|
|
275
|
+
for (const snapshot of Object.values(stored.contextSnapshots)) {
|
|
276
|
+
store.saveContextSnapshot(snapshot);
|
|
277
|
+
}
|
|
274
278
|
for (const run of Object.values(stored.agentRuns)) {
|
|
275
279
|
store.saveAgentRun(run);
|
|
276
280
|
}
|
|
@@ -451,6 +455,7 @@ export function computeStateFamilyChecksums(state) {
|
|
|
451
455
|
const workspaces = [];
|
|
452
456
|
const roleSessionSets = [];
|
|
453
457
|
const workItems = [];
|
|
458
|
+
const contextSnapshots = [];
|
|
454
459
|
const agentRuns = [];
|
|
455
460
|
const reviewRounds = [];
|
|
456
461
|
const changeSets = [];
|
|
@@ -478,6 +483,7 @@ export function computeStateFamilyChecksums(state) {
|
|
|
478
483
|
workspaces.push(...Object.values(stored.managedWorkspaces));
|
|
479
484
|
roleSessionSets.push(...Object.values(stored.roleSessionSets));
|
|
480
485
|
workItems.push(...Object.values(stored.workItems));
|
|
486
|
+
contextSnapshots.push(...Object.values(stored.contextSnapshots));
|
|
481
487
|
agentRuns.push(...Object.values(stored.agentRuns));
|
|
482
488
|
reviewRounds.push(...Object.values(stored.reviewRounds));
|
|
483
489
|
changeSets.push(...Object.values(stored.changeSets));
|
|
@@ -517,6 +523,7 @@ export function computeStateFamilyChecksums(state) {
|
|
|
517
523
|
checksums.managedWorkspace = hashRecords(workspaces);
|
|
518
524
|
checksums.taskRoleSessionSet = hashRecords(roleSessionSets);
|
|
519
525
|
checksums.workItem = hashRecords(workItems);
|
|
526
|
+
checksums.contextSnapshot = hashRecords(contextSnapshots);
|
|
520
527
|
checksums.agentRun = hashRecords(agentRuns);
|
|
521
528
|
checksums.reviewRound = hashRecords(reviewRounds);
|
|
522
529
|
checksums.changeSet = hashRecords(changeSets);
|
|
@@ -605,6 +612,7 @@ export function computeDbFamilyChecksums(home, databaseFilename) {
|
|
|
605
612
|
checksums.managedWorkspace = hashPayloadTable(db, "SELECT payload FROM managed_workspaces");
|
|
606
613
|
checksums.taskRoleSessionSet = hashPayloadTable(db, "SELECT payload FROM role_session_sets");
|
|
607
614
|
checksums.workItem = hashPayloadTable(db, "SELECT payload FROM work_items");
|
|
615
|
+
checksums.contextSnapshot = hashPayloadTable(db, "SELECT payload FROM context_snapshots");
|
|
608
616
|
checksums.agentRun = hashPayloadTable(db, "SELECT payload FROM agent_runs");
|
|
609
617
|
checksums.reviewRound = hashPayloadTable(db, "SELECT payload FROM review_rounds");
|
|
610
618
|
checksums.changeSet = hashPayloadTable(db, "SELECT payload FROM change_sets");
|
|
@@ -733,6 +741,7 @@ export function readStateFromSqlite(home) {
|
|
|
733
741
|
managedWorkspaces: {},
|
|
734
742
|
roleSessionSets: {},
|
|
735
743
|
workItems: {},
|
|
744
|
+
contextSnapshots: {},
|
|
736
745
|
agentRuns: {},
|
|
737
746
|
reviewRounds: {},
|
|
738
747
|
changeSets: {},
|
|
@@ -760,6 +769,7 @@ export function readStateFromSqlite(home) {
|
|
|
760
769
|
loadTaskPayloadMap(db, "managed_workspaces", tasks, "managedWorkspaces", (record) => managedWorkspaceKey(record.owner));
|
|
761
770
|
loadTaskPayloadMap(db, "role_session_sets", tasks, "roleSessionSets", (record) => record.owner.roleName);
|
|
762
771
|
loadTaskPayloadMap(db, "work_items", tasks, "workItems", (record) => record.id);
|
|
772
|
+
loadTaskPayloadMap(db, "context_snapshots", tasks, "contextSnapshots", (record) => record.id);
|
|
763
773
|
loadTaskPayloadMap(db, "agent_runs", tasks, "agentRuns", (record) => record.id);
|
|
764
774
|
loadTaskPayloadMap(db, "review_rounds", tasks, "reviewRounds", (record) => record.id);
|
|
765
775
|
loadTaskPayloadMap(db, "change_sets", tasks, "changeSets", (record) => record.id);
|
package/dist/tmux/tmuxManager.js
CHANGED
|
@@ -483,7 +483,7 @@ export class TmuxManager {
|
|
|
483
483
|
try {
|
|
484
484
|
output = this.run([
|
|
485
485
|
"list-panes", "-s", "-t", this.sessionName(taskId), "-F",
|
|
486
|
-
`#{window_name}${formatSeparator}#{pane_dead}${formatSeparator}#{pane_pid}${formatSeparator}#{pane_current_command}`
|
|
486
|
+
`#{window_name}${formatSeparator}#{pane_dead}${formatSeparator}#{pane_dead_status}${formatSeparator}#{pane_pid}${formatSeparator}#{pane_current_command}`
|
|
487
487
|
]);
|
|
488
488
|
}
|
|
489
489
|
catch (error) {
|
|
@@ -495,9 +495,10 @@ export class TmuxManager {
|
|
|
495
495
|
if (line.length === 0)
|
|
496
496
|
return [];
|
|
497
497
|
const separator = line.includes(encodedSeparator) ? encodedSeparator : formatSeparator;
|
|
498
|
-
const [roleName, deadText, pidText, currentCommand, ...extra] = line.split(separator);
|
|
498
|
+
const [roleName, deadText, deadStatusText, pidText, currentCommand, ...extra] = line.split(separator);
|
|
499
499
|
if (roleName === undefined
|
|
500
500
|
|| deadText === undefined
|
|
501
|
+
|| deadStatusText === undefined
|
|
501
502
|
|| pidText === undefined
|
|
502
503
|
|| currentCommand === undefined
|
|
503
504
|
|| extra.length > 0
|
|
@@ -505,11 +506,13 @@ export class TmuxManager {
|
|
|
505
506
|
throw runtimeError(`Tmux returned an invalid Task Role pane state for ${taskId}.`);
|
|
506
507
|
}
|
|
507
508
|
const pid = Number(pidText);
|
|
509
|
+
const deadStatus = Number(deadStatusText);
|
|
508
510
|
return [{
|
|
509
511
|
taskId,
|
|
510
512
|
roleName,
|
|
511
513
|
target: this.target(taskId, roleName),
|
|
512
514
|
dead: deadText === "1",
|
|
515
|
+
...(Number.isSafeInteger(deadStatus) && deadStatus >= 0 ? { deadStatus } : {}),
|
|
513
516
|
...(Number.isSafeInteger(pid) && pid > 0 ? { pid } : {}),
|
|
514
517
|
currentCommand
|
|
515
518
|
}];
|
|
@@ -532,6 +535,7 @@ export class TmuxManager {
|
|
|
532
535
|
"#{session_name}",
|
|
533
536
|
"#{window_name}",
|
|
534
537
|
"#{pane_dead}",
|
|
538
|
+
"#{pane_dead_status}",
|
|
535
539
|
"#{pane_pid}",
|
|
536
540
|
"#{pane_current_command}"
|
|
537
541
|
].join(formatSeparator)
|
|
@@ -546,10 +550,11 @@ export class TmuxManager {
|
|
|
546
550
|
if (line.length === 0)
|
|
547
551
|
return [];
|
|
548
552
|
const separator = line.includes(encodedSeparator) ? encodedSeparator : formatSeparator;
|
|
549
|
-
const [sessionName, roleName, deadText, pidText, currentCommand, ...extra] = line.split(separator);
|
|
553
|
+
const [sessionName, roleName, deadText, deadStatusText, pidText, currentCommand, ...extra] = line.split(separator);
|
|
550
554
|
if (sessionName === undefined
|
|
551
555
|
|| roleName === undefined
|
|
552
556
|
|| deadText === undefined
|
|
557
|
+
|| deadStatusText === undefined
|
|
553
558
|
|| pidText === undefined
|
|
554
559
|
|| currentCommand === undefined
|
|
555
560
|
|| extra.length > 0
|
|
@@ -563,11 +568,13 @@ export class TmuxManager {
|
|
|
563
568
|
throw runtimeError("Tmux returned an invalid Yui Role pane identity.");
|
|
564
569
|
}
|
|
565
570
|
const pid = Number(pidText);
|
|
571
|
+
const deadStatus = Number(deadStatusText);
|
|
566
572
|
return [{
|
|
567
573
|
taskId,
|
|
568
574
|
roleName,
|
|
569
575
|
target: this.target(taskId, roleName),
|
|
570
576
|
dead: deadText === "1",
|
|
577
|
+
...(Number.isSafeInteger(deadStatus) && deadStatus >= 0 ? { deadStatus } : {}),
|
|
571
578
|
...(Number.isSafeInteger(pid) && pid > 0 ? { pid } : {}),
|
|
572
579
|
currentCommand
|
|
573
580
|
}];
|
|
@@ -585,6 +592,7 @@ export class TmuxManager {
|
|
|
585
592
|
"#{session_name}",
|
|
586
593
|
"#{window_name}",
|
|
587
594
|
"#{pane_dead}",
|
|
595
|
+
"#{pane_dead_status}",
|
|
588
596
|
"#{pane_pid}",
|
|
589
597
|
"#{pane_current_command}"
|
|
590
598
|
].join(formatSeparator)
|
|
@@ -1059,10 +1067,11 @@ function parseRolePaneInventory(output, formatSeparator, encodedSeparator, sessi
|
|
|
1059
1067
|
if (line.length === 0)
|
|
1060
1068
|
return [];
|
|
1061
1069
|
const separator = line.includes(encodedSeparator) ? encodedSeparator : formatSeparator;
|
|
1062
|
-
const [sessionName, roleName, deadText, pidText, currentCommand, ...extra] = line.split(separator);
|
|
1070
|
+
const [sessionName, roleName, deadText, deadStatusText, pidText, currentCommand, ...extra] = line.split(separator);
|
|
1063
1071
|
if (sessionName === undefined
|
|
1064
1072
|
|| roleName === undefined
|
|
1065
1073
|
|| deadText === undefined
|
|
1074
|
+
|| deadStatusText === undefined
|
|
1066
1075
|
|| pidText === undefined
|
|
1067
1076
|
|| currentCommand === undefined
|
|
1068
1077
|
|| extra.length > 0
|
|
@@ -1076,11 +1085,13 @@ function parseRolePaneInventory(output, formatSeparator, encodedSeparator, sessi
|
|
|
1076
1085
|
throw runtimeError("Tmux returned an invalid Yui Role pane identity.");
|
|
1077
1086
|
}
|
|
1078
1087
|
const pid = Number(pidText);
|
|
1088
|
+
const deadStatus = Number(deadStatusText);
|
|
1079
1089
|
return [{
|
|
1080
1090
|
taskId,
|
|
1081
1091
|
roleName,
|
|
1082
1092
|
target: target(taskId, roleName),
|
|
1083
1093
|
dead: deadText === "1",
|
|
1094
|
+
...(Number.isSafeInteger(deadStatus) && deadStatus >= 0 ? { deadStatus } : {}),
|
|
1084
1095
|
...(Number.isSafeInteger(pid) && pid > 0 ? { pid } : {}),
|
|
1085
1096
|
currentCommand
|
|
1086
1097
|
}];
|
|
@@ -509,7 +509,7 @@ export function runCard(run, t, locale) {
|
|
|
509
509
|
idRow.append(node("time", "", formatDateTime(run.endedAt || run.updatedAt, locale)));
|
|
510
510
|
card.append(idRow);
|
|
511
511
|
|
|
512
|
-
card.append(richText(t("detail.instruction"), run.
|
|
512
|
+
card.append(richText(t("detail.instruction"), run.assignment?.directive || run.assignment?.action || "-", t, { className: "execute-io", threshold: 320 }));
|
|
513
513
|
if (run.summary) {
|
|
514
514
|
card.append(richText(t("detail.outcome"), run.summary, t, { className: "execute-io outcome", threshold: 320 }));
|
|
515
515
|
}
|
package/package.json
CHANGED
|
@@ -5,6 +5,10 @@ description: Lead one Yui Task from the user's core outcome by reasoning from fi
|
|
|
5
5
|
|
|
6
6
|
# Yui Leader
|
|
7
7
|
|
|
8
|
+
Follow `yui-runtime` first and load the exact current Run Context Pack before
|
|
9
|
+
making Task decisions. Recover authority from its Snapshot and deltas, never
|
|
10
|
+
from launch text or transcript memory.
|
|
11
|
+
|
|
8
12
|
Own Task direction, decomposition, semantic decisions, acceptance, integration,
|
|
9
13
|
and durable context. Yui has one work model: every bounded outcome is a
|
|
10
14
|
WorkItem. Choose one of three execution paths for each WorkItem:
|
|
@@ -213,11 +217,11 @@ yui task wake show <task-id> <wake-id>
|
|
|
213
217
|
```
|
|
214
218
|
|
|
215
219
|
For a fresh generation (no native history), or when the envelope indicates a
|
|
216
|
-
major change, start with the
|
|
217
|
-
Policy
|
|
220
|
+
major change, start with the exact Run Context Pack loaded through
|
|
221
|
+
`yui-runtime`, expand only its authorized Task and Project Policy refs, then
|
|
222
|
+
inspect Project-owned records as needed:
|
|
218
223
|
|
|
219
224
|
```sh
|
|
220
|
-
yui task context <task-id>
|
|
221
225
|
yui project show <project>
|
|
222
226
|
yui project knowledge list <project>
|
|
223
227
|
```
|
|
@@ -361,7 +365,7 @@ yui task work update <work-id> done \
|
|
|
361
365
|
Use `failed` with recovery context when it cannot be completed. Do not mark
|
|
362
366
|
work done before checking its acceptance criteria. When global review is
|
|
363
367
|
enabled, `done` submits a Candidate instead of completing the WorkItem. Read
|
|
364
|
-
|
|
368
|
+
the exact Run Context Pack and follow that Candidate's snapshotted policy.
|
|
365
369
|
|
|
366
370
|
## Create a native subagent
|
|
367
371
|
|
|
@@ -488,7 +492,8 @@ delivers evidence and moves the WorkItem to Leader review; it is not acceptance.
|
|
|
488
492
|
## Review, retry, capture, and integrate
|
|
489
493
|
|
|
490
494
|
After any Candidate is submitted, inspect its exact policy, Run result,
|
|
491
|
-
ReviewRounds, checks, and workspace through
|
|
495
|
+
ReviewRounds, checks, and workspace through the exact Run Context Pack and its
|
|
496
|
+
authorized expansions.
|
|
492
497
|
|
|
493
498
|
- `always`: wait for the automatically requested ReviewRound to become
|
|
494
499
|
terminal. Never bypass an active round.
|
|
@@ -5,6 +5,10 @@ description: Route multi-project user requests into Yui Tasks, preserve durable
|
|
|
5
5
|
|
|
6
6
|
# Yui Operator
|
|
7
7
|
|
|
8
|
+
Follow `yui-runtime` for every routed managed Run. Load only the exact
|
|
9
|
+
authorized Context Pack; do not infer Task authority from a prompt, process, or
|
|
10
|
+
workspace.
|
|
11
|
+
|
|
8
12
|
Be the task-neutral user entry point. The user should be able to discuss
|
|
9
13
|
features, bugs, investigations, and questions across multiple Projects without
|
|
10
14
|
managing Yui records. Route each request to the correct Project and Task; leave
|
|
@@ -5,6 +5,10 @@ description: Review the exact frozen WorkItem Candidate or Task-final Integratio
|
|
|
5
5
|
|
|
6
6
|
# Yui Reviewer
|
|
7
7
|
|
|
8
|
+
Follow `yui-runtime` first and load the exact current Run Context Pack. The
|
|
9
|
+
ReviewRound, Candidate, workspace, and Snapshot digest returned there are the
|
|
10
|
+
only review scope; fail closed on any mismatch.
|
|
11
|
+
|
|
8
12
|
Review only the exact frozen scope and ReviewRound assigned by the Leader; never
|
|
9
13
|
reinterpret its scope:
|
|
10
14
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: yui-runtime
|
|
3
|
+
description: Load and use the exact authorized context for every Yui-managed Leader, Worker, Reviewer, Operator, or custom Role Run, and complete that Run through its bounded control-plane protocol.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Yui Runtime
|
|
7
|
+
|
|
8
|
+
Treat the Session Manifest and Run Bootstrap Envelope as pointers, never as the
|
|
9
|
+
Task brief. Do not infer Task facts from the launch command, process list,
|
|
10
|
+
workspace layout, native transcript, or an earlier Run.
|
|
11
|
+
|
|
12
|
+
For every managed Task Run:
|
|
13
|
+
|
|
14
|
+
1. Read the exact Run identity from the newest Bootstrap Envelope.
|
|
15
|
+
2. Before acting, load its authorized pack with the exact Session CLI:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
"$YUI_SESSION_CLI" task run context "$YUI_TASK_ID/<run-id>" --json
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
3. Verify that the returned Task, Run, Role, purpose, Snapshot digest, workspace,
|
|
22
|
+
and Adapter match the Envelope and Session Manifest. Stop and report a
|
|
23
|
+
context-load failure if the pack is missing, stale, unauthorized, malformed,
|
|
24
|
+
or mismatched. Never request an inline/full-prompt fallback.
|
|
25
|
+
4. Use pack summaries and pointers first. Expand only an authorized ref when
|
|
26
|
+
its full value is needed:
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
"$YUI_SESSION_CLI" task run context expand "$YUI_TASK_ID/<run-id>" <ref-id> --mode full --json
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
5. On a later wake, request only the declared delta after the last pack cursor.
|
|
33
|
+
If no cursor is available, reload the exact pack; do not reconstruct state
|
|
34
|
+
from transcript memory.
|
|
35
|
+
|
|
36
|
+
The pack's authority view and writable Project IDs are hard boundaries. A
|
|
37
|
+
native subagent inherits the parent Run's refs and authority; it does not gain a
|
|
38
|
+
new Yui actor, Run, Session, or cross-Task read permission.
|
|
39
|
+
|
|
40
|
+
For a global Operator or custom GlobalRole Session, load the stable exact view
|
|
41
|
+
before routing or acting:
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
"$YUI_SESSION_CLI" role context "$YUI_ROLE" --json
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Global context grants no Task implementation workspace. Read a Task only after
|
|
48
|
+
the Operator has routed to its public/task-authorized context command; never
|
|
49
|
+
invent a Task Run identity for a GlobalRole.
|
|
50
|
+
|
|
51
|
+
Provider acceptance, Context load, and workflow completion are separate facts.
|
|
52
|
+
Do not treat a live pane, process output, final response, or completed Provider
|
|
53
|
+
Turn as a Yui yield. For a managed Task Run, use the exact current Run's
|
|
54
|
+
supported checkpoint/yield command as the final control-plane action, then stop
|
|
55
|
+
immediately. If that direct command is denied or stale, report the blocker once
|
|
56
|
+
and stop; do not wrap, retry, broaden permissions, or target another Run.
|
|
57
|
+
|
|
58
|
+
For a transient Provider retry Envelope, continue the failed Turn in the same
|
|
59
|
+
native Session. Do not replay the original Assignment or reload unrelated Task
|
|
60
|
+
content. Process/child replacement does not by itself authorize a new Yui
|
|
61
|
+
generation or native conversation.
|