@zq-silk/yui 2.21.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 +85 -25
- package/dist/cli/dynamicCompletion.js +4 -1
- package/dist/cli/helpRenderer.js +12 -1
- package/dist/cli/interactionPolicy.js +2 -0
- package/dist/cli/invocationRouter.js +5 -5
- package/dist/cli/roleWizard.js +5 -1
- 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 +217 -64
- package/dist/commands/taskContextCommand.js +26 -4
- package/dist/commands/taskFactCommands.js +15 -2
- package/dist/commands/taskIntegrationCommands.js +3 -3
- package/dist/commands/taskRoleRuntimeStatus.js +15 -5
- 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/taskContext.js +100 -16
- package/dist/controlPlaneCli.js +17 -7
- 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/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/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/tmux/tmuxManager.js +4 -2
- package/dist/web/webSettings.js +2 -0
- package/docs/authorization.md +18 -3
- package/docs/cli-information-contract.md +228 -6
- package/docs/cli-information-contract.zh-CN.md +95 -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 +37 -0
- package/docs/release-workflow.zh-CN.md +28 -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/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 -193
- 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 -333
- 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 +1 -1
- package/skills/yui-operator/references/web-lifecycle.md +19 -0
- package/skills/yui-operator/scripts/verify-submission.mjs +37 -0
- package/skills/yui-runtime/SKILL.md +177 -531
- 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 -111
- 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/README.md
CHANGED
|
@@ -459,6 +459,11 @@ manage global installations; do not use the global `yui` to validate local chang
|
|
|
459
459
|
Live-model, paid or shared-resource
|
|
460
460
|
tests require an explicit request for those resources.
|
|
461
461
|
|
|
462
|
+
For topic-specific evaluation and shared evidence tools, see
|
|
463
|
+
[evaluation tooling](scripts/eval/README.md).
|
|
464
|
+
`npm run eval:check` is fast and offline; `eval:context:wiring` is an explicit isolated
|
|
465
|
+
fake-Provider check, outside the default core gate. It is not model validation.
|
|
466
|
+
|
|
462
467
|
## Community and support
|
|
463
468
|
|
|
464
469
|
- Questions, bugs and feature requests: open a
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { supportedAgentAdapterIds } from "../agent/adapterCatalog.js";
|
|
2
|
+
import { CONTEXT_FAMILIES } from "../context/contextFamilies.js";
|
|
2
3
|
import { supportedAgentExecutionComponentIds } from "../agent/executionComponents.js";
|
|
3
4
|
import { productConfigurationOptions } from "../nativeAgent/product/config.js";
|
|
4
5
|
import { catalogCommands, catalogCommandOptions } from "../nativeAgent/product/catalog.js";
|
|
@@ -142,6 +143,7 @@ const roleProfileOptions = [
|
|
|
142
143
|
];
|
|
143
144
|
const roleAgentOptions = [
|
|
144
145
|
"--model", "--effort", "--permission-strategy", "--sandbox", "--approval", "--permission-mode",
|
|
146
|
+
"--exclude-tmpdir-env-var", "--exclude-slash-tmp",
|
|
145
147
|
"--allowed-tool", "--disallowed-tool", "--search"
|
|
146
148
|
];
|
|
147
149
|
const roleProfileClearOptions = [
|
|
@@ -151,7 +153,7 @@ const roleProfileClearOptions = [
|
|
|
151
153
|
];
|
|
152
154
|
const roleAgentClearOptions = [
|
|
153
155
|
"--clear-model", "--clear-effort", "--clear-allowed-tools", "--clear-disallowed-tools",
|
|
154
|
-
"--clear-search", "--clear-agent-config"
|
|
156
|
+
"--clear-search", "--clear-agent-config", "--clear-exclude-tmpdir-env-var", "--clear-exclude-slash-tmp"
|
|
155
157
|
];
|
|
156
158
|
const agentProfileOptions = [
|
|
157
159
|
"--description", "--instructions", "--skill",
|
|
@@ -164,6 +166,8 @@ const agentProfileClearOptions = [
|
|
|
164
166
|
const roleAgentOptionValues = {
|
|
165
167
|
"--sandbox": ["read-only", "workspace-write", "danger-full-access"],
|
|
166
168
|
"--approval": ["untrusted", "on-request", "never"],
|
|
169
|
+
"--exclude-tmpdir-env-var": ["true", "false"],
|
|
170
|
+
"--exclude-slash-tmp": ["true", "false"],
|
|
167
171
|
"--permission-strategy": ["default", "bypass", "configured"],
|
|
168
172
|
"--search": ["true"]
|
|
169
173
|
};
|
|
@@ -234,7 +238,8 @@ const globalSessionChildren = [
|
|
|
234
238
|
{
|
|
235
239
|
name: "retry", discovery: { surface: "public", audiences: ["public", "operator"] },
|
|
236
240
|
summary: "Inspect or control bounded Provider recovery for this Global Session.",
|
|
237
|
-
usage: "yui session retry <role> [show|cancel|disable|enable]"
|
|
241
|
+
usage: "yui session retry <role> [show|cancel|disable|enable] [--cursor <cursor> (show only)]",
|
|
242
|
+
options: ["--cursor"]
|
|
238
243
|
}
|
|
239
244
|
];
|
|
240
245
|
const profileChildren = [
|
|
@@ -426,10 +431,41 @@ const taskChildren = [
|
|
|
426
431
|
},
|
|
427
432
|
{
|
|
428
433
|
name: "context", discovery: { surface: "public", audiences: ["public", "operator", "leader", "assignment", "unbound"] },
|
|
429
|
-
summary: "Read
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
434
|
+
summary: "Read current authorized facts; discover references or inspect complete originals with a focused subcommand.",
|
|
435
|
+
executable: true,
|
|
436
|
+
usage: "yui task context <task>",
|
|
437
|
+
sections: [{ id: "read", title: "Context reads", entries: ["read", "list", "inspect", "delta"] }],
|
|
438
|
+
children: [
|
|
439
|
+
{
|
|
440
|
+
name: "read", discovery: { surface: "public", audiences: ["public", "operator", "leader", "assignment", "unbound"] },
|
|
441
|
+
summary: "Read the current bounded Task index, equivalent to task context <task>.",
|
|
442
|
+
usage: "yui task context read <task>"
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
name: "list", discovery: { surface: "public", audiences: ["public", "operator", "leader", "assignment", "unbound"] },
|
|
446
|
+
summary: "Discover one authorized family. --after filters creation time, not later edits; current excludes explicit ACK/retirement.",
|
|
447
|
+
usage: "yui task context list <task> --store <store> [--cursor <cursor>] [--limit <1..100>] [--view current|all] [--status <status>] [--after <timestamp>] [--work-item <id>]",
|
|
448
|
+
options: ["--store", "--cursor", "--limit", "--view", "--status", "--after", "--work-item"],
|
|
449
|
+
optionValues: { "--view": ["current", "all"], "--store": CONTEXT_FAMILIES }
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
name: "inspect", discovery: { surface: "public", audiences: ["public", "operator", "leader", "assignment", "unbound"] },
|
|
453
|
+
summary: "Read complete originals. Choose one single-ref or 1–8-ref batch form; finish contentPage using the same selection and cursor.",
|
|
454
|
+
usage: [
|
|
455
|
+
"yui task context inspect <task> --store <store> --ref <id> [--digest <digest>] [--cursor <cursor>]",
|
|
456
|
+
"yui task context inspect <task> --context-ref <store/refId@digest> ... [--cursor <cursor>]",
|
|
457
|
+
"yui task context inspect <task> --refs <JSON-array-of-store-refId-digest> [--cursor <cursor>]"
|
|
458
|
+
],
|
|
459
|
+
options: ["--store", "--ref", "--digest", "--context-ref", "--refs", "--cursor"],
|
|
460
|
+
optionValues: { "--store": CONTEXT_FAMILIES }
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
name: "delta", discovery: { surface: "public", audiences: ["public", "operator", "leader", "assignment", "unbound"] },
|
|
464
|
+
summary: "Read fixed-bound event history after coreCursor, not current record bodies. Use throughCursor for the next window.",
|
|
465
|
+
usage: "yui task context delta <task> --after <cursor> [--continuation <cursor>] [--limit <1..100>]",
|
|
466
|
+
options: ["--after", "--continuation", "--limit"]
|
|
467
|
+
}
|
|
468
|
+
]
|
|
433
469
|
},
|
|
434
470
|
{
|
|
435
471
|
name: "next-action", discovery: { surface: "managed", audiences: ["operator", "leader"] },
|
|
@@ -708,11 +744,11 @@ const taskChildren = [
|
|
|
708
744
|
{ name: "list", discovery: { surface: "managed", audiences: ["operator", "leader"] }, summary: "Discover recorded Role health; Host is unchecked until role status.", usage: "yui task role list <task> [--limit <1..100>] [--cursor <cursor>]", options: ["--limit", "--cursor"] },
|
|
709
745
|
{
|
|
710
746
|
name: "status", discovery: { surface: "managed", audiences: ["operator", "leader"] },
|
|
711
|
-
summary: "Show
|
|
712
|
-
usage: "yui task role status <task> <role> [--cursor <cursor>]",
|
|
713
|
-
options: ["--cursor"]
|
|
747
|
+
summary: "Show current execution observations; full includes nested original records.",
|
|
748
|
+
usage: "yui task role status <task> <role> [--view current|full] [--cursor <cursor>]",
|
|
749
|
+
options: ["--view", "--cursor"], optionValues: { "--view": ["current", "full"] }
|
|
714
750
|
},
|
|
715
|
-
{ name: "show", discovery: { surface: "managed", audiences: ["operator", "leader"] }, summary: "Show
|
|
751
|
+
{ name: "show", discovery: { surface: "managed", audiences: ["operator", "leader"] }, summary: "Show current Role configuration; full adds Session and Run history.", usage: "yui task role show <task> <role> [--view current|full] [--cursor <cursor>]", options: ["--view", "--cursor"], optionValues: { "--view": ["current", "full"] } },
|
|
716
752
|
{ name: "enable", discovery: { surface: "managed", audiences: ["operator", "leader"] }, summary: "Enable this Task Role; does not change Task execution authority.", usage: "yui task role enable <task> <role>" },
|
|
717
753
|
{ name: "disable", discovery: { surface: "managed", audiences: ["operator", "leader"] }, summary: "Block new execution of this Task Role without stopping its current Run.", usage: "yui task role disable <task> <role>" },
|
|
718
754
|
{ name: "capabilities", discovery: { surface: "managed", audiences: ["operator", "leader"] }, summary: "Read native options using this Role's desired or exact failed launch configuration.",
|
|
@@ -738,7 +774,8 @@ const taskChildren = [
|
|
|
738
774
|
{
|
|
739
775
|
name: "retry", discovery: { surface: "managed", audiences: ["operator", "leader"] },
|
|
740
776
|
summary: "Inspect or control Provider recovery without stopping an admitted Turn.",
|
|
741
|
-
usage: "yui task role session retry <task> <role> [show|cancel|disable|enable]"
|
|
777
|
+
usage: "yui task role session retry <task> <role> [show|cancel|disable|enable] [--cursor <cursor> (show only)]",
|
|
778
|
+
options: ["--cursor"]
|
|
742
779
|
},
|
|
743
780
|
{
|
|
744
781
|
name: "inspect", discovery: { surface: "managed", audiences: ["operator", "leader"] },
|
|
@@ -912,9 +949,9 @@ const taskChildren = [
|
|
|
912
949
|
{ name: "list", discovery: { surface: "managed", audiences: ["operator", "leader", "assignment"] }, summary: "Discover AgentRuns for a Task or one WorkItem.", usage: "yui task run list <task|task/work> [--limit <1..100>] [--cursor <cursor>]", options: ["--limit", "--cursor"] },
|
|
913
950
|
{
|
|
914
951
|
name: "show", discovery: { surface: "managed", audiences: ["operator", "leader", "assignment"] },
|
|
915
|
-
summary: "
|
|
916
|
-
usage: "yui task run show <task>/<run> [--cursor <cursor>] [--json]",
|
|
917
|
-
options: ["--cursor", "--json"]
|
|
952
|
+
summary: "Read full audit evidence, current status, or the complete original result without input/configuration bodies.",
|
|
953
|
+
usage: "yui task run show <task>/<run> [--view full|status|result] [--cursor <cursor>] [--json]",
|
|
954
|
+
options: ["--view", "--cursor", "--json"]
|
|
918
955
|
},
|
|
919
956
|
{
|
|
920
957
|
name: "retry", discovery: { surface: "managed", audiences: ["operator", "leader"] },
|
|
@@ -937,9 +974,12 @@ const taskChildren = [
|
|
|
937
974
|
children: [
|
|
938
975
|
{
|
|
939
976
|
name: "expand", discovery: { surface: "managed", audiences: ["operator", "leader", "assignment"] },
|
|
940
|
-
summary: "
|
|
941
|
-
usage:
|
|
942
|
-
|
|
977
|
+
summary: "Read one frozen original or 1–8 explicitly selected originals from the same authorized Run.",
|
|
978
|
+
usage: [
|
|
979
|
+
"yui task run context expand <task>/<run> <ref-id> --store <store> [--mode full] [--cursor <cursor>]",
|
|
980
|
+
"yui task run context expand <task>/<run> --context-ref <store/refId[@digest]> ... [--cursor <cursor>]"
|
|
981
|
+
],
|
|
982
|
+
options: ["--store", "--context-ref", "--mode", "--cursor"]
|
|
943
983
|
},
|
|
944
984
|
{
|
|
945
985
|
name: "delta", discovery: { surface: "managed", audiences: ["operator", "leader", "assignment"] },
|
|
@@ -1122,7 +1162,7 @@ const taskChildren = [
|
|
|
1122
1162
|
{ name: "show", discovery: { surface: "managed", audiences: ["operator", "leader"] }, summary: "Show fixed wake inputs/results; expand diagnostics with --history.", usage: "yui task wake show <task> <wake> [--history] [--cursor <cursor>]", options: ["--history", "--cursor"] },
|
|
1123
1163
|
{ name: "retry", discovery: { surface: "managed", audiences: ["operator", "leader"] }, summary: "Retry a rejected notification after correcting its cause; preserve original input.",
|
|
1124
1164
|
usage: "yui task wake retry <task> <wake> --reason <correction>", options: ["--reason"] },
|
|
1125
|
-
{ name: "resolve", discovery: { surface: "managed", audiences: ["operator", "leader"] }, summary: "Release an unknown notification
|
|
1165
|
+
{ name: "resolve", discovery: { surface: "managed", audiences: ["operator", "leader"] }, summary: "Release an unknown or rejected notification for explicit handling after quiescence evidence, without replay.",
|
|
1126
1166
|
usage: "yui task wake resolve <task> <wake> --reason <quiescence-evidence>", options: ["--reason"] }
|
|
1127
1167
|
]
|
|
1128
1168
|
},
|
|
@@ -1239,7 +1279,12 @@ export const ROOT_COMMAND = buildNode({
|
|
|
1239
1279
|
}
|
|
1240
1280
|
]
|
|
1241
1281
|
},
|
|
1242
|
-
{
|
|
1282
|
+
{
|
|
1283
|
+
name: "help", discovery: { surface: "public", audiences: ["public", "operator", "leader", "assignment", "global", "unbound"] },
|
|
1284
|
+
summary: "Show root or scoped command help; JSON defaults to immediate child summaries.",
|
|
1285
|
+
usage: ["yui help [command ...]", "yui --json help [command ...] --recursive"],
|
|
1286
|
+
options: ["--recursive"], commandPathArguments: true
|
|
1287
|
+
},
|
|
1243
1288
|
{ name: "version", discovery: { surface: "public", audiences: ["public", "operator", "leader", "assignment", "global", "unbound"] }, summary: "Print the installed Yui version." },
|
|
1244
1289
|
{
|
|
1245
1290
|
name: "update", discovery: { surface: "public", audiences: ["public", "operator"] },
|
|
@@ -1811,8 +1856,7 @@ export function findCommandNode(path, root = ROOT_COMMAND) {
|
|
|
1811
1856
|
return node;
|
|
1812
1857
|
}
|
|
1813
1858
|
export const findCommand = findCommandNode;
|
|
1814
|
-
|
|
1815
|
-
export function describeCommandTree(node) {
|
|
1859
|
+
function describeCommand(node) {
|
|
1816
1860
|
return {
|
|
1817
1861
|
path: node.path.slice(1).join(" "),
|
|
1818
1862
|
summary: node.summary,
|
|
@@ -1821,8 +1865,25 @@ export function describeCommandTree(node) {
|
|
|
1821
1865
|
options: node.options,
|
|
1822
1866
|
optionValues: node.optionValues,
|
|
1823
1867
|
argumentValues: node.argumentValues,
|
|
1824
|
-
values: node.values
|
|
1825
|
-
|
|
1868
|
+
values: node.values
|
|
1869
|
+
};
|
|
1870
|
+
}
|
|
1871
|
+
/** Complete caller-filtered tree for explicit recursive help and offline tools. */
|
|
1872
|
+
export function describeCommandTree(node) {
|
|
1873
|
+
return { ...describeCommand(node), children: visibleChildren(node).map(describeCommandTree) };
|
|
1874
|
+
}
|
|
1875
|
+
/** Complete current-command details; descendants require explicit navigation. */
|
|
1876
|
+
export function describeCommandHelp(node) {
|
|
1877
|
+
return {
|
|
1878
|
+
...describeCommand(node),
|
|
1879
|
+
children: visibleChildren(node).map(child => ({
|
|
1880
|
+
path: child.path.slice(1).join(" "), summary: child.summary
|
|
1881
|
+
})),
|
|
1882
|
+
discovery: {
|
|
1883
|
+
children: "complete-immediate-summaries",
|
|
1884
|
+
details: "yui --json help <command ...>",
|
|
1885
|
+
tree: "yui --json help [command ...] --recursive"
|
|
1886
|
+
}
|
|
1826
1887
|
};
|
|
1827
1888
|
}
|
|
1828
1889
|
export function validateCommandCatalog(root) {
|
|
@@ -1857,7 +1918,6 @@ export function validateCommandCatalog(root) {
|
|
|
1857
1918
|
|| node.children.length > 0
|
|
1858
1919
|
|| node.values.length > 0
|
|
1859
1920
|
|| node.sections.length > 0
|
|
1860
|
-
|| node.options.length > 0
|
|
1861
1921
|
|| node.hiddenOptions.length > 0
|
|
1862
1922
|
|| Object.keys(node.optionValues).length > 0
|
|
1863
1923
|
|| Object.keys(node.argumentValues).length > 0
|
|
@@ -1865,7 +1925,7 @@ export function validateCommandCatalog(root) {
|
|
|
1865
1925
|
|| node.fileArguments.length > 0
|
|
1866
1926
|
|| node.executableOptions.length > 0;
|
|
1867
1927
|
if (ownsOtherCompletionMetadata) {
|
|
1868
|
-
throw new Error(`Command-path provider must be a visible
|
|
1928
|
+
throw new Error(`Command-path provider must be a visible leaf with only flag options: ${node.path.join(" ")}`);
|
|
1869
1929
|
}
|
|
1870
1930
|
}
|
|
1871
1931
|
const immediate = new Set();
|
|
@@ -8,7 +8,10 @@ export async function resolveCompletionCandidates(input) {
|
|
|
8
8
|
const root = input.root ?? ROOT_COMMAND;
|
|
9
9
|
if (words[0] === "help") {
|
|
10
10
|
const { node, consumed } = resolveCommand(words.slice(1), root);
|
|
11
|
-
|
|
11
|
+
if (consumed !== words.length - 1)
|
|
12
|
+
return [];
|
|
13
|
+
return prefix(input.current.startsWith("-") ? findChild(root, "help")?.options ?? []
|
|
14
|
+
: visibleChildren(node).map(child => child.name), input.current);
|
|
12
15
|
}
|
|
13
16
|
const { node, consumed } = resolveCommand(words, root);
|
|
14
17
|
if (node.kind === "group" && consumed < words.length)
|
package/dist/cli/helpRenderer.js
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
import { visibleCommandSections } from "./commandCatalog.js";
|
|
1
|
+
import { orderedImmediateTokens, visibleCommandSections } from "./commandCatalog.js";
|
|
2
|
+
/** A path error needs nearby choices, not another complete help document.
|
|
3
|
+
* The caller supplies the already-filtered discovery node. */
|
|
4
|
+
export function renderCommandPathHint(node) {
|
|
5
|
+
const choices = orderedImmediateTokens(node);
|
|
6
|
+
const path = node.path.slice(1).join(" ");
|
|
7
|
+
return [
|
|
8
|
+
...(choices.length === 0 ? [] : [`Visible choices here: ${choices.join(", ")}`]),
|
|
9
|
+
`Full help: yui --json help${path ? ` ${path}` : ""}`
|
|
10
|
+
].join("\n") + "\n";
|
|
11
|
+
}
|
|
2
12
|
export function renderCommandHelp(node, version) {
|
|
3
13
|
const title = node.path.length === 1
|
|
4
14
|
? `Yui ${version}`
|
|
@@ -30,6 +40,7 @@ function describeOption(option) {
|
|
|
30
40
|
"--detach": "Return after Controller starts Web; use --status / --stop. Operator and --json starts always return.",
|
|
31
41
|
"--port": "Set the local listen port.",
|
|
32
42
|
"--json": "Emit machine-readable JSON.",
|
|
43
|
+
"--recursive": "Expand the complete caller-filtered command tree (requires --json).",
|
|
33
44
|
"--project": "Select a Project.",
|
|
34
45
|
"--role": "Select a Task role.",
|
|
35
46
|
"--summary": "Set summary text.",
|
|
@@ -88,6 +88,7 @@ export const INTERACTION_POLICIES = Object.freeze([
|
|
|
88
88
|
"--responsibility": "value", "--constraint": "value", "--expected-output": "value",
|
|
89
89
|
"--system-prompt": "value", "--skill": "value", "--model": "value",
|
|
90
90
|
"--effort": "value", "--permission-strategy": "value", "--sandbox": "value", "--approval": "value",
|
|
91
|
+
"--exclude-tmpdir-env-var": "value", "--exclude-slash-tmp": "value",
|
|
91
92
|
"--permission-mode": "value", "--allowed-tool": "value", "--disallowed-tool": "value",
|
|
92
93
|
"--search": "value"
|
|
93
94
|
}
|
|
@@ -374,6 +375,7 @@ export const INTERACTION_POLICIES = Object.freeze([
|
|
|
374
375
|
"--constraint": "value", "--expected-output": "value", "--system-prompt": "value",
|
|
375
376
|
"--skill": "value", "--model": "value", "--effort": "value",
|
|
376
377
|
"--permission-strategy": "value", "--sandbox": "value", "--approval": "value", "--permission-mode": "value",
|
|
378
|
+
"--exclude-tmpdir-env-var": "value", "--exclude-slash-tmp": "value",
|
|
377
379
|
"--allowed-tool": "value", "--disallowed-tool": "value", "--search": "value"
|
|
378
380
|
}
|
|
379
381
|
},
|
|
@@ -18,20 +18,20 @@ export function routeInvocation(args, discoveryRoot = ROOT_COMMAND) {
|
|
|
18
18
|
return { ...result, helpNode };
|
|
19
19
|
}
|
|
20
20
|
function resolveHelpPath(path, root) {
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
const recursive = path.at(-1) === "--recursive";
|
|
22
|
+
const segments = recursive ? path.slice(0, -1) : path;
|
|
23
23
|
let node = root;
|
|
24
24
|
let nearestGroup = root;
|
|
25
|
-
for (const segment of
|
|
25
|
+
for (const segment of segments) {
|
|
26
26
|
const child = findChild(node, segment);
|
|
27
27
|
if (child === undefined || child.hidden) {
|
|
28
|
-
return { kind: "path-error", typedPath: path.join(" "), helpNode: nearestGroup };
|
|
28
|
+
return { kind: "path-error", typedPath: path.join(" "), helpNode: nearestGroup, discoveryOnly: true };
|
|
29
29
|
}
|
|
30
30
|
node = child;
|
|
31
31
|
if (node.kind !== "leaf")
|
|
32
32
|
nearestGroup = node;
|
|
33
33
|
}
|
|
34
|
-
return { kind: "help", node };
|
|
34
|
+
return { kind: "help", node, recursive };
|
|
35
35
|
}
|
|
36
36
|
function resolveExecutionPath(args) {
|
|
37
37
|
let node = ROOT_COMMAND;
|
package/dist/cli/roleWizard.js
CHANGED
|
@@ -459,7 +459,11 @@ function agentFields(binding, catalog) {
|
|
|
459
459
|
agentField("permission-strategy", "Permission strategy", permission.strategy, "--permission-strategy", ["--permission-strategy", "default"], catalogField(catalog, "permission.strategy")),
|
|
460
460
|
...(binding.adapterId === "codex" && permission.strategy === "configured" ? [
|
|
461
461
|
agentField("sandbox", "Sandbox", permission.sandbox, "--sandbox", ["--permission-strategy", "default"], catalogField(catalog, "permission.sandbox")),
|
|
462
|
-
agentField("approval", "Approval", permission.approval, "--approval", ["--permission-strategy", "default"], catalogField(catalog, "permission.approval"))
|
|
462
|
+
agentField("approval", "Approval", permission.approval, "--approval", ["--permission-strategy", "default"], catalogField(catalog, "permission.approval")),
|
|
463
|
+
...(permission.sandbox === "workspace-write" ? [
|
|
464
|
+
agentField("exclude-tmpdir-env-var", "Exclude TMPDIR write access", permission.excludeTmpdirEnvVar, "--exclude-tmpdir-env-var", ["--clear-exclude-tmpdir-env-var"], catalogField(catalog, "permission.excludeTmpdirEnvVar")),
|
|
465
|
+
agentField("exclude-slash-tmp", "Exclude /tmp write access", permission.excludeSlashTmp, "--exclude-slash-tmp", ["--clear-exclude-slash-tmp"], catalogField(catalog, "permission.excludeSlashTmp"))
|
|
466
|
+
] : [])
|
|
463
467
|
] : []),
|
|
464
468
|
...(binding.adapterId === "codex" ? [
|
|
465
469
|
agentField("search", "Web search", config.search, "--search", ["--clear-search"], catalogField(catalog, "search"))
|
|
@@ -151,6 +151,21 @@ function roleContext(args, store, options) {
|
|
|
151
151
|
historyRead: "yui inbox list --view history --json",
|
|
152
152
|
note: "Historical absence of handling evidence is not new work or permission to replay effects."
|
|
153
153
|
});
|
|
154
|
+
// Only the managed Turn's exact inputs, not the available queue or history.
|
|
155
|
+
// Keep pending's cursor lineage unchanged; oversized originals retain their
|
|
156
|
+
// existing exact detail read. No delivery/claim/ACK is performed here.
|
|
157
|
+
let originalBudget = 8 * 1024;
|
|
158
|
+
const visibleIds = new Set(pending.items.map(message => message.id));
|
|
159
|
+
const category = globalInboxCategory(name, sessions);
|
|
160
|
+
const currentOriginals = selfRead ? current.filter(message => {
|
|
161
|
+
if (!visibleIds.has(message.id) || category(message) !== "current")
|
|
162
|
+
return false;
|
|
163
|
+
const bytes = Buffer.byteLength(JSON.stringify(message));
|
|
164
|
+
if (bytes > 4 * 1024 || bytes > originalBudget)
|
|
165
|
+
return false;
|
|
166
|
+
originalBudget -= bytes;
|
|
167
|
+
return true;
|
|
168
|
+
}) : [];
|
|
154
169
|
const observedAt = new Date();
|
|
155
170
|
const { oldestAgeMs, messages: _backlogMessages, ...backlog } = globalInputBacklog(queued, sessions, observedAt, {
|
|
156
171
|
attention: name === "operator" ? store.getWorkMailbox({ kind: "operator" }) : null,
|
|
@@ -191,6 +206,7 @@ function roleContext(args, store, options) {
|
|
|
191
206
|
},
|
|
192
207
|
// Reading pending input is neither delivery nor implementation.
|
|
193
208
|
pending,
|
|
209
|
+
currentOriginals,
|
|
194
210
|
backlog,
|
|
195
211
|
reads: {
|
|
196
212
|
ownInbox: "yui inbox list --view current --json",
|
|
@@ -233,13 +249,16 @@ function roleContext(args, store, options) {
|
|
|
233
249
|
""
|
|
234
250
|
].join("\n") };
|
|
235
251
|
}
|
|
236
|
-
function
|
|
252
|
+
function globalInboxCategory(name, sessions) {
|
|
237
253
|
const actor = { scope: "global", roleName: name, agentId: sessions?.activeAgentId ?? "",
|
|
238
254
|
nativeSessionId: sessions?.sessions[sessions.activeAgentId]?.nativeSessionId ?? "" };
|
|
239
255
|
const binding = sessions?.providerBinding;
|
|
240
256
|
const turn = binding?.conversations.find(c => c.epoch === binding.currentConversationEpoch)?.conversationId === actor.nativeSessionId
|
|
241
257
|
? binding?.run : undefined;
|
|
242
|
-
|
|
258
|
+
return (message) => inboxEntryCategory(message, actor, turn);
|
|
259
|
+
}
|
|
260
|
+
function currentGlobalInboxMessages(messages, name, sessions) {
|
|
261
|
+
const category = globalInboxCategory(name, sessions);
|
|
243
262
|
return pendingGlobalInboxMessages(messages).filter(message => category(message) !== "history")
|
|
244
263
|
.sort((a, b) => Number(category(b) === "current") - Number(category(a) === "current"));
|
|
245
264
|
}
|
|
@@ -506,11 +525,14 @@ function roleSession(args, store, options) {
|
|
|
506
525
|
const [command, rawName, ...tail] = args;
|
|
507
526
|
if (command === "retry") {
|
|
508
527
|
const name = roleName(rawName);
|
|
509
|
-
const
|
|
528
|
+
const parsed = readOptions(tail, ["--cursor"]);
|
|
529
|
+
const [action = "show", ...extra] = parsed.positionals;
|
|
510
530
|
if (extra.length > 0 || !["show", "cancel", "disable", "enable"].includes(action)) {
|
|
511
531
|
throw usageError("Usage: yui session retry <role> [show|cancel|disable|enable]");
|
|
512
532
|
}
|
|
513
|
-
|
|
533
|
+
if (action !== "show" && parsed.cursor !== undefined)
|
|
534
|
+
throw usageError("Only retry show accepts --cursor.");
|
|
535
|
+
return store[action === "show" ? "readTransaction" : "transaction"](tx => {
|
|
514
536
|
const role = requireRole(name, tx);
|
|
515
537
|
const sessions = tx.getGlobalRoleSessionSet(name);
|
|
516
538
|
let binding = sessions?.providerBinding ?? null;
|
|
@@ -523,12 +545,15 @@ function roleSession(args, store, options) {
|
|
|
523
545
|
}
|
|
524
546
|
const health = globalSessionHealth(role, sessions);
|
|
525
547
|
const historical = binding?.retry !== undefined && health.retry === null;
|
|
526
|
-
|
|
548
|
+
const detail = {
|
|
527
549
|
roleName: name, retry: providerRetryProjection(binding), disabled: binding?.retryDisabled ?? false,
|
|
528
550
|
selectedNativeSessionId: health.nativeSessionId,
|
|
529
551
|
retryScope: historical ? "historical-session" : "current-session"
|
|
530
|
-
}
|
|
531
|
-
|
|
552
|
+
};
|
|
553
|
+
return options.jsonOutput ? JSON.stringify(action === "show"
|
|
554
|
+
? boundedDocument(detail, `global:${name}/retry`, parsed.cursor) : detail) + "\n"
|
|
555
|
+
: (historical ? "Historical Session evidence (not the selected Session's current failure): " : "")
|
|
556
|
+
+ renderProviderRetry(binding) + "\n";
|
|
532
557
|
});
|
|
533
558
|
}
|
|
534
559
|
if (command !== "record" && command !== "replace") {
|
|
@@ -715,7 +740,7 @@ function globalRoleMessage(args, store, options) {
|
|
|
715
740
|
["--request-id", false],
|
|
716
741
|
...(action === "steer" ? [["--expected-target", false]] : [])
|
|
717
742
|
]));
|
|
718
|
-
const body = readCommandText(positionalBody, parsed.one("--body-file"), "--body", usage);
|
|
743
|
+
const body = readCommandText(positionalBody, parsed.one("--body-file"), "--body", usage, { preserveFileWhitespace: true });
|
|
719
744
|
const requestId = required(parsed.one("--request-id"), "--request-id");
|
|
720
745
|
const expectedTarget = action === "steer"
|
|
721
746
|
? required(parsed.one("--expected-target"), "--expected-target")
|
|
@@ -9,6 +9,8 @@ import { nonReplayableMessageWake, isLeaderSteer, pinMessageRevisions, releasedN
|
|
|
9
9
|
import { hasRuntimeCleanupObligation, runtimeLifecycleTarget } from "../runtime/lifecycleReservation.js";
|
|
10
10
|
import { isTaskRecordRetired, retiredTaskRecordIds } from "../task/taskRecordRetirement.js";
|
|
11
11
|
import { blocksInboxOrder, inboxEntryCategory, inboxSettled } from "../message/inboxTurn.js";
|
|
12
|
+
import { recoveredMessageContinuation } from "../controller/taskRunRecovery.js";
|
|
13
|
+
import { taskWakeInspectionCommand } from "./taskCommands.js";
|
|
12
14
|
const target = (address) => ({ kind: "role", taskId: address.taskId, roleName: address.roleName });
|
|
13
15
|
const source = (address) => `inbox:${address.scope}:${address.taskId ?? ""}:${address.roleName}`;
|
|
14
16
|
const pendingId = (pending) => `pending-${readDigest(pending)}`;
|
|
@@ -38,6 +40,16 @@ function currentTurn(store, address) {
|
|
|
38
40
|
return binding?.conversations.find(c => c.epoch === binding.currentConversationEpoch)?.conversationId === address.nativeSessionId
|
|
39
41
|
? binding?.run : undefined;
|
|
40
42
|
}
|
|
43
|
+
function isRecoveredMessage(store, address, entry) {
|
|
44
|
+
if (address.scope !== "task" || address.runId === undefined || isWake(entry))
|
|
45
|
+
return false;
|
|
46
|
+
const run = store.getRun(address.taskId, address.runId);
|
|
47
|
+
return run !== null && recoveredMessageContinuation(store, entry, run);
|
|
48
|
+
}
|
|
49
|
+
function entryCategory(store, address, entry) {
|
|
50
|
+
return isRecoveredMessage(store, address, entry) ? "current"
|
|
51
|
+
: inboxEntryCategory(entry, address, currentTurn(store, address));
|
|
52
|
+
}
|
|
41
53
|
function ownsMessage(store, address, message) {
|
|
42
54
|
if (address.roleName === "leader" && message.taskId === address.taskId && isLeaderSteer(message))
|
|
43
55
|
return true;
|
|
@@ -138,7 +150,8 @@ function blocker(store, address, entry) {
|
|
|
138
150
|
}
|
|
139
151
|
else {
|
|
140
152
|
const message = entry;
|
|
141
|
-
if (message.continuation?.runId !== undefined && message.continuation.runId !== address.runId
|
|
153
|
+
if (message.continuation?.runId !== undefined && message.continuation.runId !== address.runId
|
|
154
|
+
&& !isRecoveredMessage(store, address, message)) {
|
|
142
155
|
return "continuation-already-dispatched";
|
|
143
156
|
}
|
|
144
157
|
if (!accepted && message.inputControl?.expectedSessionId !== undefined
|
|
@@ -163,7 +176,7 @@ function checkMutation(store, address) {
|
|
|
163
176
|
}
|
|
164
177
|
function summary(store, address, entry) {
|
|
165
178
|
return { id: entry.id, kind: isWake(entry) ? "notification-window" : "message",
|
|
166
|
-
category:
|
|
179
|
+
category: entryCategory(store, address, entry),
|
|
167
180
|
createdAt: entry.createdAt, summary: summaryText(isWake(entry) ? entry.reasons.join(", ") : entry.body),
|
|
168
181
|
blocked: blocker(store, address, entry) ?? null, inbox: summaryMetadata(entry.inbox ?? null),
|
|
169
182
|
handling: inboxHandlingState(entry.inbox),
|
|
@@ -178,9 +191,14 @@ function summary(store, address, entry) {
|
|
|
178
191
|
read: `yui inbox show ${entry.id}`, ...(isWake(entry)
|
|
179
192
|
? { originals: `yui task wake show ${entry.taskId} ${entry.id} --json` } : {}) };
|
|
180
193
|
}
|
|
181
|
-
function receipt(entry) {
|
|
194
|
+
function receipt(entry, requestedId) {
|
|
195
|
+
// Pending-window inspection has no fixed originals yet. An existing wake
|
|
196
|
+
// can already have been read completely through inbox show; offer refresh
|
|
197
|
+
// without implying that claim invalidated those bodies or proved a read.
|
|
198
|
+
const originalRead = isWake(entry)
|
|
199
|
+
? { [requestedId.startsWith("pending-") ? "originals" : "refreshOriginals"]: `yui task wake show ${entry.taskId} ${entry.id} --json` } : {};
|
|
182
200
|
return { id: entry.id, inbox: entry.inbox,
|
|
183
|
-
...
|
|
201
|
+
...originalRead };
|
|
184
202
|
}
|
|
185
203
|
/** Own-address command: there is deliberately no --role, --task or --session.
|
|
186
204
|
* Reads do not claim. Exact claim precedes semantic handling; exact ack follows
|
|
@@ -198,8 +216,7 @@ export function runInboxCommand(args, store, env, now = new Date()) {
|
|
|
198
216
|
const selected = address.scope === "global" ? pendingGlobalInboxMessages(store.listGlobalRoleMessages(address.roleName))
|
|
199
217
|
: entries(store, address).filter(entry => (isWake(entry) || !retired.has(entry.id))
|
|
200
218
|
&& !inboxSettled(entry.inbox));
|
|
201
|
-
const
|
|
202
|
-
const categories = selected.map(entry => ({ entry, category: inboxEntryCategory(entry, address, turn) }));
|
|
219
|
+
const categories = selected.map(entry => ({ entry, category: entryCategory(store, address, entry) }));
|
|
203
220
|
const rank = { current: 0, available: 1, history: 2 };
|
|
204
221
|
categories.sort((a, b) => rank[a.category] - rank[b.category]);
|
|
205
222
|
const items = categories.filter(item => view === "all"
|
|
@@ -230,7 +247,17 @@ export function runInboxCommand(args, store, env, now = new Date()) {
|
|
|
230
247
|
note: "Claim this exact window before processing; claim returns its durable wake and original-read command." }, `${source(address)}/${id}`, parsed.cursor);
|
|
231
248
|
}
|
|
232
249
|
const entry = getEntry(store, address, id);
|
|
233
|
-
|
|
250
|
+
if (isWake(entry)) {
|
|
251
|
+
// Own-inbox authorization above remains the boundary. Reuse the existing
|
|
252
|
+
// bounded focused originals rather than reconstructing a second view or
|
|
253
|
+
// making a claim mutation depend on a subsequent read succeeding.
|
|
254
|
+
const focused = taskWakeInspectionCommand(["show", entry.taskId, entry.id], store);
|
|
255
|
+
if (focused.kind !== "output")
|
|
256
|
+
throw new Error("Wake inspection did not return a read result.");
|
|
257
|
+
const { wake: _wake, ...originalContext } = focused.data;
|
|
258
|
+
return boundedDocument({ ...entry, originalContext }, `${source(address)}/${id}`, parsed.cursor);
|
|
259
|
+
}
|
|
260
|
+
const value = address.scope === "task"
|
|
234
261
|
? expandTaskMessageResult(entry, (task, run) => store.getRun(task, run)) : entry;
|
|
235
262
|
return boundedDocument(value, `${source(address)}/${id}`, parsed.cursor);
|
|
236
263
|
}
|
|
@@ -262,7 +289,7 @@ export function runInboxCommand(args, store, env, now = new Date()) {
|
|
|
262
289
|
if (existing.inboxPendingId !== id) {
|
|
263
290
|
throw new Error("Inbox request id was reused for a different window.");
|
|
264
291
|
}
|
|
265
|
-
return receipt(existing);
|
|
292
|
+
return receipt(existing, id);
|
|
266
293
|
}
|
|
267
294
|
const mailbox = tx.getWorkMailbox(target(current));
|
|
268
295
|
if (!mailbox?.pending || pendingId(mailbox.pending) !== id)
|
|
@@ -310,7 +337,7 @@ export function runInboxCommand(args, store, env, now = new Date()) {
|
|
|
310
337
|
if (saved.requestId !== requestId || saved.reason !== reason || !sameSession(saved.actor, current)) {
|
|
311
338
|
throw new Error("Conflicting retirement; original disposition retained.");
|
|
312
339
|
}
|
|
313
|
-
return receipt(entry);
|
|
340
|
+
return receipt(entry, id);
|
|
314
341
|
}
|
|
315
342
|
// A retained attempt in an older conversation is still evidence of
|
|
316
343
|
// submission; changing the active Session cannot erase that boundary.
|
|
@@ -336,7 +363,7 @@ export function runInboxCommand(args, store, env, now = new Date()) {
|
|
|
336
363
|
throw new Error("Claim belongs to a previous Session; read the original and prior effects, then explicitly acknowledge only after finishing its handling.");
|
|
337
364
|
if (entry.inbox.claim.requestId !== requestId)
|
|
338
365
|
throw new Error("Entry already claimed; retain the original request id.");
|
|
339
|
-
return receipt(entry);
|
|
366
|
+
return receipt(entry, id);
|
|
340
367
|
}
|
|
341
368
|
const blocked = blocker(tx, current, entry);
|
|
342
369
|
if (blocked !== undefined)
|
|
@@ -398,7 +425,7 @@ export function runInboxCommand(args, store, env, now = new Date()) {
|
|
|
398
425
|
if (entry.inbox.ack.requestId !== requestId || entry.inbox.ack.reason !== reason
|
|
399
426
|
|| !sameSession(entry.inbox.ack.actor, current))
|
|
400
427
|
throw new Error("Conflicting acknowledgement; original disposition retained.");
|
|
401
|
-
return receipt(entry);
|
|
428
|
+
return receipt(entry, id);
|
|
402
429
|
}
|
|
403
430
|
const inbox = { ...entry.inbox,
|
|
404
431
|
ack: { requestId, actor: current, at: now.toISOString(), reason: reason } };
|
|
@@ -415,7 +442,7 @@ export function runInboxCommand(args, store, env, now = new Date()) {
|
|
|
415
442
|
}
|
|
416
443
|
}
|
|
417
444
|
save(tx, current, entry);
|
|
418
|
-
return receipt(entry);
|
|
445
|
+
return receipt(entry, id);
|
|
419
446
|
});
|
|
420
447
|
if (ids.length === 1)
|
|
421
448
|
return apply(ids[0]);
|
|
@@ -136,11 +136,8 @@ function submit(rest, store, options) {
|
|
|
136
136
|
if (requestId !== undefined && requestId.length === 0) {
|
|
137
137
|
throw usageError("--request-id is required.", usage);
|
|
138
138
|
}
|
|
139
|
-
const body = readCommandText(positionals[0], bodyFile, "--body", usage);
|
|
140
|
-
return
|
|
141
|
-
kind: "output",
|
|
142
|
-
output: submitOperatorMessage(body, taskId, store, options, intent, requestId)
|
|
143
|
-
};
|
|
139
|
+
const body = readCommandText(positionals[0], bodyFile, "--body", usage, { preserveFileWhitespace: true });
|
|
140
|
+
return submitOperatorMessage(body, taskId, store, options, intent, requestId);
|
|
144
141
|
}
|
|
145
142
|
function listSessions(args, store, options) {
|
|
146
143
|
if (args.length !== 0)
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { spawn, spawnSync } from "node:child_process";
|
|
6
6
|
import { chmodSync, cpSync, existsSync, lstatSync, mkdirSync, readdirSync, rmSync, } from "node:fs";
|
|
7
7
|
import { join, resolve } from "node:path";
|
|
8
|
+
import { pathToFileURL } from "node:url";
|
|
8
9
|
import { callController, ControllerClientError } from "../core/controllerClient.js";
|
|
9
10
|
import { processGenerationIsLive } from "../core/fileLockOwner.js";
|
|
10
11
|
import { activateRelease, ControllerStartUnconfirmedError } from "../release/releaseHandover.js";
|
|
@@ -346,10 +347,23 @@ export function createReleaseActivatePorts(overrides = {}) {
|
|
|
346
347
|
}
|
|
347
348
|
}),
|
|
348
349
|
runPreflight: overrides.runPreflight ?? ((releaseDir, home) => {
|
|
349
|
-
|
|
350
|
+
assertReleaseIsNotWorktreeOrLinked(releaseDir);
|
|
351
|
+
const manifest = verifyReleaseIntegrity(releaseDir);
|
|
352
|
+
if (resolve(releaseDir) !== resolve(releaseDirectoryFor(home, manifest))
|
|
353
|
+
|| !hasMatchingSmokeReceipt(releaseDir, manifest)) {
|
|
354
|
+
throw new Error("Release preflight requires this Home's verified installed target and matching smoke receipt.");
|
|
355
|
+
}
|
|
350
356
|
// The target owns current-record and database integrity validation.
|
|
351
357
|
// Activation never migrates; a valid but older Home still blocks here.
|
|
352
|
-
|
|
358
|
+
// Invoke its read-only primitive, not an ordinary inactive CLI command:
|
|
359
|
+
// the Home's CLI fence must remain closed until handover completes.
|
|
360
|
+
const module = pathToFileURL(join(releaseDir, "dist", "storage", "upgrade", "upgradeOrchestrator.js")).href;
|
|
361
|
+
const result = spawnSync(process.execPath, ["--input-type=module", "-e", `
|
|
362
|
+
const { runStorageUpgrade } = await import(process.argv[1]);
|
|
363
|
+
const data = await runStorageUpgrade({ home: process.argv[2], mode: "update-preflight" });
|
|
364
|
+
process.stdout.write(JSON.stringify({ ok: true, data }));
|
|
365
|
+
process.exitCode = data.outcome === "update-preflight" ? 0 : 5;
|
|
366
|
+
`, module, home], {
|
|
353
367
|
env: { ...process.env, YUI_HOME: home, NO_COLOR: "1" },
|
|
354
368
|
encoding: "utf8",
|
|
355
369
|
timeout: 60_000
|