@zq-silk/yui 2.8.1 → 2.10.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 -3
- package/dist/cli/commandCatalog.js +56 -21
- package/dist/cli/helpRenderer.js +3 -1
- package/dist/cli/interactionPolicy.js +2 -2
- package/dist/commands/durableJobCommands.js +50 -0
- package/dist/commands/globalRoleCommands.js +30 -9
- package/dist/commands/inboxCommands.js +79 -22
- package/dist/commands/projectCommands.js +4 -33
- package/dist/commands/scheduleCommands.js +45 -0
- package/dist/commands/taskActivationCommands.js +19 -5
- package/dist/commands/taskCommands.js +8 -2
- package/dist/commands/taskFactCommands.js +24 -12
- package/dist/commands/taskProjectDeliveryCommand.js +56 -0
- package/dist/commands/taskPublicationCommands.js +6 -3
- package/dist/commands/taskPublicationVerifyCommand.js +74 -28
- package/dist/commands/taskRemoteDeliveryCommand.js +5 -3
- package/dist/context/runContextPack.js +25 -4
- package/dist/context/runInputContract.js +1 -0
- package/dist/context/taskContext.js +53 -16
- package/dist/context/taskPhase.js +99 -0
- package/dist/controlPlaneCli.js +38 -17
- package/dist/controller/controller.js +35 -0
- package/dist/controller/fileSchedulerStoreAdapter.js +75 -16
- package/dist/controller/globalInputDelivery.js +17 -7
- package/dist/controller/inboxTurnCheck.js +64 -0
- package/dist/controller/jobControl.js +42 -12
- package/dist/controller/jobDefinitionControl.js +304 -0
- package/dist/controller/jobSupervisor.js +47 -32
- package/dist/controller/providerRetryAdmission.js +2 -0
- package/dist/controller/runtime.js +11 -2
- package/dist/controller/scheduleControl.js +176 -0
- package/dist/coordination/workMailbox.js +3 -3
- package/dist/external/githubPublicationVerifier.js +14 -5
- package/dist/external/gitlabPublicationVerifier.js +12 -29
- package/dist/grant/taskAuthorization.js +7 -2
- package/dist/interaction/notificationPresentation.js +12 -3
- package/dist/interaction/operatorPresentation.js +5 -0
- package/dist/job/builtinJob.js +58 -0
- package/dist/job/durableJob.js +72 -49
- package/dist/job/jobDefinition.js +68 -0
- package/dist/job/jobRunner.js +2 -1
- package/dist/job/projectRefreshRunner.js +48 -0
- package/dist/message/globalInboxRecovery.js +44 -0
- package/dist/message/globalInterrupt.js +1 -1
- package/dist/message/inboxReceipt.js +14 -6
- package/dist/message/inboxTurn.js +86 -0
- package/dist/message/message.js +11 -0
- package/dist/message/taskInboxOwnership.js +20 -6
- package/dist/repository/projectRefresh.js +58 -0
- package/dist/repository/taskWorkspacePreparer.js +2 -1
- package/dist/repository/workspaceCleanupInspection.js +6 -1
- package/dist/schedule/schedule.js +108 -0
- package/dist/scheduler/operatorEvent.js +2 -0
- package/dist/scheduler/operatorInputNotificationProcessor.js +8 -0
- package/dist/storage/contextRecords.js +8 -0
- package/dist/storage/jobSchema.js +15 -0
- package/dist/storage/maintenanceCaller.js +1 -1
- package/dist/storage/recordValidation.js +5 -0
- package/dist/storage/scheduleSchema.js +12 -0
- package/dist/storage/sqliteSchema.js +95 -24
- package/dist/storage/sqliteStore.js +123 -10
- package/dist/storage/storageVersions.js +1 -1
- package/dist/storage/storeRpc.js +5 -0
- package/dist/storage/upgrade/jobDefinitionMigration.js +22 -0
- package/dist/task/archiveDiagnostics.js +1 -1
- package/dist/task/archivePreflight.js +1 -1
- package/dist/task/projectDeliveryScope.js +20 -0
- package/dist/task/publicationToolObservation.js +126 -0
- package/dist/task/remoteDelivery.js +19 -8
- package/dist/task/remoteDeliveryService.js +5 -4
- package/dist/task/taskActivationService.js +35 -0
- package/dist/web/assets/client/app/settings.js +7 -1
- package/dist/web/assets/client/i18n/en.js +65 -2
- package/dist/web/assets/client/i18n/zh-CN.js +65 -2
- package/dist/web/assets/client/index.js +2 -0
- package/dist/web/assets/client/views/jobs.js +222 -0
- package/dist/web/assets/client/views/task/deliveryResults.js +6 -2
- package/dist/web/assets/client/views/task/page.js +11 -1
- package/dist/web/assets/shared/manageNav.js +1 -0
- package/dist/web/assets/shared/taskTabs.js +2 -2
- package/dist/web/assets/shell/settingsContent.js +3 -0
- package/dist/web/assets/styles/index.js +2 -0
- package/dist/web/assets/styles/views/jobs.js +19 -0
- package/dist/web/controllerWeb.js +73 -21
- package/dist/web/taskPreviews.js +21 -13
- package/dist/web/webAccess.js +109 -0
- package/dist/web/webJobs.js +52 -0
- package/dist/web/webServer.js +76 -44
- package/docs/architecture/capabilities-and-resources.md +6 -4
- package/docs/architecture/capabilities-and-resources.zh-CN.md +5 -4
- package/docs/cli-information-contract.md +57 -4
- package/docs/cli-information-contract.zh-CN.md +41 -2
- package/docs/job-runs.md +224 -0
- package/docs/project-delivery-scope.md +59 -0
- package/docs/release-workflow.md +86 -0
- package/docs/release-workflow.zh-CN.md +68 -0
- package/docs/schedules.md +132 -0
- package/docs/storage-baseline.md +31 -1
- package/docs/storage-baseline.zh-CN.md +25 -1
- package/docs/task-delivery.md +74 -2
- package/docs/task-delivery.zh-CN.md +39 -1
- package/docs/testing/verification-levels.md +6 -2
- package/docs/testing/verification-levels.zh-CN.md +6 -3
- package/i18n/README.zh-CN.md +6 -3
- package/package.json +4 -3
- package/skills/yui-leader/SKILL.md +44 -1
- package/skills/yui-leader/VERSION +1 -1
- package/skills/yui-leader/references/planning.md +9 -1
- package/skills/yui-operator/SKILL.md +31 -0
- package/skills/yui-operator/VERSION +1 -1
- package/skills/yui-reviewer/SKILL.md +4 -0
- package/skills/yui-reviewer/VERSION +1 -1
- package/skills/yui-runtime/SKILL.md +67 -8
- package/skills/yui-runtime/VERSION +1 -1
- package/skills/yui-runtime/references/context-ordering.md +103 -0
- package/skills/yui-runtime/references/publication.md +44 -4
- package/skills/yui-runtime/references/recovery.md +21 -0
- package/skills/yui-worker/SKILL.md +5 -0
- package/skills/yui-worker/VERSION +1 -1
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ not from terminal windows you juggle or details you have to remember.
|
|
|
30
30
|
- **Bring your own Agent** — Codex CLI, Claude Code CLI and ACP peers run behind
|
|
31
31
|
one boundary and stay replaceable without losing the Task.
|
|
32
32
|
- **Local-first and private** — everything runs on your machine for one trusted
|
|
33
|
-
user; Web
|
|
33
|
+
user; Web defaults to loopback, with explicitly enabled authenticated LAN access.
|
|
34
34
|
- **Isolated by default** — repository work happens in managed Git worktrees;
|
|
35
35
|
the stable checkout stays read-only.
|
|
36
36
|
|
|
@@ -181,6 +181,8 @@ For a visual overview, run `yui web` in another terminal. The local Web view
|
|
|
181
181
|
shows the same tasks and pending questions and lets you send messages, answer
|
|
182
182
|
questions and explicitly queue, steer or interrupt Task input. These authenticated
|
|
183
183
|
Task controls use the same operations as the CLI; Web is not a separate task system.
|
|
184
|
+
For explicit trusted-LAN binding, password protection, access URLs and Operator
|
|
185
|
+
start/status/stop, see [Controlled Web access](docs/web-access.md). HTTP is not encrypted.
|
|
184
186
|
The task list remains at the left, task details occupy the primary reading area,
|
|
185
187
|
and recorded Task messages live in a secondary discussion pane. You can resize,
|
|
186
188
|
swap or hide that pane; on narrow screens it opens over the detail. Native Sessions
|
|
@@ -311,7 +313,7 @@ the Controller are what touch the store:
|
|
|
311
313
|
it moves work and records facts — it never judges an answer
|
|
312
314
|
|
|
313
315
|
Agents work in Projects: read-only checkout + isolated worktrees.
|
|
314
|
-
Web (yui web):
|
|
316
|
+
Web (yui web): local by default + explicitly authenticated LAN access.
|
|
315
317
|
```
|
|
316
318
|
|
|
317
319
|
### Layered design
|
|
@@ -321,7 +323,7 @@ never a fixed workflow:
|
|
|
321
323
|
|
|
322
324
|
```text
|
|
323
325
|
Experience — how you interact
|
|
324
|
-
CLI (Operator) · Web (
|
|
326
|
+
CLI (Operator) · Web (local / authenticated LAN) · native Agent sessions
|
|
325
327
|
collect input · show facts · confirm actions · invoke capabilities
|
|
326
328
|
▼
|
|
327
329
|
Intelligence — who decides
|
|
@@ -275,7 +275,7 @@ const taskChildren = [
|
|
|
275
275
|
{
|
|
276
276
|
name: "project", discovery: { surface: "managed", audiences: ["operator", "leader"] },
|
|
277
277
|
summary: "Manage Projects bound to a Task.",
|
|
278
|
-
sections: [{ id: "manage", title: "Commands", entries: ["list", "add"] }],
|
|
278
|
+
sections: [{ id: "manage", title: "Commands", entries: ["list", "add", "delivery"] }],
|
|
279
279
|
children: [
|
|
280
280
|
{
|
|
281
281
|
name: "list", discovery: { surface: "public", audiences: ["public", "operator", "leader"] },
|
|
@@ -287,6 +287,13 @@ const taskChildren = [
|
|
|
287
287
|
summary: "Add a Project to a Task.",
|
|
288
288
|
usage: "yui task project add <task> <project> [--base <ref>] [--directory <name>]",
|
|
289
289
|
options: ["--base", "--directory"]
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
name: "delivery", discovery: { surface: "public", audiences: ["public", "operator", "leader"] },
|
|
293
|
+
summary: "Record a sourced Task Project delivery requirement; never grants cleanup or execution authority.",
|
|
294
|
+
usage: "yui task project delivery <task> <project-id> --requirement <required|excluded> --reason <text> --source-message <message-id> --purpose <exact-quote> --if-current <event-id|none>",
|
|
295
|
+
options: ["--requirement", "--reason", "--source-message", "--purpose", "--if-current"],
|
|
296
|
+
optionValues: { "--requirement": ["required", "excluded"] }
|
|
290
297
|
}
|
|
291
298
|
]
|
|
292
299
|
},
|
|
@@ -314,8 +321,8 @@ const taskChildren = [
|
|
|
314
321
|
name: "request", discovery: { surface: "public", audiences: ["public", "operator", "leader"] },
|
|
315
322
|
summary: "Record an Activation request. Every active Task gets a managed main workspace. empty adds no execution environment; scratch adopts a separate scratch environment; local requires a registered Resource and grant, not a Project ID.",
|
|
316
323
|
usage: "yui task activation request <task> --request-id <id> "
|
|
317
|
-
+ "--environment <empty|scratch|local:<resource>:<read|write>>",
|
|
318
|
-
options: ["--request-id", "--environment"],
|
|
324
|
+
+ "--environment <empty|scratch|local:<resource>:<read|write>> [--source-message <id> | --source-text <exact-input>]",
|
|
325
|
+
options: ["--request-id", "--environment", "--source-message", "--source-text"],
|
|
319
326
|
examples: [
|
|
320
327
|
"yui task activation request <task> --request-id start-1 --environment empty",
|
|
321
328
|
"yui task activation request <task> --request-id start-1 --environment scratch"
|
|
@@ -643,8 +650,8 @@ const taskChildren = [
|
|
|
643
650
|
{
|
|
644
651
|
name: "upsert", discovery: { surface: "managed", audiences: ["operator", "leader"] },
|
|
645
652
|
summary: "Create or immutably update an external PR/MR and its publication state.",
|
|
646
|
-
usage: "yui task publication upsert <task> --project <project> --provider <github|gitlab> --repository <owner/name> --kind <pull-request|merge-request> --id <external-id> [--url <url>] [--title <text>] [--source-branch <branch>] [--target-branch <branch>] [--local-commit <sha>] [--head-commit <sha>] [--remote-commit <sha>] [--state <open|merged|closed>] [--reported
|
|
647
|
-
options: ["--project", "--provider", "--repository", "--kind", "--id", "--url", "--title", "--source-branch", "--target-branch", "--local-commit", "--head-commit", "--remote-commit", "--state", "--reported", "--
|
|
653
|
+
usage: "yui task publication upsert <task> --project <project> --provider <github|gitlab> --repository <owner/name> --kind <pull-request|merge-request> --id <external-id> [--url <url>] [--title <text>] [--source-branch <branch>] [--target-branch <branch>] [--local-commit <sha>] [--head-commit <sha>] [--remote-commit <sha>] [--state <open|merged|closed>] [--reported] [--evidence <text>] [--merged-at <iso-timestamp>]",
|
|
654
|
+
options: ["--project", "--provider", "--repository", "--kind", "--id", "--url", "--title", "--source-branch", "--target-branch", "--local-commit", "--head-commit", "--remote-commit", "--state", "--reported", "--evidence", "--merged-at"]
|
|
648
655
|
},
|
|
649
656
|
{
|
|
650
657
|
name: "diff", discovery: { surface: "managed", audiences: ["operator", "leader"] },
|
|
@@ -660,8 +667,9 @@ const taskChildren = [
|
|
|
660
667
|
},
|
|
661
668
|
{
|
|
662
669
|
name: "verify", discovery: { surface: "managed", audiences: ["operator", "leader"] },
|
|
663
|
-
summary: "
|
|
664
|
-
usage: "yui task publication verify (<task>/<publication-id> | <task> <publication-id>)"
|
|
670
|
+
summary: "Record exact authorized tool evidence, or query the optional gh/glab adapter; verification is separate from Task coverage.",
|
|
671
|
+
usage: "yui task publication verify (<task>/<publication-id> | <task> <publication-id>) [--observation <json>]",
|
|
672
|
+
options: ["--observation"]
|
|
665
673
|
},
|
|
666
674
|
{
|
|
667
675
|
name: "list", discovery: { surface: "public", audiences: ["public", "operator", "leader"] },
|
|
@@ -738,7 +746,7 @@ const taskChildren = [
|
|
|
738
746
|
},
|
|
739
747
|
{
|
|
740
748
|
name: "new", discovery: { surface: "managed", audiences: ["operator", "leader"] },
|
|
741
|
-
summary: "
|
|
749
|
+
summary: "Stop exact execution, then initialize a successor without replaying retained inbox obligations; preserve claims, context and workspaces.",
|
|
742
750
|
usage: "yui task role session new <task> <role> --reason <text>",
|
|
743
751
|
options: ["--reason"]
|
|
744
752
|
}
|
|
@@ -1016,15 +1024,15 @@ const taskChildren = [
|
|
|
1016
1024
|
},
|
|
1017
1025
|
{
|
|
1018
1026
|
name: "brief", discovery: { surface: "managed", audiences: ["operator", "leader"] },
|
|
1019
|
-
summary: "Manage the Task
|
|
1027
|
+
summary: "Manage the Leader-maintained Task summary; live lifecycle and authority remain separate facts.",
|
|
1020
1028
|
sections: [{ id: "manage", title: "Commands", entries: ["show", "update"] }],
|
|
1021
1029
|
children: [
|
|
1022
1030
|
{ name: "show", discovery: { surface: "managed", audiences: ["operator", "leader"] }, summary: "Show the Task Brief.", usage: "yui task brief show <task> [--cursor <cursor>]", options: ["--cursor"] },
|
|
1023
1031
|
{
|
|
1024
1032
|
name: "update", discovery: { surface: "managed", audiences: ["operator", "leader"] },
|
|
1025
1033
|
summary: "Create or update the Task Brief.",
|
|
1026
|
-
usage: "yui task brief update <task> [--objective <text>] [--boundary <text> ...] [--approach <text>] [--focus <text>] [--leader-summary <text>]",
|
|
1027
|
-
options: ["--objective", "--boundary", "--approach", "--focus", "--leader-summary"]
|
|
1034
|
+
usage: "yui task brief update <task> --if-current <writeGuard> [--objective <text>] [--boundary <text> ...] [--approach <text>] [--focus <text>] [--leader-summary <text>]",
|
|
1035
|
+
options: ["--if-current", "--objective", "--boundary", "--approach", "--focus", "--leader-summary"]
|
|
1028
1036
|
}
|
|
1029
1037
|
]
|
|
1030
1038
|
},
|
|
@@ -1136,7 +1144,7 @@ export const ROOT_COMMAND = buildNode({
|
|
|
1136
1144
|
] },
|
|
1137
1145
|
{ id: "workflow", title: "Workflow", entries: ["agent", "operator", "role", "inbox", "project", "task"] },
|
|
1138
1146
|
{ id: "configuration", title: "Configuration", entries: ["config"] },
|
|
1139
|
-
{ id: "operations", title: "Operations", entries: ["web", "controller", "session", "execution", "capability", "job", "jobs", "telemetry", "release"] },
|
|
1147
|
+
{ id: "operations", title: "Operations", entries: ["web", "controller", "session", "execution", "capability", "job", "schedule", "jobs", "telemetry", "release"] },
|
|
1140
1148
|
{ id: "resources", title: "Resources", entries: ["resources"] },
|
|
1141
1149
|
{ id: "internal", title: "Internal", entries: ["internal"] }
|
|
1142
1150
|
],
|
|
@@ -1163,11 +1171,12 @@ export const ROOT_COMMAND = buildNode({
|
|
|
1163
1171
|
{
|
|
1164
1172
|
name: "inbox",
|
|
1165
1173
|
summary: "Read and explicitly handle the current managed Agent's own inbox.",
|
|
1166
|
-
sections: [{ id: "commands", title: "Commands", entries: ["list", "show", "claim", "ack"] }],
|
|
1174
|
+
sections: [{ id: "commands", title: "Commands", entries: ["list", "show", "claim", "ack", "retire"] }],
|
|
1167
1175
|
children: [
|
|
1168
1176
|
{ name: "list", discovery: { surface: "managed", audiences: ["operator", "global", "leader", "assignment"] },
|
|
1169
1177
|
summary: "Discover unhandled own-address entries, including accepted delivery, with current identity and separate handling receipts.",
|
|
1170
|
-
usage: "yui inbox list [--limit <1..100>] [--cursor <cursor>]",
|
|
1178
|
+
usage: "yui inbox list [--view current|history|all] [--limit <1..100>] [--cursor <cursor>]",
|
|
1179
|
+
options: ["--view", "--limit", "--cursor"], optionValues: { "--view": ["current", "history", "all"] } },
|
|
1171
1180
|
{ name: "show", discovery: { surface: "managed", audiences: ["operator", "global", "leader", "assignment"] },
|
|
1172
1181
|
summary: "Read an exact original or fixed notification window without acknowledgement.",
|
|
1173
1182
|
usage: "yui inbox show <entry> [--cursor <cursor>]", options: ["--cursor"] },
|
|
@@ -1175,8 +1184,12 @@ export const ROOT_COMMAND = buildNode({
|
|
|
1175
1184
|
summary: "Reserve 1..16 exact entries for handling in this turn; never starts a model turn.",
|
|
1176
1185
|
usage: "yui inbox claim <entry> [<entry> ...] --request-id <id>", options: ["--request-id"] },
|
|
1177
1186
|
{ name: "ack", discovery: { surface: "managed", audiences: ["operator", "global", "leader", "assignment"] },
|
|
1178
|
-
summary: "
|
|
1187
|
+
summary: "Record handling, including a rightful successor's disposition of an unchanged prior claim; never proves native acceptance or authorizes replay.",
|
|
1179
1188
|
usage: "yui inbox ack <entry> [<entry> ...] --request-id <id> --reason <disposition>",
|
|
1189
|
+
options: ["--request-id", "--reason"] },
|
|
1190
|
+
{ name: "retire", discovery: { surface: "managed", audiences: ["operator", "global"] },
|
|
1191
|
+
summary: "Explicitly retire obsolete proven-unsubmitted Global input, preserving its original target and evidence.",
|
|
1192
|
+
usage: "yui inbox retire <entry> [<entry> ...] --request-id <id> --reason <disposition>",
|
|
1180
1193
|
options: ["--request-id", "--reason"] }
|
|
1181
1194
|
]
|
|
1182
1195
|
},
|
|
@@ -1191,8 +1204,8 @@ export const ROOT_COMMAND = buildNode({
|
|
|
1191
1204
|
children: [
|
|
1192
1205
|
{
|
|
1193
1206
|
name: "list", discovery: { surface: "public", audiences: ["public", "operator"] }, summary: "Discover Global Messages without consuming input.",
|
|
1194
|
-
usage: "yui role message list <role> [--pending|--diagnostics|--diagnostic <key>] [--limit <1..100>] [--cursor <cursor>]",
|
|
1195
|
-
options: ["--pending", "--diagnostics", "--diagnostic", "--limit", "--cursor"]
|
|
1207
|
+
usage: "yui role message list <role> [--current|--pending|--diagnostics|--diagnostic <key>] [--limit <1..100>] [--cursor <cursor>]",
|
|
1208
|
+
options: ["--current", "--pending", "--diagnostics", "--diagnostic", "--limit", "--cursor"]
|
|
1196
1209
|
},
|
|
1197
1210
|
{
|
|
1198
1211
|
name: "show", discovery: { surface: "public", audiences: ["public", "operator"] }, summary: "Read one exact Global Message; follow contentPage.nextCursor for long content.",
|
|
@@ -1242,8 +1255,8 @@ export const ROOT_COMMAND = buildNode({
|
|
|
1242
1255
|
{
|
|
1243
1256
|
name: "web", discovery: { surface: "public", audiences: ["public", "operator"] },
|
|
1244
1257
|
summary: "Serve the control room using the running Controller's capability Host.",
|
|
1245
|
-
usage: "yui web [--host <
|
|
1246
|
-
options: ["--host", "--port", "--status", "--stop"]
|
|
1258
|
+
usage: "yui web [--host <IP|localhost>] [--port <port>] [--auth-file <absolute-path>] [--detach] | --status | --stop",
|
|
1259
|
+
options: ["--host", "--port", "--auth-file", "--detach", "--status", "--stop"]
|
|
1247
1260
|
},
|
|
1248
1261
|
{
|
|
1249
1262
|
name: "controller", discovery: { surface: "public", audiences: ["public", "operator"] },
|
|
@@ -1641,15 +1654,37 @@ export const ROOT_COMMAND = buildNode({
|
|
|
1641
1654
|
},
|
|
1642
1655
|
{
|
|
1643
1656
|
name: "job", discovery: { surface: "managed", audiences: ["operator", "leader", "assignment"] },
|
|
1644
|
-
summary: "
|
|
1645
|
-
sections: [{ id: "manage", title: "Commands", entries: ["start", "get", "cancel", "acknowledge"] }],
|
|
1657
|
+
summary: "Manage stable Job definitions and exact execution Runs (not scheduler wakes).",
|
|
1658
|
+
sections: [{ id: "manage", title: "Commands", entries: ["define", "update", "list", "show", "run", "runs", "run-get", "logs", "run-cancel", "run-acknowledge", "start", "get", "cancel", "acknowledge"] }],
|
|
1646
1659
|
children: [
|
|
1660
|
+
...["define", "update", "list", "show", "run", "runs", "run-get", "logs", "run-cancel", "run-acknowledge"].map(name => ({
|
|
1661
|
+
name, discovery: { surface: "managed", audiences: ["operator", "leader", "assignment"] },
|
|
1662
|
+
summary: `${name} a stable Job or exact Run.`,
|
|
1663
|
+
usage: `yui job ${name} (--task <id>|--global)${name === "list" ? "" : " --job <id>"}`
|
|
1664
|
+
+ (name === "define" || name === "update" ? " --title <text> --input <configuration-json>" : "")
|
|
1665
|
+
+ (name === "update" ? " --revision <current>" : "")
|
|
1666
|
+
+ (name === "run" ? " --request-id <key> [--retry-of <run-id>]" : "")
|
|
1667
|
+
+ (["run-get", "logs", "run-cancel", "run-acknowledge"].includes(name) ? " --run <run-id>" : "")
|
|
1668
|
+
})),
|
|
1647
1669
|
{ name: "start", discovery: { surface: "managed", audiences: ["operator", "leader", "assignment"] }, summary: "Start a DurableJob under an explicit request identity.", usage: "yui job start --request-id <id> --task <id> --project <project> --head <sha> --workspace <dir> --step <name>=<command> [--step ...] [--owner task|work-item:<id>|integration-attempt:<id>] [--env <k=v>...]" },
|
|
1648
1670
|
{ name: "get", discovery: { surface: "managed", audiences: ["operator", "leader", "assignment"] }, summary: "Show a DurableJob record and its terminal result.", usage: "yui job get --task <id> --job <job-id>" },
|
|
1649
1671
|
{ name: "cancel", discovery: { surface: "managed", audiences: ["operator", "leader", "assignment"] }, summary: "Request cancellation of a running or queued DurableJob.", usage: "yui job cancel --task <id> --job <job-id>" },
|
|
1650
1672
|
{ name: "acknowledge", discovery: { surface: "managed", audiences: ["operator", "leader", "assignment"] }, summary: "Acknowledge an unknown-needs-attention DurableJob so Task lifecycle gates can proceed.", usage: "yui job acknowledge --task <id> --job <job-id>" }
|
|
1651
1673
|
]
|
|
1652
1674
|
},
|
|
1675
|
+
{
|
|
1676
|
+
name: "schedule", discovery: { surface: "managed", audiences: ["operator", "leader", "assignment"] },
|
|
1677
|
+
summary: "Manage persistent time plans referencing scoped Jobs.",
|
|
1678
|
+
sections: [{ id: "manage", title: "Commands", entries: ["create", "list", "show", "update", "enable", "disable"] }],
|
|
1679
|
+
children: ["create", "list", "show", "update", "enable", "disable"].map(name => ({
|
|
1680
|
+
name, discovery: { surface: "managed", audiences: ["operator", "leader", "assignment"] },
|
|
1681
|
+
summary: `${name} a Schedule; disabling never cancels an admitted Run.`,
|
|
1682
|
+
usage: `yui schedule ${name} (--global|--task <id>)${name === "list" ? "" : " --schedule <id>"}`
|
|
1683
|
+
+ (name === "create" ? " --job <id> --rule <json>" : "")
|
|
1684
|
+
+ (name === "update" ? " --rule <json> [--job <id>]" : "")
|
|
1685
|
+
+ (["update", "enable", "disable"].includes(name) ? " --revision <observed>" : "")
|
|
1686
|
+
}))
|
|
1687
|
+
},
|
|
1653
1688
|
{
|
|
1654
1689
|
name: "jobs", discovery: { surface: "public", audiences: ["public", "operator"] },
|
|
1655
1690
|
summary: "Inspect scheduler wake and recovery records.",
|
package/dist/cli/helpRenderer.js
CHANGED
|
@@ -25,7 +25,9 @@ function describeOption(option) {
|
|
|
25
25
|
"--agent": "Select an Agent.",
|
|
26
26
|
"--base": "Set the base Git reference.",
|
|
27
27
|
"--input": "Set dispatch input.",
|
|
28
|
-
"--host": "Set the loopback
|
|
28
|
+
"--host": "Set the listen IP (default 127.0.0.1); non-loopback requires --auth-file.",
|
|
29
|
+
"--auth-file": "Owner-only file with a unique 32–128 character password; browser username is yui. HTTP is not encrypted.",
|
|
30
|
+
"--detach": "Return after Controller starts Web; use --status / --stop. Operator and --json starts always return.",
|
|
29
31
|
"--port": "Set the local listen port.",
|
|
30
32
|
"--json": "Emit machine-readable JSON.",
|
|
31
33
|
"--project": "Select a Project.",
|
|
@@ -185,7 +185,7 @@ export const INTERACTION_POLICIES = Object.freeze([
|
|
|
185
185
|
actionTarget: true,
|
|
186
186
|
statuses: ["draft"]
|
|
187
187
|
}],
|
|
188
|
-
trailingOptions: { "--request-id": "value", "--environment": "value" }
|
|
188
|
+
trailingOptions: { "--request-id": "value", "--environment": "value", "--source-message": "value", "--source-text": "value" }
|
|
189
189
|
},
|
|
190
190
|
{
|
|
191
191
|
commandPath: ["task", "activation", "cancel"],
|
|
@@ -615,7 +615,7 @@ export const INTERACTION_POLICIES = Object.freeze([
|
|
|
615
615
|
].map(([group, command]) => {
|
|
616
616
|
const trailingOptions = {};
|
|
617
617
|
if (group === "brief" && command === "update") {
|
|
618
|
-
Object.assign(trailingOptions, { "--objective": "value", "--boundary": "value", "--approach": "value", "--focus": "value", "--leader-summary": "value" });
|
|
618
|
+
Object.assign(trailingOptions, { "--if-current": "value", "--objective": "value", "--boundary": "value", "--approach": "value", "--focus": "value", "--leader-summary": "value" });
|
|
619
619
|
}
|
|
620
620
|
else if (group === "decision" && command === "record") {
|
|
621
621
|
Object.assign(trailingOptions, { "--title": "value", "--rationale": "value" });
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { usageError } from "../errors/cliError.js";
|
|
2
2
|
import { ensureFileTaskController } from "../controller/clientRuntime.js";
|
|
3
|
+
import { callFileTaskController } from "../controller/clientRuntime.js";
|
|
3
4
|
import { acknowledgeDurableJob, cancelDurableJob, getDurableJob, startDurableJob } from "../controller/jobClient.js";
|
|
4
5
|
import { resolveJobCaller, taskLocalActor } from "../task/taskAuthority.js";
|
|
5
6
|
/**
|
|
@@ -14,6 +15,9 @@ export const JOB_OWNER_USAGE = "task|work-item:<id>|integration-attempt:<id>";
|
|
|
14
15
|
*/
|
|
15
16
|
export async function runDurableJobCommand(args, options) {
|
|
16
17
|
const [command, ...rest] = args;
|
|
18
|
+
if (command !== undefined && ["define", "update", "list", "show", "run", "runs", "run-get", "run-cancel", "run-acknowledge", "logs"].includes(command)) {
|
|
19
|
+
return definitionCommand(command, rest, options);
|
|
20
|
+
}
|
|
17
21
|
if (command === "start")
|
|
18
22
|
return startJob(rest, options);
|
|
19
23
|
if (command === "get")
|
|
@@ -31,6 +35,52 @@ export async function runDurableJobCommand(args, options) {
|
|
|
31
35
|
+ "yui job cancel --task <id> --job <job-id>\n"
|
|
32
36
|
+ "yui job acknowledge --task <id> --job <job-id>");
|
|
33
37
|
}
|
|
38
|
+
async function definitionCommand(command, args, options) {
|
|
39
|
+
const flags = new Map();
|
|
40
|
+
for (let i = 0; i < args.length; i++) {
|
|
41
|
+
const flag = args[i];
|
|
42
|
+
if (!["--global", "--task", "--job", "--title", "--input", "--revision", "--request-id", "--retry-of", "--run"].includes(flag)
|
|
43
|
+
|| flags.has(flag))
|
|
44
|
+
throw usageError(`Unknown or repeated Job flag: ${flag}.`);
|
|
45
|
+
if (flag === "--global") {
|
|
46
|
+
flags.set(flag, "true");
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const value = args[++i];
|
|
50
|
+
if (value === undefined || value.startsWith("--"))
|
|
51
|
+
throw usageError(`Missing value: ${flag}.`);
|
|
52
|
+
flags.set(flag, value);
|
|
53
|
+
}
|
|
54
|
+
if (flags.has("--global") === flags.has("--task"))
|
|
55
|
+
throw usageError("Choose exactly one of --task <id> or --global.");
|
|
56
|
+
const taskId = flags.get("--task");
|
|
57
|
+
const caller = resolveJobCaller(options.environment, taskId ?? "");
|
|
58
|
+
const scope = taskId === undefined ? { kind: "global" } : { kind: "task", taskId };
|
|
59
|
+
let configuration;
|
|
60
|
+
if (flags.has("--input")) {
|
|
61
|
+
try {
|
|
62
|
+
configuration = JSON.parse(flags.get("--input"));
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
throw usageError("--input must be a JSON Job configuration.");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const requestId = flags.get("--request-id");
|
|
69
|
+
if (command === "run" && !requestId)
|
|
70
|
+
throw usageError("job run requires --request-id.");
|
|
71
|
+
const params = {
|
|
72
|
+
op: command, scope, caller,
|
|
73
|
+
...(flags.has("--job") ? { id: flags.get("--job") } : {}),
|
|
74
|
+
...(flags.has("--title") ? { title: flags.get("--title") } : {}),
|
|
75
|
+
...(configuration === undefined ? {} : { configuration }),
|
|
76
|
+
...(flags.has("--revision") ? { expectedRevision: Number(flags.get("--revision")) } : {}),
|
|
77
|
+
...(flags.has("--run") ? { runId: flags.get("--run") } : {}),
|
|
78
|
+
...(flags.has("--retry-of") ? { retryOf: flags.get("--retry-of") } : {}),
|
|
79
|
+
...(command === "run" ? { trigger: { source: flags.has("--retry-of") ? "retry" : "manual", key: requestId } } : {})
|
|
80
|
+
};
|
|
81
|
+
const result = await callFileTaskController(options.home, "job.definition", params, { environment: options.environment });
|
|
82
|
+
return `${JSON.stringify(result, null, 2)}\n`;
|
|
83
|
+
}
|
|
34
84
|
async function startJob(args, options) {
|
|
35
85
|
const parsed = parseStartArgs(args);
|
|
36
86
|
await ensureFileTaskController(options.home, { environment: options.environment });
|
|
@@ -6,6 +6,7 @@ import { controlProviderRetry, providerRetryProjection, providerRetrySummary, re
|
|
|
6
6
|
import { pendingGlobalInboxMessages, inboxHandlingState, globalInboxDeliveryState } from "../message/inboxReceipt.js";
|
|
7
7
|
import { settleGlobalRetryInput } from "../message/globalProviderRetry.js";
|
|
8
8
|
import { globalInputBacklog } from "../message/globalInputBacklog.js";
|
|
9
|
+
import { inboxEntryCategory } from "../message/inboxTurn.js";
|
|
9
10
|
import { checkCurrentSkills, SKILL_REUSE_RULE } from "../context/currentSkills.js";
|
|
10
11
|
import { runtimeDiagnosticGroups, runtimeDiagnosticEvidence } from "../controller/globalRuntimeAttention.js";
|
|
11
12
|
import { roleSkillIds } from "../context/roleSessionContext.js";
|
|
@@ -131,10 +132,16 @@ function roleContext(args, store, options) {
|
|
|
131
132
|
// through distinct receipts; a context read does neither.
|
|
132
133
|
const messages = store.listGlobalRoleMessages(name);
|
|
133
134
|
const queued = messages.filter((message) => message.delivery === undefined
|
|
134
|
-
&& message.inbox
|
|
135
|
+
&& message.inbox === undefined
|
|
135
136
|
&& message.notDelivered === undefined
|
|
136
137
|
&& (message.interruptThen !== undefined || message.inputControl?.action === "queue"));
|
|
137
|
-
const
|
|
138
|
+
const unhandled = pendingGlobalInboxMessages(messages);
|
|
139
|
+
const current = currentGlobalInboxMessages(messages, name, sessions);
|
|
140
|
+
const pending = recordPage(current.map(globalMessageSummary), `global:${name}/messages/current`, { limit: 8 }, {
|
|
141
|
+
historyCount: unhandled.length - current.length,
|
|
142
|
+
historyRead: "yui inbox list --view history --json",
|
|
143
|
+
note: "Historical absence of handling evidence is not new work or permission to replay effects."
|
|
144
|
+
});
|
|
138
145
|
const observedAt = new Date();
|
|
139
146
|
const { oldestAgeMs, messages: _backlogMessages, ...backlog } = globalInputBacklog(queued, sessions, observedAt, {
|
|
140
147
|
attention: name === "operator" ? store.getWorkMailbox({ kind: "operator" }) : null,
|
|
@@ -175,9 +182,9 @@ function roleContext(args, store, options) {
|
|
|
175
182
|
pending,
|
|
176
183
|
backlog,
|
|
177
184
|
reads: {
|
|
178
|
-
ownInbox: "yui inbox list --json",
|
|
185
|
+
ownInbox: "yui inbox list --view current --json",
|
|
179
186
|
messages: `role message list ${name}`,
|
|
180
|
-
pending: `role message list ${name} --
|
|
187
|
+
pending: `role message list ${name} --current`,
|
|
181
188
|
detail: `role message show ${name} <message-id>`,
|
|
182
189
|
diagnostics: `role message list ${name} --diagnostics`,
|
|
183
190
|
retry: `session retry ${name} show`
|
|
@@ -213,6 +220,16 @@ function roleContext(args, store, options) {
|
|
|
213
220
|
""
|
|
214
221
|
].join("\n") };
|
|
215
222
|
}
|
|
223
|
+
function currentGlobalInboxMessages(messages, name, sessions) {
|
|
224
|
+
const actor = { scope: "global", roleName: name, agentId: sessions?.activeAgentId ?? "",
|
|
225
|
+
nativeSessionId: sessions?.sessions[sessions.activeAgentId]?.nativeSessionId ?? "" };
|
|
226
|
+
const binding = sessions?.providerBinding;
|
|
227
|
+
const turn = binding?.conversations.find(c => c.epoch === binding.currentConversationEpoch)?.conversationId === actor.nativeSessionId
|
|
228
|
+
? binding?.run : undefined;
|
|
229
|
+
const category = (message) => inboxEntryCategory(message, actor, turn);
|
|
230
|
+
return pendingGlobalInboxMessages(messages).filter(message => category(message) !== "history")
|
|
231
|
+
.sort((a, b) => Number(category(b) === "current") - Number(category(a) === "current"));
|
|
232
|
+
}
|
|
216
233
|
function globalMessageSummary(message) {
|
|
217
234
|
return {
|
|
218
235
|
id: message.id, createdAt: message.createdAt, kind: message.kind,
|
|
@@ -626,17 +643,18 @@ function globalRoleMessage(args, store, options) {
|
|
|
626
643
|
}
|
|
627
644
|
requireRole(name, store);
|
|
628
645
|
const pending = tail.includes("--pending");
|
|
646
|
+
const current = tail.includes("--current");
|
|
629
647
|
const diagnostics = tail.includes("--diagnostics");
|
|
630
|
-
const parsed = readOptions(tail.filter(arg => arg !== "--pending" && arg !== "--diagnostics"), action === "list"
|
|
648
|
+
const parsed = readOptions(tail.filter(arg => arg !== "--pending" && arg !== "--current" && arg !== "--diagnostics"), action === "list"
|
|
631
649
|
? ["--cursor", "--limit", "--diagnostic"] : ["--cursor"]);
|
|
632
650
|
const diagnostic = parsed.values.get("--diagnostic");
|
|
633
|
-
if (Number(pending) + Number(diagnostics) + Number(diagnostic !== undefined) > 1
|
|
651
|
+
if (Number(pending) + Number(current) + Number(diagnostics) + Number(diagnostic !== undefined) > 1
|
|
634
652
|
|| action === "show" && diagnostics)
|
|
635
653
|
throw usageError("Choose one Message discovery view.");
|
|
636
654
|
const messages = store.listGlobalRoleMessages(name);
|
|
637
655
|
let data;
|
|
638
656
|
if (action === "show") {
|
|
639
|
-
if (parsed.positionals.length !== 1 || pending)
|
|
657
|
+
if (parsed.positionals.length !== 1 || pending || current)
|
|
640
658
|
throw usageError("Role message show <role> <message-id> [--cursor <cursor>].");
|
|
641
659
|
const message = messages.find(m => m.id === parsed.positionals[0]);
|
|
642
660
|
if (message === undefined)
|
|
@@ -654,8 +672,9 @@ function globalRoleMessage(args, store, options) {
|
|
|
654
672
|
return { kind: "output", output: `${JSON.stringify(data)}\n`, data };
|
|
655
673
|
}
|
|
656
674
|
const selected = diagnostic !== undefined ? runtimeDiagnosticEvidence(messages, diagnostic)
|
|
657
|
-
:
|
|
658
|
-
|
|
675
|
+
: current ? currentGlobalInboxMessages(messages, name, store.getGlobalRoleSessionSet(name))
|
|
676
|
+
: pending ? pendingGlobalInboxMessages(messages) : [...messages].reverse();
|
|
677
|
+
data = recordPage(selected.map(globalMessageSummary), `global:${name}/messages/${diagnostic === undefined ? current ? "current" : pending ? "pending" : "all" : `diagnostic/${diagnostic}`}`, parsed);
|
|
659
678
|
}
|
|
660
679
|
return { kind: "output", output: `${JSON.stringify(data, null, 2)}\n`, data };
|
|
661
680
|
}
|
|
@@ -711,6 +730,8 @@ function messageGlobalInput(name, input, store, options) {
|
|
|
711
730
|
}
|
|
712
731
|
store.updateGlobalRoleMessage({ ...persisted.message, control: {
|
|
713
732
|
requestId, receiptId: `steer:${name}/${persisted.message.id}`,
|
|
733
|
+
target: { agentId: resolution.target.agentId, nativeSessionId: resolution.target.nativeSessionId,
|
|
734
|
+
attemptId: resolution.target.attemptId },
|
|
714
735
|
outcome: "pending", observedAt: now.toISOString()
|
|
715
736
|
} });
|
|
716
737
|
return {
|