analyzthis_design 2.5.1 → 2.6.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/HOW-TO-USE.md +249 -326
- package/README.md +71 -25
- package/agents/calibration-benchmark.json +187 -0
- package/agents/cards/anuj.md +1 -1
- package/agents/cards/arjun.md +1 -1
- package/agents/cards/kavi.md +2 -1
- package/agents/cards/mood-board.md +7 -7
- package/agents/cards/noor.md +1 -1
- package/agents/cards/priya.md +1 -1
- package/agents/cards/zara.md +3 -3
- package/agents/chain.json +1 -1
- package/agents/design-spec-schema.json +18 -1
- package/agents/manifests/mood-board.json +13 -8
- package/agents/model-policy.json +12 -0
- package/agents/router.json +2 -2
- package/agents/session-schema.json +12 -2
- package/dist/HOW-TO-USE.md +249 -326
- package/dist/README.md +71 -25
- package/dist/agents/calibration-benchmark.json +187 -0
- package/dist/agents/cards/anuj.md +1 -1
- package/dist/agents/cards/arjun.md +1 -1
- package/dist/agents/cards/kavi.md +2 -1
- package/dist/agents/cards/mood-board.md +7 -7
- package/dist/agents/cards/noor.md +1 -1
- package/dist/agents/cards/priya.md +1 -1
- package/dist/agents/cards/zara.md +3 -3
- package/dist/agents/chain.json +1 -1
- package/dist/agents/design-spec-schema.json +18 -1
- package/dist/agents/manifests/mood-board.json +13 -8
- package/dist/agents/model-policy.json +12 -0
- package/dist/agents/router.json +2 -2
- package/dist/agents/session-schema.json +12 -2
- package/dist/bin/cli.js +308 -10
- package/dist/lib/calibrate.js +816 -0
- package/dist/lib/chunk-executor.js +41 -1
- package/dist/lib/chunk-models.js +4 -18
- package/dist/lib/chunk-router.js +22 -6
- package/dist/lib/chunk-run.js +55 -1
- package/dist/lib/chunk-synthesis.js +18 -2
- package/dist/lib/chunk-telemetry.js +77 -17
- package/dist/lib/collect.js +15 -1
- package/dist/lib/cost.js +15 -7
- package/dist/lib/design-spec.js +32 -2
- package/dist/lib/evolution-metrics.js +23 -1
- package/dist/lib/feedback-submit.js +50 -1
- package/dist/lib/feedback.js +15 -0
- package/dist/lib/install.js +1 -0
- package/dist/lib/lessons.js +8 -0
- package/dist/lib/mcp-server.js +189 -7
- package/dist/lib/model-policy.js +174 -0
- package/dist/lib/model-registry.js +71 -0
- package/dist/lib/moodboard-film.js +119 -0
- package/dist/lib/moodboard-view.js +426 -0
- package/dist/lib/moodboard.js +638 -27
- package/dist/lib/orchestrator/run.js +67 -8
- package/dist/lib/outcome.js +7 -2
- package/dist/lib/output-quality.js +95 -0
- package/dist/lib/reference-pack.js +9 -1
- package/dist/lib/session.js +48 -4
- package/dist/lib/system-prompt.js +3 -0
- package/dist/lib/ui-libraries.js +232 -0
- package/dist/skills/anuj/SKILL.md +4 -0
- package/dist/skills/arjun/SKILL.md +2 -0
- package/dist/skills/arjun/references/lens.md +2 -0
- package/dist/skills/design-director/SKILL.md +2 -1
- package/dist/skills/design-reference/SKILL.md +6 -0
- package/dist/skills/design-reference/motion.csv +11 -0
- package/dist/skills/design-reference/schema.json +12 -0
- package/dist/skills/design-reference/stacks/shadcn.csv +6 -0
- package/dist/skills/design-reference/ui-libraries.csv +46 -0
- package/dist/skills/design-spec/SKILL.md +1 -1
- package/dist/skills/getting-started/SKILL.md +2 -2
- package/dist/skills/kavi/SKILL.md +3 -2
- package/dist/skills/meera/SKILL.md +2 -0
- package/dist/skills/mood-board/SKILL.md +94 -87
- package/dist/skills/noor/SKILL.md +4 -0
- package/dist/skills/persona-orchestrator/references/lens.md +4 -4
- package/dist/skills/priya/SKILL.md +5 -0
- package/dist/skills/raj/SKILL.md +2 -0
- package/dist/skills/zara/SKILL.md +49 -4
- package/package.json +13 -2
- package/skills/anuj/SKILL.md +4 -0
- package/skills/arjun/SKILL.md +2 -0
- package/skills/arjun/references/lens.md +2 -0
- package/skills/design-director/SKILL.md +2 -1
- package/skills/design-reference/SKILL.md +6 -0
- package/skills/design-reference/motion.csv +11 -0
- package/skills/design-reference/schema.json +12 -0
- package/skills/design-reference/stacks/shadcn.csv +6 -0
- package/skills/design-reference/ui-libraries.csv +46 -0
- package/skills/design-spec/SKILL.md +1 -1
- package/skills/getting-started/SKILL.md +2 -2
- package/skills/kavi/SKILL.md +3 -2
- package/skills/meera/SKILL.md +2 -0
- package/skills/mood-board/SKILL.md +94 -87
- package/skills/noor/SKILL.md +4 -0
- package/skills/persona-orchestrator/references/lens.md +4 -4
- package/skills/priya/SKILL.md +5 -0
- package/skills/raj/SKILL.md +2 -0
- package/skills/zara/SKILL.md +49 -4
|
@@ -30,8 +30,9 @@
|
|
|
30
30
|
"experts": ["string — persona ids"],
|
|
31
31
|
"reason": "string"
|
|
32
32
|
},
|
|
33
|
+
"active_run": "object | null — { id, mode, at }; feedback only accepts outputs carrying this run id",
|
|
33
34
|
"persona_outputs": {
|
|
34
|
-
"<persona_id>": "object —
|
|
35
|
+
"<persona_id>": "object — output plus run_id, attribution { provider, model, model_id, effort, policy_version, prompt_hash, validator_version }, quality, and accepted state"
|
|
35
36
|
},
|
|
36
37
|
"full_prompts": {
|
|
37
38
|
"<persona_id>": "object — { system: string, user: string } exact prompts sent to LLM for training"
|
|
@@ -73,6 +74,8 @@
|
|
|
73
74
|
"correction": "string — how the user corrected or what they wanted instead",
|
|
74
75
|
"tags": ["string — e.g. wrong_hierarchy, invented_tokens, off_brief"],
|
|
75
76
|
"original_output": "string — snapshot of persona output at feedback time",
|
|
77
|
+
"run_id": "string | null — exact run that produced the rated output",
|
|
78
|
+
"attribution": "object — provider/model/effort and policy metadata copied from the output",
|
|
76
79
|
"submitted_at": "ISO 8601 | omitted — set when feedback submit succeeds",
|
|
77
80
|
"context": "object — task_map_summary, problem_type, mode"
|
|
78
81
|
}
|
|
@@ -83,6 +86,13 @@
|
|
|
83
86
|
},
|
|
84
87
|
"vault_path": "string — Obsidian vault written by Kavi collect (empty until first collect)",
|
|
85
88
|
"last_collect_at": "ISO 8601 timestamp — last successful collect run",
|
|
89
|
+
"installed_ui_libraries": {
|
|
90
|
+
"installed": [{ "library": "string", "job": "string", "how": "package.json | folder | package+folder" }],
|
|
91
|
+
"missing_defaults": [{ "job": "string", "library": "string", "install": "string", "docs": "string" }],
|
|
92
|
+
"full_kits": ["string — Chakra, Mantine, HeroUI, MUI, Ant Design, Ark"],
|
|
93
|
+
"mixed_kits": "boolean — more than one full kit, or a full kit plus Shadcn",
|
|
94
|
+
"folders": ["string — components/ui, components/magicui, ..."]
|
|
95
|
+
},
|
|
86
96
|
"deliberation": {
|
|
87
97
|
"round": "number — current deliberation round",
|
|
88
98
|
"max_rounds": "number",
|
|
@@ -141,7 +151,7 @@
|
|
|
141
151
|
"output_tokens_est": "number — estimated output tokens across the last run",
|
|
142
152
|
"cache_hits": "number — retrieve/cache hits during the last run",
|
|
143
153
|
"mode": "lite | full",
|
|
144
|
-
"effort_log": [{ "persona": "string", "effort": "trivial|standard|hard", "model": "string|null", "scoped_mode": "string|null" }],
|
|
154
|
+
"effort_log": [{ "persona": "string", "effort": "trivial|standard|hard", "provider": "string|null", "model": "string|null", "model_id": "string|null", "input_tokens": "number", "output_tokens": "number", "run_id": "string", "scoped_mode": "string|null" }],
|
|
145
155
|
"cost_usd": "number — estimated $ cost of the run from config.pricing (0 when pricing missing)",
|
|
146
156
|
"deliberation_rounds": "number — adversarial rounds executed in last run",
|
|
147
157
|
"objections_raised": "number",
|
package/dist/bin/cli.js
CHANGED
|
@@ -19,6 +19,7 @@ const designSpec = require('../lib/design-spec');
|
|
|
19
19
|
const { run: orchestratorRun } = require('../lib/orchestrator/run');
|
|
20
20
|
const hostLlm = require('../lib/host-llm');
|
|
21
21
|
const moodboard = require('../lib/moodboard');
|
|
22
|
+
const calibrator = require('../lib/calibrate');
|
|
22
23
|
|
|
23
24
|
const HELP = `
|
|
24
25
|
Analyzthis_Design — 8 AI design personas with a personal knowledge bank
|
|
@@ -79,6 +80,9 @@ Usage:
|
|
|
79
80
|
── Efficiency / cost commands ────────────────────────────────
|
|
80
81
|
metrics Print the last run's cost metrics (--all for every project)
|
|
81
82
|
cost Print the last run's $ cost from config.pricing (--all for every project)
|
|
83
|
+
calibrate Compare available models on the fixed persona benchmark
|
|
84
|
+
(--max-usd 5, --max-calls 500, --runs 3, --judge, --apply)
|
|
85
|
+
Preview only with --dry-run; share text-free results with --share
|
|
82
86
|
receipt Inferred token receipt for host (slash/MCP) turns — not a bill
|
|
83
87
|
export-training Write accepted-output JSONL pairs for LoRA prep
|
|
84
88
|
(--persona <id>, --all, --output <path>)
|
|
@@ -98,12 +102,26 @@ Usage:
|
|
|
98
102
|
full: all 19 named tools. Or ANALYZTHIS_MCP_CATALOG=full
|
|
99
103
|
|
|
100
104
|
── Mood board commands ─────────────────────────────────────
|
|
101
|
-
moodboard create --task <text>
|
|
102
|
-
[--
|
|
103
|
-
|
|
104
|
-
moodboard
|
|
105
|
-
|
|
106
|
-
[--
|
|
105
|
+
moodboard create --task <text> Start a visual mood board (Zara scouts element crops)
|
|
106
|
+
[--adjectives a,b,c] [--not "..."] [--sections components,typography]
|
|
107
|
+
[--kind mood] for the older link-and-tag board
|
|
108
|
+
moodboard brief --board <id> Edit the brief [--adjectives] [--not] [--sections] [--yes]
|
|
109
|
+
moodboard capture-script Print the page script that reads real colours/fonts
|
|
110
|
+
[--selector ".pricing-card"]
|
|
111
|
+
moodboard tile --board <id> Add one element crop: --page <url> --image <file|url>
|
|
112
|
+
--element "<what>" --section <id> [--steal] [--refuse]
|
|
113
|
+
[--peak] [--colors #hex,..] [--fonts a,b] [--concept]
|
|
114
|
+
[--video film.webm] [--stills a.png,b.png]
|
|
115
|
+
moodboard film --board <id> Record real sites scrolling as motion tiles: --url <url>
|
|
116
|
+
(repeatable) [--section motion] [--steal] [--refuse]
|
|
117
|
+
Needs playwright-core + Google Chrome
|
|
118
|
+
moodboard critique --board <id> Team votes on each tile (advice only)
|
|
119
|
+
moodboard votes --board <id> Save team votes from a JSON file --votes votes.json
|
|
120
|
+
moodboard show --board <id> Open the clickable board on 127.0.0.1 [--port 4317]
|
|
121
|
+
moodboard decide --board <id> Your choice: --tile <n> --decision keep|maybe|reject|clear
|
|
122
|
+
moodboard rescout --board <id> Send Zara back with your note [--note "..."]
|
|
123
|
+
moodboard lock --board <id> Lock your direction for every persona [--note "..."]
|
|
124
|
+
moodboard add --board <id> Add a reference to a link board and rerun critique
|
|
107
125
|
moodboard list List mood boards for this project
|
|
108
126
|
|
|
109
127
|
── Reference data (retrieve-on-demand) ───────────────────────
|
|
@@ -156,6 +174,14 @@ Usage:
|
|
|
156
174
|
--budget free | cheap | auto — chunk model budget (run command; default: auto)
|
|
157
175
|
--sequential Run chunks sequentially (run command; default on)
|
|
158
176
|
--max-chunks Cap number of planner chunks (run command; default 6)
|
|
177
|
+
--max-usd Calibration hard spending limit in USD (default 5)
|
|
178
|
+
--max-calls Calibration hard model-call limit (default 500)
|
|
179
|
+
--runs Calibration repeats per fixed task/model (default 3)
|
|
180
|
+
--delta Non-inferiority margin on the 0-1 score scale (default 0.05)
|
|
181
|
+
--judge Enable blind cross-family calibration judges
|
|
182
|
+
--apply Write qualified calibration winners to the local policy
|
|
183
|
+
--resume Resume a calibration checkpoint path
|
|
184
|
+
--share Opt-in submission of text-free fixed-benchmark aggregates
|
|
159
185
|
--unchunked Force legacy single-pass orchestrator (run command)
|
|
160
186
|
--output Write final session-state.json to this path (run / run-unchunked command); or JSONL path (export-training)
|
|
161
187
|
--persona Persona id (session accept; export-training; feedback commands)
|
|
@@ -210,7 +236,10 @@ Usage:
|
|
|
210
236
|
npx analyzthis_design research --query "EY design system tokens"
|
|
211
237
|
|
|
212
238
|
npx analyzthis_design moodboard create --task "B2B fintech dashboard, trustworthy, high-contrast" --auto
|
|
239
|
+
npx analyzthis_design moodboard create --task "Invoice approval, partner signs" --adjectives calm,precise,trusted --not "AI purple hero"
|
|
240
|
+
npx analyzthis_design moodboard tile --board <id> --page https://linear.app/pricing --image ./crop.png --element "Pricing card" --section components --steal "one quiet CTA"
|
|
213
241
|
npx analyzthis_design moodboard critique --board <boardId>
|
|
242
|
+
npx analyzthis_design moodboard show --board <boardId>
|
|
214
243
|
npx analyzthis_design moodboard add --board <boardId> --url https://dribbble.com/shots/example --title "Alt hero" --tags "landing,trust"
|
|
215
244
|
|
|
216
245
|
npx analyzthis_design retrieve --file colors.csv --column "Product Type" --keywords saas,dashboard
|
|
@@ -326,6 +355,10 @@ const boardVal = getFlag('board');
|
|
|
326
355
|
const titleVal = getFlag('title');
|
|
327
356
|
const descVal = getFlag('desc');
|
|
328
357
|
const autoFlag = flags.includes('--auto');
|
|
358
|
+
const kindVal = getFlag('kind');
|
|
359
|
+
const stealVal = getFlag('steal');
|
|
360
|
+
const refuseVal = getFlag('refuse');
|
|
361
|
+
const peakVal = getFlag('peak');
|
|
329
362
|
const budgetVal = getFlag('budget');
|
|
330
363
|
const sequentialFlag = flags.includes('--sequential');
|
|
331
364
|
const maxChunksVal = getFlag('max-chunks');
|
|
@@ -335,6 +368,32 @@ const fixFlag = flags.includes('--fix') || flags.includes('--no');
|
|
|
335
368
|
const likedFlag = flags.includes('--liked');
|
|
336
369
|
const becauseVal = getFlag('because');
|
|
337
370
|
const sendFlag = flags.includes('--send');
|
|
371
|
+
const applyFlag = flags.includes('--apply');
|
|
372
|
+
const shareFlag = flags.includes('--share');
|
|
373
|
+
const judgeFlag = flags.includes('--judge');
|
|
374
|
+
const maxUsdVal = getFlag('max-usd');
|
|
375
|
+
const maxCallsVal = getFlag('max-calls');
|
|
376
|
+
const runsVal = getFlag('runs');
|
|
377
|
+
const deltaVal = getFlag('delta');
|
|
378
|
+
const resumeVal = getFlag('resume');
|
|
379
|
+
const sectionVal = getFlag('section');
|
|
380
|
+
const sectionsVal = getFlag('sections');
|
|
381
|
+
const elementVal = getFlag('element');
|
|
382
|
+
const imageVal = getFlag('image');
|
|
383
|
+
const tileVal = getFlag('tile');
|
|
384
|
+
const decisionVal = getFlag('decision');
|
|
385
|
+
const noteVal = getFlag('note');
|
|
386
|
+
const portVal = getFlag('port');
|
|
387
|
+
const selectorVal = getFlag('selector');
|
|
388
|
+
const adjectivesVal = getFlag('adjectives');
|
|
389
|
+
const notThisVal = getFlag('not');
|
|
390
|
+
const colorsVal = getFlag('colors');
|
|
391
|
+
const fontsVal = getFlag('fonts');
|
|
392
|
+
const votesVal = getFlag('votes');
|
|
393
|
+
const conceptFlag = flags.includes('--concept');
|
|
394
|
+
const videoVal = getFlag('video');
|
|
395
|
+
const stillsVal = getFlag('stills');
|
|
396
|
+
const splitList = (raw) => (raw ? raw.split(',').map((s) => s.trim()).filter(Boolean) : undefined);
|
|
338
397
|
|
|
339
398
|
// ─── Commands ────────────────────────────────────────────────────────────────
|
|
340
399
|
|
|
@@ -660,7 +719,7 @@ switch (cmd) {
|
|
|
660
719
|
const msub = flags.find((f) => !f.startsWith('--')) || 'create';
|
|
661
720
|
if (msub === 'create') {
|
|
662
721
|
if (!taskVal) {
|
|
663
|
-
console.error('\n ✗ --task is required. Example: npx analyzthis_design moodboard create --task "B2B fintech dashboard" --
|
|
722
|
+
console.error('\n ✗ --task is required. Example: npx analyzthis_design moodboard create --task "B2B fintech dashboard" --adjectives calm,dense,trusted\n');
|
|
664
723
|
process.exit(1);
|
|
665
724
|
}
|
|
666
725
|
(async () => {
|
|
@@ -675,11 +734,23 @@ switch (cmd) {
|
|
|
675
734
|
project: projectVal,
|
|
676
735
|
task: taskVal,
|
|
677
736
|
urls: urls,
|
|
737
|
+
kind: kindVal || 'ui',
|
|
678
738
|
discover: autoFlag || urls.length > 0,
|
|
679
739
|
dryRun: dryRunFlag,
|
|
740
|
+
brief: { adjectives: splitList(adjectivesVal), not_this: notThisVal || '', sections: splitList(sectionsVal) },
|
|
680
741
|
});
|
|
681
|
-
console.log(`\n✅ Mood board created: ${result.board.board_id}`);
|
|
682
|
-
|
|
742
|
+
console.log(`\n✅ ${result.board.kind === 'ui' ? 'Mood board (visual)' : 'Link mood board'} created: ${result.board.board_id}`);
|
|
743
|
+
if (result.board.kind === 'ui') {
|
|
744
|
+
console.log(` Sections: ${result.board.brief.sections.join(', ')}`);
|
|
745
|
+
console.log(` Scout: Zara round ${result.board.scout.round} — ${result.board.scout.status}`);
|
|
746
|
+
console.log(` Next: Zara crops elements, then moodboard tile --board ${result.board.board_id} --page <url> --image <file> --element "<what>" --section components`);
|
|
747
|
+
console.log(` Then: moodboard show --board ${result.board.board_id} (you decide in the browser)`);
|
|
748
|
+
console.log('');
|
|
749
|
+
console.log(result.board.scout.brief);
|
|
750
|
+
console.log('');
|
|
751
|
+
} else {
|
|
752
|
+
console.log(` References: ${result.board.references.length}`);
|
|
753
|
+
}
|
|
683
754
|
console.log(` Board dir: ${result.boardDir}`);
|
|
684
755
|
console.log(` Workspace: ${result.workspacePath}\n`);
|
|
685
756
|
if (dryRunFlag) {
|
|
@@ -712,6 +783,10 @@ switch (cmd) {
|
|
|
712
783
|
});
|
|
713
784
|
console.log(`\n✅ Mood board critique complete: ${result.board.board_id}`);
|
|
714
785
|
console.log(` Verdict: ${result.board.synthesis?.verdict || 'n/a'}`);
|
|
786
|
+
if (result.board.kind === 'ui' && result.board.scout) {
|
|
787
|
+
console.log(` Scout: round ${result.board.scout.round} — ${result.board.scout.status}`);
|
|
788
|
+
console.log(` Team votes are advice. You decide: moodboard show --board ${result.board.board_id}`);
|
|
789
|
+
}
|
|
715
790
|
console.log(` Rounds: ${result.board.deliberation?.round || 0}`);
|
|
716
791
|
console.log(` Board: ${result.boardDir || path.join(session.sessionDir(projectVal || session.getProjectId()), 'moodboard', boardVal)}`);
|
|
717
792
|
console.log(` Workspace: ${result.workspacePath}\n`);
|
|
@@ -726,6 +801,149 @@ switch (cmd) {
|
|
|
726
801
|
})();
|
|
727
802
|
break;
|
|
728
803
|
}
|
|
804
|
+
if (msub === 'film') {
|
|
805
|
+
const urls = flags.filter((f, i) => i > 0 && flags[i - 1] === '--url' && !f.startsWith('--'))
|
|
806
|
+
.concat(flags.filter((f) => f.startsWith('--url=')).map((f) => f.slice(6)));
|
|
807
|
+
if (!boardVal || !urls.length) {
|
|
808
|
+
console.error('\n ✗ --board and --url are required. Example: npx analyzthis_design moodboard film --board <id> --url https://osmo.supply --steal "easing taste"\n');
|
|
809
|
+
process.exit(1);
|
|
810
|
+
}
|
|
811
|
+
(async () => {
|
|
812
|
+
try {
|
|
813
|
+
console.log(`\n 🎬 Filming ${urls.length} site${urls.length === 1 ? '' : 's'} (about 15 seconds each)…`);
|
|
814
|
+
const out = await require('../lib/moodboard-film').filmTiles({
|
|
815
|
+
project: projectVal, boardId: boardVal, urls,
|
|
816
|
+
section: sectionVal, element: elementVal, steal: stealVal, refuse: refuseVal, peak: peakVal,
|
|
817
|
+
});
|
|
818
|
+
out.failed.forEach((f) => console.error(` ✗ ${f.url}: ${f.reason}`));
|
|
819
|
+
const added = out.saved ? out.saved.added : [];
|
|
820
|
+
(out.saved ? out.saved.skipped : []).forEach((s) => console.error(` ✗ ${s.element}: ${s.reason}`));
|
|
821
|
+
if (!added.length) process.exit(1);
|
|
822
|
+
console.log(`\n✅ ${added.length} film tile${added.length === 1 ? '' : 's'} added: ${added.map((t) => '#' + t.n + ' ' + t.site).join(', ')}`);
|
|
823
|
+
console.log(` Next: moodboard show --board ${boardVal}\n`);
|
|
824
|
+
} catch (err) {
|
|
825
|
+
console.error(`\n ✗ ${err.message}\n`);
|
|
826
|
+
process.exit(1);
|
|
827
|
+
}
|
|
828
|
+
})();
|
|
829
|
+
break;
|
|
830
|
+
}
|
|
831
|
+
if (msub === 'tile' || msub === 'frames') {
|
|
832
|
+
const pageUrl = getFlag('page') || urlVal;
|
|
833
|
+
if (!boardVal || !pageUrl) {
|
|
834
|
+
console.error('\n ✗ --board and --page are required. Example: npx analyzthis_design moodboard tile --board <id> --page https://linear.app/pricing --image ./crop.png --element "Pricing card" --section components --steal "one quiet CTA"\n');
|
|
835
|
+
process.exit(1);
|
|
836
|
+
}
|
|
837
|
+
try {
|
|
838
|
+
const result = moodboard.addTiles({
|
|
839
|
+
project: projectVal,
|
|
840
|
+
boardId: boardVal,
|
|
841
|
+
tile: {
|
|
842
|
+
page_url: pageUrl,
|
|
843
|
+
element: elementVal || titleVal || '',
|
|
844
|
+
section: sectionVal || 'components',
|
|
845
|
+
image_path: imageVal && !/^https?:\/\//i.test(imageVal) ? imageVal : undefined,
|
|
846
|
+
image_url: imageVal && /^https?:\/\//i.test(imageVal) ? imageVal : (msub === 'frames' ? urlVal : undefined),
|
|
847
|
+
video_path: videoVal,
|
|
848
|
+
stills: splitList(stillsVal),
|
|
849
|
+
tokens: { colors: splitList(colorsVal), fonts: splitList(fontsVal) },
|
|
850
|
+
steal: stealVal || '',
|
|
851
|
+
refuse: refuseVal || '',
|
|
852
|
+
peak: peakVal || '',
|
|
853
|
+
concept: conceptFlag,
|
|
854
|
+
},
|
|
855
|
+
});
|
|
856
|
+
if (result.skipped.length) {
|
|
857
|
+
console.error(`\n ✗ Not added: ${result.skipped.map((s) => s.reason).join('; ')}\n`);
|
|
858
|
+
process.exit(1);
|
|
859
|
+
}
|
|
860
|
+
console.log(`\n✅ Tile #${result.added[0].n} added (${result.board.tiles.length} on the board)`);
|
|
861
|
+
console.log(` Next: more tiles, then moodboard critique or moodboard show --board ${result.board.board_id}\n`);
|
|
862
|
+
} catch (err) {
|
|
863
|
+
console.error(`\n ✗ ${err.message}\n`);
|
|
864
|
+
process.exit(1);
|
|
865
|
+
}
|
|
866
|
+
break;
|
|
867
|
+
}
|
|
868
|
+
if (msub === 'brief') {
|
|
869
|
+
try {
|
|
870
|
+
const result = moodboard.setBrief({
|
|
871
|
+
project: projectVal, boardId: boardVal,
|
|
872
|
+
adjectives: splitList(adjectivesVal), not_this: notThisVal, sections: splitList(sectionsVal),
|
|
873
|
+
confirmed_by_user: yesFlag ? true : undefined,
|
|
874
|
+
});
|
|
875
|
+
console.log(`\n✅ Brief saved: ${JSON.stringify(result.board.brief)}\n`);
|
|
876
|
+
} catch (err) {
|
|
877
|
+
console.error(`\n ✗ ${err.message}\n`);
|
|
878
|
+
process.exit(1);
|
|
879
|
+
}
|
|
880
|
+
break;
|
|
881
|
+
}
|
|
882
|
+
if (msub === 'votes') {
|
|
883
|
+
try {
|
|
884
|
+
const raw = JSON.parse(fs.readFileSync(votesVal, 'utf8'));
|
|
885
|
+
const result = moodboard.recordPersonaVotes({ project: projectVal, boardId: boardVal, votes: raw.votes || [], verdict: raw.verdict, summary: raw.summary });
|
|
886
|
+
console.log(`\n✅ Team advice saved. ${result.ignored.length} ignored. Next: moodboard show --board ${result.board.board_id}\n`);
|
|
887
|
+
} catch (err) {
|
|
888
|
+
console.error(`\n ✗ ${err.message} (usage: moodboard votes --board <id> --votes votes.json)\n`);
|
|
889
|
+
process.exit(1);
|
|
890
|
+
}
|
|
891
|
+
break;
|
|
892
|
+
}
|
|
893
|
+
if (msub === 'decide') {
|
|
894
|
+
try {
|
|
895
|
+
moodboard.recordUserDecision({ project: projectVal, boardId: boardVal, tile: tileVal, decision: decisionVal, note: noteVal || '' });
|
|
896
|
+
console.log(`\n✅ Tile ${tileVal}: ${decisionVal}. Your choice overrides every persona.\n`);
|
|
897
|
+
} catch (err) {
|
|
898
|
+
console.error(`\n ✗ ${err.message} (usage: moodboard decide --board <id> --tile 3 --decision keep|maybe|reject|clear --note "...")\n`);
|
|
899
|
+
process.exit(1);
|
|
900
|
+
}
|
|
901
|
+
break;
|
|
902
|
+
}
|
|
903
|
+
if (msub === 'rescout') {
|
|
904
|
+
try {
|
|
905
|
+
const result = moodboard.requestRescout({ project: projectVal, boardId: boardVal, note: noteVal || '' });
|
|
906
|
+
console.log(`\n✅ Zara goes back out (round ${result.board.scout.round}).\n\n${result.board.scout.brief}\n`);
|
|
907
|
+
} catch (err) {
|
|
908
|
+
console.error(`\n ✗ ${err.message}\n`);
|
|
909
|
+
process.exit(1);
|
|
910
|
+
}
|
|
911
|
+
break;
|
|
912
|
+
}
|
|
913
|
+
if (msub === 'lock') {
|
|
914
|
+
try {
|
|
915
|
+
const result = moodboard.lockDirection({ project: projectVal, boardId: boardVal, note: noteVal || '' });
|
|
916
|
+
const d = result.board.direction;
|
|
917
|
+
console.log(`\n✅ Direction locked: ${d.kept.length} kept, ${d.rejected.length} rejected. Saved to session as design_direction.`);
|
|
918
|
+
if (d.palette.length) console.log(` Palette: ${d.palette.join(' ')}`);
|
|
919
|
+
if (d.fonts.length) console.log(` Fonts: ${d.fonts.join(', ')}`);
|
|
920
|
+
console.log('');
|
|
921
|
+
} catch (err) {
|
|
922
|
+
console.error(`\n ✗ ${err.message}\n`);
|
|
923
|
+
process.exit(1);
|
|
924
|
+
}
|
|
925
|
+
break;
|
|
926
|
+
}
|
|
927
|
+
if (msub === 'show') {
|
|
928
|
+
if (!boardVal) {
|
|
929
|
+
console.error('\n ✗ --board is required. Example: npx analyzthis_design moodboard show --board <id>\n');
|
|
930
|
+
process.exit(1);
|
|
931
|
+
}
|
|
932
|
+
require('../lib/moodboard-view').serveBoard({ project: projectVal, boardId: boardVal, port: portVal != null ? portVal : undefined, onChange: (what, b) => {
|
|
933
|
+
console.log(` ${new Date().toLocaleTimeString()} ${what} — scout: ${b.scout && b.scout.status}`);
|
|
934
|
+
} }).then((live) => {
|
|
935
|
+
console.log(`\n✅ Mood board live at ${live.url}`);
|
|
936
|
+
console.log(' Open it in the browser. Keep / maybe / reject saves instantly. Ctrl+C to stop.\n');
|
|
937
|
+
}).catch((err) => {
|
|
938
|
+
console.error(`\n ✗ ${err.message}\n`);
|
|
939
|
+
process.exit(1);
|
|
940
|
+
});
|
|
941
|
+
break;
|
|
942
|
+
}
|
|
943
|
+
if (msub === 'capture-script') {
|
|
944
|
+
console.log(moodboard.captureScript(selectorVal || 'body', getFlag('text') || ''));
|
|
945
|
+
break;
|
|
946
|
+
}
|
|
729
947
|
if (msub === 'add') {
|
|
730
948
|
if (!boardVal) {
|
|
731
949
|
console.error('\n ✗ --board is required. Example: npx analyzthis_design moodboard add --board <id> --url <url>\n');
|
|
@@ -776,7 +994,7 @@ switch (cmd) {
|
|
|
776
994
|
}
|
|
777
995
|
break;
|
|
778
996
|
}
|
|
779
|
-
console.error('\n Unknown moodboard subcommand. Use: create | critique | add | list\n');
|
|
997
|
+
console.error('\n Unknown moodboard subcommand. Use: create | brief | tile | critique | votes | show | decide | rescout | lock | capture-script | add | list\n');
|
|
780
998
|
process.exit(1);
|
|
781
999
|
}
|
|
782
1000
|
|
|
@@ -1000,6 +1218,86 @@ switch (cmd) {
|
|
|
1000
1218
|
break;
|
|
1001
1219
|
}
|
|
1002
1220
|
|
|
1221
|
+
case 'calibrate': {
|
|
1222
|
+
(async () => {
|
|
1223
|
+
try {
|
|
1224
|
+
if (shareFlag && dryRunFlag && resumeVal) {
|
|
1225
|
+
const saved = JSON.parse(fs.readFileSync(path.resolve(resumeVal), 'utf8'));
|
|
1226
|
+
const shared = await feedbackSubmit.submitCalibration(saved, { dryRun: true, yes: yesFlag });
|
|
1227
|
+
console.log(`\n── Calibration share preview (${shared.rows.length} text-free rows) ──`);
|
|
1228
|
+
console.log(JSON.stringify(shared.rows[0], null, 2));
|
|
1229
|
+
console.log('');
|
|
1230
|
+
return;
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
const options = {
|
|
1234
|
+
maxUsd: maxUsdVal == null ? 5 : Number(maxUsdVal),
|
|
1235
|
+
maxCalls: maxCallsVal == null ? 500 : Number(maxCallsVal),
|
|
1236
|
+
runs: runsVal == null ? 3 : Number(runsVal),
|
|
1237
|
+
delta: deltaVal == null ? 0.05 : Number(deltaVal),
|
|
1238
|
+
judge: judgeFlag,
|
|
1239
|
+
apply: applyFlag,
|
|
1240
|
+
resume: resumeVal || null,
|
|
1241
|
+
};
|
|
1242
|
+
const preview = await calibrator.preview(options);
|
|
1243
|
+
console.log('\n── Calibration preview ─────────────────────────────');
|
|
1244
|
+
console.log(` Models: ${preview.models}`);
|
|
1245
|
+
console.log(` Fixed tasks: ${preview.tasks}`);
|
|
1246
|
+
console.log(` Planned calls: ${preview.estimated_calls}/${options.maxCalls}`);
|
|
1247
|
+
console.log(` Worst-case cost: $${preview.estimated_usd.toFixed(4)}/$${options.maxUsd.toFixed(2)}`);
|
|
1248
|
+
if (!preview.allowed) {
|
|
1249
|
+
console.error(` Blocked by: ${preview.reasons.join(', ')}\n`);
|
|
1250
|
+
process.exitCode = 1;
|
|
1251
|
+
return;
|
|
1252
|
+
}
|
|
1253
|
+
if (dryRunFlag) {
|
|
1254
|
+
console.log(' Preview only: no model calls or policy writes.\n');
|
|
1255
|
+
return;
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
if (!yesFlag) {
|
|
1259
|
+
if (!process.stdin.isTTY) {
|
|
1260
|
+
throw new Error('Non-interactive terminal. Pass --yes after reviewing the cost preview.');
|
|
1261
|
+
}
|
|
1262
|
+
const readline = require('readline');
|
|
1263
|
+
const approved = await new Promise((resolve) => {
|
|
1264
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
1265
|
+
rl.question('Run this calibration? [y/N] ', (answer) => {
|
|
1266
|
+
rl.close();
|
|
1267
|
+
resolve(/^y(es)?$/i.test(String(answer || '').trim()));
|
|
1268
|
+
});
|
|
1269
|
+
});
|
|
1270
|
+
if (!approved) {
|
|
1271
|
+
console.log('\n Calibration cancelled.\n');
|
|
1272
|
+
return;
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
const result = await calibrator.calibrate(options);
|
|
1277
|
+
console.log(`\n── Calibration ${result.status} ─────────────────────`);
|
|
1278
|
+
console.log(` Calls: ${result.calls}`);
|
|
1279
|
+
console.log(` Cost: $${Number(result.spent_usd || 0).toFixed(4)}`);
|
|
1280
|
+
console.log(` Checkpoint: ${result.checkpoint}`);
|
|
1281
|
+
Object.entries(result.selections || {}).forEach(([persona, efforts]) => {
|
|
1282
|
+
Object.entries(efforts).forEach(([effort, selection]) => {
|
|
1283
|
+
console.log(` ${persona}/${effort}: ${selection.winner || 'keep current'} (${selection.reason})`);
|
|
1284
|
+
});
|
|
1285
|
+
});
|
|
1286
|
+
if (result.policy_file) console.log(` Local policy: ${result.policy_file}`);
|
|
1287
|
+
|
|
1288
|
+
if (shareFlag) {
|
|
1289
|
+
const shared = await feedbackSubmit.submitCalibration(result, { dryRun: false, yes: yesFlag });
|
|
1290
|
+
console.log(` Shared: ${shared.submitted || 0} fixed-benchmark rows`);
|
|
1291
|
+
}
|
|
1292
|
+
console.log('');
|
|
1293
|
+
} catch (error) {
|
|
1294
|
+
console.error(`\n ✗ ${error.message}\n`);
|
|
1295
|
+
process.exitCode = 1;
|
|
1296
|
+
}
|
|
1297
|
+
})();
|
|
1298
|
+
break;
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1003
1301
|
case 'scores': {
|
|
1004
1302
|
const em = require('../lib/evolution-metrics');
|
|
1005
1303
|
if (flags.includes('--submit') || flags.includes('--submit-dry-run')) {
|