@zq-silk/yui 2.20.0 → 2.22.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/README.md +5 -0
- package/dist/cli/commandCatalog.js +88 -28
- package/dist/cli/dynamicCompletion.js +4 -1
- package/dist/cli/helpRenderer.js +12 -1
- package/dist/cli/interactionPolicy.js +2 -0
- package/dist/cli/invocationAuthority.js +2 -6
- package/dist/cli/invocationRouter.js +5 -5
- package/dist/cli/managedDiagnostics.js +24 -16
- package/dist/cli/roleWizard.js +5 -1
- package/dist/commands/durableJobCommands.js +2 -3
- package/dist/commands/globalRoleCommands.js +33 -8
- package/dist/commands/inboxCommands.js +39 -12
- package/dist/commands/operatorCommands.js +2 -5
- package/dist/commands/releaseCommands.js +16 -2
- package/dist/commands/roleConfiguration.js +25 -2
- package/dist/commands/sessionCommands.js +5 -2
- package/dist/commands/taskCommands.js +225 -99
- package/dist/commands/taskContextCommand.js +26 -4
- package/dist/commands/taskFactCommands.js +20 -7
- package/dist/commands/taskIntegrationCommands.js +3 -3
- package/dist/commands/taskRoleRuntimeStatus.js +15 -5
- package/dist/commands/taskUsageCommand.js +2 -6
- package/dist/commands/textInput.js +2 -2
- package/dist/context/contextFamilies.js +10 -0
- package/dist/context/currentSkills.js +6 -4
- package/dist/context/runContextPack.js +44 -5
- package/dist/context/runInputContract.js +1 -1
- package/dist/context/sessionBootstrapManifest.js +7 -5
- package/dist/context/sessionSkillNotice.js +53 -0
- package/dist/context/taskCatalog.js +4 -13
- package/dist/context/taskContext.js +135 -103
- package/dist/context/taskSearch.js +3 -7
- package/dist/controlPlaneCli.js +23 -25
- package/dist/controller/agentRuntimeObserver.js +57 -12
- package/dist/controller/clientRuntime.js +37 -8
- package/dist/controller/controller.js +3 -1
- package/dist/controller/diagnosticJournal.js +10 -2
- package/dist/controller/fileSchedulerStoreAdapter.js +72 -24
- package/dist/controller/jobClient.js +2 -2
- package/dist/controller/jobControl.js +2 -2
- package/dist/controller/jobDefinitionControl.js +5 -1
- package/dist/controller/messageHealth.js +4 -3
- package/dist/controller/providerRetryAdmission.js +15 -1
- package/dist/controller/providerRetryDelivery.js +18 -2
- package/dist/controller/runtime.js +15 -5
- package/dist/controller/runtimeEventInbox.js +107 -13
- package/dist/controller/runtimeEventProcessor.js +3 -3
- package/dist/controller/taskRunRecovery.js +153 -0
- package/dist/core/controllerClient.js +16 -2
- package/dist/core/controllerServer.js +14 -5
- package/dist/core/controllerTelemetry.js +51 -5
- package/dist/errors/cliFailure.js +14 -5
- package/dist/executor/agentAdapter.js +32 -4
- package/dist/executor/agentConfigurationFields.js +2 -0
- package/dist/executor/taskAgentCapabilities.js +2 -2
- package/dist/integration/gitIntegrationService.js +3 -2
- package/dist/integration/integrationSourceApplication.js +12 -1
- package/dist/interaction/notificationPresentation.js +11 -16
- package/dist/interaction/operatorPresentation.js +1 -1
- package/dist/message/messageContinuation.js +3 -1
- package/dist/output/boundedRead.js +36 -7
- package/dist/output/rolePresentation.js +3 -1
- package/dist/runtime/agentHost.js +12 -3
- package/dist/runtime/codexAppServerRuntime.js +110 -24
- package/dist/runtime/codexInteractiveHost.js +46 -0
- package/dist/runtime/providerRetry.js +5 -2
- package/dist/runtime/providerRuntimeIdentity.js +1 -1
- package/dist/runtime/structuredProviderHost.js +32 -34
- package/dist/scheduler/wakeupQueue.js +10 -4
- package/dist/storage/sqliteSchema.js +9 -0
- package/dist/storage/storageVersions.js +1 -1
- package/dist/task/taskAuthority.js +7 -3
- package/dist/tmux/tmuxManager.js +4 -2
- package/dist/web/webSettings.js +2 -0
- package/docs/authorization.md +18 -3
- package/docs/cli-information-contract.md +245 -6
- package/docs/cli-information-contract.zh-CN.md +107 -5
- package/docs/managed-turn-and-session-runtime.md +82 -21
- package/docs/managed-turn-and-session-runtime.zh-CN.md +56 -13
- package/docs/provider-retry.md +11 -0
- package/docs/release-workflow.md +62 -0
- package/docs/release-workflow.zh-CN.md +46 -0
- package/docs/roles-and-configuration.md +28 -0
- package/docs/roles-and-configuration.zh-CN.md +21 -0
- package/docs/storage-baseline.md +4 -1
- package/docs/storage-baseline.zh-CN.md +1 -1
- package/docs/task-delivery.md +7 -0
- package/docs/task-delivery.zh-CN.md +5 -0
- package/docs/task-discovery.md +5 -5
- package/docs/task-discovery.zh-CN.md +4 -4
- package/docs/testing/review-evaluation.md +7 -7
- package/docs/testing/review-evaluation.zh-CN.md +7 -7
- package/docs/testing/verification-levels.md +45 -2
- package/docs/testing/verification-levels.zh-CN.md +21 -2
- package/i18n/README.zh-CN.md +6 -0
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +98 -189
- package/skills/yui-leader/VERSION +1 -1
- package/skills/yui-leader/references/artifacts.md +41 -0
- package/skills/yui-leader/references/assignment-execution.md +140 -0
- package/skills/yui-leader/references/completion.md +79 -0
- package/skills/yui-leader/references/delivery-scope.md +26 -0
- package/skills/yui-leader/references/execution.md +16 -487
- package/skills/yui-leader/references/implementation.md +81 -0
- package/skills/yui-leader/references/planning.md +7 -45
- package/skills/yui-leader/references/review.md +90 -0
- package/skills/yui-leader/references/task-progress.md +23 -0
- package/skills/yui-leader/references/work-allocation.md +118 -0
- package/skills/yui-operator/SKILL.md +77 -331
- package/skills/yui-operator/VERSION +1 -1
- package/skills/yui-operator/references/body-transport.md +62 -0
- package/skills/yui-operator/references/configuration.md +47 -0
- package/skills/yui-operator/references/lifecycle.md +41 -0
- package/skills/yui-operator/references/progress.md +39 -0
- package/skills/yui-operator/references/routing.md +57 -0
- package/skills/yui-operator/references/submission.md +56 -0
- package/skills/yui-operator/references/task-delivery.md +5 -2
- package/skills/yui-operator/references/web-lifecycle.md +19 -0
- package/skills/yui-operator/scripts/verify-submission.mjs +37 -0
- package/skills/yui-reviewer/SKILL.md +4 -2
- package/skills/yui-reviewer/VERSION +1 -1
- package/skills/yui-runtime/SKILL.md +177 -505
- package/skills/yui-runtime/VERSION +1 -1
- package/skills/yui-runtime/references/archive.md +51 -0
- package/skills/yui-runtime/references/command-discovery.md +41 -0
- package/skills/yui-runtime/references/completed-followup.md +65 -0
- package/skills/yui-runtime/references/context-ordering.md +3 -34
- package/skills/yui-runtime/references/context-reads.md +61 -0
- package/skills/yui-runtime/references/dispatched-run.md +61 -0
- package/skills/yui-runtime/references/execution-failure.md +105 -0
- package/skills/yui-runtime/references/global-context.md +18 -0
- package/skills/yui-runtime/references/global-input-controls.md +44 -0
- package/skills/yui-runtime/references/host-custody.md +30 -0
- package/skills/yui-runtime/references/inbox-recovery.md +77 -0
- package/skills/yui-runtime/references/incremental-context.md +40 -0
- package/skills/yui-runtime/references/publication.md +4 -104
- package/skills/yui-runtime/references/recovery.md +32 -192
- package/skills/yui-runtime/references/session-identity.md +18 -0
- package/skills/yui-runtime/references/session-replacement.md +45 -0
- package/skills/yui-runtime/references/uncertain-execution.md +29 -0
- package/skills/yui-worker/SKILL.md +7 -4
- package/skills/yui-worker/VERSION +1 -1
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { createTaskBrief, updateTaskBrief } from "../brief/taskBrief.js";
|
|
2
|
-
import {
|
|
2
|
+
import { assertTaskReadable, resolveContextReader } from "../context/taskContext.js";
|
|
3
3
|
import { taskRecordList } from "./taskContextCommand.js";
|
|
4
4
|
import { materialize } from "../context/taskContext.js";
|
|
5
5
|
import { enqueueWork } from "../coordination/workMailboxQueue.js";
|
|
6
6
|
import { createDecision, supersedeDecision } from "../decision/decision.js";
|
|
7
|
+
import { readDigest } from "../output/boundedRead.js";
|
|
7
8
|
import { dataError, usageError } from "../errors/cliError.js";
|
|
8
9
|
import { createMilestone } from "../milestone/milestone.js";
|
|
9
10
|
import { assertTaskOpen, clock, exactPositionals, leaderActionEventPayload, leaderMailbox, notifyMailbox, output, parseMultiValueTail, parseTail, presentTime, recordTaskEvent, requiredOption, requiredText, requireTask, taskActor, taskMailbox, taskRef } from "./taskCommandSupport.js";
|
|
@@ -15,7 +16,7 @@ export function taskBriefCommand(args, store, options) {
|
|
|
15
16
|
exactPositionals(rest, 1, "Task brief show usage: yui task brief show <task>.");
|
|
16
17
|
const { task, brief, writeGuard, phase } = store.readTransaction(reader => {
|
|
17
18
|
const task = requireTask(reader, rest[0]);
|
|
18
|
-
|
|
19
|
+
assertTaskReadable(reader, task.id, options.environment);
|
|
19
20
|
const caller = resolveContextReader(reader, options.environment ?? {});
|
|
20
21
|
const shared = caller === undefined || caller.roleName === "leader";
|
|
21
22
|
return { task, brief: reader.getTaskBrief(task.id),
|
|
@@ -107,6 +108,18 @@ export function taskBriefCommand(args, store, options) {
|
|
|
107
108
|
? "Task brief command is required."
|
|
108
109
|
: `Unknown command: task brief ${command}`);
|
|
109
110
|
}
|
|
111
|
+
function decisionReceipt(decision) {
|
|
112
|
+
// A short saved value lets the caller inspect the actual effect without
|
|
113
|
+
// another read. Bound the complete JSON record, including title/reason.
|
|
114
|
+
const contentOmitted = Buffer.byteLength(JSON.stringify(decision)) > 2048;
|
|
115
|
+
const value = contentOmitted ? {
|
|
116
|
+
id: decision.id, taskId: decision.taskId, status: decision.status,
|
|
117
|
+
createdAt: decision.createdAt, updatedAt: decision.updatedAt
|
|
118
|
+
} : decision;
|
|
119
|
+
return { taskId: decision.taskId, effect: "saved", contentOmitted, decision: { ...value,
|
|
120
|
+
digest: readDigest(decision), rationaleBytes: Buffer.byteLength(decision.rationale)
|
|
121
|
+
}, ...(contentOmitted ? { read: `yui task decision show ${decision.taskId} ${decision.id} --json` } : {}) };
|
|
122
|
+
}
|
|
110
123
|
export function taskDecisionCommand(args, store, options) {
|
|
111
124
|
const [command, ...rest] = args;
|
|
112
125
|
if (command === "record") {
|
|
@@ -136,7 +149,7 @@ export function taskDecisionCommand(args, store, options) {
|
|
|
136
149
|
notifyMailbox(options.runtime, taskMailbox(result.task.id));
|
|
137
150
|
if (result.task.status === "active")
|
|
138
151
|
notifyMailbox(options.runtime, leaderMailbox(result.task.id));
|
|
139
|
-
return output(`Recorded decision ${result.decision.id} for ${result.task.id}\n
|
|
152
|
+
return output(`Recorded decision ${result.decision.id} for ${result.task.id}\n`, decisionReceipt(result.decision));
|
|
140
153
|
}
|
|
141
154
|
if (command === "list") {
|
|
142
155
|
return taskRecordList(rest, store, "task-decision", options.environment);
|
|
@@ -144,7 +157,7 @@ export function taskDecisionCommand(args, store, options) {
|
|
|
144
157
|
if (command === "show") {
|
|
145
158
|
exactPositionals(rest, 2, "Task decision show usage: yui task decision show <task> <decision>.");
|
|
146
159
|
const task = requireTask(store, rest[0]);
|
|
147
|
-
|
|
160
|
+
assertTaskReadable(store, task.id, options.environment);
|
|
148
161
|
const decision = store.getDecision(task.id, rest[1]);
|
|
149
162
|
if (decision === null)
|
|
150
163
|
throw dataError(`Decision not found: ${rest[1]}.`);
|
|
@@ -190,7 +203,7 @@ export function taskDecisionCommand(args, store, options) {
|
|
|
190
203
|
notifyMailbox(options.runtime, taskMailbox(result.task.id));
|
|
191
204
|
if (result.task.status === "active")
|
|
192
205
|
notifyMailbox(options.runtime, leaderMailbox(result.task.id));
|
|
193
|
-
return output(`Superseded decision ${result.decision.id} for ${result.task.id}\n
|
|
206
|
+
return output(`Superseded decision ${result.decision.id} for ${result.task.id}\n`, decisionReceipt(result.decision));
|
|
194
207
|
}
|
|
195
208
|
throw usageError(command === undefined
|
|
196
209
|
? "Task decision command is required."
|
|
@@ -228,7 +241,7 @@ export function taskMilestoneCommand(args, store, options) {
|
|
|
228
241
|
if (command === "show") {
|
|
229
242
|
exactPositionals(rest, 2, "Task milestone show usage: yui task milestone show <task> <milestone>.");
|
|
230
243
|
const task = requireTask(store, rest[0]);
|
|
231
|
-
|
|
244
|
+
assertTaskReadable(store, task.id, options.environment);
|
|
232
245
|
const milestone = store.getMilestone(task.id, rest[1]);
|
|
233
246
|
if (milestone === null)
|
|
234
247
|
throw dataError(`Milestone not found: ${rest[1]}.`);
|
|
@@ -254,7 +267,7 @@ export function taskEventCommand(args, store, options = {}) {
|
|
|
254
267
|
if (command === "show") {
|
|
255
268
|
exactPositionals(rest, 2, "Task event show usage: yui task event show <task> <event>.");
|
|
256
269
|
const task = requireTask(store, rest[0]);
|
|
257
|
-
|
|
270
|
+
assertTaskReadable(store, task.id, options.environment);
|
|
258
271
|
const event = store.queryContextRecords(task.id, {
|
|
259
272
|
family: "task-event", ids: [rest[1]], limit: 1
|
|
260
273
|
}).records[0]?.value;
|
|
@@ -167,10 +167,10 @@ async function continueIntegration(args, store, home, now, options) {
|
|
|
167
167
|
|| integration.resolution?.action !== "manual-resolution")) {
|
|
168
168
|
throw usageError(`Integration is not ready to continue: ${integration.id}/${integration.status}.`);
|
|
169
169
|
}
|
|
170
|
-
return runIntegration(store, home, integration, now, options);
|
|
170
|
+
return runIntegration(store, home, integration, now, options, "continue");
|
|
171
171
|
}
|
|
172
|
-
async function runIntegration(store, home, integration, now, options) {
|
|
173
|
-
const result = await new GitIntegrationService(home, store, undefined, now, options.environment, undefined, options.jobPort).integrate(integration.taskId, integration.id);
|
|
172
|
+
async function runIntegration(store, home, integration, now, options, intent) {
|
|
173
|
+
const result = await new GitIntegrationService(home, store, undefined, now, options.environment, undefined, options.jobPort).integrate(integration.taskId, integration.id, undefined, intent);
|
|
174
174
|
const output = result.status === "committed"
|
|
175
175
|
? `Integrated ${integrationSourceLabel(result.attempt)} into ${result.attempt.targetRef} with CAS (${result.attempt.id})\n`
|
|
176
176
|
: result.status === "conflicted"
|
|
@@ -49,6 +49,16 @@ export function withTaskRoleHostObservation(status, host) {
|
|
|
49
49
|
};
|
|
50
50
|
}
|
|
51
51
|
export function inspectTaskRoleRuntimeStatuses(taskId, roles, store, panes, now = new Date()) {
|
|
52
|
+
if (roles.length === 0)
|
|
53
|
+
return [];
|
|
54
|
+
// One inspection shares the same Task history across Roles. This is local
|
|
55
|
+
// read reuse, not a cache of runtime health or provider observations.
|
|
56
|
+
const events = store.listEvents(taskId);
|
|
57
|
+
const history = {
|
|
58
|
+
events,
|
|
59
|
+
runs: operationalTaskRecords(store.listRuns(taskId), events, "run"),
|
|
60
|
+
workspaces: store.listManagedWorkspaces(taskId)
|
|
61
|
+
};
|
|
52
62
|
const taskOpenInputRequestCount = store.listInputRequests(taskId)
|
|
53
63
|
.filter((request) => request.status === "open").length;
|
|
54
64
|
const panesByRole = new Map();
|
|
@@ -57,7 +67,7 @@ export function inspectTaskRoleRuntimeStatuses(taskId, roles, store, panes, now
|
|
|
57
67
|
if (current === undefined || current.dead && !pane.dead)
|
|
58
68
|
panesByRole.set(pane.roleName, pane);
|
|
59
69
|
}
|
|
60
|
-
return roles.map((role) => inspectTaskRoleRuntimeStatus(taskId, role, store, panesByRole.get(role.name), role.name === "leader" ? taskOpenInputRequestCount : 0, now));
|
|
70
|
+
return roles.map((role) => inspectTaskRoleRuntimeStatus(taskId, role, store, panesByRole.get(role.name), role.name === "leader" ? taskOpenInputRequestCount : 0, now, history));
|
|
61
71
|
}
|
|
62
72
|
export function renderTaskRoleRuntimeStatus(status) {
|
|
63
73
|
const activeRun = status.activeRun === null
|
|
@@ -185,12 +195,12 @@ export function taskRoleTmuxLabel(status) {
|
|
|
185
195
|
? "running"
|
|
186
196
|
: `running (${status.tmux.currentCommand})`;
|
|
187
197
|
}
|
|
188
|
-
function inspectTaskRoleRuntimeStatus(taskId, role, store, pane, openInputRequestCount, now) {
|
|
198
|
+
function inspectTaskRoleRuntimeStatus(taskId, role, store, pane, openInputRequestCount, now, history) {
|
|
189
199
|
const activeRun = store.getActiveRun(taskId, role.name);
|
|
190
200
|
// The last AgentRun outcome is a separate axis from the Session lifecycle. A
|
|
191
201
|
// Session that stops after its AgentRun completed must not retroactively turn
|
|
192
202
|
// that AgentRun into a failure; the status display keeps both visible.
|
|
193
|
-
const lastRun =
|
|
203
|
+
const lastRun = history.runs
|
|
194
204
|
.filter((candidate) => candidate.roleName === role.name)
|
|
195
205
|
.sort((left, right) => Date.parse(right.updatedAt) - Date.parse(left.updatedAt))[0]
|
|
196
206
|
?? null;
|
|
@@ -221,12 +231,12 @@ function inspectTaskRoleRuntimeStatus(taskId, role, store, pane, openInputReques
|
|
|
221
231
|
// distinct from the WorkItem Develop workspace.
|
|
222
232
|
const actualWorkspaceRoot = effectiveLaunch?.workspace.root ?? role.workspace;
|
|
223
233
|
const managedWorkspace = activeRun?.workspace
|
|
224
|
-
??
|
|
234
|
+
?? history.workspaces.find(({ root }) => root === actualWorkspaceRoot)
|
|
225
235
|
?? null;
|
|
226
236
|
const workspace = managedWorkspace === null
|
|
227
237
|
? { managed: false, path: actualWorkspaceRoot }
|
|
228
238
|
: { ...managedWorkspace, managed: true };
|
|
229
|
-
const events =
|
|
239
|
+
const { events } = history;
|
|
230
240
|
const sessionTokens = projectSessionTokenMetrics(events, resolveSessionTokenIdentity(nativeSession === null
|
|
231
241
|
? null
|
|
232
242
|
: { taskId, roleName: role.name, ...nativeSession }));
|
|
@@ -1,18 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { assertTaskReadable } from "../context/taskContext.js";
|
|
2
2
|
import { readTaskUsage } from "../runtime/taskUsageQuery.js";
|
|
3
3
|
import { formatUsageMetric } from "../runtime/taskUsageMetrics.js";
|
|
4
4
|
import { exactPositionals, output, parseTail, requireTask } from "./taskCommandSupport.js";
|
|
5
5
|
import { usageError } from "../errors/cliError.js";
|
|
6
|
-
import { taskActor } from "../task/taskAuthority.js";
|
|
7
6
|
export function taskUsageCommand(args, store, options) {
|
|
8
7
|
const usage = "yui task usage <task> [--limit <0..50>] [--offset <n>]";
|
|
9
8
|
const parsed = parseTail(args, new Set(["--limit", "--offset"]), usage);
|
|
10
9
|
exactPositionals(parsed.positionals, 1, usage);
|
|
11
10
|
const task = requireTask(store, parsed.positionals[0]);
|
|
12
|
-
|
|
13
|
-
// Assignment. Reading the Task record alone does not authorize these facts.
|
|
14
|
-
taskActor(options.environment, task.id);
|
|
15
|
-
assertContextRecordReadable(store, task.id, "task", task.id, options.environment);
|
|
11
|
+
assertTaskReadable(store, task.id, options.environment);
|
|
16
12
|
const limit = Number(parsed.options.get("--limit") ?? 0), offset = Number(parsed.options.get("--offset") ?? 0);
|
|
17
13
|
if (!Number.isSafeInteger(limit) || limit < 0 || limit > 50 || !Number.isSafeInteger(offset) || offset < 0) {
|
|
18
14
|
throw usageError(usage);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
import { usageError } from "../errors/cliError.js";
|
|
3
|
-
export function readCommandText(inline, file, label, usage) {
|
|
3
|
+
export function readCommandText(inline, file, label, usage, options = {}) {
|
|
4
4
|
if ((inline === undefined) === (file === undefined)) {
|
|
5
5
|
throw usageError(`Specify exactly one of ${label} or ${label}-file.`, usage);
|
|
6
6
|
}
|
|
@@ -11,5 +11,5 @@ export function readCommandText(inline, file, label, usage) {
|
|
|
11
11
|
if (normalized.length === 0 || normalized.includes("\0")) {
|
|
12
12
|
throw usageError(`${label} is required.`, usage);
|
|
13
13
|
}
|
|
14
|
-
return normalized;
|
|
14
|
+
return file !== undefined && options.preserveFileWhitespace ? value : normalized;
|
|
15
15
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Public current-Context family names, shared by reads and CLI discovery.
|
|
2
|
+
* Listing a family grants no permission to read its records.
|
|
3
|
+
*/
|
|
4
|
+
export const CONTEXT_FAMILIES = Object.freeze([
|
|
5
|
+
"task", "task-brief", "remote-delivery", "role", "role-profile",
|
|
6
|
+
"project-policy", "project-knowledge", "input-request", "work-item",
|
|
7
|
+
"accepted-work-item", "candidate", "environment-preparation", "managed-workspace",
|
|
8
|
+
"change-set", "task-message", "run", "source-run", "review-round", "mailbox",
|
|
9
|
+
"task-decision", "task-milestone", "job", "publication", "task-event"
|
|
10
|
+
]);
|
|
@@ -42,7 +42,9 @@ export function checkCurrentSkills(home, ids) {
|
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
44
|
export const SKILL_CHECK_COMMAND = "yui session skills --json";
|
|
45
|
-
export const SKILL_REUSE_RULE = "
|
|
46
|
-
+ "
|
|
47
|
-
+ "
|
|
48
|
-
+ "
|
|
45
|
+
export const SKILL_REUSE_RULE = "The managed Host checks current Skill versions/availability before each input; "
|
|
46
|
+
+ "do not repeat an explicit Host check. Without that notice, check through the Manifest's command. "
|
|
47
|
+
+ "Reuse unchanged full instructions in context; messages alone require no reload. "
|
|
48
|
+
+ "Read affected entries/references fully on change or localized loss. On first entry, recovery or lost context, "
|
|
49
|
+
+ "rebuild the current working set from applicable Skill entry points and action-relevant references, not all past procedures. "
|
|
50
|
+
+ "Metadata proves neither loading, memory nor authority.";
|
|
@@ -371,9 +371,11 @@ export function runContextEntry(pack) {
|
|
|
371
371
|
const { skillPackages: _packages, pointers: _pointers, deltaRefs, liveTaskState, input, ...identity } = pack;
|
|
372
372
|
const { directive, ...inputIdentity } = input;
|
|
373
373
|
const { items, ...pointerPage } = runContextPointerPage(pack, { limit: 16 });
|
|
374
|
+
const directiveSummary = directive === undefined ? undefined : summaryText(directive);
|
|
374
375
|
return {
|
|
375
376
|
...identity, input: { ...inputIdentity, ...(directive === undefined ? {} : {
|
|
376
|
-
directiveSummary
|
|
377
|
+
...(directiveSummary === directive ? { directive, directiveOmitted: false }
|
|
378
|
+
: { directiveSummary, directiveOmitted: true })
|
|
377
379
|
}) }, pointers: items, pointerPage,
|
|
378
380
|
deltaRefs: deltaRefs.slice(0, 16), deltaRefsTotal: deltaRefs.length,
|
|
379
381
|
inventory: { ...pack.inventory, complete: pointerPage.complete },
|
|
@@ -386,9 +388,16 @@ export function runContextEntry(pack) {
|
|
|
386
388
|
},
|
|
387
389
|
reads: {
|
|
388
390
|
inbox: "yui inbox list --view current --json",
|
|
389
|
-
|
|
391
|
+
...(items.length > 0 ? {
|
|
392
|
+
expand: `yui task run context expand ${pack.identity.taskId}/${pack.identity.runId} --context-ref <store/refId> [--context-ref <store/refId> ...] --mode full --json`
|
|
393
|
+
} : {}),
|
|
394
|
+
...(!pointerPage.complete ? {
|
|
395
|
+
refs: `yui task run context ${pack.identity.taskId}/${pack.identity.runId} --view refs`
|
|
396
|
+
} : {}),
|
|
390
397
|
full: `yui task run context ${pack.identity.taskId}/${pack.identity.runId} --view full`,
|
|
391
|
-
|
|
398
|
+
...(directiveSummary !== directive ? {
|
|
399
|
+
input: `yui task run context ${pack.identity.taskId}/${pack.identity.runId} --view input`
|
|
400
|
+
} : {}),
|
|
392
401
|
live: `yui task context ${pack.identity.taskId}`
|
|
393
402
|
}
|
|
394
403
|
};
|
|
@@ -413,7 +422,7 @@ function readLiveTaskState(store, taskId) {
|
|
|
413
422
|
}));
|
|
414
423
|
return Object.freeze({
|
|
415
424
|
providerRetries: Object.freeze(store.listRoleSessionSets(taskId).flatMap(set => set.providerBinding?.retry === undefined
|
|
416
|
-
? [] : [{ roleName: set.owner.roleName, retry: providerRetrySummary(set.providerBinding) }])),
|
|
425
|
+
? [] : [{ roleName: set.owner.roleName, retry: providerRetrySummary(set.providerBinding, `yui task role session retry ${taskId} ${set.owner.roleName} show --json`) }])),
|
|
417
426
|
activeRuns: Object.freeze(activeRuns),
|
|
418
427
|
activeTaskReviews: Object.freeze(activeTaskReviews)
|
|
419
428
|
});
|
|
@@ -422,6 +431,34 @@ export function expandRunContextRef(store, taskId, runId, refId, refStore) {
|
|
|
422
431
|
requireIdentity(refStore, "Context ref store");
|
|
423
432
|
const run = requireExactRun(store, taskId, runId);
|
|
424
433
|
const snapshot = readRunContextSnapshot(store, run);
|
|
434
|
+
return expandSnapshotRef(snapshot, refId, refStore);
|
|
435
|
+
}
|
|
436
|
+
/** Explicit originals from one already-authorized frozen Run, not live Task
|
|
437
|
+
* discovery. Read the snapshot once and reject the entire selection on drift. */
|
|
438
|
+
export function expandRunContextRefs(store, taskId, runId, selectors) {
|
|
439
|
+
if (selectors.length < 1 || selectors.length > 8)
|
|
440
|
+
throw new Error("Run Context batch requires 1..8 exact references.");
|
|
441
|
+
const seen = new Set();
|
|
442
|
+
for (const ref of selectors) {
|
|
443
|
+
requireIdentity(ref.store, "Context ref store");
|
|
444
|
+
requireIdentity(ref.refId, "Context ref id");
|
|
445
|
+
if (ref.digest !== undefined && !/^[a-f0-9]{64}$/.test(ref.digest))
|
|
446
|
+
throw new Error("An explicit Run Context digest must be exact.");
|
|
447
|
+
const key = JSON.stringify([ref.store, ref.refId]);
|
|
448
|
+
if (seen.has(key))
|
|
449
|
+
throw new Error("Duplicate Run Context batch reference.");
|
|
450
|
+
seen.add(key);
|
|
451
|
+
}
|
|
452
|
+
const snapshot = readRunContextSnapshot(store, requireExactRun(store, taskId, runId));
|
|
453
|
+
const items = selectors.map(ref => {
|
|
454
|
+
const expanded = expandSnapshotRef(snapshot, ref.refId, ref.store);
|
|
455
|
+
if (ref.digest !== undefined && expanded.ref.digest !== ref.digest)
|
|
456
|
+
throw new Error(`Run Context reference digest does not match its frozen Snapshot: ${ref.store}/${ref.refId}.`);
|
|
457
|
+
return expanded;
|
|
458
|
+
});
|
|
459
|
+
return { taskId, runId, items };
|
|
460
|
+
}
|
|
461
|
+
function expandSnapshotRef(snapshot, refId, refStore) {
|
|
425
462
|
const authorized = snapshot.refs.filter((ref) => (ref.refId === refId && ref.store === refStore));
|
|
426
463
|
const selector = `${refStore}/${refId}`;
|
|
427
464
|
if (authorized.length !== 1) {
|
|
@@ -770,7 +807,9 @@ function materialize(layer, store, refId, value) {
|
|
|
770
807
|
summary: (store === "project-knowledge"
|
|
771
808
|
? [title, `version: ${record.version}`, ...(record.scope === undefined ? [] : [`scope: ${record.scope}`]),
|
|
772
809
|
...(record.expiresWhen === undefined ? [] : [`expiresWhen: ${record.expiresWhen}`])].join("; ")
|
|
773
|
-
:
|
|
810
|
+
: store === "task-message" && typeof record.body === "string"
|
|
811
|
+
? summaryText(`Excerpt: ${record.body}`, 160)
|
|
812
|
+
: title).slice(0, 400)
|
|
774
813
|
}),
|
|
775
814
|
value
|
|
776
815
|
});
|
|
@@ -79,7 +79,7 @@ export function serializeRunInputEnvelope(value) {
|
|
|
79
79
|
.join(",");
|
|
80
80
|
const snapshot = normalized.contextSnapshotRef;
|
|
81
81
|
const lines = [
|
|
82
|
-
"Yui AgentRun input.
|
|
82
|
+
"Yui AgentRun input. Follow the Session Manifest profile and current Skills; use the Host check when supplied.",
|
|
83
83
|
`${normalized.subject.taskId === undefined ? "" : `task=${normalized.subject.taskId} `}run=${normalized.runId} role=${normalized.roleName}`,
|
|
84
84
|
`source=${normalized.source.type}/${normalized.source.channel} purpose=${normalized.purpose} subject=${subject || "global"} snapshot=${snapshot === undefined ? "none" : `${snapshot.id}@${snapshot.digest}`}`,
|
|
85
85
|
normalized.deltaRefIds.length === 0
|
|
@@ -18,13 +18,15 @@ export function withSessionContextPointer(text, environment) {
|
|
|
18
18
|
text
|
|
19
19
|
].join("\n");
|
|
20
20
|
}
|
|
21
|
-
/**
|
|
21
|
+
/** Host metadata checks do not prove instructions survived context compaction.
|
|
22
|
+
* Unmediated/native clients retain the explicit diagnostic fallback. */
|
|
22
23
|
export function sessionContextInstructions(manifestPath, digest) {
|
|
23
24
|
return `Yui Session Manifest: ${manifestPath}${digest === undefined ? "" : ` (digest ${digest})`}. `
|
|
24
|
-
+
|
|
25
|
-
+ `(
|
|
26
|
-
+ "
|
|
27
|
-
+
|
|
25
|
+
+ "For inputs carrying the Yui Host Skill-check notice, engineering has checked current versions; do not repeat that check. "
|
|
26
|
+
+ `Otherwise run its contextProtocol.skillCheckCommand (fallback: ${SKILL_CHECK_COMMAND}). `
|
|
27
|
+
+ "On first entry or lost instructions, read the current applicable Skill entry points, then only references needed for the current action. "
|
|
28
|
+
+ "On change reload affected instructions. Compaction does not require restoring every previously used procedure. "
|
|
29
|
+
+ "Preserve the Manifest Role profile; metadata never proves loading or memory.";
|
|
28
30
|
}
|
|
29
31
|
/** The caller must already pass the ordinary managed Session/CLI/Home checks.
|
|
30
32
|
* Old manifests remain immutable audit records, while this read resolves their
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { checkSessionSkills } from "./sessionBootstrapManifest.js";
|
|
2
|
+
/** Host-local last accepted metadata, never a model loading/memory receipt.
|
|
3
|
+
* A new Host/attachment starts cold. No durable schema or input replay is added. */
|
|
4
|
+
export function createSessionSkillNotice(home) {
|
|
5
|
+
let previous;
|
|
6
|
+
let generation = 0;
|
|
7
|
+
const invalidate = () => { previous = undefined; generation += 1; };
|
|
8
|
+
return {
|
|
9
|
+
invalidate,
|
|
10
|
+
prepare(text, environment, sessionKey, options = {}) {
|
|
11
|
+
const manifest = environment.YUI_SESSION_MANIFEST;
|
|
12
|
+
if (manifest === undefined)
|
|
13
|
+
return { text, commit() { } };
|
|
14
|
+
if (options.recovery)
|
|
15
|
+
invalidate();
|
|
16
|
+
let current;
|
|
17
|
+
try {
|
|
18
|
+
current = checkSessionSkills(home, manifest);
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
invalidate();
|
|
22
|
+
throw error; // Do not submit business input with an invalid current installation.
|
|
23
|
+
}
|
|
24
|
+
const key = JSON.stringify([sessionKey, manifest, current.roleProfileRef]);
|
|
25
|
+
const skills = new Map(current.skills.map(skill => [skill.id, JSON.stringify({
|
|
26
|
+
id: skill.id, path: skill.path, version: skill.version
|
|
27
|
+
})]));
|
|
28
|
+
const cold = previous?.key !== key;
|
|
29
|
+
const changed = [...skills].filter(([id, value]) => cold || previous.skills.get(id) !== value)
|
|
30
|
+
.map(([, value]) => value);
|
|
31
|
+
const removed = !cold && [...previous.skills.keys()].some(id => !skills.has(id));
|
|
32
|
+
// Every input is checked, but only a lifecycle/metadata event needs an
|
|
33
|
+
// instruction-loading notice. This marker distinguishes Host-mediated
|
|
34
|
+
// input from an unmediated client without restating the operating manual.
|
|
35
|
+
const lines = ["Yui Host checked current Skills; no Agent check needed."];
|
|
36
|
+
if (cold || changed.length > 0 || removed) {
|
|
37
|
+
lines.push(`Yui Session Manifest: ${manifest}`, cold
|
|
38
|
+
? `First input or recovered attachment: read the exact Role profile at ${current.roleProfileRef.path} and the full current listed Skill entry points. Follow references only for the action you are taking, not to restore every previously used procedure. A Task role-profile projection is not this profile.`
|
|
39
|
+
: "Skill metadata changed: load affected entries and applicable references; retain other complete instructions.", `Current Skill pointers: [${(removed ? [...skills.values()] : changed).join(",")}]`, "Metadata is not a loading receipt. Read each required file through EOF; if output is truncated, finish the missing ranges. Recover missing instructions for the current task, not the whole manual.");
|
|
40
|
+
}
|
|
41
|
+
const preparedGeneration = generation;
|
|
42
|
+
return {
|
|
43
|
+
text: `${lines.join("\n")}\n\n${text}`,
|
|
44
|
+
commit() {
|
|
45
|
+
if (generation !== preparedGeneration)
|
|
46
|
+
return;
|
|
47
|
+
previous = { key, skills };
|
|
48
|
+
generation += 1;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
@@ -50,26 +50,17 @@ export function parseTaskCatalogOptions(args) {
|
|
|
50
50
|
...(values.has("--cursor") ? { cursor: values.get("--cursor") } : {})
|
|
51
51
|
};
|
|
52
52
|
}
|
|
53
|
-
/** Task-local Leaders discover only their Task. Assignment Roles use their
|
|
54
|
-
* existing Context pack: whole-Task counts would leak unrelated assignments. */
|
|
55
|
-
export function taskCatalogScope(store, environment) {
|
|
56
|
-
const caller = resolveContextReader(store, environment);
|
|
57
|
-
if (caller !== undefined && caller.roleName !== "leader") {
|
|
58
|
-
throw usageError("Task discovery is unavailable to an Assignment-scoped Role; use its authorized Run Context.");
|
|
59
|
-
}
|
|
60
|
-
return caller?.taskId;
|
|
61
|
-
}
|
|
62
53
|
export function readTaskCatalog(store, options, environment = {}) {
|
|
63
54
|
return store.transaction(reader => {
|
|
64
|
-
|
|
55
|
+
resolveContextReader(reader, environment);
|
|
65
56
|
const { cursor: rawCursor, ...filters } = options;
|
|
66
57
|
if (!Number.isSafeInteger(filters.limit) || filters.limit < 1 || filters.limit > MAX_LIMIT) {
|
|
67
58
|
throw usageError("Task catalog limit must be between 1 and 100.");
|
|
68
59
|
}
|
|
69
|
-
const scope = contextContentDigest({ taskId:
|
|
60
|
+
const scope = contextContentDigest({ taskId: null, ...filters });
|
|
70
61
|
const cursor = rawCursor === undefined ? undefined : decodeCursor(rawCursor, scope);
|
|
71
62
|
const facts = reader.queryTaskCatalog({
|
|
72
|
-
...filters,
|
|
63
|
+
...filters,
|
|
73
64
|
...(cursor === undefined ? {} : { after: cursor.after, through: cursor.through }),
|
|
74
65
|
limit: options.limit + 1
|
|
75
66
|
});
|
|
@@ -106,7 +97,7 @@ export function readTaskCatalog(store, options, environment = {}) {
|
|
|
106
97
|
}));
|
|
107
98
|
const response = {
|
|
108
99
|
view: "compact",
|
|
109
|
-
scope: { taskId:
|
|
100
|
+
scope: { taskId: null, archived: options.all ? "included" : "excluded",
|
|
110
101
|
attention: "authorized-catalog-before-filters", executionSignals: "raw-inspection-candidates-not-execution-status" },
|
|
111
102
|
filters, total: facts.total, counts: facts.counts, attention,
|
|
112
103
|
tasks: [],
|