@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,361 @@
|
|
|
1
|
+
// Agent development backlog actions and action plan derived from local learning signals.
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
buildAgentBacklogExecutionQueue,
|
|
5
|
+
classifyAgentBacklogCommand,
|
|
6
|
+
summarizeAgentBacklogCommandSafety,
|
|
7
|
+
} from "./signals-backlog-commands.mjs";
|
|
8
|
+
import {
|
|
9
|
+
defaultLearningEvalReportPath,
|
|
10
|
+
evalReportPathForTemplate,
|
|
11
|
+
} from "./signals-eval.mjs";
|
|
12
|
+
import { commandFromArgs, commandSpec } from "./signals-shared.mjs";
|
|
13
|
+
import { defaultLearningEvalPath } from "./workspace.mjs";
|
|
14
|
+
|
|
15
|
+
export function agentAction({
|
|
16
|
+
id,
|
|
17
|
+
priority,
|
|
18
|
+
category,
|
|
19
|
+
title,
|
|
20
|
+
rationale,
|
|
21
|
+
command = "",
|
|
22
|
+
commandArgs = [],
|
|
23
|
+
applyCommand = "",
|
|
24
|
+
applyCommandArgs = [],
|
|
25
|
+
evidence = {},
|
|
26
|
+
}) {
|
|
27
|
+
const normalizedCommandArgs = Array.isArray(commandArgs) ? commandArgs.map((item) => String(item)) : [];
|
|
28
|
+
const normalizedApplyCommandArgs = Array.isArray(applyCommandArgs) ? applyCommandArgs.map((item) => String(item)) : [];
|
|
29
|
+
return {
|
|
30
|
+
id,
|
|
31
|
+
priority,
|
|
32
|
+
category,
|
|
33
|
+
title,
|
|
34
|
+
rationale,
|
|
35
|
+
command: command || (normalizedCommandArgs.length > 0 ? commandFromArgs(normalizedCommandArgs) : ""),
|
|
36
|
+
commandArgs: normalizedCommandArgs,
|
|
37
|
+
applyCommand: applyCommand || (normalizedApplyCommandArgs.length > 0 ? commandFromArgs(normalizedApplyCommandArgs) : ""),
|
|
38
|
+
applyCommandArgs: normalizedApplyCommandArgs,
|
|
39
|
+
evidence,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function agentDevelopmentStatus(actions) {
|
|
44
|
+
if ((actions || []).some((item) => item.priority === "p0")) return "fail";
|
|
45
|
+
if ((actions || []).some((item) => item.priority === "p1")) return "warn";
|
|
46
|
+
return "pass";
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function buildAgentBacklogActionPlan({ actions = [], commands = {}, privacy = {} } = {}) {
|
|
50
|
+
const agentBacklogJsonArgs = Array.isArray(commands.agentBacklogJsonArgs) && commands.agentBacklogJsonArgs.length > 0
|
|
51
|
+
? commands.agentBacklogJsonArgs
|
|
52
|
+
: ["design-ai", "learn", "--agent-backlog", "--strict", "--json"];
|
|
53
|
+
const steps = actions.map((action, index) => {
|
|
54
|
+
const commandArgs = Array.isArray(action.commandArgs) ? action.commandArgs.map((item) => String(item)) : [];
|
|
55
|
+
const command = String(action.command || (commandArgs.length > 0 ? commandFromArgs(commandArgs) : ""));
|
|
56
|
+
const applyCommandArgs = Array.isArray(action.applyCommandArgs) ? action.applyCommandArgs.map((item) => String(item)) : [];
|
|
57
|
+
const applyCommand = String(action.applyCommand || (applyCommandArgs.length > 0 ? commandFromArgs(applyCommandArgs) : ""));
|
|
58
|
+
const commandSafety = classifyAgentBacklogCommand(command);
|
|
59
|
+
const applyCommandSafety = applyCommand ? classifyAgentBacklogCommand(applyCommand) : null;
|
|
60
|
+
return {
|
|
61
|
+
rank: action.rank ?? index + 1,
|
|
62
|
+
actionId: action.id || "",
|
|
63
|
+
priority: action.priority || "p3",
|
|
64
|
+
category: action.category || "other",
|
|
65
|
+
title: action.title || "",
|
|
66
|
+
command,
|
|
67
|
+
commandArgs,
|
|
68
|
+
applyCommand,
|
|
69
|
+
applyCommandArgs,
|
|
70
|
+
applyCommandSafety,
|
|
71
|
+
applyRequiresReviewBeforeMutation: Boolean(applyCommandSafety?.requiresCleanWorkspace),
|
|
72
|
+
expectedOutcome: action.rationale || "",
|
|
73
|
+
verification: command
|
|
74
|
+
? applyCommand
|
|
75
|
+
? [
|
|
76
|
+
"Run the preview command first and inspect the proposed local learning profile changes.",
|
|
77
|
+
"Run the apply command only after operator review confirms the target profile path and mutation scope.",
|
|
78
|
+
"Re-run `design-ai learn --agent-backlog --strict --json` after the apply step to confirm the backlog status improved.",
|
|
79
|
+
]
|
|
80
|
+
: commandSafety.requiresCleanWorkspace
|
|
81
|
+
? [
|
|
82
|
+
"Run the command in a clean working tree or disposable workspace, then inspect generated or changed files before committing.",
|
|
83
|
+
"Re-run `design-ai learn --agent-backlog --strict --json` after the step to confirm the backlog status improved.",
|
|
84
|
+
]
|
|
85
|
+
: [
|
|
86
|
+
"Run the command and inspect the preview/report output before applying any follow-up changes.",
|
|
87
|
+
"Re-run `design-ai learn --agent-backlog --strict --json` after the step to confirm the backlog status improved.",
|
|
88
|
+
]
|
|
89
|
+
: [
|
|
90
|
+
"Review the action manually, then refresh the agent backlog report.",
|
|
91
|
+
],
|
|
92
|
+
requiresReviewBeforeMutation: commandSafety.requiresCleanWorkspace,
|
|
93
|
+
commandSafety,
|
|
94
|
+
};
|
|
95
|
+
});
|
|
96
|
+
const safetySummary = summarizeAgentBacklogCommandSafety(steps);
|
|
97
|
+
const executionQueue = buildAgentBacklogExecutionQueue(steps, {
|
|
98
|
+
refreshCommandArgs: agentBacklogJsonArgs,
|
|
99
|
+
});
|
|
100
|
+
const verification = [
|
|
101
|
+
commands.signalsJson
|
|
102
|
+
? {
|
|
103
|
+
label: "Refresh signal registry JSON",
|
|
104
|
+
command: commands.signalsJson,
|
|
105
|
+
commandArgs: Array.isArray(commands.signalsJsonArgs) ? commands.signalsJsonArgs : [],
|
|
106
|
+
}
|
|
107
|
+
: null,
|
|
108
|
+
commands.signalsReport
|
|
109
|
+
? {
|
|
110
|
+
label: "Save signal registry Markdown handoff",
|
|
111
|
+
command: commands.signalsReport,
|
|
112
|
+
commandArgs: Array.isArray(commands.signalsReportArgs) ? commands.signalsReportArgs : [],
|
|
113
|
+
}
|
|
114
|
+
: null,
|
|
115
|
+
{
|
|
116
|
+
label: "Gate focused agent backlog",
|
|
117
|
+
...commandSpec(agentBacklogJsonArgs),
|
|
118
|
+
},
|
|
119
|
+
].filter(Boolean);
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
version: 1,
|
|
123
|
+
stepCount: steps.length,
|
|
124
|
+
nextStep: steps[0] || null,
|
|
125
|
+
steps,
|
|
126
|
+
safetySummary,
|
|
127
|
+
executionQueue,
|
|
128
|
+
verification,
|
|
129
|
+
boundaries: {
|
|
130
|
+
reportMutatesProfile: Boolean(privacy.mutatesProfile),
|
|
131
|
+
reportMutatesSkillFiles: Boolean(privacy.mutatesSkillFiles),
|
|
132
|
+
reportCallsExternalAiApis: Boolean(privacy.callsExternalAiApis),
|
|
133
|
+
generatedFromLocalSignals: true,
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function buildAgentDevelopmentBacklog({
|
|
139
|
+
audit,
|
|
140
|
+
usage,
|
|
141
|
+
evals,
|
|
142
|
+
checkCapture,
|
|
143
|
+
workspace,
|
|
144
|
+
filePath,
|
|
145
|
+
usageFile,
|
|
146
|
+
signalSource,
|
|
147
|
+
}) {
|
|
148
|
+
const actions = [];
|
|
149
|
+
|
|
150
|
+
if (!audit.exists) {
|
|
151
|
+
const previewCommand = commandSpec(["design-ai", "learn", "--init", "--dry-run", "--file", filePath]);
|
|
152
|
+
const applyCommand = commandSpec(["design-ai", "learn", "--init", "--yes", "--file", filePath]);
|
|
153
|
+
actions.push(agentAction({
|
|
154
|
+
id: "agent-learning-profile-init",
|
|
155
|
+
priority: "p1",
|
|
156
|
+
category: "learning-profile",
|
|
157
|
+
title: "Initialize the local learning profile before agent development review.",
|
|
158
|
+
rationale: "Signal registry output is incomplete until a profile exists.",
|
|
159
|
+
...previewCommand,
|
|
160
|
+
applyCommand: applyCommand.command,
|
|
161
|
+
applyCommandArgs: applyCommand.commandArgs,
|
|
162
|
+
evidence: {
|
|
163
|
+
profileExists: false,
|
|
164
|
+
},
|
|
165
|
+
}));
|
|
166
|
+
} else if (audit.summary.failures > 0) {
|
|
167
|
+
actions.push(agentAction({
|
|
168
|
+
id: "agent-learning-profile-audit-fix",
|
|
169
|
+
priority: "p0",
|
|
170
|
+
category: "learning-profile",
|
|
171
|
+
title: "Fix learning profile audit failures before using signals as a development gate.",
|
|
172
|
+
rationale: "Audit failures can make learned context selection and downstream signal summaries unreliable.",
|
|
173
|
+
...commandSpec(["design-ai", "learn", "--audit", "--file", filePath]),
|
|
174
|
+
evidence: {
|
|
175
|
+
failures: audit.summary.failures,
|
|
176
|
+
warnings: audit.summary.warnings,
|
|
177
|
+
},
|
|
178
|
+
}));
|
|
179
|
+
} else if (audit.summary.warnings > 0) {
|
|
180
|
+
actions.push(agentAction({
|
|
181
|
+
id: "agent-learning-profile-audit-review",
|
|
182
|
+
priority: "p1",
|
|
183
|
+
category: "learning-profile",
|
|
184
|
+
title: "Review learning profile audit warnings before promoting agent behavior.",
|
|
185
|
+
rationale: "Warnings are not blockers, but they should be resolved before treating local learning as release evidence.",
|
|
186
|
+
...commandSpec(["design-ai", "learn", "--audit", "--file", filePath]),
|
|
187
|
+
evidence: {
|
|
188
|
+
warnings: audit.summary.warnings,
|
|
189
|
+
},
|
|
190
|
+
}));
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (!usage.exists || usage.eventCount === 0) {
|
|
194
|
+
actions.push(agentAction({
|
|
195
|
+
id: "agent-learning-usage-record",
|
|
196
|
+
priority: "p2",
|
|
197
|
+
category: "usage-signals",
|
|
198
|
+
title: "Record prompt or pack usage with learning enabled.",
|
|
199
|
+
rationale: "Usage sidecar events show which learned entries actually affect agent prompts without storing raw brief text.",
|
|
200
|
+
...commandSpec([
|
|
201
|
+
"env",
|
|
202
|
+
`DESIGN_AI_LEARNING_FILE=${filePath}`,
|
|
203
|
+
`DESIGN_AI_LEARNING_USAGE_FILE=${usageFile}`,
|
|
204
|
+
"design-ai",
|
|
205
|
+
"prompt",
|
|
206
|
+
"audit a design artifact",
|
|
207
|
+
"--with-learning",
|
|
208
|
+
"--json",
|
|
209
|
+
]),
|
|
210
|
+
evidence: {
|
|
211
|
+
usageExists: Boolean(usage.exists),
|
|
212
|
+
eventCount: usage.eventCount || 0,
|
|
213
|
+
},
|
|
214
|
+
}));
|
|
215
|
+
}
|
|
216
|
+
if (usage.staleSelectedEntryCount > 0) {
|
|
217
|
+
actions.push(agentAction({
|
|
218
|
+
id: "agent-learning-usage-stale-review",
|
|
219
|
+
priority: "p1",
|
|
220
|
+
category: "usage-signals",
|
|
221
|
+
title: "Review stale selected learning ids in the usage sidecar.",
|
|
222
|
+
rationale: "Stale ids indicate usage evidence is no longer aligned with the active profile.",
|
|
223
|
+
...commandSpec(["design-ai", "learn", "--usage", "--file", filePath, "--usage-file", usageFile]),
|
|
224
|
+
evidence: {
|
|
225
|
+
staleSelectedEntryCount: usage.staleSelectedEntryCount,
|
|
226
|
+
},
|
|
227
|
+
}));
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (evals.files.length === 0) {
|
|
231
|
+
const evalOutputFile = defaultLearningEvalPath(filePath);
|
|
232
|
+
actions.push(agentAction({
|
|
233
|
+
id: "agent-eval-checkpoint-generate",
|
|
234
|
+
priority: "p1",
|
|
235
|
+
category: "eval-harness",
|
|
236
|
+
title: "Generate and run route, prompt, pack, or learning eval checkpoints.",
|
|
237
|
+
rationale: "Agent development needs replayable checkpoints before signal registry output can act as a gate.",
|
|
238
|
+
...commandSpec(["design-ai", "learn", "--eval-template", "--file", filePath, "--json", "--out", evalOutputFile]),
|
|
239
|
+
evidence: {
|
|
240
|
+
evalSignalCount: 0,
|
|
241
|
+
evalOutputFile,
|
|
242
|
+
},
|
|
243
|
+
}));
|
|
244
|
+
}
|
|
245
|
+
if (evals.failed > 0) {
|
|
246
|
+
actions.push(agentAction({
|
|
247
|
+
id: "agent-eval-failure-review",
|
|
248
|
+
priority: "p0",
|
|
249
|
+
category: "eval-harness",
|
|
250
|
+
title: "Fix failing eval signal reports before continuing agent development.",
|
|
251
|
+
rationale: "Failed checkpoints are the strongest deterministic signal that route, prompt, pack, or learning behavior drifted.",
|
|
252
|
+
...commandSpec(["design-ai", "learn", "--signals", "--from-file", signalSource || ".", "--file", filePath, "--usage-file", usageFile, "--json"]),
|
|
253
|
+
evidence: {
|
|
254
|
+
failed: evals.failed,
|
|
255
|
+
warned: evals.warned,
|
|
256
|
+
},
|
|
257
|
+
}));
|
|
258
|
+
} else if (evals.templates > 0) {
|
|
259
|
+
const templateFile = Array.isArray(evals.templateFiles) && evals.templateFiles.length > 0
|
|
260
|
+
? evals.templateFiles[0].file
|
|
261
|
+
: "";
|
|
262
|
+
const evalReportFile = templateFile ? evalReportPathForTemplate(templateFile) : defaultLearningEvalReportPath(filePath);
|
|
263
|
+
actions.push(agentAction({
|
|
264
|
+
id: "agent-eval-template-replay",
|
|
265
|
+
priority: "p1",
|
|
266
|
+
category: "eval-harness",
|
|
267
|
+
title: "Replay template-only eval signal files as executed reports.",
|
|
268
|
+
rationale: "Templates are useful setup artifacts, but executed reports provide stronger evidence for agent behavior.",
|
|
269
|
+
...commandSpec([
|
|
270
|
+
"design-ai",
|
|
271
|
+
"learn",
|
|
272
|
+
"--eval",
|
|
273
|
+
"--from-file",
|
|
274
|
+
templateFile || defaultLearningEvalPath(filePath),
|
|
275
|
+
"--file",
|
|
276
|
+
filePath,
|
|
277
|
+
"--strict",
|
|
278
|
+
"--json",
|
|
279
|
+
"--out",
|
|
280
|
+
evalReportFile,
|
|
281
|
+
]),
|
|
282
|
+
evidence: {
|
|
283
|
+
templates: evals.templates,
|
|
284
|
+
templateFile: templateFile || defaultLearningEvalPath(filePath),
|
|
285
|
+
evalReportFile,
|
|
286
|
+
},
|
|
287
|
+
}));
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (checkCapture.count > 0) {
|
|
291
|
+
actions.push(agentAction({
|
|
292
|
+
id: "agent-skill-proposal-preview",
|
|
293
|
+
priority: "p2",
|
|
294
|
+
category: "skill-evolution",
|
|
295
|
+
title: "Preview skill instruction deltas from repeated check-capture signals.",
|
|
296
|
+
rationale: "Captured warn/fail check results can become deterministic skill improvements without mutating skill files automatically.",
|
|
297
|
+
...commandSpec(["design-ai", "learn", "--propose-skills", "--from-file", signalSource || ".", "--file", filePath, "--usage-file", usageFile, "--json"]),
|
|
298
|
+
evidence: {
|
|
299
|
+
checkCaptureCount: checkCapture.count,
|
|
300
|
+
categoryCounts: checkCapture.categoryCounts,
|
|
301
|
+
},
|
|
302
|
+
}));
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (workspace.nextActionCounts.fail > 0 || workspace.nextActionCounts.warn > 0) {
|
|
306
|
+
actions.push(agentAction({
|
|
307
|
+
id: "agent-workspace-readiness-review",
|
|
308
|
+
priority: workspace.nextActionCounts.fail > 0 ? "p0" : "p1",
|
|
309
|
+
category: "workspace-readiness",
|
|
310
|
+
title: "Resolve workspace readiness actions before treating agent development evidence as complete.",
|
|
311
|
+
rationale: "Workspace readiness joins git, repository metadata, learning, usage, and eval freshness into the operator handoff gate.",
|
|
312
|
+
...commandSpec(["design-ai", "workspace", "--learning-file", filePath, "--learning-usage", usageFile, "--strict", "--json"]),
|
|
313
|
+
evidence: {
|
|
314
|
+
fail: workspace.nextActionCounts.fail || 0,
|
|
315
|
+
warn: workspace.nextActionCounts.warn || 0,
|
|
316
|
+
nextActionCount: workspace.nextActionCount || 0,
|
|
317
|
+
},
|
|
318
|
+
}));
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const priorityOrder = { p0: 0, p1: 1, p2: 2, p3: 3 };
|
|
322
|
+
const actionOrder = {
|
|
323
|
+
"agent-learning-profile-audit-fix": 0,
|
|
324
|
+
"agent-learning-profile-init": 1,
|
|
325
|
+
"agent-learning-profile-audit-review": 2,
|
|
326
|
+
"agent-learning-usage-stale-review": 3,
|
|
327
|
+
"agent-workspace-readiness-review": 4,
|
|
328
|
+
"agent-eval-failure-review": 5,
|
|
329
|
+
"agent-eval-checkpoint-generate": 6,
|
|
330
|
+
"agent-eval-template-replay": 7,
|
|
331
|
+
"agent-learning-usage-record": 8,
|
|
332
|
+
"agent-skill-proposal-preview": 9,
|
|
333
|
+
};
|
|
334
|
+
const sortedActions = actions
|
|
335
|
+
.sort((a, b) => (
|
|
336
|
+
priorityOrder[a.priority] - priorityOrder[b.priority]
|
|
337
|
+
|| (actionOrder[a.id] ?? 100) - (actionOrder[b.id] ?? 100)
|
|
338
|
+
|| a.category.localeCompare(b.category)
|
|
339
|
+
|| a.id.localeCompare(b.id)
|
|
340
|
+
))
|
|
341
|
+
.map((item, index) => ({
|
|
342
|
+
rank: index + 1,
|
|
343
|
+
...item,
|
|
344
|
+
}));
|
|
345
|
+
|
|
346
|
+
return {
|
|
347
|
+
status: agentDevelopmentStatus(sortedActions),
|
|
348
|
+
actionCount: sortedActions.length,
|
|
349
|
+
p0Count: sortedActions.filter((item) => item.priority === "p0").length,
|
|
350
|
+
p1Count: sortedActions.filter((item) => item.priority === "p1").length,
|
|
351
|
+
p2Count: sortedActions.filter((item) => item.priority === "p2").length,
|
|
352
|
+
p3Count: sortedActions.filter((item) => item.priority === "p3").length,
|
|
353
|
+
actions: sortedActions,
|
|
354
|
+
privacy: {
|
|
355
|
+
mutatesProfile: false,
|
|
356
|
+
mutatesSkillFiles: false,
|
|
357
|
+
callsExternalAiApis: false,
|
|
358
|
+
storesRawBriefText: false,
|
|
359
|
+
},
|
|
360
|
+
};
|
|
361
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
// Eval signal file discovery and summarization for the learning signal registry.
|
|
2
|
+
|
|
3
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
|
|
6
|
+
import { defaultLearningFile } from "./learn.mjs";
|
|
7
|
+
import { worstStatus } from "./signals-shared.mjs";
|
|
8
|
+
import { defaultLearningEvalPath } from "./workspace.mjs";
|
|
9
|
+
|
|
10
|
+
export const DEFAULT_SIGNAL_EVAL_FILES = [
|
|
11
|
+
"route-eval.json",
|
|
12
|
+
"route-eval-report.json",
|
|
13
|
+
"prompt-eval.json",
|
|
14
|
+
"prompt-eval-report.json",
|
|
15
|
+
"pack-eval.json",
|
|
16
|
+
"pack-eval-report.json",
|
|
17
|
+
"learning-eval.json",
|
|
18
|
+
"learning-eval-report.json",
|
|
19
|
+
];
|
|
20
|
+
export function inferSignalKind(payload, filePath = "") {
|
|
21
|
+
const sourceName = path.basename(filePath).toLowerCase();
|
|
22
|
+
const cases = Array.isArray(payload?.cases) ? payload.cases : [];
|
|
23
|
+
|
|
24
|
+
if (sourceName.includes("route")) return "route-eval";
|
|
25
|
+
if (sourceName.includes("prompt")) return "prompt-eval";
|
|
26
|
+
if (sourceName.includes("pack")) return "pack-eval";
|
|
27
|
+
if (sourceName.includes("learning")) return "learning-eval";
|
|
28
|
+
|
|
29
|
+
if (payload?.sourceRouteVersion) return "route-eval";
|
|
30
|
+
if (payload?.sourcePromptVersion) return "prompt-eval";
|
|
31
|
+
if (payload?.sourcePackVersion) return "pack-eval";
|
|
32
|
+
if (payload?.sourceProfile) return "learning-eval";
|
|
33
|
+
if (cases.some((item) => item && typeof item === "object" && "topRouteId" in item)) return "route-eval";
|
|
34
|
+
if (cases.some((item) => item && typeof item === "object" && "missingPromptFragments" in item)) return "prompt-eval";
|
|
35
|
+
if (cases.some((item) => item && typeof item === "object" && ("contextStatus" in item || "pack" in item))) return "pack-eval";
|
|
36
|
+
if (cases.some((item) => item && typeof item === "object" && ("selectedEntryIds" in item || "expectedSelectedIds" in item))) return "learning-eval";
|
|
37
|
+
|
|
38
|
+
return "unknown-eval";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function summarizeCaseCounts(payload) {
|
|
42
|
+
const summary = payload?.summary && typeof payload.summary === "object" ? payload.summary : null;
|
|
43
|
+
const cases = Array.isArray(payload?.cases) ? payload.cases : [];
|
|
44
|
+
if (summary) {
|
|
45
|
+
return {
|
|
46
|
+
caseCount: Number.isInteger(summary.total) ? summary.total : cases.length,
|
|
47
|
+
passed: Number.isInteger(summary.pass) ? summary.pass : 0,
|
|
48
|
+
warned: Number.isInteger(summary.warn) ? summary.warn : 0,
|
|
49
|
+
failed: Number.isInteger(summary.fail) ? summary.fail : 0,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
caseCount: cases.length,
|
|
55
|
+
passed: cases.filter((item) => item?.status === "pass").length,
|
|
56
|
+
warned: cases.filter((item) => item?.status === "warn").length,
|
|
57
|
+
failed: cases.filter((item) => item?.status === "fail").length,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function summarizeSignalEvalFile(filePath) {
|
|
62
|
+
const resolvedFile = path.resolve(filePath);
|
|
63
|
+
if (!existsSync(resolvedFile)) {
|
|
64
|
+
return {
|
|
65
|
+
file: resolvedFile,
|
|
66
|
+
exists: false,
|
|
67
|
+
kind: inferSignalKind(null, resolvedFile),
|
|
68
|
+
shape: "missing",
|
|
69
|
+
status: "missing",
|
|
70
|
+
caseCount: 0,
|
|
71
|
+
passed: 0,
|
|
72
|
+
warned: 0,
|
|
73
|
+
failed: 0,
|
|
74
|
+
generatedAt: "",
|
|
75
|
+
error: "",
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
let payload = null;
|
|
80
|
+
try {
|
|
81
|
+
payload = JSON.parse(readFileSync(resolvedFile, "utf8"));
|
|
82
|
+
} catch {
|
|
83
|
+
return {
|
|
84
|
+
file: resolvedFile,
|
|
85
|
+
exists: true,
|
|
86
|
+
kind: inferSignalKind(null, resolvedFile),
|
|
87
|
+
shape: "invalid-json",
|
|
88
|
+
status: "fail",
|
|
89
|
+
caseCount: 0,
|
|
90
|
+
passed: 0,
|
|
91
|
+
warned: 0,
|
|
92
|
+
failed: 0,
|
|
93
|
+
generatedAt: "",
|
|
94
|
+
error: "Signal eval file is not valid JSON.",
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const hasCases = Array.isArray(payload?.cases);
|
|
99
|
+
const isReport = typeof payload?.status === "string" || Boolean(payload?.summary);
|
|
100
|
+
const counts = summarizeCaseCounts(payload);
|
|
101
|
+
const status = isReport
|
|
102
|
+
? String(payload.status || worstStatus([
|
|
103
|
+
counts.failed > 0 ? "fail" : "",
|
|
104
|
+
counts.warned > 0 ? "warn" : "",
|
|
105
|
+
"pass",
|
|
106
|
+
])).trim()
|
|
107
|
+
: "template";
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
file: resolvedFile,
|
|
111
|
+
exists: true,
|
|
112
|
+
kind: inferSignalKind(payload, resolvedFile),
|
|
113
|
+
shape: isReport ? "report" : "template",
|
|
114
|
+
status: hasCases ? status : "fail",
|
|
115
|
+
caseCount: counts.caseCount,
|
|
116
|
+
passed: counts.passed,
|
|
117
|
+
warned: counts.warned,
|
|
118
|
+
failed: counts.failed,
|
|
119
|
+
generatedAt: String(payload?.generatedAt || ""),
|
|
120
|
+
error: hasCases ? "" : "Signal eval file must include a cases array.",
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function resolveSignalFiles({ signalSource = "", root = process.cwd(), extraFiles = [] } = {}) {
|
|
125
|
+
const resolvedSource = signalSource ? path.resolve(signalSource) : path.resolve(root);
|
|
126
|
+
const resolvedExtraFiles = (Array.isArray(extraFiles) ? extraFiles : [])
|
|
127
|
+
.filter(Boolean)
|
|
128
|
+
.map((filePath) => path.resolve(filePath))
|
|
129
|
+
.filter((filePath) => existsSync(filePath));
|
|
130
|
+
const uniqueFiles = (files = []) => [...new Set([...files, ...resolvedExtraFiles])];
|
|
131
|
+
if (existsSync(resolvedSource) && statSync(resolvedSource).isDirectory()) {
|
|
132
|
+
return uniqueFiles(DEFAULT_SIGNAL_EVAL_FILES
|
|
133
|
+
.map((fileName) => path.join(resolvedSource, fileName))
|
|
134
|
+
.filter((filePath) => existsSync(filePath)));
|
|
135
|
+
}
|
|
136
|
+
if (signalSource) return uniqueFiles([resolvedSource]);
|
|
137
|
+
return uniqueFiles([]);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function evalReportPathForTemplate(filePath = "") {
|
|
141
|
+
const resolvedFile = path.resolve(filePath);
|
|
142
|
+
const dir = path.dirname(resolvedFile);
|
|
143
|
+
const ext = path.extname(resolvedFile);
|
|
144
|
+
const base = path.basename(resolvedFile, ext);
|
|
145
|
+
if (base.endsWith("-report")) return resolvedFile;
|
|
146
|
+
if (base.endsWith("-eval")) return path.join(dir, `${base}-report${ext || ".json"}`);
|
|
147
|
+
return path.join(dir, `${base}-report${ext || ".json"}`);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function defaultLearningEvalReportPath(filePath = defaultLearningFile()) {
|
|
151
|
+
return evalReportPathForTemplate(defaultLearningEvalPath(filePath));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function evalSignalEvidenceKey(file = {}) {
|
|
155
|
+
return `${file.kind || "unknown-eval"}\n${path.dirname(file.file || "")}`;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function summarizeEvalSignals(evalFiles = []) {
|
|
159
|
+
const reportKeys = new Set(
|
|
160
|
+
evalFiles
|
|
161
|
+
.filter((item) => item.shape === "report")
|
|
162
|
+
.map((item) => evalSignalEvidenceKey(item)),
|
|
163
|
+
);
|
|
164
|
+
const unresolvedTemplates = evalFiles.filter((item) => (
|
|
165
|
+
item.shape === "template" && !reportKeys.has(evalSignalEvidenceKey(item))
|
|
166
|
+
));
|
|
167
|
+
return {
|
|
168
|
+
reports: evalFiles.filter((item) => item.shape === "report").length,
|
|
169
|
+
templates: unresolvedTemplates.length,
|
|
170
|
+
rawTemplates: evalFiles.filter((item) => item.shape === "template").length,
|
|
171
|
+
templateFiles: unresolvedTemplates,
|
|
172
|
+
failed: evalFiles.filter((item) => item.status === "fail").length,
|
|
173
|
+
warned: evalFiles.filter((item) => item.status === "warn").length,
|
|
174
|
+
passed: evalFiles.filter((item) => item.status === "pass").length,
|
|
175
|
+
};
|
|
176
|
+
}
|