@zq-silk/yui 2.19.0 → 2.21.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.
Files changed (58) hide show
  1. package/dist/cli/commandCatalog.js +5 -3
  2. package/dist/cli/invocationAuthority.js +2 -6
  3. package/dist/cli/managedDiagnostics.js +24 -16
  4. package/dist/commands/durableJobCommands.js +2 -3
  5. package/dist/commands/roleConfiguration.js +17 -0
  6. package/dist/commands/taskCommands.js +9 -36
  7. package/dist/commands/taskFactCommands.js +5 -5
  8. package/dist/commands/taskUsageCommand.js +2 -6
  9. package/dist/context/taskCatalog.js +4 -13
  10. package/dist/context/taskContext.js +35 -87
  11. package/dist/context/taskSearch.js +3 -7
  12. package/dist/controlPlaneCli.js +6 -18
  13. package/dist/controller/fileSchedulerStoreAdapter.js +22 -2
  14. package/dist/controller/jobClient.js +2 -2
  15. package/dist/controller/jobControl.js +2 -2
  16. package/dist/controller/jobDefinitionControl.js +5 -1
  17. package/dist/controller/runtimeLaunchCoordinator.js +12 -1
  18. package/dist/executor/agentExecutor.js +7 -0
  19. package/dist/executor/fileRoleLaunchPlanner.js +22 -6
  20. package/dist/executor/taskAgentCapabilities.js +2 -2
  21. package/dist/output/rolePresentation.js +1 -0
  22. package/dist/role/instanceCode.js +7 -0
  23. package/dist/role/role.js +10 -0
  24. package/dist/runtime/agentEndpoint.js +1 -0
  25. package/dist/runtime/agentHost.js +9 -1
  26. package/dist/runtime/launchBroker.js +3 -0
  27. package/dist/runtime/runtimeBinding.js +3 -0
  28. package/dist/runtime/sessionTitle.js +29 -9
  29. package/dist/runtime/structuredProviderHost.js +11 -1
  30. package/dist/runtime/tmuxAdapters.js +4 -0
  31. package/dist/storage/sqliteSchema.js +10 -0
  32. package/dist/storage/storageVersions.js +1 -1
  33. package/dist/task/taskAuthority.js +7 -3
  34. package/docs/cli-information-contract.md +17 -0
  35. package/docs/cli-information-contract.zh-CN.md +12 -0
  36. package/docs/release-workflow.md +54 -0
  37. package/docs/release-workflow.zh-CN.md +40 -0
  38. package/docs/roles-and-configuration.md +49 -0
  39. package/docs/roles-and-configuration.zh-CN.md +38 -0
  40. package/docs/storage-baseline.md +4 -1
  41. package/docs/storage-baseline.zh-CN.md +1 -1
  42. package/docs/task-discovery.md +5 -5
  43. package/docs/task-discovery.zh-CN.md +4 -4
  44. package/docs/testing/verification-levels.md +2 -2
  45. package/docs/testing/verification-levels.zh-CN.md +1 -1
  46. package/package.json +1 -1
  47. package/skills/yui-leader/SKILL.md +10 -6
  48. package/skills/yui-leader/VERSION +1 -1
  49. package/skills/yui-operator/SKILL.md +5 -3
  50. package/skills/yui-operator/VERSION +1 -1
  51. package/skills/yui-operator/references/task-delivery.md +4 -1
  52. package/skills/yui-reviewer/SKILL.md +4 -2
  53. package/skills/yui-reviewer/VERSION +1 -1
  54. package/skills/yui-runtime/SKILL.md +34 -8
  55. package/skills/yui-runtime/VERSION +1 -1
  56. package/skills/yui-runtime/references/publication.md +16 -9
  57. package/skills/yui-worker/SKILL.md +7 -4
  58. package/skills/yui-worker/VERSION +1 -1
@@ -136,6 +136,7 @@ const agentChildren = [
136
136
  { name: "remove", discovery: { surface: "public", audiences: ["public", "operator"] }, summary: "Remove a configured Agent.", usage: "yui config agent remove <id>" }
137
137
  ];
138
138
  const roleProfileOptions = [
139
+ "--instance-code",
139
140
  "--description", "--responsibility", "--constraint",
140
141
  "--expected-output", "--system-prompt", "--skill"
141
142
  ];
@@ -144,6 +145,7 @@ const roleAgentOptions = [
144
145
  "--allowed-tool", "--disallowed-tool", "--search"
145
146
  ];
146
147
  const roleProfileClearOptions = [
148
+ "--clear-instance-code",
147
149
  "--clear-description", "--clear-responsibilities", "--clear-constraints",
148
150
  "--clear-expected-output", "--clear-system-prompt", "--clear-skills"
149
151
  ];
@@ -399,19 +401,19 @@ const taskChildren = [
399
401
  fileOptions: ["--summary-file"]
400
402
  },
401
403
  {
402
- name: "list", discovery: { surface: "public", audiences: ["public", "operator", "leader"] },
404
+ name: "list", discovery: { surface: "public", audiences: ["public", "operator", "leader", "assignment"] },
403
405
  summary: "Discover Tasks through a bounded, filterable catalog.",
404
406
  usage: "yui task list [--all] [--source <ordinary|job>] [--status <status>] [--project <id>] [--search <text>] [--attention <category>] [--limit <1..100>] [--cursor <cursor>]",
405
407
  options: ["--all", "--source", "--status", "--project", "--search", "--attention", "--limit", "--cursor"]
406
408
  },
407
409
  {
408
- name: "search", discovery: { surface: "public", audiences: ["public", "operator", "leader"] },
410
+ name: "search", discovery: { surface: "public", audiences: ["public", "operator", "leader", "assignment"] },
409
411
  summary: "Search authorized Task bodies and return exact, reference-only source citations.",
410
412
  usage: "yui task search <query> [--task <id>] [--kind <brief|message|decision|result|completion>] [--limit <1..100>] [--cursor <cursor>]",
411
413
  options: ["--task", "--kind", "--limit", "--cursor"]
412
414
  },
413
415
  { name: "show", discovery: { surface: "public", audiences: ["public", "operator", "leader", "assignment"] }, summary: "Show Task metadata and counts; long details use contentPage.", usage: "yui task show <id> [--cursor <cursor>]", options: ["--cursor"] },
414
- { name: "usage", discovery: { surface: "public", audiences: ["public", "operator", "leader"] }, summary: "Read bounded Task usage and sourced costs; request detail pages explicitly.", usage: "yui task usage <task> [--limit <0..50>] [--offset <n>]", options: ["--limit", "--offset"] },
416
+ { name: "usage", discovery: { surface: "public", audiences: ["public", "operator", "leader", "assignment"] }, summary: "Read bounded Task usage and sourced costs; request detail pages explicitly.", usage: "yui task usage <task> [--limit <0..50>] [--offset <n>]", options: ["--limit", "--offset"] },
415
417
  {
416
418
  name: "artifact", discovery: { surface: "managed", audiences: ["operator", "leader"] },
417
419
  summary: "Save Task files in local Git and read current or commit-pinned content.",
@@ -4,7 +4,7 @@ import { requireManagedGlobalCaller } from "../runtime/managedCaller.js";
4
4
  import { routeInvocation } from "./invocationRouter.js";
5
5
  import { findInteractionPolicy } from "./interactionPolicy.js";
6
6
  import { TASK_RECORD_ID_PREFIXES } from "../task/taskRecordReference.js";
7
- import { taskDiagnosticTarget } from "./managedDiagnostics.js";
7
+ import { isTaskReadCommand } from "./managedDiagnostics.js";
8
8
  /** Configuration reads remain available; every Home configuration mutation
9
9
  * has one owner, irrespective of which config subcommand parses its flags. */
10
10
  export function assertConfigurationAuthority(args, store, env) {
@@ -37,12 +37,8 @@ export function assertTaskInvocationScope(args, env) {
37
37
  }
38
38
  if (args[0] !== "task" || ["list", "search"].includes(args[1] ?? ""))
39
39
  return;
40
- const diagnostic = taskDiagnosticTarget(args);
41
- if (diagnostic !== undefined) {
42
- if (diagnostic !== env.YUI_TASK_ID)
43
- throw usageError("Command target is outside the caller's Task.");
40
+ if (isTaskReadCommand(args))
44
41
  return;
45
- }
46
42
  const invocation = routeInvocation([...args]);
47
43
  if (invocation.kind !== "execute")
48
44
  return;
@@ -1,20 +1,28 @@
1
- /** Read/repair routing, not an alternative grant. Callers still prove their
2
- * Home and Role identity; writes still require current Session authority. */
3
- export function taskDiagnosticTarget(args) {
1
+ /** Explicit effect classification, not a verb-name heuristic. Ordinary reads
2
+ * authenticate the caller but do not borrow the target Task's authority.
3
+ * Mixed commands (retry, base status) stay mutating unless this exact form is
4
+ * read-only. Domain parsers still reject unknown flags and malformed targets. */
5
+ export function isTaskReadCommand(args) {
4
6
  if (args[0] !== "task")
5
- return undefined;
6
- if (["show", "context", "next-action", "archive-preflight"].includes(args[1] ?? "")) {
7
- return args[1] === "context" && ["read", "list", "inspect", "delta"].includes(args[2] ?? "")
8
- ? args[3] : args[2];
9
- }
10
- if (args[1] === "role" && ["list", "status", "show"].includes(args[2] ?? ""))
11
- return args[3];
12
- if (args[1] === "role" && args[2] === "session" && args[3] === "inspect")
13
- return args[4];
14
- if (["message", "run", "wake", "input"].includes(args[1] ?? "")
7
+ return false;
8
+ if (["list", "search", "show", "usage", "next-action", "remote-delivery", "archive-preflight"].includes(args[1] ?? ""))
9
+ return true;
10
+ if (args[1] === "context")
11
+ return true;
12
+ if (["brief", "decision", "milestone", "event", "message", "run", "wake", "input", "work", "publication"].includes(args[1] ?? "")
15
13
  && ["list", "show"].includes(args[2] ?? ""))
16
- return args[3]?.split("/")[0];
17
- return undefined;
14
+ return true;
15
+ if (args[1] === "artifact" && ["list", "read"].includes(args[2] ?? ""))
16
+ return true;
17
+ if (args[1] === "run" && args[2] === "context")
18
+ return true;
19
+ if (args[1] === "role" && ["list", "status", "show"].includes(args[2] ?? ""))
20
+ return true;
21
+ if (args[1] === "role" && args[2] === "session") {
22
+ return args[3] === "inspect"
23
+ || args[3] === "retry" && (args.length === 6 || args.length === 7 && args[6] === "show");
24
+ }
25
+ return false;
18
26
  }
19
27
  export function operatorOfflineCommand(args) {
20
28
  return (args[0] === "controller"
@@ -25,5 +33,5 @@ export function operatorOfflineCommand(args) {
25
33
  || (args[0] === "session" && ["context", "reconcile"].includes(args[1] ?? ""))
26
34
  || (args[0] === "role" && args[1] === "message" && ["list", "show"].includes(args[2] ?? ""))
27
35
  || (args[0] === "task" && args[1] === "list")
28
- || taskDiagnosticTarget(args) !== undefined;
36
+ || isTaskReadCommand(args);
29
37
  }
@@ -2,7 +2,7 @@ import { usageError } from "../errors/cliError.js";
2
2
  import { ensureFileTaskController } from "../controller/clientRuntime.js";
3
3
  import { callFileTaskController } from "../controller/clientRuntime.js";
4
4
  import { acknowledgeDurableJob, cancelDurableJob, getDurableJob, startDurableJob } from "../controller/jobClient.js";
5
- import { resolveJobCaller, taskLocalActor } from "../task/taskAuthority.js";
5
+ import { resolveJobCaller, resolveJobReadCaller, taskLocalActor } from "../task/taskAuthority.js";
6
6
  import { boundedJobArtifactPayload } from "../artifacts/jobArtifactTransport.js";
7
7
  import { readFileSync, statSync } from "node:fs";
8
8
  /**
@@ -177,8 +177,7 @@ async function startJob(args, options) {
177
177
  }
178
178
  async function getJob(args, options) {
179
179
  const ref = parseRefArgs(args, "get");
180
- const caller = resolveJobCaller(options.environment, ref.taskId);
181
- await ensureFileTaskController(options.home, { environment: options.environment });
180
+ const caller = resolveJobReadCaller(options.environment, ref.taskId);
182
181
  const job = await getDurableJob(options.home, ref.taskId, ref.jobId, caller);
183
182
  if (options.json === true)
184
183
  return `${JSON.stringify(job, null, 2)}\n`;
@@ -1,4 +1,5 @@
1
1
  import { usageError } from "../errors/cliError.js";
2
+ import { validateInstanceCode } from "../role/instanceCode.js";
2
3
  import { parseEnabled } from "../role/availability.js";
3
4
  import { defaultRoleAgentConfig, resolveAgentAdapter } from "../executor/agentAdapter.js";
4
5
  const PROFILE_OPTIONS = [
@@ -66,6 +67,8 @@ export function roleOptionSpecs(input) {
66
67
  ...(input.includeWorkspace === true ? [["--workspace", "value"]] : []),
67
68
  ...(input.update ? [["--yes", "flag"]] : []),
68
69
  ...(input.update ? [["--enabled", "value"]] : []),
70
+ ["--instance-code", "value"],
71
+ ...(input.update ? [["--clear-instance-code", "flag"]] : []),
69
72
  ...PROFILE_OPTIONS,
70
73
  ...agentValueOptions,
71
74
  ...agentRepeatableOptions,
@@ -105,6 +108,7 @@ export function parseRoleOptions(args, specs, usage) {
105
108
  }
106
109
  export function roleProfileFrom(parsed) {
107
110
  return {
111
+ ...roleDisplayPatch(parsed),
108
112
  ...(parsed.has("--description") ? { description: requiredText(parsed.one("--description")) } : {}),
109
113
  responsibilities: parsed.many("--responsibility").map(requiredText),
110
114
  constraints: parsed.many("--constraint").map(requiredText),
@@ -125,6 +129,7 @@ export function roleProfilePatch(parsed) {
125
129
  ["--skill", "--clear-skills"]
126
130
  ]);
127
131
  return {
132
+ ...roleDisplayPatch(parsed),
128
133
  ...(parsed.has("--enabled") ? { enabled: parseEnabled(parsed.one("--enabled")) } : {}),
129
134
  ...(parsed.has("--description") ? { description: requiredText(parsed.one("--description")) } : {}),
130
135
  ...(parsed.has("--clear-description") ? { description: undefined } : {}),
@@ -144,6 +149,18 @@ export function roleProfilePatch(parsed) {
144
149
  ...(parsed.has("--clear-skills") ? { skills: [] } : {})
145
150
  };
146
151
  }
152
+ function roleDisplayPatch(parsed) {
153
+ assertPairs(parsed, [["--instance-code", "--clear-instance-code"]]);
154
+ try {
155
+ return {
156
+ ...(parsed.has("--instance-code") ? { instanceCode: validateInstanceCode(parsed.one("--instance-code")) } : {}),
157
+ ...(parsed.has("--clear-instance-code") ? { instanceCode: undefined } : {})
158
+ };
159
+ }
160
+ catch (error) {
161
+ throw usageError(error instanceof Error ? error.message : String(error));
162
+ }
163
+ }
147
164
  export function hasAgentConfigOptions(parsed) {
148
165
  return [...parsed.seen].some((option) => AGENT_CONFIG_OPTIONS.has(option));
149
166
  }
@@ -11,7 +11,7 @@ import { sourceRunContextValue } from "../context/sourceRunContext.js";
11
11
  import { buildRunContextDelta, buildRunContextPack, runContextEntry, runContextPointerPage, contextSnapshotDeltaRefIds, expandRunContextRef, freezeReviewStageContextSnapshot, freezeRunContextSnapshot, freezeWorkItemExecutionAssignmentContextSnapshot, freezeCandidateContextSnapshot, readRunContextSnapshot, synthesisSourceRunIds } from "../context/runContextPack.js";
12
12
  import { createRunInput } from "../context/runInputContract.js";
13
13
  import { parseTaskCatalogOptions, readTaskCatalog, renderTaskCatalog } from "../context/taskCatalog.js";
14
- import { assertContextRecordReadable, readTaskContextResource } from "../context/taskContext.js";
14
+ import { assertTaskReadable, readTaskContextResource, resolveContextReader } from "../context/taskContext.js";
15
15
  import { parseTaskSearchOptions, searchTaskBodies } from "../context/taskSearch.js";
16
16
  import { boundedDocument, readOptions, messageReceipt, recordPage } from "../output/boundedRead.js";
17
17
  import { referencedWakeRunIds } from "../context/wakeRunReferences.js";
@@ -46,7 +46,7 @@ import { resolveRecordedTaskFinalReviewContract } from "../review/taskFinalRevie
46
46
  import { copyGlobalRoleToTaskRole, activeRoleAgentBinding, createRole, createRoleAgentBinding, switchActiveRoleAgent, unbindRoleAgent, updateRole } from "../role/role.js";
47
47
  import { roleLaunchEventPayload, saveTaskRoleUpdate } from "../role/taskRoleUpdate.js";
48
48
  import { RUNTIME_SESSION_REPLACE_REQUIRED_REASON, runtimeLifecycleTarget } from "../runtime/lifecycleReservation.js";
49
- import { currentManagedRuntime, resolveManagedTaskReader } from "../runtime/managedCaller.js";
49
+ import { currentManagedRuntime } from "../runtime/managedCaller.js";
50
50
  import { controlProviderRetry, providerRunRetry, providerRetryProjection, renderProviderRetry } from "../runtime/providerRetry.js";
51
51
  import { currentProviderConversation, transferProviderAuthority } from "../runtime/providerRuntimeIdentity.js";
52
52
  import { projectProviderContinuations } from "../runtime/runtimeContinuationProjection.js";
@@ -1684,7 +1684,7 @@ function taskMessageCommand(args, store, options) {
1684
1684
  const parsed = readOptions(rest, ["--cursor"]);
1685
1685
  exactPositionals(parsed.positionals, 1, usage);
1686
1686
  const ref = taskRecordReference(parsed.positionals[0], "message", "Message reference", options);
1687
- assertContextRecordReadable(store, ref.taskId, "task-message", ref.localId, options.environment);
1687
+ assertTaskReadable(store, ref.taskId, options.environment);
1688
1688
  const message = store.queryContextRecords(ref.taskId, {
1689
1689
  family: "task-message", ids: [ref.localId], limit: 1
1690
1690
  }).records[0]?.value;
@@ -2512,14 +2512,8 @@ function taskRoleSessionCommand(args, store, options) {
2512
2512
  const role = requireRole(tx, task.id, roleName);
2513
2513
  if (action !== "show")
2514
2514
  taskActor(tx, options, task.id);
2515
- else {
2516
- const reader = resolveManagedTaskReader(tx, options.environment);
2517
- if (reader === undefined)
2518
- taskActor(tx, options, task.id);
2519
- else if (reader.taskId !== task.id || reader.roleName !== "leader" && reader.roleName !== role.name) {
2520
- throw usageError("Provider retry read is outside the caller's Task/Role.");
2521
- }
2522
- }
2515
+ else
2516
+ resolveContextReader(tx, options.environment ?? {});
2523
2517
  const sessions = tx.getTaskRoleSessionSet(task.id, role.name);
2524
2518
  let binding = sessions?.providerBinding ?? null;
2525
2519
  if (action !== "show") {
@@ -2538,12 +2532,7 @@ function taskRoleSessionCommand(args, store, options) {
2538
2532
  exactPositionals(rest, 2, "Task Role Session inspect usage: yui task role session inspect <task> <role>.");
2539
2533
  const task = requireTask(store, rest[0]);
2540
2534
  const role = requireRole(store, task.id, rest[1]);
2541
- const reader = resolveManagedTaskReader(store, options.environment);
2542
- if (reader === undefined)
2543
- taskActor(store, options, task.id);
2544
- else if (reader.taskId !== task.id || (reader.roleName !== "leader" && reader.roleName !== role.name)) {
2545
- throw usageError("Session inspection is outside the caller's Task/Role.");
2546
- }
2535
+ resolveContextReader(store, options.environment ?? {});
2547
2536
  const sessions = store.getTaskRoleSessionSet(task.id, role.name);
2548
2537
  const active = sessions?.sessions[sessions.activeAgentId] ?? null;
2549
2538
  const binding = sessions?.providerBinding ?? null;
@@ -4823,30 +4812,14 @@ function parseRunContextReference(value) {
4823
4812
  }
4824
4813
  return { taskId, runId };
4825
4814
  }
4826
- /**
4827
- * A AgentRun Context Pack is information the Role's own runtime reads in order to
4828
- * work. Authorization is therefore scope-shaped, not schedule-shaped: the
4829
- * caller must be the current runtime of the Task Role that owns the AgentRun,
4830
- * proven by its per-Session caller key against durable state.
4831
- *
4832
- * It deliberately does not require the AgentRun to still be the active one. An
4833
- * Agent whose AgentRun has advanced must still be able to read the context it was
4834
- * given; losing read access to its own Role's history is what forces an
4835
- * otherwise healthy Agent to stop and escalate to a human.
4836
- */
4815
+ /** Frozen packs are readable evidence. Their execution authority still belongs
4816
+ * exclusively to the dispatched Run; reading does not adopt that identity. */
4837
4817
  function authorizeRunContext(store, taskId, runId, environment) {
4838
- const managed = environment?.YUI_SESSION_SCOPE !== undefined
4839
- || environment?.YUI_TASK_ID !== undefined
4840
- || environment?.YUI_ROLE !== undefined;
4841
- if (!managed)
4842
- return;
4818
+ resolveContextReader(store, environment ?? {});
4843
4819
  const run = store.getRun(taskId, runId);
4844
4820
  if (run === null) {
4845
4821
  throw usageError(`AgentRun Context access is not authorized: ${taskId}/${runId}.`);
4846
4822
  }
4847
- if (currentManagedRuntime(store, environment, taskId, run.roleName) === undefined) {
4848
- throw usageError(`AgentRun Context access requires the current runtime of ${taskId}/${run.roleName}.`);
4849
- }
4850
4823
  }
4851
4824
  function listRuns(args, store, options) {
4852
4825
  const reference = args[0];
@@ -1,5 +1,5 @@
1
1
  import { createTaskBrief, updateTaskBrief } from "../brief/taskBrief.js";
2
- import { assertContextRecordReadable, resolveContextReader } from "../context/taskContext.js";
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";
@@ -15,7 +15,7 @@ export function taskBriefCommand(args, store, options) {
15
15
  exactPositionals(rest, 1, "Task brief show usage: yui task brief show <task>.");
16
16
  const { task, brief, writeGuard, phase } = store.readTransaction(reader => {
17
17
  const task = requireTask(reader, rest[0]);
18
- assertContextRecordReadable(reader, task.id, "task-brief", task.id, options.environment);
18
+ assertTaskReadable(reader, task.id, options.environment);
19
19
  const caller = resolveContextReader(reader, options.environment ?? {});
20
20
  const shared = caller === undefined || caller.roleName === "leader";
21
21
  return { task, brief: reader.getTaskBrief(task.id),
@@ -144,7 +144,7 @@ export function taskDecisionCommand(args, store, options) {
144
144
  if (command === "show") {
145
145
  exactPositionals(rest, 2, "Task decision show usage: yui task decision show <task> <decision>.");
146
146
  const task = requireTask(store, rest[0]);
147
- assertContextRecordReadable(store, task.id, "task-decision", rest[1], options.environment);
147
+ assertTaskReadable(store, task.id, options.environment);
148
148
  const decision = store.getDecision(task.id, rest[1]);
149
149
  if (decision === null)
150
150
  throw dataError(`Decision not found: ${rest[1]}.`);
@@ -228,7 +228,7 @@ export function taskMilestoneCommand(args, store, options) {
228
228
  if (command === "show") {
229
229
  exactPositionals(rest, 2, "Task milestone show usage: yui task milestone show <task> <milestone>.");
230
230
  const task = requireTask(store, rest[0]);
231
- assertContextRecordReadable(store, task.id, "task-milestone", rest[1], options.environment);
231
+ assertTaskReadable(store, task.id, options.environment);
232
232
  const milestone = store.getMilestone(task.id, rest[1]);
233
233
  if (milestone === null)
234
234
  throw dataError(`Milestone not found: ${rest[1]}.`);
@@ -254,7 +254,7 @@ export function taskEventCommand(args, store, options = {}) {
254
254
  if (command === "show") {
255
255
  exactPositionals(rest, 2, "Task event show usage: yui task event show <task> <event>.");
256
256
  const task = requireTask(store, rest[0]);
257
- assertContextRecordReadable(store, task.id, "task-event", rest[1], options.environment);
257
+ assertTaskReadable(store, task.id, options.environment);
258
258
  const event = store.queryContextRecords(task.id, {
259
259
  family: "task-event", ids: [rest[1]], limit: 1
260
260
  }).records[0]?.value;
@@ -1,18 +1,14 @@
1
- import { assertContextRecordReadable } from "../context/taskContext.js";
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
- // Task-lifetime aggregation spans every Role, beyond a Worker/Reviewer
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);
@@ -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
- const taskId = taskCatalogScope(reader, environment);
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: taskId ?? null, ...filters });
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, ...(taskId === undefined ? {} : { taskId }),
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: taskId ?? null, archived: options.all ? "included" : "excluded",
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: [],