@design-ai/cli 4.56.0 → 4.57.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/.claude-plugin/plugin.json +109 -25
- package/CHANGELOG.md +36 -0
- package/README.ko.md +9 -26
- package/README.md +10 -23
- package/cli/bin/design-ai.mjs +1 -0
- package/cli/commands/help.mjs +7 -4
- package/cli/commands/index.mjs +292 -0
- package/cli/commands/learn-help.mjs +149 -0
- package/cli/commands/learn-print-profile.mjs +373 -0
- package/cli/commands/learn-print-restore.mjs +349 -0
- package/cli/commands/learn-print-signals.mjs +453 -0
- package/cli/commands/learn.mjs +60 -1281
- package/cli/commands/pack.mjs +7 -3
- package/cli/commands/prompt.mjs +7 -3
- package/cli/commands/search.mjs +94 -1
- package/cli/lib/dispatch.mjs +3 -0
- package/cli/lib/embedding-index.mjs +199 -0
- package/cli/lib/embedding-provider.mjs +121 -0
- package/cli/lib/embedding-rerank.mjs +52 -0
- package/cli/lib/learn-args.mjs +490 -0
- package/cli/lib/learn-backup.mjs +748 -0
- package/cli/lib/learn-curation.mjs +612 -0
- package/cli/lib/learn-eval.mjs +459 -0
- package/cli/lib/learn-profile.mjs +763 -0
- package/cli/lib/learn-select.mjs +223 -0
- package/cli/lib/learn-shared.mjs +158 -0
- package/cli/lib/learn-test-support.mjs +218 -0
- package/cli/lib/learn-usage.mjs +360 -0
- package/cli/lib/learn.mjs +83 -3694
- package/cli/lib/lexical.mjs +137 -0
- package/cli/lib/local-config.mjs +110 -0
- package/cli/lib/mcp-server.mjs +13 -3
- package/cli/lib/pack.mjs +31 -4
- package/cli/lib/prompt.mjs +42 -4
- package/cli/lib/recall.mjs +193 -0
- package/cli/lib/retrieval-index.mjs +0 -0
- package/cli/lib/search-ranked.mjs +170 -0
- package/cli/lib/search.mjs +11 -1
- package/cli/lib/signals-backlog-commands.mjs +673 -0
- package/cli/lib/signals-backlog.mjs +361 -0
- package/cli/lib/signals-eval.mjs +176 -0
- package/cli/lib/signals-readiness.mjs +247 -0
- package/cli/lib/signals-registry.mjs +377 -0
- package/cli/lib/signals-render.mjs +478 -0
- package/cli/lib/signals-shared.mjs +75 -0
- package/cli/lib/signals.mjs +16 -2337
- package/cli/lib/site-bundle-handoff-expected.mjs +173 -0
- package/cli/lib/site-bundle-handoff-runbook-action-summary.mjs +332 -0
- package/cli/lib/site-bundle-handoff-runbook-human-lines.mjs +167 -0
- package/cli/lib/site-bundle-handoff-runbook-maps.mjs +238 -0
- package/cli/lib/site-bundle-handoff-runbook-next-step.mjs +278 -0
- package/cli/lib/site-bundle-handoff-runbook.mjs +44 -931
- package/cli/lib/site-test-support.mjs +68 -0
- package/cli/lib/skill-proposals-apply-commands.mjs +135 -0
- package/cli/lib/skill-proposals-apply-contract.mjs +750 -0
- package/cli/lib/skill-proposals-apply-plan.mjs +118 -0
- package/cli/lib/skill-proposals-generate.mjs +298 -0
- package/cli/lib/skill-proposals-render.mjs +532 -0
- package/cli/lib/skill-proposals-review.mjs +262 -0
- package/cli/lib/skill-proposals.mjs +15 -2046
- package/cli/lib/workspace-args.mjs +83 -0
- package/cli/lib/workspace-git.mjs +169 -0
- package/cli/lib/workspace-learning.mjs +483 -0
- package/cli/lib/workspace-repo.mjs +139 -0
- package/cli/lib/workspace-report.mjs +283 -0
- package/cli/lib/workspace-test-support.mjs +99 -0
- package/cli/lib/workspace.mjs +30 -1056
- package/docs/AI-LEARNING-PHASE2.md +215 -0
- package/docs/DISTRIBUTION.ko.md +2 -2
- package/docs/DISTRIBUTION.md +2 -2
- package/docs/NEXT-SURFACE-DECISION.md +125 -0
- package/docs/PRODUCT-READINESS.md +3 -3
- package/docs/RELEASE-GATES.ko.md +35 -0
- package/docs/RELEASE-GATES.md +234 -0
- package/docs/ROADMAP.md +53 -8
- package/docs/external-status.md +6 -8
- package/docs/inspection-20260630.md +169 -0
- package/docs/integrations/design-ai-mcp-server.md +4 -4
- package/docs/reference/ant-design.md +413 -0
- package/docs/reference/awesome-design-md.md +439 -0
- package/docs/reference/mui.md +783 -0
- package/docs/reference/shadcn-ui.md +298 -0
- package/examples/component-accordion-actions.md +5 -5
- package/examples/component-accordion-details.md +5 -5
- package/examples/component-accordion-summary.md +5 -5
- package/examples/component-accordion.md +3 -3
- package/examples/component-affix.md +1 -1
- package/examples/component-alert-dialog.md +1 -1
- package/examples/component-alert-title.md +1 -1
- package/examples/component-alert.md +3 -3
- package/examples/component-anchor.md +1 -1
- package/examples/component-app-bar.md +1 -1
- package/examples/component-aspect-ratio.md +1 -1
- package/examples/component-auto-complete.md +2 -2
- package/examples/component-avatar-group.md +5 -5
- package/examples/component-avatar.md +3 -3
- package/examples/component-back-top.md +1 -1
- package/examples/component-backdrop.md +1 -1
- package/examples/component-badge.md +3 -3
- package/examples/component-border-beam.md +3 -3
- package/examples/component-bottom-navigation.md +1 -1
- package/examples/component-box.md +1 -1
- package/examples/component-breadcrumb.md +3 -3
- package/examples/component-button-base.md +3 -3
- package/examples/component-button-group.md +2 -2
- package/examples/component-button.md +3 -3
- package/examples/component-calendar.md +2 -2
- package/examples/component-card-actions.md +1 -1
- package/examples/component-card-content.md +1 -1
- package/examples/component-card-header.md +1 -1
- package/examples/component-card-media.md +1 -1
- package/examples/component-card.md +3 -3
- package/examples/component-carousel.md +2 -2
- package/examples/component-cascader.md +1 -1
- package/examples/component-chart.md +1 -1
- package/examples/component-checkbox.md +3 -3
- package/examples/component-click-away-listener.md +1 -1
- package/examples/component-code.md +1 -1
- package/examples/component-collapsible.md +1 -1
- package/examples/component-color-picker.md +1 -1
- package/examples/component-combobox.md +1 -1
- package/examples/component-command.md +1 -1
- package/examples/component-config-provider.md +3 -3
- package/examples/component-context-menu.md +1 -1
- package/examples/component-css-baseline.md +3 -3
- package/examples/component-date-picker.md +2 -2
- package/examples/component-descriptions.md +1 -1
- package/examples/component-dialog-actions.md +1 -1
- package/examples/component-dialog-content-text.md +1 -1
- package/examples/component-dialog-content.md +1 -1
- package/examples/component-dialog-title.md +1 -1
- package/examples/component-dialog.md +2 -2
- package/examples/component-divider.md +3 -3
- package/examples/component-drawer.md +3 -3
- package/examples/component-dropdown.md +3 -3
- package/examples/component-empty.md +2 -2
- package/examples/component-fade.md +1 -1
- package/examples/component-field.md +1 -1
- package/examples/component-filled-input.md +1 -1
- package/examples/component-flex.md +1 -1
- package/examples/component-float-button.md +2 -2
- package/examples/component-form-control-label.md +1 -1
- package/examples/component-form-control.md +1 -1
- package/examples/component-form-controls.md +1 -1
- package/examples/component-form-group.md +1 -1
- package/examples/component-form-helper-text.md +1 -1
- package/examples/component-form-label.md +1 -1
- package/examples/component-form.md +2 -2
- package/examples/component-grid.md +2 -2
- package/examples/component-grow.md +1 -1
- package/examples/component-hover-card.md +1 -1
- package/examples/component-icon-button.md +1 -1
- package/examples/component-icon.md +1 -1
- package/examples/component-image-list.md +1 -1
- package/examples/component-image.md +1 -1
- package/examples/component-input-adornment.md +1 -1
- package/examples/component-input-base.md +1 -1
- package/examples/component-input-number.md +1 -1
- package/examples/component-input-otp.md +2 -2
- package/examples/component-input.md +3 -3
- package/examples/component-item.md +1 -1
- package/examples/component-label.md +1 -1
- package/examples/component-layout.md +1 -1
- package/examples/component-link.md +1 -1
- package/examples/component-list-item-avatar.md +1 -1
- package/examples/component-list-item-button.md +1 -1
- package/examples/component-list-item-icon.md +1 -1
- package/examples/component-list-item-text.md +1 -1
- package/examples/component-list-item.md +1 -1
- package/examples/component-list-subheader.md +1 -1
- package/examples/component-list.md +2 -2
- package/examples/component-masonry.md +1 -1
- package/examples/component-mentions.md +1 -1
- package/examples/component-menu-item.md +1 -1
- package/examples/component-menu-list.md +1 -1
- package/examples/component-menu.md +1 -1
- package/examples/component-menubar.md +1 -1
- package/examples/component-message.md +1 -1
- package/examples/component-mobile-stepper.md +1 -1
- package/examples/component-modal.md +5 -5
- package/examples/component-navigation-menu.md +1 -1
- package/examples/component-notification.md +1 -1
- package/examples/component-outlined-input.md +1 -1
- package/examples/component-pagination.md +3 -3
- package/examples/component-paper.md +1 -1
- package/examples/component-popconfirm.md +1 -1
- package/examples/component-popover.md +3 -3
- package/examples/component-popper.md +1 -1
- package/examples/component-progress.md +2 -2
- package/examples/component-qr-code.md +1 -1
- package/examples/component-radio.md +3 -3
- package/examples/component-rate.md +2 -2
- package/examples/component-resizable.md +1 -1
- package/examples/component-result.md +1 -1
- package/examples/component-scroll-area.md +1 -1
- package/examples/component-segmented.md +3 -3
- package/examples/component-select.md +3 -3
- package/examples/component-separator.md +1 -1
- package/examples/component-sheet.md +1 -1
- package/examples/component-sidebar.md +1 -1
- package/examples/component-skeleton.md +3 -3
- package/examples/component-slide.md +1 -1
- package/examples/component-slider.md +3 -3
- package/examples/component-snackbar-content.md +1 -1
- package/examples/component-snackbar.md +1 -1
- package/examples/component-sonner.md +1 -1
- package/examples/component-space.md +1 -1
- package/examples/component-speed-dial-action.md +1 -1
- package/examples/component-speed-dial.md +1 -1
- package/examples/component-spin.md +2 -2
- package/examples/component-spinner.md +1 -1
- package/examples/component-splitter.md +2 -2
- package/examples/component-stack.md +1 -1
- package/examples/component-statistic.md +1 -1
- package/examples/component-step-button.md +4 -4
- package/examples/component-step-connector.md +4 -4
- package/examples/component-step-content.md +1 -1
- package/examples/component-step-icon.md +1 -1
- package/examples/component-step-label.md +1 -1
- package/examples/component-step.md +2 -2
- package/examples/component-steps.md +2 -2
- package/examples/component-swipeable-drawer.md +1 -1
- package/examples/component-switch.md +3 -3
- package/examples/component-tab-scroll-button.md +5 -5
- package/examples/component-tab.md +1 -1
- package/examples/component-table-body.md +1 -1
- package/examples/component-table-cell.md +1 -1
- package/examples/component-table-container.md +1 -1
- package/examples/component-table-footer.md +1 -1
- package/examples/component-table-head.md +1 -1
- package/examples/component-table-pagination.md +1 -1
- package/examples/component-table-row.md +1 -1
- package/examples/component-table-sort-label.md +1 -1
- package/examples/component-table.md +2 -2
- package/examples/component-tabs.md +3 -3
- package/examples/component-tag-badge.md +2 -2
- package/examples/component-tag.md +1 -1
- package/examples/component-textarea-autosize.md +1 -1
- package/examples/component-textarea.md +1 -1
- package/examples/component-time-picker.md +1 -1
- package/examples/component-timeline.md +1 -1
- package/examples/component-toast.md +4 -4
- package/examples/component-toggle-button.md +1 -1
- package/examples/component-toggle.md +1 -1
- package/examples/component-toolbar.md +1 -1
- package/examples/component-tooltip.md +3 -3
- package/examples/component-tour.md +1 -1
- package/examples/component-transfer.md +1 -1
- package/examples/component-tree-select.md +1 -1
- package/examples/component-tree.md +1 -1
- package/examples/component-typography.md +2 -2
- package/examples/component-upload.md +1 -1
- package/examples/component-watermark.md +1 -1
- package/examples/component-zoom.md +1 -1
- package/knowledge/COVERAGE.md +4 -3
- package/knowledge/components/INDEX.md +202 -202
- package/knowledge/patterns/brand-references.md +72 -72
- package/package.json +1 -1
- package/tools/audit/local-ci.py +16 -1
- package/tools/audit/package-smoke.py +611 -9
- package/tools/audit/registry-smoke.py +534 -0
- package/tools/audit/release-metadata.py +47 -1
- package/tools/audit/smoke_assertions.py +915 -13
- package/tools/migrations/refs-links-to-reference-pages.py +179 -0
|
@@ -0,0 +1,750 @@
|
|
|
1
|
+
// Apply-plan command contract construction for skill proposals.
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
APPLY_PLAN_BASE_COMMAND,
|
|
5
|
+
APPLY_PLAN_FOLLOW_UP_COMMAND_DESCRIPTIONS,
|
|
6
|
+
APPLY_PLAN_FOLLOW_UP_COMMAND_DISPLAY_LABELS,
|
|
7
|
+
APPLY_PLAN_FOLLOW_UP_COMMAND_OUTPUT_ARTIFACTS,
|
|
8
|
+
APPLY_PLAN_FOLLOW_UP_COMMAND_OUTPUT_ARTIFACT_ACTIONS,
|
|
9
|
+
APPLY_PLAN_FOLLOW_UP_COMMAND_OUTPUT_ARTIFACT_APPLY_PRECONDITION_IDS,
|
|
10
|
+
APPLY_PLAN_FOLLOW_UP_COMMAND_OUTPUT_ARTIFACT_APPLY_PRECONDITION_LABELS,
|
|
11
|
+
APPLY_PLAN_FOLLOW_UP_COMMAND_OUTPUT_ARTIFACT_DISPOSITIONS,
|
|
12
|
+
APPLY_PLAN_FOLLOW_UP_COMMAND_OUTPUT_ARTIFACT_MANUAL_APPLY_CANDIDATES,
|
|
13
|
+
APPLY_PLAN_FOLLOW_UP_COMMAND_OUTPUT_ARTIFACT_MEDIA_TYPES,
|
|
14
|
+
APPLY_PLAN_FOLLOW_UP_COMMAND_OUTPUT_ARTIFACT_REQUIRES_CLEAN_WORKSPACE_BEFORE_APPLY,
|
|
15
|
+
APPLY_PLAN_FOLLOW_UP_COMMAND_OUTPUT_ARTIFACT_REQUIRES_MANUAL_REVIEW,
|
|
16
|
+
APPLY_PLAN_FOLLOW_UP_COMMAND_OUTPUT_ARTIFACT_REVIEW_INSTRUCTIONS,
|
|
17
|
+
APPLY_PLAN_FOLLOW_UP_COMMAND_OUTPUT_ARTIFACT_TYPES,
|
|
18
|
+
APPLY_PLAN_FOLLOW_UP_COMMAND_POLICIES,
|
|
19
|
+
APPLY_PLAN_FOLLOW_UP_COMMAND_SPECS,
|
|
20
|
+
APPLY_PLAN_FORBIDDEN_FLAGS,
|
|
21
|
+
argsEndWith,
|
|
22
|
+
argsStartWith,
|
|
23
|
+
commandArgCheck,
|
|
24
|
+
} from "./skill-proposals-apply-commands.mjs";
|
|
25
|
+
|
|
26
|
+
function applyPreconditionsForCommandKey(commandKey) {
|
|
27
|
+
const ids = APPLY_PLAN_FOLLOW_UP_COMMAND_OUTPUT_ARTIFACT_APPLY_PRECONDITION_IDS[commandKey] || [];
|
|
28
|
+
const labels = APPLY_PLAN_FOLLOW_UP_COMMAND_OUTPUT_ARTIFACT_APPLY_PRECONDITION_LABELS[commandKey] || [];
|
|
29
|
+
return ids.map((id, index) => ({
|
|
30
|
+
id,
|
|
31
|
+
label: labels[index] || id,
|
|
32
|
+
required: true,
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function applyPreconditionIsSatisfied(precondition) {
|
|
37
|
+
return precondition?.satisfied === true;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function manualApplyBlockedReason({ manualApplyCandidate, requiredPendingApplyPreconditionCount }) {
|
|
41
|
+
if (!manualApplyCandidate) {
|
|
42
|
+
return {
|
|
43
|
+
code: "not-manual-apply-candidate",
|
|
44
|
+
message: "This output artifact is review-only and cannot be applied.",
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
if (requiredPendingApplyPreconditionCount > 0) {
|
|
48
|
+
return {
|
|
49
|
+
code: "required-preconditions-pending",
|
|
50
|
+
message: "Complete required apply preconditions before applying this patch preview.",
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return { code: "", message: "" };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function manualApplyStatus({ manualApplyCandidate, manualApplyReady }) {
|
|
57
|
+
if (manualApplyReady) return "ready";
|
|
58
|
+
if (manualApplyCandidate) return "blocked";
|
|
59
|
+
return "not-applicable";
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function manualApplyStatusLabel(status) {
|
|
63
|
+
if (status === "ready") return "Ready to apply";
|
|
64
|
+
if (status === "blocked") return "Blocked";
|
|
65
|
+
return "Review only";
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function manualApplyStatusTone(status) {
|
|
69
|
+
if (status === "ready") return "success";
|
|
70
|
+
if (status === "blocked") return "warning";
|
|
71
|
+
return "neutral";
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function buildApplyPlanCommandContract(followUpCommands, reviewFile) {
|
|
75
|
+
const requiredKeys = Object.keys(APPLY_PLAN_FOLLOW_UP_COMMAND_SPECS);
|
|
76
|
+
const commandArgs = Object.fromEntries(Object.entries(followUpCommands).map(([key, value]) => [
|
|
77
|
+
key,
|
|
78
|
+
Array.isArray(value?.commandArgs) ? value.commandArgs : [],
|
|
79
|
+
]));
|
|
80
|
+
const missingCommandKeys = requiredKeys.filter((key) => !Array.isArray(commandArgs[key]) || commandArgs[key].length === 0);
|
|
81
|
+
const unexpectedCommandKeys = Object.keys(commandArgs).filter((key) => !requiredKeys.includes(key));
|
|
82
|
+
const checks = [
|
|
83
|
+
commandArgCheck({
|
|
84
|
+
id: "required-command-keys-present",
|
|
85
|
+
passed: missingCommandKeys.length === 0,
|
|
86
|
+
message: missingCommandKeys.length === 0
|
|
87
|
+
? "All required apply-plan follow-up commands are present."
|
|
88
|
+
: "Some required apply-plan follow-up commands are missing.",
|
|
89
|
+
evidence: { requiredKeys, missingCommandKeys },
|
|
90
|
+
}),
|
|
91
|
+
commandArgCheck({
|
|
92
|
+
id: "no-unexpected-command-keys",
|
|
93
|
+
passed: unexpectedCommandKeys.length === 0,
|
|
94
|
+
message: unexpectedCommandKeys.length === 0
|
|
95
|
+
? "No unexpected apply-plan follow-up commands are present."
|
|
96
|
+
: "Unexpected apply-plan follow-up command keys were found.",
|
|
97
|
+
evidence: { unexpectedCommandKeys },
|
|
98
|
+
}),
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
for (const key of requiredKeys) {
|
|
102
|
+
const args = commandArgs[key] || [];
|
|
103
|
+
const reviewFileIndex = args.indexOf("--review-file");
|
|
104
|
+
checks.push(commandArgCheck({
|
|
105
|
+
id: `${key}-base-command`,
|
|
106
|
+
passed: argsStartWith(args, APPLY_PLAN_BASE_COMMAND),
|
|
107
|
+
message: `${key} starts with design-ai learn --propose-skills.`,
|
|
108
|
+
evidence: { commandArgs: args.slice(0, APPLY_PLAN_BASE_COMMAND.length) },
|
|
109
|
+
}));
|
|
110
|
+
checks.push(commandArgCheck({
|
|
111
|
+
id: `${key}-review-file-context`,
|
|
112
|
+
passed: Boolean(reviewFile) && reviewFileIndex >= 0 && args[reviewFileIndex + 1] === reviewFile,
|
|
113
|
+
message: `${key} preserves the configured review file.`,
|
|
114
|
+
evidence: { reviewFile, commandReviewFile: reviewFileIndex >= 0 ? args[reviewFileIndex + 1] || "" : "" },
|
|
115
|
+
}));
|
|
116
|
+
checks.push(commandArgCheck({
|
|
117
|
+
id: `${key}-expected-suffix`,
|
|
118
|
+
passed: argsEndWith(args, APPLY_PLAN_FOLLOW_UP_COMMAND_SPECS[key]),
|
|
119
|
+
message: `${key} ends with the expected action flags.`,
|
|
120
|
+
evidence: { expectedSuffix: APPLY_PLAN_FOLLOW_UP_COMMAND_SPECS[key], actualSuffix: args.slice(-APPLY_PLAN_FOLLOW_UP_COMMAND_SPECS[key].length) },
|
|
121
|
+
}));
|
|
122
|
+
checks.push(commandArgCheck({
|
|
123
|
+
id: `${key}-read-only-flags`,
|
|
124
|
+
passed: APPLY_PLAN_FORBIDDEN_FLAGS.every((flag) => !args.includes(flag)),
|
|
125
|
+
message: `${key} does not include write/apply confirmation flags.`,
|
|
126
|
+
evidence: { forbiddenFlags: APPLY_PLAN_FORBIDDEN_FLAGS },
|
|
127
|
+
}));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const failures = checks.filter((check) => check.level === "fail").length;
|
|
131
|
+
const warnings = checks.filter((check) => check.level === "warn").length;
|
|
132
|
+
const passes = checks.filter((check) => check.level === "pass").length;
|
|
133
|
+
const checkCount = checks.length;
|
|
134
|
+
const failedChecks = checks
|
|
135
|
+
.filter((check) => check.level === "fail")
|
|
136
|
+
.map((check) => ({
|
|
137
|
+
id: check.id,
|
|
138
|
+
message: check.message,
|
|
139
|
+
evidence: check.evidence || {},
|
|
140
|
+
}));
|
|
141
|
+
const nextCommandKey = failures > 0 ? "" : "reviewCheckJson";
|
|
142
|
+
const nextCommand = nextCommandKey ? followUpCommands[nextCommandKey]?.command || "" : "";
|
|
143
|
+
const nextCommandArgs = nextCommandKey ? commandArgs[nextCommandKey] || [] : [];
|
|
144
|
+
const nextCommandRunPolicy = nextCommandKey ? "preview-only" : "";
|
|
145
|
+
const nextCommandSafety = nextCommandKey
|
|
146
|
+
? {
|
|
147
|
+
level: "read-only",
|
|
148
|
+
writesLocalFiles: false,
|
|
149
|
+
mutatesLocalState: false,
|
|
150
|
+
mutatesProfile: false,
|
|
151
|
+
mutatesReviewFile: false,
|
|
152
|
+
mutatesSkillFiles: false,
|
|
153
|
+
callsExternalAiApis: false,
|
|
154
|
+
requiresCleanWorkspace: false,
|
|
155
|
+
reason: "The next apply-plan follow-up command only checks proposal review readiness and does not mutate local state.",
|
|
156
|
+
}
|
|
157
|
+
: {};
|
|
158
|
+
const commandSequence = failures > 0
|
|
159
|
+
? []
|
|
160
|
+
: requiredKeys.map((key, index) => {
|
|
161
|
+
const writesOutputArtifact = key === "reviewCheckReport" || key === "proposalPatchPreview";
|
|
162
|
+
return {
|
|
163
|
+
step: index + 1,
|
|
164
|
+
key,
|
|
165
|
+
command: followUpCommands[key]?.command || "",
|
|
166
|
+
commandArgs: commandArgs[key] || [],
|
|
167
|
+
runPolicy: APPLY_PLAN_FOLLOW_UP_COMMAND_POLICIES[key] || "preview-only",
|
|
168
|
+
safety: {
|
|
169
|
+
level: writesOutputArtifact ? "local-output" : "read-only",
|
|
170
|
+
writesLocalFiles: writesOutputArtifact,
|
|
171
|
+
writesOutputArtifact,
|
|
172
|
+
mutatesLocalState: writesOutputArtifact,
|
|
173
|
+
mutatesProfile: false,
|
|
174
|
+
mutatesReviewFile: false,
|
|
175
|
+
mutatesSkillFiles: false,
|
|
176
|
+
callsExternalAiApis: false,
|
|
177
|
+
requiresCleanWorkspace: false,
|
|
178
|
+
reason: writesOutputArtifact
|
|
179
|
+
? "This follow-up command writes a local preview artifact with --out but does not mutate learning, review, or skill files."
|
|
180
|
+
: "This follow-up command validates readiness without writing local files or mutating local state.",
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
});
|
|
184
|
+
const commandSequenceSummary = {
|
|
185
|
+
executable: failures === 0,
|
|
186
|
+
blocked: failures > 0,
|
|
187
|
+
stepCount: commandSequence.length,
|
|
188
|
+
readOnlyStepCount: commandSequence.filter((item) => item.safety?.level === "read-only").length,
|
|
189
|
+
localOutputStepCount: commandSequence.filter((item) => item.safety?.level === "local-output").length,
|
|
190
|
+
writesLocalFiles: commandSequence.some((item) => Boolean(item.safety?.writesLocalFiles)),
|
|
191
|
+
writesOutputArtifacts: commandSequence.some((item) => Boolean(item.safety?.writesOutputArtifact)),
|
|
192
|
+
mutatesProfile: commandSequence.some((item) => Boolean(item.safety?.mutatesProfile)),
|
|
193
|
+
mutatesReviewFile: commandSequence.some((item) => Boolean(item.safety?.mutatesReviewFile)),
|
|
194
|
+
mutatesSkillFiles: commandSequence.some((item) => Boolean(item.safety?.mutatesSkillFiles)),
|
|
195
|
+
callsExternalAiApis: commandSequence.some((item) => Boolean(item.safety?.callsExternalAiApis)),
|
|
196
|
+
requiresCleanWorkspace: commandSequence.some((item) => Boolean(item.safety?.requiresCleanWorkspace)),
|
|
197
|
+
runPolicy: failures > 0 ? "blocked" : "mixed-preview-local-output",
|
|
198
|
+
reason: failures > 0
|
|
199
|
+
? "Command contract failures must be fixed before running follow-up commands."
|
|
200
|
+
: "The sequence combines read-only readiness checks with local output artifact previews; it does not mutate learning, review, or skill files.",
|
|
201
|
+
};
|
|
202
|
+
const commandSequenceKeys = commandSequence.map((item) => item.key);
|
|
203
|
+
const commandSequenceByKey = Object.fromEntries(commandSequence.map((item) => [item.key, item]));
|
|
204
|
+
const operatorRunbookStages = failures > 0
|
|
205
|
+
? []
|
|
206
|
+
: [
|
|
207
|
+
{
|
|
208
|
+
step: 1,
|
|
209
|
+
key: "previewArtifacts",
|
|
210
|
+
label: "Generate optional review artifacts",
|
|
211
|
+
kind: "local-output-preview",
|
|
212
|
+
required: false,
|
|
213
|
+
commandKeys: ["reviewCheckReport", "proposalPatchPreview"],
|
|
214
|
+
commands: ["reviewCheckReport", "proposalPatchPreview"].map((key) => commandSequenceByKey[key]),
|
|
215
|
+
reason: "Optional Markdown review and patch preview artifacts can be generated before manual skill edits.",
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
step: 2,
|
|
219
|
+
key: "manualSkillEdit",
|
|
220
|
+
label: "Apply accepted skill deltas manually",
|
|
221
|
+
kind: "manual-review",
|
|
222
|
+
required: true,
|
|
223
|
+
commandKeys: [],
|
|
224
|
+
commands: [],
|
|
225
|
+
reason: "No apply-plan command mutates skill files; the operator must manually edit accepted skill deltas after review.",
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
step: 3,
|
|
229
|
+
key: "reviewReadiness",
|
|
230
|
+
label: "Run review readiness check",
|
|
231
|
+
kind: "read-only-check",
|
|
232
|
+
required: true,
|
|
233
|
+
commandKeys: ["reviewCheckJson"],
|
|
234
|
+
commands: [commandSequenceByKey.reviewCheckJson],
|
|
235
|
+
reason: "Run the read-only review check after manual skill edits to verify proposal review state.",
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
step: 4,
|
|
239
|
+
key: "strictGate",
|
|
240
|
+
label: "Run strict readiness gate",
|
|
241
|
+
kind: "read-only-gate",
|
|
242
|
+
required: true,
|
|
243
|
+
commandKeys: ["strictGate"],
|
|
244
|
+
commands: [commandSequenceByKey.strictGate],
|
|
245
|
+
reason: "Run the strict gate before marking accepted proposals applied.",
|
|
246
|
+
},
|
|
247
|
+
];
|
|
248
|
+
const operatorRunbookStageKeys = operatorRunbookStages.map((stage) => stage.key);
|
|
249
|
+
const operatorRunbookStageByKey = Object.fromEntries(operatorRunbookStages.map((stage) => [stage.key, stage]));
|
|
250
|
+
const summarizeOperatorRunbookStage = (stage) => {
|
|
251
|
+
if (!stage) return {};
|
|
252
|
+
const commandSafetyItems = stage.commands
|
|
253
|
+
.map((command) => command?.safety)
|
|
254
|
+
.filter((safety) => safety && typeof safety === "object");
|
|
255
|
+
const writesLocalFiles = commandSafetyItems.some((safety) => Boolean(safety.writesLocalFiles));
|
|
256
|
+
const writesOutputArtifacts = commandSafetyItems.some((safety) => Boolean(safety.writesOutputArtifact));
|
|
257
|
+
const mutatesLocalState = commandSafetyItems.some((safety) => Boolean(safety.mutatesLocalState));
|
|
258
|
+
const mutatesProfile = commandSafetyItems.some((safety) => Boolean(safety.mutatesProfile));
|
|
259
|
+
const mutatesReviewFile = commandSafetyItems.some((safety) => Boolean(safety.mutatesReviewFile));
|
|
260
|
+
const mutatesSkillFiles = commandSafetyItems.some((safety) => Boolean(safety.mutatesSkillFiles));
|
|
261
|
+
const callsExternalAiApis = commandSafetyItems.some((safety) => Boolean(safety.callsExternalAiApis));
|
|
262
|
+
const requiresCleanWorkspace = commandSafetyItems.some((safety) => Boolean(safety.requiresCleanWorkspace));
|
|
263
|
+
return {
|
|
264
|
+
key: stage.key,
|
|
265
|
+
step: stage.step,
|
|
266
|
+
label: stage.label,
|
|
267
|
+
kind: stage.kind,
|
|
268
|
+
required: stage.required,
|
|
269
|
+
hasCommands: stage.commandKeys.length > 0,
|
|
270
|
+
commandCount: stage.commandKeys.length,
|
|
271
|
+
commandKeys: stage.commandKeys,
|
|
272
|
+
writesLocalFiles,
|
|
273
|
+
writesOutputArtifacts,
|
|
274
|
+
mutatesLocalState,
|
|
275
|
+
mutatesProfile,
|
|
276
|
+
mutatesReviewFile,
|
|
277
|
+
mutatesSkillFiles,
|
|
278
|
+
callsExternalAiApis,
|
|
279
|
+
requiresCleanWorkspace,
|
|
280
|
+
reason: stage.reason,
|
|
281
|
+
};
|
|
282
|
+
};
|
|
283
|
+
const nextStage = failures > 0
|
|
284
|
+
? null
|
|
285
|
+
: operatorRunbookStageByKey.previewArtifacts || null;
|
|
286
|
+
const nextRequiredStage = failures > 0
|
|
287
|
+
? null
|
|
288
|
+
: operatorRunbookStages.find((stage) => stage.required) || null;
|
|
289
|
+
const nextRequiredCommandStage = failures > 0
|
|
290
|
+
? null
|
|
291
|
+
: operatorRunbookStages.find((stage) => stage.required && stage.commandKeys.length > 0) || null;
|
|
292
|
+
const nextStageSummary = summarizeOperatorRunbookStage(nextStage);
|
|
293
|
+
const nextRequiredStageSummary = summarizeOperatorRunbookStage(nextRequiredStage);
|
|
294
|
+
const nextRequiredCommandStageSummary = summarizeOperatorRunbookStage(nextRequiredCommandStage);
|
|
295
|
+
const summarizeDecisionCommand = (command) => command
|
|
296
|
+
? {
|
|
297
|
+
step: command.step,
|
|
298
|
+
key: command.key,
|
|
299
|
+
command: command.command,
|
|
300
|
+
commandArgs: command.commandArgs,
|
|
301
|
+
runPolicy: command.runPolicy,
|
|
302
|
+
safetyLevel: command.safety?.level || "",
|
|
303
|
+
safety: {
|
|
304
|
+
level: command.safety?.level || "",
|
|
305
|
+
writesLocalFiles: Boolean(command.safety?.writesLocalFiles),
|
|
306
|
+
writesOutputArtifact: Boolean(command.safety?.writesOutputArtifact),
|
|
307
|
+
mutatesLocalState: Boolean(command.safety?.mutatesLocalState),
|
|
308
|
+
mutatesProfile: Boolean(command.safety?.mutatesProfile),
|
|
309
|
+
mutatesReviewFile: Boolean(command.safety?.mutatesReviewFile),
|
|
310
|
+
mutatesSkillFiles: Boolean(command.safety?.mutatesSkillFiles),
|
|
311
|
+
callsExternalAiApis: Boolean(command.safety?.callsExternalAiApis),
|
|
312
|
+
requiresCleanWorkspace: Boolean(command.safety?.requiresCleanWorkspace),
|
|
313
|
+
reason: command.safety?.reason || "",
|
|
314
|
+
},
|
|
315
|
+
writesLocalFiles: Boolean(command.safety?.writesLocalFiles),
|
|
316
|
+
writesOutputArtifact: Boolean(command.safety?.writesOutputArtifact),
|
|
317
|
+
mutatesLocalState: Boolean(command.safety?.mutatesLocalState),
|
|
318
|
+
mutatesProfile: Boolean(command.safety?.mutatesProfile),
|
|
319
|
+
mutatesReviewFile: Boolean(command.safety?.mutatesReviewFile),
|
|
320
|
+
mutatesSkillFiles: Boolean(command.safety?.mutatesSkillFiles),
|
|
321
|
+
callsExternalAiApis: Boolean(command.safety?.callsExternalAiApis),
|
|
322
|
+
requiresCleanWorkspace: Boolean(command.safety?.requiresCleanWorkspace),
|
|
323
|
+
}
|
|
324
|
+
: {};
|
|
325
|
+
const decisionCommands = failures > 0
|
|
326
|
+
? []
|
|
327
|
+
: (nextStage?.commands || []).map((command) => summarizeDecisionCommand(command));
|
|
328
|
+
const decisionCommandByKey = Object.fromEntries(decisionCommands.map((command) => [command.key, command]));
|
|
329
|
+
const decisionCommandStepByKey = Object.fromEntries(decisionCommands.map((command) => [command.key, command.step]));
|
|
330
|
+
const decisionCommandRunPolicyByKey = Object.fromEntries(
|
|
331
|
+
decisionCommands.map((command) => [command.key, command.runPolicy]),
|
|
332
|
+
);
|
|
333
|
+
const decisionCommandSafetyLevelByKey = Object.fromEntries(
|
|
334
|
+
decisionCommands.map((command) => [command.key, command.safetyLevel]),
|
|
335
|
+
);
|
|
336
|
+
const decisionCommandArgsByKey = Object.fromEntries(
|
|
337
|
+
decisionCommands.map((command) => [command.key, command.commandArgs]),
|
|
338
|
+
);
|
|
339
|
+
const decisionCommandStringByKey = Object.fromEntries(
|
|
340
|
+
decisionCommands.map((command) => [command.key, command.command]),
|
|
341
|
+
);
|
|
342
|
+
const decisionCommandDisplayLabelByKey = Object.fromEntries(
|
|
343
|
+
decisionCommands.map((command) => [
|
|
344
|
+
command.key,
|
|
345
|
+
APPLY_PLAN_FOLLOW_UP_COMMAND_DISPLAY_LABELS[command.key] || command.key,
|
|
346
|
+
]),
|
|
347
|
+
);
|
|
348
|
+
const decisionCommandDescriptionByKey = Object.fromEntries(
|
|
349
|
+
decisionCommands.map((command) => [
|
|
350
|
+
command.key,
|
|
351
|
+
APPLY_PLAN_FOLLOW_UP_COMMAND_DESCRIPTIONS[command.key] || "",
|
|
352
|
+
]),
|
|
353
|
+
);
|
|
354
|
+
const decisionCommandOutputArtifactByKey = Object.fromEntries(
|
|
355
|
+
decisionCommands.map((command) => [
|
|
356
|
+
command.key,
|
|
357
|
+
APPLY_PLAN_FOLLOW_UP_COMMAND_OUTPUT_ARTIFACTS[command.key] || "",
|
|
358
|
+
]),
|
|
359
|
+
);
|
|
360
|
+
const decisionCommandOutputArtifactTypeByKey = Object.fromEntries(
|
|
361
|
+
decisionCommands.map((command) => [
|
|
362
|
+
command.key,
|
|
363
|
+
APPLY_PLAN_FOLLOW_UP_COMMAND_OUTPUT_ARTIFACT_TYPES[command.key] || "",
|
|
364
|
+
]),
|
|
365
|
+
);
|
|
366
|
+
const decisionCommandOutputArtifactActionByKey = Object.fromEntries(
|
|
367
|
+
decisionCommands.map((command) => [
|
|
368
|
+
command.key,
|
|
369
|
+
APPLY_PLAN_FOLLOW_UP_COMMAND_OUTPUT_ARTIFACT_ACTIONS[command.key] || "",
|
|
370
|
+
]),
|
|
371
|
+
);
|
|
372
|
+
const decisionCommandOutputArtifactMediaTypeByKey = Object.fromEntries(
|
|
373
|
+
decisionCommands.map((command) => [
|
|
374
|
+
command.key,
|
|
375
|
+
APPLY_PLAN_FOLLOW_UP_COMMAND_OUTPUT_ARTIFACT_MEDIA_TYPES[command.key] || "",
|
|
376
|
+
]),
|
|
377
|
+
);
|
|
378
|
+
const decisionCommandOutputArtifactDispositionByKey = Object.fromEntries(
|
|
379
|
+
decisionCommands.map((command) => [
|
|
380
|
+
command.key,
|
|
381
|
+
APPLY_PLAN_FOLLOW_UP_COMMAND_OUTPUT_ARTIFACT_DISPOSITIONS[command.key] || "",
|
|
382
|
+
]),
|
|
383
|
+
);
|
|
384
|
+
const decisionCommandOutputArtifactManualApplyCandidateByKey = Object.fromEntries(
|
|
385
|
+
decisionCommands.map((command) => [
|
|
386
|
+
command.key,
|
|
387
|
+
APPLY_PLAN_FOLLOW_UP_COMMAND_OUTPUT_ARTIFACT_MANUAL_APPLY_CANDIDATES[command.key] || false,
|
|
388
|
+
]),
|
|
389
|
+
);
|
|
390
|
+
const decisionCommandOutputArtifactRequiresManualReviewByKey = Object.fromEntries(
|
|
391
|
+
decisionCommands.map((command) => [
|
|
392
|
+
command.key,
|
|
393
|
+
APPLY_PLAN_FOLLOW_UP_COMMAND_OUTPUT_ARTIFACT_REQUIRES_MANUAL_REVIEW[command.key] || false,
|
|
394
|
+
]),
|
|
395
|
+
);
|
|
396
|
+
const decisionCommandOutputArtifactReviewInstructionByKey = Object.fromEntries(
|
|
397
|
+
decisionCommands.map((command) => [
|
|
398
|
+
command.key,
|
|
399
|
+
APPLY_PLAN_FOLLOW_UP_COMMAND_OUTPUT_ARTIFACT_REVIEW_INSTRUCTIONS[command.key] || "",
|
|
400
|
+
]),
|
|
401
|
+
);
|
|
402
|
+
const decisionCommandOutputArtifactRequiresCleanWorkspaceBeforeApplyByKey = Object.fromEntries(
|
|
403
|
+
decisionCommands.map((command) => [
|
|
404
|
+
command.key,
|
|
405
|
+
APPLY_PLAN_FOLLOW_UP_COMMAND_OUTPUT_ARTIFACT_REQUIRES_CLEAN_WORKSPACE_BEFORE_APPLY[command.key] || false,
|
|
406
|
+
]),
|
|
407
|
+
);
|
|
408
|
+
const decisionCommandOutputArtifactApplyPreconditionIdsByKey = Object.fromEntries(
|
|
409
|
+
decisionCommands.map((command) => [
|
|
410
|
+
command.key,
|
|
411
|
+
[...(APPLY_PLAN_FOLLOW_UP_COMMAND_OUTPUT_ARTIFACT_APPLY_PRECONDITION_IDS[command.key] || [])],
|
|
412
|
+
]),
|
|
413
|
+
);
|
|
414
|
+
const decisionCommandOutputArtifactApplyPreconditionLabelsByKey = Object.fromEntries(
|
|
415
|
+
decisionCommands.map((command) => [
|
|
416
|
+
command.key,
|
|
417
|
+
[...(APPLY_PLAN_FOLLOW_UP_COMMAND_OUTPUT_ARTIFACT_APPLY_PRECONDITION_LABELS[command.key] || [])],
|
|
418
|
+
]),
|
|
419
|
+
);
|
|
420
|
+
const decisionCommandOutputArtifactApplyPreconditionsByKey = Object.fromEntries(
|
|
421
|
+
decisionCommands.map((command) => [
|
|
422
|
+
command.key,
|
|
423
|
+
applyPreconditionsForCommandKey(command.key),
|
|
424
|
+
]),
|
|
425
|
+
);
|
|
426
|
+
const decisionCommandOutputArtifactApplyPreconditionCountByKey = Object.fromEntries(
|
|
427
|
+
decisionCommands.map((command) => [
|
|
428
|
+
command.key,
|
|
429
|
+
decisionCommandOutputArtifactApplyPreconditionsByKey[command.key]?.length || 0,
|
|
430
|
+
]),
|
|
431
|
+
);
|
|
432
|
+
const decisionCommandOutputArtifactRequiredApplyPreconditionCountByKey = Object.fromEntries(
|
|
433
|
+
decisionCommands.map((command) => [
|
|
434
|
+
command.key,
|
|
435
|
+
(decisionCommandOutputArtifactApplyPreconditionsByKey[command.key] || [])
|
|
436
|
+
.filter((precondition) => precondition.required).length,
|
|
437
|
+
]),
|
|
438
|
+
);
|
|
439
|
+
const decisionCommandOutputArtifactSatisfiedApplyPreconditionCountByKey = Object.fromEntries(
|
|
440
|
+
decisionCommands.map((command) => [
|
|
441
|
+
command.key,
|
|
442
|
+
(decisionCommandOutputArtifactApplyPreconditionsByKey[command.key] || [])
|
|
443
|
+
.filter((precondition) => applyPreconditionIsSatisfied(precondition)).length,
|
|
444
|
+
]),
|
|
445
|
+
);
|
|
446
|
+
const decisionCommandOutputArtifactPendingApplyPreconditionCountByKey = Object.fromEntries(
|
|
447
|
+
decisionCommands.map((command) => [
|
|
448
|
+
command.key,
|
|
449
|
+
(decisionCommandOutputArtifactApplyPreconditionsByKey[command.key] || [])
|
|
450
|
+
.filter((precondition) => !applyPreconditionIsSatisfied(precondition)).length,
|
|
451
|
+
]),
|
|
452
|
+
);
|
|
453
|
+
const decisionCommandOutputArtifactRequiredPendingApplyPreconditionCountByKey = Object.fromEntries(
|
|
454
|
+
decisionCommands.map((command) => [
|
|
455
|
+
command.key,
|
|
456
|
+
(decisionCommandOutputArtifactApplyPreconditionsByKey[command.key] || [])
|
|
457
|
+
.filter((precondition) => precondition.required && !applyPreconditionIsSatisfied(precondition)).length,
|
|
458
|
+
]),
|
|
459
|
+
);
|
|
460
|
+
const decisionCommandOutputArtifactManualApplyReadyByKey = Object.fromEntries(
|
|
461
|
+
decisionCommands.map((command) => [
|
|
462
|
+
command.key,
|
|
463
|
+
Boolean(decisionCommandOutputArtifactManualApplyCandidateByKey[command.key])
|
|
464
|
+
&& (decisionCommandOutputArtifactRequiredPendingApplyPreconditionCountByKey[command.key] || 0) === 0,
|
|
465
|
+
]),
|
|
466
|
+
);
|
|
467
|
+
const decisionCommandOutputArtifactManualApplyStatusByKey = Object.fromEntries(
|
|
468
|
+
decisionCommands.map((command) => [
|
|
469
|
+
command.key,
|
|
470
|
+
manualApplyStatus({
|
|
471
|
+
manualApplyCandidate: Boolean(decisionCommandOutputArtifactManualApplyCandidateByKey[command.key]),
|
|
472
|
+
manualApplyReady: Boolean(decisionCommandOutputArtifactManualApplyReadyByKey[command.key]),
|
|
473
|
+
}),
|
|
474
|
+
]),
|
|
475
|
+
);
|
|
476
|
+
const decisionCommandOutputArtifactManualApplyStatusLabelByKey = Object.fromEntries(
|
|
477
|
+
decisionCommands.map((command) => [
|
|
478
|
+
command.key,
|
|
479
|
+
manualApplyStatusLabel(decisionCommandOutputArtifactManualApplyStatusByKey[command.key]),
|
|
480
|
+
]),
|
|
481
|
+
);
|
|
482
|
+
const decisionCommandOutputArtifactManualApplyStatusToneByKey = Object.fromEntries(
|
|
483
|
+
decisionCommands.map((command) => [
|
|
484
|
+
command.key,
|
|
485
|
+
manualApplyStatusTone(decisionCommandOutputArtifactManualApplyStatusByKey[command.key]),
|
|
486
|
+
]),
|
|
487
|
+
);
|
|
488
|
+
const decisionCommandOutputArtifactManualApplyBlockedReasonByKey = Object.fromEntries(
|
|
489
|
+
decisionCommands.map((command) => [
|
|
490
|
+
command.key,
|
|
491
|
+
manualApplyBlockedReason({
|
|
492
|
+
manualApplyCandidate: Boolean(decisionCommandOutputArtifactManualApplyCandidateByKey[command.key]),
|
|
493
|
+
requiredPendingApplyPreconditionCount: decisionCommandOutputArtifactRequiredPendingApplyPreconditionCountByKey[command.key] || 0,
|
|
494
|
+
}).message,
|
|
495
|
+
]),
|
|
496
|
+
);
|
|
497
|
+
const decisionCommandOutputArtifactManualApplyBlockedReasonCodeByKey = Object.fromEntries(
|
|
498
|
+
decisionCommands.map((command) => [
|
|
499
|
+
command.key,
|
|
500
|
+
manualApplyBlockedReason({
|
|
501
|
+
manualApplyCandidate: Boolean(decisionCommandOutputArtifactManualApplyCandidateByKey[command.key]),
|
|
502
|
+
requiredPendingApplyPreconditionCount: decisionCommandOutputArtifactRequiredPendingApplyPreconditionCountByKey[command.key] || 0,
|
|
503
|
+
}).code,
|
|
504
|
+
]),
|
|
505
|
+
);
|
|
506
|
+
const decisionNextCommand = decisionCommands[0] || {};
|
|
507
|
+
const decisionNextCommandDisplayLabel = decisionNextCommand.key
|
|
508
|
+
? decisionCommandDisplayLabelByKey[decisionNextCommand.key] || decisionNextCommand.key
|
|
509
|
+
: "";
|
|
510
|
+
const decisionNextCommandDescription = decisionNextCommand.key
|
|
511
|
+
? decisionCommandDescriptionByKey[decisionNextCommand.key] || ""
|
|
512
|
+
: "";
|
|
513
|
+
const decisionNextCommandOutputArtifact = decisionNextCommand.key
|
|
514
|
+
? decisionCommandOutputArtifactByKey[decisionNextCommand.key] || ""
|
|
515
|
+
: "";
|
|
516
|
+
const decisionNextCommandOutputArtifactType = decisionNextCommand.key
|
|
517
|
+
? decisionCommandOutputArtifactTypeByKey[decisionNextCommand.key] || ""
|
|
518
|
+
: "";
|
|
519
|
+
const decisionNextCommandOutputArtifactAction = decisionNextCommand.key
|
|
520
|
+
? decisionCommandOutputArtifactActionByKey[decisionNextCommand.key] || ""
|
|
521
|
+
: "";
|
|
522
|
+
const decisionNextCommandOutputArtifactMediaType = decisionNextCommand.key
|
|
523
|
+
? decisionCommandOutputArtifactMediaTypeByKey[decisionNextCommand.key] || ""
|
|
524
|
+
: "";
|
|
525
|
+
const decisionNextCommandOutputArtifactDisposition = decisionNextCommand.key
|
|
526
|
+
? decisionCommandOutputArtifactDispositionByKey[decisionNextCommand.key] || ""
|
|
527
|
+
: "";
|
|
528
|
+
const decisionNextCommandOutputArtifactManualApplyCandidate = decisionNextCommand.key
|
|
529
|
+
? decisionCommandOutputArtifactManualApplyCandidateByKey[decisionNextCommand.key] || false
|
|
530
|
+
: false;
|
|
531
|
+
const decisionNextCommandOutputArtifactRequiresManualReview = decisionNextCommand.key
|
|
532
|
+
? decisionCommandOutputArtifactRequiresManualReviewByKey[decisionNextCommand.key] || false
|
|
533
|
+
: false;
|
|
534
|
+
const decisionNextCommandOutputArtifactReviewInstruction = decisionNextCommand.key
|
|
535
|
+
? decisionCommandOutputArtifactReviewInstructionByKey[decisionNextCommand.key] || ""
|
|
536
|
+
: "";
|
|
537
|
+
const decisionNextCommandOutputArtifactRequiresCleanWorkspaceBeforeApply = decisionNextCommand.key
|
|
538
|
+
? decisionCommandOutputArtifactRequiresCleanWorkspaceBeforeApplyByKey[decisionNextCommand.key] || false
|
|
539
|
+
: false;
|
|
540
|
+
const decisionNextCommandOutputArtifactApplyPreconditionIds = decisionNextCommand.key
|
|
541
|
+
? decisionCommandOutputArtifactApplyPreconditionIdsByKey[decisionNextCommand.key] || []
|
|
542
|
+
: [];
|
|
543
|
+
const decisionNextCommandOutputArtifactApplyPreconditionLabels = decisionNextCommand.key
|
|
544
|
+
? decisionCommandOutputArtifactApplyPreconditionLabelsByKey[decisionNextCommand.key] || []
|
|
545
|
+
: [];
|
|
546
|
+
const decisionNextCommandOutputArtifactApplyPreconditions = decisionNextCommand.key
|
|
547
|
+
? decisionCommandOutputArtifactApplyPreconditionsByKey[decisionNextCommand.key] || []
|
|
548
|
+
: [];
|
|
549
|
+
const decisionNextCommandOutputArtifactApplyPreconditionCount = decisionNextCommand.key
|
|
550
|
+
? decisionCommandOutputArtifactApplyPreconditionCountByKey[decisionNextCommand.key] || 0
|
|
551
|
+
: 0;
|
|
552
|
+
const decisionNextCommandOutputArtifactRequiredApplyPreconditionCount = decisionNextCommand.key
|
|
553
|
+
? decisionCommandOutputArtifactRequiredApplyPreconditionCountByKey[decisionNextCommand.key] || 0
|
|
554
|
+
: 0;
|
|
555
|
+
const decisionNextCommandOutputArtifactSatisfiedApplyPreconditionCount = decisionNextCommand.key
|
|
556
|
+
? decisionCommandOutputArtifactSatisfiedApplyPreconditionCountByKey[decisionNextCommand.key] || 0
|
|
557
|
+
: 0;
|
|
558
|
+
const decisionNextCommandOutputArtifactPendingApplyPreconditionCount = decisionNextCommand.key
|
|
559
|
+
? decisionCommandOutputArtifactPendingApplyPreconditionCountByKey[decisionNextCommand.key] || 0
|
|
560
|
+
: 0;
|
|
561
|
+
const decisionNextCommandOutputArtifactRequiredPendingApplyPreconditionCount = decisionNextCommand.key
|
|
562
|
+
? decisionCommandOutputArtifactRequiredPendingApplyPreconditionCountByKey[decisionNextCommand.key] || 0
|
|
563
|
+
: 0;
|
|
564
|
+
const decisionNextCommandOutputArtifactManualApplyReady = decisionNextCommand.key
|
|
565
|
+
? decisionCommandOutputArtifactManualApplyReadyByKey[decisionNextCommand.key] || false
|
|
566
|
+
: false;
|
|
567
|
+
const decisionNextCommandOutputArtifactManualApplyStatus = decisionNextCommand.key
|
|
568
|
+
? decisionCommandOutputArtifactManualApplyStatusByKey[decisionNextCommand.key] || "not-applicable"
|
|
569
|
+
: "not-applicable";
|
|
570
|
+
const decisionNextCommandOutputArtifactManualApplyStatusLabel = decisionNextCommand.key
|
|
571
|
+
? decisionCommandOutputArtifactManualApplyStatusLabelByKey[decisionNextCommand.key] || "Review only"
|
|
572
|
+
: "Review only";
|
|
573
|
+
const decisionNextCommandOutputArtifactManualApplyStatusTone = decisionNextCommand.key
|
|
574
|
+
? decisionCommandOutputArtifactManualApplyStatusToneByKey[decisionNextCommand.key] || "neutral"
|
|
575
|
+
: "neutral";
|
|
576
|
+
const decisionNextCommandOutputArtifactManualApplyBlockedReason = decisionNextCommand.key
|
|
577
|
+
? decisionCommandOutputArtifactManualApplyBlockedReasonByKey[decisionNextCommand.key] || ""
|
|
578
|
+
: "";
|
|
579
|
+
const decisionNextCommandOutputArtifactManualApplyBlockedReasonCode = decisionNextCommand.key
|
|
580
|
+
? decisionCommandOutputArtifactManualApplyBlockedReasonCodeByKey[decisionNextCommand.key] || ""
|
|
581
|
+
: "";
|
|
582
|
+
const operatorRunbookStageSelection = failures > 0
|
|
583
|
+
? {}
|
|
584
|
+
: {
|
|
585
|
+
strategy: "optional-preview-before-required-manual-edit",
|
|
586
|
+
decision: {
|
|
587
|
+
action: "offer-optional-preview",
|
|
588
|
+
stageKey: "previewArtifacts",
|
|
589
|
+
stageKind: "local-output-preview",
|
|
590
|
+
required: false,
|
|
591
|
+
hasCommands: true,
|
|
592
|
+
commandCount: decisionCommands.length,
|
|
593
|
+
commandKeys: ["reviewCheckReport", "proposalPatchPreview"],
|
|
594
|
+
commands: decisionCommands,
|
|
595
|
+
commandByKey: decisionCommandByKey,
|
|
596
|
+
commandStepByKey: decisionCommandStepByKey,
|
|
597
|
+
commandRunPolicyByKey: decisionCommandRunPolicyByKey,
|
|
598
|
+
commandSafetyLevelByKey: decisionCommandSafetyLevelByKey,
|
|
599
|
+
commandArgsByKey: decisionCommandArgsByKey,
|
|
600
|
+
commandStringByKey: decisionCommandStringByKey,
|
|
601
|
+
commandDisplayLabelByKey: decisionCommandDisplayLabelByKey,
|
|
602
|
+
commandDescriptionByKey: decisionCommandDescriptionByKey,
|
|
603
|
+
commandOutputArtifactByKey: decisionCommandOutputArtifactByKey,
|
|
604
|
+
commandOutputArtifactTypeByKey: decisionCommandOutputArtifactTypeByKey,
|
|
605
|
+
commandOutputArtifactActionByKey: decisionCommandOutputArtifactActionByKey,
|
|
606
|
+
commandOutputArtifactMediaTypeByKey: decisionCommandOutputArtifactMediaTypeByKey,
|
|
607
|
+
commandOutputArtifactDispositionByKey: decisionCommandOutputArtifactDispositionByKey,
|
|
608
|
+
commandOutputArtifactManualApplyCandidateByKey: decisionCommandOutputArtifactManualApplyCandidateByKey,
|
|
609
|
+
commandOutputArtifactRequiresManualReviewByKey: decisionCommandOutputArtifactRequiresManualReviewByKey,
|
|
610
|
+
commandOutputArtifactReviewInstructionByKey: decisionCommandOutputArtifactReviewInstructionByKey,
|
|
611
|
+
commandOutputArtifactRequiresCleanWorkspaceBeforeApplyByKey: decisionCommandOutputArtifactRequiresCleanWorkspaceBeforeApplyByKey,
|
|
612
|
+
commandOutputArtifactApplyPreconditionIdsByKey: decisionCommandOutputArtifactApplyPreconditionIdsByKey,
|
|
613
|
+
commandOutputArtifactApplyPreconditionLabelsByKey: decisionCommandOutputArtifactApplyPreconditionLabelsByKey,
|
|
614
|
+
commandOutputArtifactApplyPreconditionsByKey: decisionCommandOutputArtifactApplyPreconditionsByKey,
|
|
615
|
+
commandOutputArtifactApplyPreconditionCountByKey: decisionCommandOutputArtifactApplyPreconditionCountByKey,
|
|
616
|
+
commandOutputArtifactRequiredApplyPreconditionCountByKey: decisionCommandOutputArtifactRequiredApplyPreconditionCountByKey,
|
|
617
|
+
commandOutputArtifactSatisfiedApplyPreconditionCountByKey: decisionCommandOutputArtifactSatisfiedApplyPreconditionCountByKey,
|
|
618
|
+
commandOutputArtifactPendingApplyPreconditionCountByKey: decisionCommandOutputArtifactPendingApplyPreconditionCountByKey,
|
|
619
|
+
commandOutputArtifactRequiredPendingApplyPreconditionCountByKey: decisionCommandOutputArtifactRequiredPendingApplyPreconditionCountByKey,
|
|
620
|
+
commandOutputArtifactManualApplyReadyByKey: decisionCommandOutputArtifactManualApplyReadyByKey,
|
|
621
|
+
commandOutputArtifactManualApplyStatusByKey: decisionCommandOutputArtifactManualApplyStatusByKey,
|
|
622
|
+
commandOutputArtifactManualApplyStatusLabelByKey: decisionCommandOutputArtifactManualApplyStatusLabelByKey,
|
|
623
|
+
commandOutputArtifactManualApplyStatusToneByKey: decisionCommandOutputArtifactManualApplyStatusToneByKey,
|
|
624
|
+
commandOutputArtifactManualApplyBlockedReasonByKey: decisionCommandOutputArtifactManualApplyBlockedReasonByKey,
|
|
625
|
+
commandOutputArtifactManualApplyBlockedReasonCodeByKey: decisionCommandOutputArtifactManualApplyBlockedReasonCodeByKey,
|
|
626
|
+
nextCommandEntry: decisionNextCommand,
|
|
627
|
+
nextCommandKey: decisionNextCommand.key || "",
|
|
628
|
+
nextCommandDisplayLabel: decisionNextCommandDisplayLabel,
|
|
629
|
+
nextCommandDescription: decisionNextCommandDescription,
|
|
630
|
+
nextCommandOutputArtifact: decisionNextCommandOutputArtifact,
|
|
631
|
+
nextCommandOutputArtifactType: decisionNextCommandOutputArtifactType,
|
|
632
|
+
nextCommandOutputArtifactAction: decisionNextCommandOutputArtifactAction,
|
|
633
|
+
nextCommandOutputArtifactMediaType: decisionNextCommandOutputArtifactMediaType,
|
|
634
|
+
nextCommandOutputArtifactDisposition: decisionNextCommandOutputArtifactDisposition,
|
|
635
|
+
nextCommandOutputArtifactManualApplyCandidate: decisionNextCommandOutputArtifactManualApplyCandidate,
|
|
636
|
+
nextCommandOutputArtifactRequiresManualReview: decisionNextCommandOutputArtifactRequiresManualReview,
|
|
637
|
+
nextCommandOutputArtifactReviewInstruction: decisionNextCommandOutputArtifactReviewInstruction,
|
|
638
|
+
nextCommandOutputArtifactRequiresCleanWorkspaceBeforeApply: decisionNextCommandOutputArtifactRequiresCleanWorkspaceBeforeApply,
|
|
639
|
+
nextCommandOutputArtifactApplyPreconditionIds: decisionNextCommandOutputArtifactApplyPreconditionIds,
|
|
640
|
+
nextCommandOutputArtifactApplyPreconditionLabels: decisionNextCommandOutputArtifactApplyPreconditionLabels,
|
|
641
|
+
nextCommandOutputArtifactApplyPreconditions: decisionNextCommandOutputArtifactApplyPreconditions,
|
|
642
|
+
nextCommandOutputArtifactApplyPreconditionCount: decisionNextCommandOutputArtifactApplyPreconditionCount,
|
|
643
|
+
nextCommandOutputArtifactRequiredApplyPreconditionCount: decisionNextCommandOutputArtifactRequiredApplyPreconditionCount,
|
|
644
|
+
nextCommandOutputArtifactSatisfiedApplyPreconditionCount: decisionNextCommandOutputArtifactSatisfiedApplyPreconditionCount,
|
|
645
|
+
nextCommandOutputArtifactPendingApplyPreconditionCount: decisionNextCommandOutputArtifactPendingApplyPreconditionCount,
|
|
646
|
+
nextCommandOutputArtifactRequiredPendingApplyPreconditionCount: decisionNextCommandOutputArtifactRequiredPendingApplyPreconditionCount,
|
|
647
|
+
nextCommandOutputArtifactManualApplyReady: decisionNextCommandOutputArtifactManualApplyReady,
|
|
648
|
+
nextCommandOutputArtifactManualApplyStatus: decisionNextCommandOutputArtifactManualApplyStatus,
|
|
649
|
+
nextCommandOutputArtifactManualApplyStatusLabel: decisionNextCommandOutputArtifactManualApplyStatusLabel,
|
|
650
|
+
nextCommandOutputArtifactManualApplyStatusTone: decisionNextCommandOutputArtifactManualApplyStatusTone,
|
|
651
|
+
nextCommandOutputArtifactManualApplyBlockedReason: decisionNextCommandOutputArtifactManualApplyBlockedReason,
|
|
652
|
+
nextCommandOutputArtifactManualApplyBlockedReasonCode: decisionNextCommandOutputArtifactManualApplyBlockedReasonCode,
|
|
653
|
+
nextCommandStep: decisionNextCommand.step || 0,
|
|
654
|
+
nextCommand: decisionNextCommand.command || "",
|
|
655
|
+
nextCommandArgs: decisionNextCommand.commandArgs || [],
|
|
656
|
+
nextCommandRunPolicy: decisionNextCommand.runPolicy || "",
|
|
657
|
+
nextCommandSafetyLevel: decisionNextCommand.safetyLevel || "",
|
|
658
|
+
nextCommandSafety: decisionNextCommand.safety || {},
|
|
659
|
+
runPolicy: "optional-local-output-preview",
|
|
660
|
+
safety: {
|
|
661
|
+
level: nextStageSummary.writesLocalFiles ? "local-output" : "read-only",
|
|
662
|
+
writesLocalFiles: nextStageSummary.writesLocalFiles,
|
|
663
|
+
writesOutputArtifacts: nextStageSummary.writesOutputArtifacts,
|
|
664
|
+
mutatesLocalState: nextStageSummary.mutatesLocalState,
|
|
665
|
+
mutatesProfile: nextStageSummary.mutatesProfile,
|
|
666
|
+
mutatesReviewFile: nextStageSummary.mutatesReviewFile,
|
|
667
|
+
mutatesSkillFiles: nextStageSummary.mutatesSkillFiles,
|
|
668
|
+
callsExternalAiApis: nextStageSummary.callsExternalAiApis,
|
|
669
|
+
requiresCleanWorkspace: nextStageSummary.requiresCleanWorkspace,
|
|
670
|
+
reason: "The selected decision only writes optional local preview artifacts and does not mutate learning, review, or skill files.",
|
|
671
|
+
},
|
|
672
|
+
nextRequiredStageKey: nextRequiredStage?.key || "",
|
|
673
|
+
nextRequiredCommandStageKey: nextRequiredCommandStage?.key || "",
|
|
674
|
+
requiresOperatorActionBeforeRequiredCommands: true,
|
|
675
|
+
reason: "Offer optional local preview artifacts first; the required path still starts with manual skill edits before read-only command gates.",
|
|
676
|
+
},
|
|
677
|
+
stageOrder: operatorRunbookStageKeys,
|
|
678
|
+
nextStageKey: "previewArtifacts",
|
|
679
|
+
nextStageCommandKeys: ["reviewCheckReport", "proposalPatchPreview"],
|
|
680
|
+
nextStage: nextStageSummary,
|
|
681
|
+
nextRequiredStageKey: nextRequiredStage?.key || "",
|
|
682
|
+
nextRequiredStageCommandKeys: nextRequiredStage?.commandKeys || [],
|
|
683
|
+
nextRequiredStage: nextRequiredStageSummary,
|
|
684
|
+
nextRequiredCommandStageKey: nextRequiredCommandStage?.key || "",
|
|
685
|
+
nextRequiredCommandStageCommandKeys: nextRequiredCommandStage?.commandKeys || [],
|
|
686
|
+
nextRequiredCommandStage: nextRequiredCommandStageSummary,
|
|
687
|
+
reason: "Offer optional local preview artifacts first, then require the manual skill edit before read-only review and strict gates.",
|
|
688
|
+
};
|
|
689
|
+
const operatorRunbook = {
|
|
690
|
+
version: 1,
|
|
691
|
+
executable: failures === 0,
|
|
692
|
+
blocked: failures > 0,
|
|
693
|
+
stageCount: operatorRunbookStages.length,
|
|
694
|
+
requiredStageCount: operatorRunbookStages.filter((stage) => stage.required).length,
|
|
695
|
+
commandStageCount: operatorRunbookStages.filter((stage) => stage.commandKeys.length > 0).length,
|
|
696
|
+
nextStageKey: failures > 0 ? "" : "previewArtifacts",
|
|
697
|
+
nextStageCommandKeys: failures > 0 ? [] : ["reviewCheckReport", "proposalPatchPreview"],
|
|
698
|
+
nextRequiredStageKey: nextRequiredStage?.key || "",
|
|
699
|
+
nextRequiredStageCommandKeys: nextRequiredStage?.commandKeys || [],
|
|
700
|
+
nextRequiredCommandStageKey: nextRequiredCommandStage?.key || "",
|
|
701
|
+
nextRequiredCommandStageCommandKeys: nextRequiredCommandStage?.commandKeys || [],
|
|
702
|
+
stageSelection: operatorRunbookStageSelection,
|
|
703
|
+
stageKeys: operatorRunbookStageKeys,
|
|
704
|
+
stageByKey: operatorRunbookStageByKey,
|
|
705
|
+
stages: operatorRunbookStages,
|
|
706
|
+
reason: failures > 0
|
|
707
|
+
? "Command contract failures must be fixed before running the operator runbook."
|
|
708
|
+
: "Generate optional local review artifacts, apply accepted skill deltas manually, then run read-only review and strict readiness gates.",
|
|
709
|
+
};
|
|
710
|
+
return {
|
|
711
|
+
version: 1,
|
|
712
|
+
valid: failures === 0,
|
|
713
|
+
status: failures > 0 ? "fail" : "pass",
|
|
714
|
+
commandCount: Object.keys(commandArgs).length,
|
|
715
|
+
requiredKeys,
|
|
716
|
+
missingCommandKeys,
|
|
717
|
+
unexpectedCommandKeys,
|
|
718
|
+
baseCommand: [...APPLY_PLAN_BASE_COMMAND],
|
|
719
|
+
reviewFileRequired: true,
|
|
720
|
+
reviewFile,
|
|
721
|
+
forbiddenFlags: [...APPLY_PLAN_FORBIDDEN_FLAGS],
|
|
722
|
+
checkCount,
|
|
723
|
+
passCount: passes,
|
|
724
|
+
warningCount: warnings,
|
|
725
|
+
failureCount: failures,
|
|
726
|
+
failedCheckIds: failedChecks.map((check) => check.id),
|
|
727
|
+
failedChecks,
|
|
728
|
+
nextCommandKey,
|
|
729
|
+
nextCommand,
|
|
730
|
+
nextCommandArgs,
|
|
731
|
+
nextCommandRunPolicy,
|
|
732
|
+
nextCommandSafety,
|
|
733
|
+
commandSequenceCount: commandSequence.length,
|
|
734
|
+
commandSequence,
|
|
735
|
+
commandSequenceSummary,
|
|
736
|
+
commandSequenceKeys,
|
|
737
|
+
commandSequenceByKey,
|
|
738
|
+
operatorRunbook,
|
|
739
|
+
nextAction: failures > 0
|
|
740
|
+
? "Fix command contract failures before running follow-up commands."
|
|
741
|
+
: "Run reviewCheckJson after manual skill edits, then use strictGate before marking proposals applied.",
|
|
742
|
+
checks,
|
|
743
|
+
summary: {
|
|
744
|
+
failures,
|
|
745
|
+
warnings,
|
|
746
|
+
passes,
|
|
747
|
+
total: checkCount,
|
|
748
|
+
},
|
|
749
|
+
};
|
|
750
|
+
}
|