analyzthis_design 2.0.1 → 2.1.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.
Files changed (46) hide show
  1. package/README.md +10 -5
  2. package/agents/cards/evolve-check.md +38 -0
  3. package/agents/manifests/evolve-check.json +16 -0
  4. package/dist/README.md +10 -5
  5. package/dist/agents/cards/evolve-check.md +38 -0
  6. package/dist/agents/manifests/evolve-check.json +16 -0
  7. package/dist/bin/cli.js +1225 -1
  8. package/dist/lib/cache.js +111 -1
  9. package/dist/lib/chunk-executor.js +219 -1
  10. package/dist/lib/chunk-models.js +228 -1
  11. package/dist/lib/chunk-planner.js +328 -1
  12. package/dist/lib/chunk-router.js +66 -1
  13. package/dist/lib/chunk-run.js +199 -1
  14. package/dist/lib/chunk-synthesis.js +176 -1
  15. package/dist/lib/chunk-telemetry.js +88 -1
  16. package/dist/lib/collect.js +858 -1
  17. package/dist/lib/cost.js +119 -1
  18. package/dist/lib/dedup.js +167 -1
  19. package/dist/lib/deliberation.js +721 -1
  20. package/dist/lib/design-spec.js +236 -1
  21. package/dist/lib/evolution-metrics.js +197 -0
  22. package/dist/lib/evolve.js +361 -1
  23. package/dist/lib/export.js +77 -1
  24. package/dist/lib/feedback-submit.js +324 -1
  25. package/dist/lib/feedback.js +182 -1
  26. package/dist/lib/host-llm.js +251 -1
  27. package/dist/lib/install.js +301 -1
  28. package/dist/lib/knowledge.js +384 -1
  29. package/dist/lib/lessons.js +217 -1
  30. package/dist/lib/moodboard.js +563 -1
  31. package/dist/lib/orchestrator/run.js +935 -1
  32. package/dist/lib/outcome.js +193 -1
  33. package/dist/lib/platforms.js +166 -1
  34. package/dist/lib/provider.js +57 -1
  35. package/dist/lib/query-expander.js +83 -1
  36. package/dist/lib/ranker.js +105 -1
  37. package/dist/lib/reference-pack.js +221 -1
  38. package/dist/lib/research.js +143 -1
  39. package/dist/lib/retrieve.js +131 -1
  40. package/dist/lib/session.js +185 -1
  41. package/dist/lib/source-discovery.js +486 -1
  42. package/dist/lib/synthesis.js +155 -1
  43. package/dist/lib/token-gate.js +46 -1
  44. package/dist/skills/evolve-check/SKILL.md +106 -0
  45. package/package.json +3 -6
  46. package/skills/evolve-check/SKILL.md +106 -0
package/dist/bin/cli.js CHANGED
@@ -1,2 +1,1226 @@
1
1
  #!/usr/bin/env node
2
- 'use strict';const path=require('path'),os=require('os'),fs=require('fs'),{install,remove,SKILLS,TARGET_DIRS,printWelcomeBanner}=require('../lib/install'),{resolveTargets,ALL_TARGET_IDS}=require('../lib/platforms'),{connect,disconnect,sync,status}=require('../lib/knowledge'),session=require('../lib/session'),research=require('../lib/research'),retrieve=require('../lib/retrieve'),{exportTraining}=require('../lib/export'),feedback=require('../lib/feedback'),feedbackSubmit=require('../lib/feedback-submit'),cost=require('../lib/cost'),{collect}=require('../lib/collect'),designSpec=require('../lib/design-spec'),{run:orchestratorRun}=require('../lib/orchestrator/run'),hostLlm=require('../lib/host-llm'),moodboard=require('../lib/moodboard'),HELP='\x0aAnalyzthis_Design\x20—\x208\x20AI\x20design\x20personas\x20with\x20a\x20personal\x20knowledge\x20bank\x0a\x0aUsage:\x0a\x20\x20npx\x20analyzthis_design\x20[command]\x20[options]\x0a\x0a──\x20Skill\x20commands\x20───────────────────────────────────────────\x0a\x20\x20install\x20\x20\x20\x20Copy\x20all\x20skills\x20to\x20the\x20target\x20AI\x20tool\x27s\x20directory\x20\x20(default)\x0a\x20\x20remove\x20\x20\x20\x20\x20Delete\x20installed\x20skills\x20from\x20the\x20target\x20AI\x20tool\x27s\x20directory\x0a\x20\x20list\x20\x20\x20\x20\x20\x20\x20Show\x20installed\x20skills\x20for\x20a\x20target\x0a\x20\x20welcome\x20\x20\x20\x20Print\x20getting-started\x20banner\x20for\x20your\x20AI\x20tool\x20(--target)\x0a\x0a──\x20Knowledge\x20bank\x20commands\x20──────────────────────────────────\x0a\x20\x20connect\x20\x20\x20\x20Register\x20a\x20vault\x20or\x20knowledge\x20folder\x20as\x20a\x20source\x0a\x20\x20sync\x20\x20\x20\x20\x20\x20\x20Read\x20all\x20sources\x20and\x20build\x20the\x20knowledge-bank\x20skill\x0a\x20\x20disconnect\x20Remove\x20a\x20source\x20from\x20the\x20registry\x0a\x20\x20status\x20\x20\x20\x20\x20Show\x20connected\x20sources\x20and\x20last\x20sync\x20time\x0a\x20\x20collect\x20\x20\x20\x20Kavi:\x20scan\x20codebase\x20→\x20Obsidian\x20vault\x20→\x20enrich\x20→\x20sync\x20knowledge\x20bank\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20(--vault\x20path,\x20--dry-run,\x20--no-enrich,\x20--no-web,\x20--no-discover,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20--web-limit\x20N,\x20--target\x20cursor|claude|codex|grok|windsurf|agents|all)\x0a\x0a──\x20Design\x20spec\x20commands\x20─────────────────────────────────────\x0a\x20\x20spec\x20show\x20\x20\x20\x20\x20\x20Print\x20design_spec\x20from\x20session\x20state\x0a\x20\x20spec\x20validate\x20\x20Validate\x20a\x20DesignSpec\x20JSON\x20file\x20(--file)\x20or\x20session\x0a\x20\x20spec\x20save\x20\x20\x20\x20\x20\x20Save\x20DesignSpec\x20JSON\x20to\x20session\x20(--file\x20required)\x0a\x20\x20spec\x20template\x20\x20Print\x20empty\x20DesignSpec\x20template\x20block\x0a\x0a──\x20Session\x20commands\x20(agentic\x20orchestrator)\x20──────────────────\x0a\x20\x20session\x20init\x20\x20\x20\x20Create\x20a\x20fresh\x20session-state.json\x20for\x20this\x20project\x0a\x20\x20session\x20show\x20\x20\x20\x20Print\x20the\x20current\x20session-state.json\x0a\x20\x20session\x20reset\x20\x20\x20Delete\x20the\x20session\x20state\x20for\x20this\x20project\x20(--all\x20for\x20every\x20project)\x0a\x20\x20session\x20accept\x20\x20Mark\x20a\x20persona\x27s\x20last\x20output\x20accepted,\x20for\x20training\x20export\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20(--persona\x20<id>,\x20optional\x20--reject\x20to\x20unmark)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20Optional\x20feedback:\x20--comment,\x20--correction,\x20--rating\x201-5,\x20--tags\x20a,b\x0a\x0a──\x20Persona\x20feedback\x20commands\x20─────────────────────────────────\x0a\x20\x20feedback\x20record\x20\x20\x20Record\x20unhappiness\x20or\x20a\x20correction\x20for\x20a\x20persona\x20output\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20(--persona\x20<id>,\x20--comment,\x20--correction,\x20--rating\x201-5,\x20--tags)\x0a\x20\x20feedback\x20list\x20\x20\x20\x20\x20List\x20feedback\x20entries\x20for\x20this\x20project\x20(--all\x20for\x20every\x20project)\x0a\x20\x20feedback\x20export\x20\x20\x20Export\x20rejected\x20+\x20correction\x20JSONL\x20pairs\x20for\x20training\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20(--persona\x20<id>,\x20--all,\x20--output\x20<path>,\x20--include-positive)\x0a\x20\x20feedback\x20submit\x20\x20\x20Opt-in:\x20send\x20anonymized\x20corrections\x20to\x20community\x20store\x20(Supabase)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20(--yes\x20skip\x20prompt,\x20--dry-run\x20preview,\x20--all\x20unsent\x20across\x20projects)\x0a\x20\x20feedback\x20status\x20\x20\x20Show\x20submit\x20consent,\x20endpoint\x20config,\x20unsent\x20count\x0a\x20\x20feedback\x20revoke\x20\x20\x20Revoke\x20opt-in\x20consent\x20for\x20community\x20submit\x0a\x0a──\x20Efficiency\x20/\x20cost\x20commands\x20────────────────────────────────\x0a\x20\x20metrics\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20Print\x20the\x20last\x20run\x27s\x20cost\x20metrics\x20(--all\x20for\x20every\x20project)\x0a\x20\x20cost\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20Print\x20the\x20last\x20run\x27s\x20$\x20cost\x20from\x20config.pricing\x20(--all\x20for\x20every\x20project)\x0a\x20\x20export-training\x20\x20\x20\x20\x20Write\x20accepted-output\x20JSONL\x20pairs\x20for\x20LoRA\x20prep\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20(--persona\x20<id>,\x20--all,\x20--output\x20<path>)\x0a\x20\x20feedback\x20export\x20\x20\x20\x20\x20Write\x20rejected\x20+\x20correction\x20JSONL\x20pairs\x20(DPO\x20/\x20negative\x20examples)\x0a\x0a──\x20Research\x20commands\x20────────────────────────────────────────\x0a\x20\x20research\x20--url\x20<url>\x20\x20\x20\x20\x20\x20\x20Fetch\x20a\x20URL\x20and\x20append\x20to\x20session\x20web-context.md\x0a\x20\x20research\x20--query\x20<text>\x20\x20\x20\x20Search\x20stub\x20(or\x20provider)\x20appended\x20to\x20web-context.md\x0a\x0a──\x20Mood\x20board\x20commands\x20─────────────────────────────────────\x0a\x20\x20moodboard\x20create\x20--task\x20<text>\x20\x20\x20Build\x20a\x20mood\x20board\x20from\x20web\x20+\x20DS\x20references\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20[--url\x20<url>\x20...]\x20[--auto]\x0a\x20\x20moodboard\x20critique\x20--board\x20<id>\x20\x20Run\x20team\x20deliberation\x20over\x20a\x20board\x0a\x20\x20moodboard\x20add\x20--board\x20<id>\x20\x20\x20\x20\x20\x20\x20Add\x20a\x20user\x20reference\x20and\x20rerun\x20critique\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20[--url\x20<url>]\x20[--title\x20<t>]\x20[--desc\x20<d>]\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20[--tags\x20a,b]\x20[--note\x20<text>]\x0a\x20\x20moodboard\x20list\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20List\x20mood\x20boards\x20for\x20this\x20project\x0a\x0a──\x20Reference\x20data\x20(retrieve-on-demand)\x20───────────────────────\x0a\x20\x20retrieve\x20--file\x20<csv>\x20--column\x20<col>\x20--keywords\x20a,b\x20\x20\x20Filtered,\x20citation-ready\x20rows\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20--limit\x20N\x20\x20\x20(default\x203)\x0a\x0a──\x20Orchestrator\x20(standalone\x20runtime)\x20────────────────────────\x0a\x20\x20run\x20--task\x20<text>\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20DEFAULT\x20v2.0:\x20frontier\x20planner\x20→\x20cheap\x20chunk\x20models\x20→\x20synthesis\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20--budget\x20free\x20\x20\x20\x20only\x20zero-cost\x20models\x20(Ollama,\x20free\x20APIs)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20--budget\x20cheap\x20\x20\x20include\x20cheap\x20cloud\x20models\x20with\x20user\x20keys\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20--sequential\x20\x20\x20\x20\x20run\x20chunks\x20sequentially\x20(default)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20--max-chunks\x20N\x20\x20\x20cap\x20chunks\x20(default\x206)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20--dry-run\x20\x20\x20\x20\x20\x20\x20\x20show\x20planner\x20output\x20without\x20executing\x20chunks\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20--unchunked\x20\x20\x20\x20\x20\x20use\x20the\x20legacy\x20single-pass\x20orchestrator\x0a\x0a\x20\x20run-unchunked\x20--task\x20<text>\x20\x20Legacy\x20non-chunked\x20orchestrator\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20--continue\x20\x20\x20\x20\x20resume\x20after\x20/devi\x20fills\x20pending\x20responses\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20--lite\x20(default)\x20MoE\x20subset\x20only\x20|\x20--full\x20allow\x20full\x20chain\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20--experts\x20a,b\x20\x20\x20\x20explicit\x20override,\x20skips\x20the\x20router\x20entirely\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20--deliberate\x20\x20\x20\x20\x20adversarial\x20satisfaction\x20loops\x20(default\x20on)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20--no-deliberate\x20\x20legacy\x20sequential\x20pass-the-parcel\x20mode\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20--max-rounds\x20N\x20\x20\x20cap\x20deliberation\x20rounds\x20(default\x203)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20--satisfaction\x20X\x20satisfaction\x20threshold\x200.0-1.0\x20(default\x200.4)\x0a\x0a──\x20Devi\x20(host\x20LLM\x20—\x20no\x20API\x20keys)\x20────────────────────────────\x0a\x20\x20devi\x20status\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20List\x20pending\x20persona\x20prompts\x20awaiting\x20host\x20LLM\x20responses\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20(--run\x20path\x20to\x20a\x20specific\x20run\x20directory)\x0a\x20\x20devi\x20respond\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20Submit\x20a\x20persona\x20response\x20file\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20(--run\x20path,\x20--step\x20001-arjun,\x20--file\x20response.md)\x0a\x0a──\x20Options\x20──────────────────────────────────────────────────\x0a\x20\x20--target\x20\x20\x20Platform:\x20cursor\x20|\x20claude\x20|\x20codex\x20|\x20grok\x20|\x20windsurf\x20|\x20agents\x20|\x20all\x20\x20(default:\x20cursor)\x0a\x20\x20--force\x20\x20\x20\x20Overwrite\x20existing\x20skills\x20on\x20install\x0a\x20\x20--vault\x20\x20\x20\x20Path\x20to\x20Obsidian\x20vault\x20or\x20markdown\x20folder\x20(connect\x20command)\x0a\x20\x20--tags\x20\x20\x20\x20\x20Comma-separated\x20tags\x20to\x20filter\x20by,\x20e.g.\x20design,brand,ux\x0a\x20\x20--include\x20\x20Comma-separated\x20sub-folder\x20names\x20to\x20include,\x20e.g.\x20Design,Brand\x0a\x20\x20--project\x20\x20Project\x20id\x20override\x20for\x20session/research/run\x20commands\x20(default:\x20derived\x20from\x20cwd)\x0a\x20\x20--all\x20\x20\x20\x20\x20\x20With\x20\x22session\x20reset\x22,\x20clear\x20every\x20project\x27s\x20session\x20state\x0a\x20\x20--url\x20\x20\x20\x20\x20\x20URL\x20to\x20fetch\x20(research\x20command)\x0a\x20\x20--query\x20\x20\x20\x20Search\x20query\x20(research\x20command)\x0a\x20\x20--task\x20\x20\x20\x20\x20Task\x20description\x20(run\x20command)\x0a\x20\x20--figma\x20\x20\x20\x20Figma\x20URL\x20(run\x20command)\x0a\x20\x20--provider\x20anthropic\x20|\x20openai\x20|\x20google\x20|\x20zai\x20|\x20ollama\x20|\x20groq\x20|\x20together\x20|\x20openrouter\x20|\x20deepseek\x20|\x20host\x20(default:\x20auto)\x0a\x20\x20--model\x20\x20\x20\x20Model\x20override\x20(run\x20/\x20run-unchunked\x20command)\x0a\x20\x20--continue\x20With\x20\x22run-unchunked\x22,\x20resume\x20host-mode\x20run\x20after\x20devi\x20respond\x0a\x20\x20--dry-run\x20\x20Print\x20routing\x20+\x20chain\x20without\x20calling\x20any\x20LLM\x20(run\x20/\x20run-unchunked\x20command);\x20or\x20show\x20planner\x20output\x0a\x20\x20--lite\x20\x20\x20\x20\x20Force\x20MoE\x20subset\x20only,\x20even\x20for\x20full_screen_review\x20(run-unchunked\x20command;\x20default)\x0a\x20\x20--full\x20\x20\x20\x20\x20Allow\x20the\x20full\x20design-critic\x20chain\x20for\x20full_screen_review\x20(run-unchunked\x20command)\x0a\x20\x20--experts\x20\x20Comma-separated\x20persona\x20ids,\x20bypasses\x20the\x20router\x20entirely\x20(run-unchunked\x20command)\x0a\x20\x20--budget\x20\x20\x20free\x20|\x20cheap\x20|\x20auto\x20—\x20chunk\x20model\x20budget\x20(run\x20command;\x20default:\x20auto)\x0a\x20\x20--sequential\x20\x20Run\x20chunks\x20sequentially\x20(run\x20command;\x20default\x20on)\x0a\x20\x20--max-chunks\x20\x20Cap\x20number\x20of\x20planner\x20chunks\x20(run\x20command;\x20default\x206)\x0a\x20\x20--unchunked\x20\x20\x20Force\x20legacy\x20single-pass\x20orchestrator\x20(run\x20command)\x0a\x20\x20--output\x20\x20\x20Write\x20final\x20session-state.json\x20to\x20this\x20path\x20(run\x20/\x20run-unchunked\x20command);\x20or\x20JSONL\x20path\x20(export-training)\x0a\x20\x20--persona\x20\x20Persona\x20id\x20(session\x20accept;\x20export-training;\x20feedback\x20commands)\x0a\x20\x20--reject\x20\x20\x20With\x20\x22session\x20accept\x22,\x20mark\x20the\x20output\x20rejected\x20instead\x20of\x20accepted\x0a\x20\x20--comment\x20\x20What\x20was\x20wrong\x20or\x20what\x20you\x20liked\x20(session\x20accept\x20/\x20feedback\x20record)\x0a\x20\x20--correction\x20\x20How\x20you\x20fixed\x20it\x20or\x20what\x20you\x20wanted\x20instead\x20(session\x20accept\x20/\x20feedback\x20record)\x0a\x20\x20--rating\x20\x20\x201\x20(very\x20unhappy)\x20to\x205\x20(very\x20happy)\x20—\x20feedback\x20record\x20/\x20session\x20accept\x0a\x20\x20--include-positive\x20\x20With\x20\x22feedback\x20export\x22,\x20include\x20satisfied\x20entries\x20too\x0a\x20\x20--yes\x20\x20\x20\x20\x20\x20With\x20\x22feedback\x20submit\x22,\x20accept\x20consent\x20prompt\x20without\x20asking\x20again\x0a\x20\x20--deliberate\x20\x20With\x20\x22run\x22,\x20force\x20adversarial\x20deliberation\x20loops\x0a\x20\x20--no-deliberate\x20\x20With\x20\x22run\x22,\x20legacy\x20sequential\x20handoff\x20(no\x20objection\x20rounds)\x0a\x20\x20--max-rounds\x20\x20With\x20\x22run\x22,\x20cap\x20deliberation\x20rounds\x20(default\x203)\x0a\x20\x20--satisfaction\x20\x20With\x20\x22run\x22,\x20satisfaction\x20threshold\x200.0-1.0\x20(default\x200.4)\x0a\x20\x20--no-enrich\x20\x20With\x20\x22collect\x22,\x20write\x20draft\x20vault\x20+\x20sync\x20without\x20LLM\x20enrichment\x0a\x20\x20--no-web\x20\x20\x20\x20\x20With\x20\x22collect\x22,\x20skip\x20fetching\x20URLs\x20from\x20config/PRDs/README\x0a\x20\x20--no-discover\x20With\x20\x22collect\x22,\x20skip\x20Obsidian/vault/knowledge-graph\x20discovery\x0a\x20\x20--web-limit\x20\x20Cap\x20external\x20URLs\x20fetched\x20during\x20collect\x20(default:\x2010)\x0a\x20\x20--limit\x20\x20\x20\x20Cap\x20notes\x20enriched\x20(collect)\x20or\x20retrieve\x20rows\x20(retrieve)\x0a\x20\x20--board\x20\x20\x20\x20Mood\x20board\x20id\x20(moodboard\x20critique\x20/\x20add)\x0a\x20\x20--title\x20\x20\x20\x20Reference\x20title\x20(moodboard\x20add)\x0a\x20\x20--desc\x20\x20\x20\x20\x20Reference\x20description\x20(moodboard\x20add)\x0a\x20\x20--auto\x20\x20\x20\x20\x20With\x20moodboard\x20create,\x20discover\x20references\x20without\x20explicit\x20URLs\x0a\x20\x20--help\x20\x20\x20\x20\x20Show\x20this\x20help\x20message\x0a\x0a──\x20Examples\x20─────────────────────────────────────────────────\x0a\x20\x20npx\x20analyzthis_design\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20#\x20install\x20for\x20Cursor\x0a\x20\x20npx\x20analyzthis_design\x20--target\x20all\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20#\x20install\x20for\x20all\x20tools\x0a\x20\x20npx\x20analyzthis_design\x20welcome\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20#\x20re-print\x20getting-started\x20help\x0a\x20\x20npx\x20analyzthis_design\x20welcome\x20--target\x20claude\x0a\x0a\x20\x20npx\x20analyzthis_design\x20collect\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20#\x20Kavi:\x20scan\x20→\x20vault\x20→\x20enrich\x20→\x20sync\x0a\x20\x20npx\x20analyzthis_design\x20collect\x20--dry-run\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20#\x20preview\x20classification\x20+\x20web\x20URLs\x0a\x20\x20npx\x20analyzthis_design\x20collect\x20--no-enrich\x20--limit\x2050\x0a\x20\x20npx\x20analyzthis_design\x20collect\x20--no-web\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20#\x20skip\x20external\x20URL\x20fetch\x0a\x20\x20npx\x20analyzthis_design\x20collect\x20--vault\x20~/Documents/MyVault\x20--target\x20all\x0a\x0a\x20\x20npx\x20analyzthis_design\x20connect\x20--vault\x20~/Documents/MyVault\x0a\x20\x20npx\x20analyzthis_design\x20connect\x20--vault\x20~/docs\x20--tags\x20design,brand,product\x0a\x20\x20npx\x20analyzthis_design\x20connect\x20--vault\x20~/vault\x20--include\x20Design,Research\x0a\x20\x20npx\x20analyzthis_design\x20sync\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20#\x20sync\x20to\x20Cursor\x0a\x20\x20npx\x20analyzthis_design\x20sync\x20--target\x20all\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20#\x20sync\x20to\x20all\x20tools\x0a\x20\x20npx\x20analyzthis_design\x20status\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20#\x20show\x20sources\x0a\x20\x20npx\x20analyzthis_design\x20disconnect\x20--vault\x20~/Documents/MyVault\x0a\x0a\x20\x20npx\x20analyzthis_design\x20session\x20init\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20#\x20start\x20a\x20new\x20session\x20for\x20this\x20repo\x0a\x20\x20npx\x20analyzthis_design\x20session\x20show\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20#\x20inspect\x20current\x20session\x20state\x0a\x20\x20npx\x20analyzthis_design\x20session\x20reset\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20#\x20clear\x20session\x20state\x20for\x20this\x20repo\x0a\x0a\x20\x20npx\x20analyzthis_design\x20research\x20--url\x20https://example.com/design-tokens\x0a\x20\x20npx\x20analyzthis_design\x20research\x20--query\x20\x22EY\x20design\x20system\x20tokens\x22\x0a\x0a\x20\x20npx\x20analyzthis_design\x20moodboard\x20create\x20--task\x20\x22B2B\x20fintech\x20dashboard,\x20trustworthy,\x20high-contrast\x22\x20--auto\x0a\x20\x20npx\x20analyzthis_design\x20moodboard\x20critique\x20--board\x20<boardId>\x0a\x20\x20npx\x20analyzthis_design\x20moodboard\x20add\x20--board\x20<boardId>\x20--url\x20https://dribbble.com/shots/example\x20--title\x20\x22Alt\x20hero\x22\x20--tags\x20\x22landing,trust\x22\x0a\x0a\x20\x20npx\x20analyzthis_design\x20retrieve\x20--file\x20colors.csv\x20--column\x20\x22Product\x20Type\x22\x20--keywords\x20saas,dashboard\x0a\x20\x20npx\x20analyzthis_design\x20retrieve\x20--file\x20styles.csv\x20--column\x20\x22Best\x20For\x22\x20--keywords\x20b2b\x20--limit\x203\x0a\x0a\x20\x20npx\x20analyzthis_design\x20run\x20--task\x20\x22Fix\x20contrast\x20on\x20landing\x20page\x22\x20--dry-run\x0a\x20\x20npx\x20analyzthis_design\x20run\x20--task\x20\x22Review\x20this\x20screen\x22\x20--budget\x20free\x0a\x20\x20npx\x20analyzthis_design\x20run\x20--task\x20\x22Review\x20this\x20screen\x22\x20--budget\x20cheap\x20--sequential\x0a\x20\x20npx\x20analyzthis_design\x20run-unchunked\x20--task\x20\x22Just\x20check\x20spacing\x22\x20--experts\x20arjun\x0a\x20\x20npx\x20analyzthis_design\x20devi\x20status\x0a\x20\x20npx\x20analyzthis_design\x20devi\x20respond\x20--run\x20~/.analyzthis_design/runs/...\x20--step\x20001-arjun\x20--file\x20out.md\x0a\x20\x20npx\x20analyzthis_design\x20run-unchunked\x20--task\x20\x22Review\x20this\x20screen\x22\x20--provider\x20anthropic\x0a\x0a\x20\x20npx\x20analyzthis_design\x20session\x20accept\x20--persona\x20arjun\x0a\x20\x20npx\x20analyzthis_design\x20session\x20accept\x20--persona\x20arjun\x20--reject\x20\x5c\x0a\x20\x20\x20\x20--comment\x20\x22Invented\x20tokens\x20not\x20in\x20our\x20DS\x22\x20\x5c\x0a\x20\x20\x20\x20--correction\x20\x22Use\x20--color-primary\x20and\x20spacing-4\x20from\x20tokens.css\x22\x20\x5c\x0a\x20\x20\x20\x20--rating\x202\x20--tags\x20invented_tokens,missed_ds\x0a\x20\x20npx\x20analyzthis_design\x20feedback\x20record\x20--persona\x20arjun\x20--rating\x202\x20--comment\x20\x22...\x22\x20--correction\x20\x22...\x22\x0a\x20\x20npx\x20analyzthis_design\x20feedback\x20list\x0a\x20\x20npx\x20analyzthis_design\x20feedback\x20export\x20--persona\x20arjun\x20--all\x0a\x20\x20npx\x20analyzthis_design\x20feedback\x20submit\x20--dry-run\x0a\x20\x20npx\x20analyzthis_design\x20feedback\x20submit\x20--all\x20--yes\x0a\x20\x20npx\x20analyzthis_design\x20feedback\x20status\x0a\x20\x20npx\x20analyzthis_design\x20metrics\x0a\x20\x20npx\x20analyzthis_design\x20cost\x0a\x20\x20npx\x20analyzthis_design\x20export-training\x20--persona\x20arjun\x20--all\x0a\x0a──\x20Install\x20paths\x20────────────────────────────────────────────\x0a\x20\x20Cursor\x20\x20\x20\x20\x20→\x20~/.cursor/skills/\x0a\x20\x20Claude\x20\x20\x20\x20\x20→\x20~/.claude/skills/\x20(+\x20legacy\x20~/.claude/commands/)\x0a\x20\x20Codex\x20\x20\x20\x20\x20\x20→\x20~/.codex/skills/\x0a\x20\x20Grok\x20\x20\x20\x20\x20\x20\x20→\x20~/.grok/skills/\x0a\x20\x20Windsurf\x20\x20\x20→\x20~/.codeium/windsurf/skills/\x0a\x20\x20agents\x20\x20\x20\x20\x20→\x20~/.agents/skills/\x20\x20(cross-tool\x20discovery)\x0a\x0a──\x20Knowledge\x20bank\x20config\x20────────────────────────────────────\x0a\x20\x20Config\x20\x20→\x20~/.analyzthis_design/config.json\x0a\x0aDocs:\x20https://github.com/rishikeshjoshi/analyzthis_design\x0a',[,,cmd,...flags]=process['argv'];function getFlag(a){const c=flags['find'](g=>g['startsWith']('--'+a+'='));if(c)return c['split']('=')['slice'](0x1)['join']('=');const f=flags['indexOf']('--'+a);if(f!==-0x1&&flags[f+0x1]&&!flags[f+0x1]['startsWith']('--'))return flags[f+0x1];return null;}function parseFeedbackTags(a){if(!a)return[];return a['split'](',')['map'](c=>c['trim']()['toLowerCase']())['filter'](Boolean);}const force=flags['includes']('--force'),targetVal=getFlag('target')||'cursor',vaultVal=getFlag('vault'),tagsVal=getFlag('tags'),includeVal=getFlag('include'),projectVal=getFlag('project'),allFlag=flags['includes']('--all'),urlVal=getFlag('url'),queryVal=getFlag('query'),taskVal=getFlag('task'),figmaVal=getFlag('figma'),providerVal=getFlag('provider'),modelVal=getFlag('model'),outputVal=getFlag('output'),dryRunFlag=flags['includes']('--dry-run'),liteFlag=flags['includes']('--lite'),fullFlag=flags['includes']('--full'),expertsVal=getFlag('experts'),fileVal=getFlag('file'),columnVal=getFlag('column'),keywordsVal=getFlag('keywords'),limitVal=getFlag('limit'),personaVal=getFlag('persona'),rejectFlag=flags['includes']('--reject'),commentVal=getFlag('comment'),correctionVal=getFlag('correction'),ratingVal=getFlag('rating'),includePositiveFlag=flags['includes']('--include-positive'),yesFlag=flags['includes']('--yes'),deliberateFlag=flags['includes']('--deliberate'),noDeliberateFlag=flags['includes']('--no-deliberate'),maxRoundsVal=getFlag('max-rounds'),satisfactionVal=getFlag('satisfaction'),continueFlag=flags['includes']('--continue'),runDirVal=getFlag('run'),stepVal=getFlag('step'),noEnrichFlag=flags['includes']('--no-enrich'),noWebFlag=flags['includes']('--no-web'),noDiscoverFlag=flags['includes']('--no-discover'),webLimitVal=getFlag('web-limit'),boardVal=getFlag('board'),titleVal=getFlag('title'),descVal=getFlag('desc'),autoFlag=flags['includes']('--auto'),budgetVal=getFlag('budget'),sequentialFlag=flags['includes']('--sequential'),maxChunksVal=getFlag('max-chunks'),unchunkedFlag=flags['includes']('--unchunked');switch(cmd){case undefined:case'install':install({'force':force,'target':targetVal});break;case'remove':case'uninstall':remove({'target':targetVal});break;case'welcome':{const targets=resolveTargets(targetVal)||['cursor'];for(const tId of targets)printWelcomeBanner(tId);break;}case'list':{const {TARGETS}=require('../lib/platforms'),targets=resolveTargets(targetVal);!targets&&(console['error']('\x0a\x20\x20✗\x20\x20Unknown\x20target\x20\x22'+targetVal+'\x22.\x20Choose:\x20'+ALL_TARGET_IDS['join'](',\x20')+',\x20all\x0a'),process['exit'](0x1));for(const tId of targets){const t=TARGETS[tId];console['log']('\x0aInstalled\x20Analyzthis_Design\x20skills\x20['+t['label']+']\x20('+t['root']+'):\x0a');for(const skill of SKILLS){const asDir=path['join'](t['root'],skill),asFile=path['join'](t['root'],skill+'.md');let exists=fs['existsSync'](asDir)||fs['existsSync'](asFile);!exists&&t['also']&&(exists=fs['existsSync'](path['join'](t['also']['root'],skill))||fs['existsSync'](path['join'](t['also']['root'],skill+'.md'))),console['log']('\x20\x20'+(exists?'✅':'✗\x20')+'\x20'+skill);}}console['log']('');break;}case'connect':{!vaultVal&&(console['error']('\x0a\x20\x20✗\x20\x20--vault\x20is\x20required.\x20\x20Example:\x20npx\x20analyzthis_design\x20connect\x20--vault\x20~/Documents/MyVault\x0a'),process['exit'](0x1));try{const tags=tagsVal?tagsVal['split'](',')['map'](a=>a['trim']()):[],include=includeVal?includeVal['split'](',')['map'](a=>a['trim']()):[],abs=connect({'vaultPath':vaultVal,'tags':tags,'include':include});console['log']('\x0a✅\x20Connected:\x20'+abs);if(tags['length'])console['log']('\x20\x20\x20Tags\x20filter:\x20\x20\x20\x20'+tags['join'](',\x20'));if(include['length'])console['log']('\x20\x20\x20Folder\x20filter:\x20\x20'+include['join'](',\x20'));console['log']('\x0a\x20\x20\x20Run\x20\x22npx\x20analyzthis_design\x20sync\x22\x20to\x20build\x20the\x20knowledge\x20bank.\x0a');}catch(h){console['error']('\x0a\x20\x20✗\x20\x20'+h['message']+'\x0a'),process['exit'](0x1);}break;}case'disconnect':{!vaultVal&&(console['error']('\x0a\x20\x20✗\x20\x20--vault\x20is\x20required.\x20\x20Example:\x20npx\x20analyzthis_design\x20disconnect\x20--vault\x20~/Documents/MyVault\x0a'),process['exit'](0x1));disconnect(vaultVal),console['log']('\x0a🗑\x20\x20Disconnected:\x20'+path['resolve'](vaultVal)+'\x0a');break;}case'sync':{const {resolveTargets,ALL_TARGET_IDS}=require('../lib/platforms'),targets=resolveTargets(targetVal);!targets&&(console['error']('\x0a\x20\x20✗\x20\x20Unknown\x20target\x20\x22'+targetVal+'\x22.\x20Choose:\x20'+ALL_TARGET_IDS['join'](',\x20')+',\x20all\x0a'),process['exit'](0x1));console['log']('\x0a⏳\x20Syncing\x20knowledge\x20bank...\x0a');try{const result=sync({'targets':targets});if(result['message'])console['log']('\x20\x20⚠\x20\x20'+result['message']+'\x0a');else{console['log']('✅\x20Synced\x20'+result['synced']+'\x20note(s)\x20into\x20the\x20knowledge\x20bank.');for(const t of result['copiedTo'])console['log']('\x20\x20\x20•\x20'+t);console['log']('\x0a💡\x20The\x20knowledge\x20bank\x20is\x20now\x20active.\x20All\x20personas\x20will\x20read\x20it\x20first.\x0a');}}catch(i){console['error']('\x0a\x20\x20✗\x20\x20Sync\x20failed:\x20'+i['message']+'\x0a'),process['exit'](0x1);}break;}case'status':{const cfg=status();if(!cfg['sources']||cfg['sources']['length']===0x0)console['log']('\x0a\x20\x20No\x20knowledge\x20sources\x20connected.\x0a\x20\x20Run:\x20npx\x20analyzthis_design\x20connect\x20--vault\x20/path/to/vault\x0a');else{console['log']('\x0a📚\x20Knowledge\x20bank\x20sources\x20('+cfg['sources']['length']+'):\x0a');for(const s of cfg['sources']){console['log']('\x20\x20•\x20'+s['path']);if(s['tags']['length'])console['log']('\x20\x20\x20\x20Tags:\x20\x20\x20\x20'+s['tags']['join'](',\x20'));if(s['include']['length'])console['log']('\x20\x20\x20\x20Folders:\x20'+s['include']['join'](',\x20'));console['log']('\x20\x20\x20\x20Added:\x20\x20\x20'+s['addedAt']);}if(cfg['lastSync'])console['log']('\x0a\x20\x20Last\x20sync:\x20'+cfg['lastSync']);console['log']('');}break;}case'session':{const sub=flags['find'](a=>!a['startsWith']('--'));switch(sub){case'init':{const {projectId,filePath}=session['init']({'project':projectVal});console['log']('\x0a✅\x20Session\x20initialized\x20for\x20project\x20\x22'+projectId+'\x22'),console['log']('\x20\x20\x20'+filePath+'\x0a');break;}case'show':{const state=session['show']({'project':projectVal});!state?console['log']('\x0a\x20\x20No\x20session\x20found.\x20Run:\x20npx\x20analyzthis_design\x20session\x20init\x0a'):console['log'](JSON['stringify'](state,null,0x2));break;}case'reset':{const result=session['reset']({'project':projectVal,'all':allFlag});console['log']('\x0a🗑\x20\x20Session\x20reset:\x20'+result['removed']+'\x0a');break;}case'accept':{!personaVal&&(console['error']('\x0a\x20\x20✗\x20\x20--persona\x20is\x20required.\x20\x20Example:\x20npx\x20analyzthis_design\x20session\x20accept\x20--persona\x20arjun\x0a'),process['exit'](0x1));if(commentVal||correctionVal||ratingVal)try{const fb=feedback['recordFeedback']({'project':projectVal,'persona':personaVal,'satisfied':!rejectFlag,'rating':ratingVal!=null?Number(ratingVal):undefined,'comment':commentVal||'','correction':correctionVal||'','tags':parseFeedbackTags(tagsVal),'markRejected':!![]});console['log']('\x0a✅\x20Marked\x20\x22'+personaVal+'\x22\x20as\x20'+(rejectFlag?'rejected':'accepted')+'\x20with\x20feedback\x20('+fb['entry']['id']+').\x0a');}catch(j){console['error']('\x0a\x20\x20✗\x20\x20'+j['message']+'\x0a'),process['exit'](0x1);}else{const result=session['markAccepted']({'project':projectVal,'persona':personaVal,'accepted':!rejectFlag});!result['updated']?console['log']('\x0a\x20\x20⚠\x20\x20'+result['reason']+'\x0a'):console['log']('\x0a✅\x20Marked\x20\x22'+personaVal+'\x22\x20output\x20as\x20'+(rejectFlag?'rejected':'accepted')+'.\x0a');}break;}default:console['error']('\x0aUnknown\x20session\x20subcommand:\x20\x22'+(sub||'')+'\x22.\x20Use:\x20init\x20|\x20show\x20|\x20reset\x20|\x20accept\x0a'),process['exit'](0x1);}break;}case'spec':{const sub=flags[0x0]||'show';if(sub==='template'){console['log']('\x0a'+designSpec['templateMarkdown']()+'\x0a');break;}if(sub==='show'){const row=designSpec['showFromSession']({'project':projectVal});if(!row){console['log']('\x0a\x20\x20No\x20design_spec\x20in\x20session.\x20Run\x20/design-director\x20or\x20/ux-ideator\x20Phase\x207\x20first.\x0a');break;}console['log']('\x0a──\x20design_spec\x20──────────────────────────────────────'),console['log'](JSON['stringify'](row['design_spec'],null,0x2)),console['log']('');break;}if(sub==='save'){!fileVal&&(console['error']('\x0a\x20\x20✗\x20\x20spec\x20save\x20requires\x20--file\x20<path.json>\x0a'),process['exit'](0x1));try{const raw=fs['readFileSync'](path['resolve'](fileVal),'utf8'),spec=JSON['parse'](raw),validation=designSpec['validateDesignSpec'](spec);if(!validation['valid']){console['log']('\x0a✗\x20\x20Cannot\x20save\x20invalid\x20spec:\x0a');for(const e of validation['errors'])console['log']('\x20\x20\x20•\x20'+e);console['log'](''),process['exit'](0x1);}const saved=designSpec['saveToSession'](spec,{'project':projectVal,'merge':![]});console['log']('\x0a✅\x20Saved\x20design_spec\x20to\x20session\x20('+saved['projectId']+')\x0a');}catch(l){console['error']('\x0a\x20\x20✗\x20\x20'+l['message']+'\x0a'),process['exit'](0x1);}break;}if(sub==='validate'){try{let result;if(fileVal)result=designSpec['validateFile'](fileVal);else{const row=designSpec['showFromSession']({'project':projectVal});!row&&(console['error']('\x0a\x20\x20✗\x20\x20No\x20design_spec\x20in\x20session\x20and\x20no\x20--file\x20provided.\x0a'),process['exit'](0x1)),result={'spec':row['design_spec'],...designSpec['validateDesignSpec'](row['design_spec'])};}if(result['valid'])console['log']('\x0a✅\x20DesignSpec\x20is\x20valid.\x0a'),result['spec']&&!fileVal&&console['log']('\x20\x20\x20status:\x20'+result['spec']['status']+'\x20|\x20screen:\x20'+result['spec']['screen_name']+'\x0a');else{console['log']('\x0a✗\x20\x20DesignSpec\x20validation\x20failed:\x0a');for(const e of result['errors'])console['log']('\x20\x20\x20•\x20'+e);console['log'](''),process['exit'](0x1);}}catch(n){console['error']('\x0a\x20\x20✗\x20\x20'+n['message']+'\x0a'),process['exit'](0x1);}break;}console['error']('\x0a\x20\x20✗\x20\x20Unknown\x20spec\x20subcommand.\x20Use:\x20spec\x20show\x20|\x20validate\x20|\x20save\x20|\x20template\x0a'),process['exit'](0x1);}case'collect':{collect({'project':projectVal,'vault':vaultVal||undefined,'dryRun':dryRunFlag,'enrich':!noEnrichFlag,'web':!noWebFlag,'discoverSources':!noDiscoverFlag,'webLimit':webLimitVal?parseInt(webLimitVal,0xa):null,'limit':limitVal?parseInt(limitVal,0xa):null,'target':targetVal,'provider':providerVal,'model':modelVal})['catch'](a=>{console['error']('\x0a\x20\x20✗\x20\x20Collect\x20failed:\x20'+a['message']+'\x0a'),process['exit'](0x1);});break;}case'research':{((async()=>{try{if(urlVal){console['log']('\x0a⏳\x20Fetching\x20'+urlVal+'...\x0a');const a=await research['researchUrl']({'url':urlVal,'project':projectVal});console['log']('✅\x20Wrote\x20'+a['chars']+'\x20chars\x20to\x20'+a['filePath']+'\x0a');}else{if(queryVal){console['log']('\x0a⏳\x20Researching\x20\x22'+queryVal+'\x22...\x0a');const c=await research['researchQuery']({'query':queryVal,'project':projectVal});c['mode']==='stub'?(console['log']('⚠\x20\x20No\x20research.provider\x20configured\x20—\x20wrote\x20a\x20stub\x20for\x20the\x20host\x20IDE\x20to\x20fill.'),console['log']('\x20\x20\x20'+c['filePath']),console['log']('\x20\x20\x20Tip:\x20set\x20research.provider\x20in\x20~/.analyzthis_design/config.json,\x20or\x20use\x20WebSearch\x20in\x20Cursor.\x0a')):console['log']('✅\x20Wrote\x20'+c['chars']+'\x20chars\x20to\x20'+c['filePath']+'\x0a');}else console['error']('\x0a\x20\x20✗\x20\x20Provide\x20--url\x20<url>\x20or\x20--query\x20<text>\x0a'),process['exit'](0x1);}}catch(f){console['error']('\x0a\x20\x20✗\x20\x20Research\x20failed:\x20'+f['message']+'\x0a'),process['exit'](0x1);}})());break;}case'moodboard':{const msub=flags['find'](a=>!a['startsWith']('--'))||'create';if(msub==='create'){!taskVal&&(console['error']('\x0a\x20\x20✗\x20\x20--task\x20is\x20required.\x20\x20Example:\x20npx\x20analyzthis_design\x20moodboard\x20create\x20--task\x20\x22B2B\x20fintech\x20dashboard\x22\x20--auto\x0a'),process['exit'](0x1));((async()=>{try{const a=[],c=flags['filter'](g=>g['startsWith']('--url='))['map'](g=>g['split']('=')['slice'](0x1)['join']('='));for(let g=0x0;g<flags['length'];g++){if(flags[g]==='--url'&&flags[g+0x1]&&!flags[g+0x1]['startsWith']('--'))a['push'](flags[g+0x1]);}for(const o of c)if(a['indexOf'](o)===-0x1)a['push'](o);const f=await moodboard['buildMoodBoard']({'project':projectVal,'task':taskVal,'urls':a,'discover':autoFlag||a['length']>0x0,'dryRun':dryRunFlag});console['log']('\x0a✅\x20Mood\x20board\x20created:\x20'+f['board']['board_id']),console['log']('\x20\x20\x20References:\x20'+f['board']['references']['length']),console['log']('\x20\x20\x20Board\x20dir:\x20\x20'+f['boardDir']),console['log']('\x20\x20\x20Workspace:\x20\x20'+f['workspacePath']+'\x0a'),dryRunFlag&&(console['log'](JSON['stringify'](f['board'],null,0x2)['slice'](0x0,0x7d0)),console['log'](''));}catch(q){console['error']('\x0a\x20\x20✗\x20\x20Mood\x20board\x20create\x20failed:\x20'+q['message']+'\x0a'),process['exit'](0x1);}})());break;}if(msub==='critique'){!boardVal&&(console['error']('\x0a\x20\x20✗\x20\x20--board\x20is\x20required.\x20\x20Example:\x20npx\x20analyzthis_design\x20moodboard\x20critique\x20--board\x20<id>\x0a'),process['exit'](0x1));((async()=>{try{const a=await moodboard['critiqueMoodBoard']({'project':projectVal,'boardId':boardVal,'provider':providerVal,'model':modelVal,'dryRun':dryRunFlag,'noDeliberate':noDeliberateFlag,'maxRounds':maxRoundsVal,'satisfaction':satisfactionVal});console['log']('\x0a✅\x20Mood\x20board\x20critique\x20complete:\x20'+a['board']['board_id']),console['log']('\x20\x20\x20Verdict:\x20'+(a['board']['synthesis']?.['verdict']||'n/a')),console['log']('\x20\x20\x20Rounds:\x20\x20'+(a['board']['deliberation']?.['round']||0x0)),console['log']('\x20\x20\x20Board:\x20\x20\x20'+(a['boardDir']||path['join'](session['sessionDir'](projectVal||session['getProjectId']()),'moodboard',boardVal))),console['log']('\x20\x20\x20Workspace:\x20'+a['workspacePath']+'\x0a');}catch(c){c['name']==='HostLlmPendingError'&&(hostLlm['printDeviInstructions'](c),process['exit'](0x2)),console['error']('\x0a\x20\x20✗\x20\x20Mood\x20board\x20critique\x20failed:\x20'+c['message']+'\x0a'),process['exit'](0x1);}})());break;}if(msub==='add'){!boardVal&&(console['error']('\x0a\x20\x20✗\x20\x20--board\x20is\x20required.\x20\x20Example:\x20npx\x20analyzthis_design\x20moodboard\x20add\x20--board\x20<id>\x20--url\x20<url>\x0a'),process['exit'](0x1));((async()=>{try{const a=tagsVal?tagsVal['split'](',')['map'](f=>f['trim']())['filter'](Boolean):[],c=await moodboard['addUserReferenceAndRerun']({'project':projectVal,'boardId':boardVal,'reference':{'url':urlVal||'','title':titleVal||'','description':descVal||'','tags':a,'note':commentVal||''},'provider':providerVal,'model':modelVal,'dryRun':dryRunFlag,'noDeliberate':noDeliberateFlag,'maxRounds':maxRoundsVal,'satisfaction':satisfactionVal});console['log']('\x0a✅\x20Added\x20reference\x20to\x20board\x20'+c['board']['board_id']+':\x20'+c['added']['id']),console['log']('\x20\x20\x20Total\x20references:\x20'+c['board']['references']['length']),console['log']('\x20\x20\x20Verdict:\x20'+(c['board']['synthesis']?.['verdict']||'n/a')+'\x0a');}catch(f){f['name']==='HostLlmPendingError'&&(hostLlm['printDeviInstructions'](f),process['exit'](0x2)),console['error']('\x0a\x20\x20✗\x20\x20Mood\x20board\x20add\x20failed:\x20'+f['message']+'\x0a'),process['exit'](0x1);}})());break;}if(msub==='list'){const boards=moodboard['listBoards'](projectVal);if(!boards['length'])console['log']('\x0a\x20\x20No\x20mood\x20boards\x20found\x20for\x20this\x20project.\x0a');else{console['log']('\x0a──\x20Mood\x20boards\x20('+boards['length']+')\x20──');for(const b of boards)console['log']('\x20\x20•\x20'+b);console['log']('');}break;}console['error']('\x0a\x20\x20Unknown\x20moodboard\x20subcommand.\x20Use:\x20create\x20|\x20critique\x20|\x20add\x20|\x20list\x0a'),process['exit'](0x1);}case'retrieve':{!fileVal&&(console['error']('\x0a\x20\x20✗\x20\x20--file\x20is\x20required.\x20\x20Example:\x20npx\x20analyzthis_design\x20retrieve\x20--file\x20colors.csv\x20--column\x20\x22Product\x20Type\x22\x20--keywords\x20saas\x0a'),process['exit'](0x1));try{const keywords=keywordsVal?keywordsVal['split'](',')['map'](a=>a['trim']())['filter'](Boolean):[],filters=columnVal&&keywords['length']?[{'column':columnVal,'anyOf':keywords}]:[],limit=limitVal?parseInt(limitVal,0xa):0x3,result=retrieve['retrieve']({'file':fileVal,'filters':filters,'limit':limit});if(!result['rows']['length'])console['log']('\x0a\x20\x20No\x20rows\x20matched\x20in\x20'+fileVal+(columnVal?'\x20for\x20column\x20\x22'+columnVal+'\x22':'')+(keywords['length']?'\x20with\x20keywords:\x20'+keywords['join'](',\x20'):'')+'.\x0a');else{console['log']('\x0a📋\x20'+result['rows']['length']+'/'+result['matched']+'\x20matching\x20row(s)\x20in\x20'+fileVal+(result['cacheHit']?'\x20(cache\x20hit)':'')+':\x0a');for(const row of result['rows']){console['log']('\x20\x20Row\x20'+row['__no']+':');for(const [k,v]of Object['entries'](row)){if(k['startsWith']('__')||!v)continue;console['log']('\x20\x20\x20\x20'+k+':\x20'+v);}console['log']('');}if(columnVal)console['log']('\x20\x20Citation\x20format:\x20['+fileVal+',\x20row\x20N:\x20\x22'+columnVal+'\x20value\x22]\x0a');}}catch(r){console['error']('\x0a\x20\x20✗\x20\x20'+r['message']+'\x0a'),process['exit'](0x1);}break;}case'run':{!taskVal&&(console['error']('\x0a\x20\x20✗\x20\x20--task\x20is\x20required.\x20\x20Example:\x20npx\x20analyzthis_design\x20run\x20--task\x20\x22Review\x20onboarding\x20flow\x22\x20--budget\x20free\x0a'),process['exit'](0x1));((async()=>{try{const a=await orchestratorRun({'task':taskVal,'figma':figmaVal||'','project':projectVal,'provider':providerVal,'model':modelVal,'dryRun':dryRunFlag,'budget':budgetVal||'auto','sequential':sequentialFlag||!flags['includes']('--parallel'),'maxChunks':maxChunksVal?parseInt(maxChunksVal,0xa):null,'unchunked':unchunkedFlag,'output':outputVal,'continueRun':continueFlag});if(dryRunFlag){console['log']('\x0a──\x20Chunk\x20plan\x20(dry\x20run)\x20──'),console['log'](JSON['stringify'](a['plan']||a,null,0x2)['slice'](0x0,0xbb8)),console['log']('');return;}if(a['mode']==='host_pending'||a['host_pending']){const c=a['host_pending'];console['log']('\x0a╔══════════════════════════════════════════════════════════════════════╗'),console['log']('║\x20\x20DEVI\x20—\x20Host\x20LLM\x20pending\x20(chunk\x20planner)\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20║'),console['log']('╚══════════════════════════════════════════════════════════════════════╝\x0a'),console['log']('\x20\x20Step:\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20'+c['step_id']),console['log']('\x20\x20Prompt\x20file:\x20\x20\x20\x20\x20\x20'+path['join'](c['run_dir'],'pending',c['step_id']+'.json')),console['log']('\x20\x20Run\x20directory:\x20\x20\x20\x20'+c['run_dir']),console['log']('\x0a\x20\x20In\x20Cursor,\x20invoke:\x20\x20/devi'),console['log']('\x20\x20Or\x20submit\x20response:'),console['log']('\x20\x20\x20\x20npx\x20analyzthis_design\x20devi\x20respond\x20--run\x20'+c['run_dir']+'\x20--step\x20'+c['step_id']+'\x20--file\x20response.md'),console['log']('\x20\x20Then\x20continue:'),console['log']('\x20\x20\x20\x20npx\x20analyzthis_design\x20run\x20--continue\x20--task\x20\x22'+taskVal+'\x22\x0a'),process['exit'](0x2);return;}}catch(f){f['name']==='HostLlmPendingError'&&(hostLlm['printDeviInstructions'](f),process['exit'](0x2)),console['error']('\x0a\x20\x20✗\x20\x20Run\x20failed:\x20'+f['message']+'\x0a'),process['exit'](0x1);}})());break;}case'run-unchunked':{let runTask=taskVal;if(!runTask&&continueFlag){const st=session['show']({'project':projectVal});runTask=st?.['host_run']?.['task']||hostLlm['loadManifest'](st?.['host_run']?.['run_dir']||'')?.['task']||st?.['digest']?.['task_map_summary'];}!runTask&&(console['error']('\x0a\x20\x20✗\x20\x20--task\x20is\x20required.\x20\x20Example:\x20npx\x20analyzthis_design\x20run-unchunked\x20--task\x20\x22Fix\x20contrast\x22\x20--dry-run\x0a'),process['exit'](0x1));orchestratorRun({'task':runTask,'figma':figmaVal||'','provider':providerVal,'model':modelVal,'dryRun':dryRunFlag,'lite':liteFlag,'full':fullFlag,'deliberate':deliberateFlag?!![]:null,'noDeliberate':noDeliberateFlag,'maxRounds':maxRoundsVal,'satisfaction':satisfactionVal,'continueRun':continueFlag,'experts':expertsVal?expertsVal['split'](',')['map'](a=>a['trim']())['filter'](Boolean):null,'project':projectVal,'output':outputVal,'unchunked':!![]})['catch'](a=>{if(a['name']==='HostLlmPendingError')process['exit'](0x2);console['error']('\x0a\x20\x20✗\x20\x20Run\x20failed:\x20'+a['message']+'\x0a'),process['exit'](0x1);});break;}case'devi':{const sub=flags[0x0];if(sub==='status'){let runDir=runDirVal;if(!runDir){const st=session['show']({'project':projectVal});runDir=st?.['host_run']?.['run_dir']||hostLlm['findLatestRun'](st?.['project_id']||session['getProjectId']())?.['runDir'];}if(!runDir||!fs['existsSync'](runDir)){console['log']('\x0a\x20\x20No\x20host\x20run\x20found.\x20Start\x20one:\x20npx\x20analyzthis_design\x20run\x20--task\x20\x22...\x22\x20--full\x0a');break;}const pending=hostLlm['listPending'](runDir);console['log']('\x0a📋\x20Devi\x20—\x20host\x20run:\x20'+runDir+'\x0a');for(const p of pending){console['log']('\x20\x20'+(p['hasResponse']?'✅':'⏳')+'\x20'+p['stepId']+'\x20('+p['personaId']+')');}const waiting=pending['filter'](a=>!a['hasResponse']);waiting['length']?console['log']('\x0a\x20\x20'+waiting['length']+'\x20pending\x20—\x20invoke\x20/devi\x20in\x20Cursor\x20or\x20devi\x20respond\x20for\x20each\x20step.\x0a'):console['log']('\x0a\x20\x20All\x20responses\x20present\x20—\x20run:\x20npx\x20analyzthis_design\x20run\x20--continue\x20--task\x20\x22...\x22\x0a');break;}if(sub==='respond'){(!runDirVal||!stepVal||!fileVal)&&(console['error']('\x0a\x20\x20✗\x20\x20devi\x20respond\x20requires\x20--run,\x20--step,\x20and\x20--file\x0a'),process['exit'](0x1));const text=fs['readFileSync'](path['resolve'](fileVal),'utf8');hostLlm['submitResponse'](path['resolve'](runDirVal),stepVal,text),console['log']('\x0a✅\x20Wrote\x20response\x20for\x20'+stepVal+'\x0a');break;}console['log']('\x0a\x20\x20Usage:\x20devi\x20status\x20|\x20devi\x20respond\x20--run\x20<dir>\x20--step\x20<id>\x20--file\x20<path>\x0a');break;}case'metrics':{const projectIds=allFlag?session['listProjects']():[projectVal||session['getProjectId']()];if(!projectIds['length']){console['log']('\x0a\x20\x20No\x20sessions\x20found.\x0a');break;}console['log']('\x0a📊\x20Last-run\x20metrics\x0a');for(const projectId of projectIds){const state=session['show']({'project':projectId});if(!state)continue;const m=state['metrics']||{};console['log']('\x20\x20'+projectId),console['log']('\x20\x20\x20\x20mode:\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20'+(m['mode']??'n/a')),console['log']('\x20\x20\x20\x20llm_calls:\x20\x20\x20\x20\x20\x20\x20\x20\x20'+(m['llm_calls']??0x0)),console['log']('\x20\x20\x20\x20experts_run:\x20\x20\x20\x20\x20\x20\x20'+((m['experts_run']||[])['join'](',\x20')||'none')),console['log']('\x20\x20\x20\x20input_tokens_est:\x20\x20'+(m['input_tokens_est']??0x0)),console['log']('\x20\x20\x20\x20output_tokens_est:\x20'+(m['output_tokens_est']??0x0)),console['log']('\x20\x20\x20\x20cache_hits:\x20\x20\x20\x20\x20\x20\x20\x20'+(m['cache_hits']??0x0)),console['log']('\x20\x20\x20\x20deliberation_rounds:\x20'+(m['deliberation_rounds']??0x0)),console['log']('\x20\x20\x20\x20objections_raised:\x20'+(m['objections_raised']??0x0)),console['log']('\x20\x20\x20\x20objections_resolved:\x20'+(m['objections_resolved']??0x0)),console['log']('\x20\x20\x20\x20raj_escalations:\x20\x20\x20'+(m['raj_escalations']??0x0));const d=state['deliberation'];d?.['mode']&&console['log']('\x20\x20\x20\x20deliberation_mode:\x20'+d['mode']+',\x20consensus='+d['consensus_reached']),console['log']('');}break;}case'cost':{cost['report']({'project':projectVal,'all':allFlag});break;}case'feedback':{const sub=flags[0x0]||'record';if(sub==='record'){!personaVal&&(console['error']('\x0a\x20\x20✗\x20\x20--persona\x20is\x20required.\x0a'),console['error']('\x20\x20Example:\x20npx\x20analyzthis_design\x20feedback\x20record\x20--persona\x20arjun\x20--rating\x202\x20\x5c\x0a'),console['error']('\x20\x20\x20\x20--comment\x20\x22Invented\x20tokens\x22\x20--correction\x20\x22Use\x20tokens.css\x20primary\x20+\x20spacing-4\x22\x0a'),process['exit'](0x1));const ratingNum=ratingVal!=null?Number(ratingVal):undefined,satisfied=ratingNum!=null?ratingNum>=0x4:![];try{const result=feedback['recordFeedback']({'project':projectVal,'persona':personaVal,'satisfied':satisfied,'rating':ratingNum,'comment':commentVal||'','correction':correctionVal||'','tags':parseFeedbackTags(tagsVal),'markRejected':!satisfied});console['log']('\x0a📝\x20Feedback\x20recorded\x20for\x20\x22'+personaVal+'\x22\x20('+result['entry']['id']+').'),console['log']('\x20\x20\x20Global\x20log:\x20'+result['globalFile']+'\x0a');}catch(u){console['error']('\x0a\x20\x20✗\x20\x20'+u['message']+'\x0a'),process['exit'](0x1);}break;}if(sub==='list'){const items=feedback['listFeedback']({'project':projectVal,'all':allFlag});if(!items['length']){console['log']('\x0a\x20\x20No\x20feedback\x20entries\x20yet.\x0a'),console['log']('\x20\x20Record\x20one:\x20npx\x20analyzthis_design\x20feedback\x20record\x20--persona\x20arjun\x20--rating\x202\x20--comment\x20\x22...\x22\x0a');break;}console['log']('\x0a──\x20Feedback\x20('+items['length']+')\x20───────────────────────────────');for(const e of items){const mood=e['satisfied']?'✅':'⚠️',rating=e['rating']!=null?'\x20rating='+e['rating']:'',tags=e['tags']?.['length']?'\x20['+e['tags']['join'](',\x20')+']':'',sent=e['submitted_at']?'\x20📤':'';console['log'](mood+'\x20'+e['at']+'\x20\x20'+e['persona']+rating+tags+sent);if(e['comment'])console['log']('\x20\x20\x20comment:\x20'+e['comment']['slice'](0x0,0x78)+(e['comment']['length']>0x78?'…':''));if(e['correction'])console['log']('\x20\x20\x20correction:\x20'+e['correction']['slice'](0x0,0x78)+(e['correction']['length']>0x78?'…':''));}console['log']('');break;}if(sub==='export'){try{const result=feedback['exportCorrections']({'persona':personaVal,'project':projectVal,'all':allFlag,'output':outputVal,'includePositive':includePositiveFlag});console['log']('\x0a✅\x20Wrote\x20'+result['pairs']+'\x20correction\x20pair(s)\x20to\x20'+result['filePath']),!result['pairs']&&(console['log']('\x20\x20\x20No\x20entries\x20with\x20comment/correction\x20found.\x20Record\x20feedback\x20first.'),console['log']('\x20\x20\x20Tags\x20hint:\x20'+feedback['ISSUE_TAG_HINTS']['slice'](0x0,0x6)['join'](',\x20')+',\x20…')),console['log']('');}catch(w){console['error']('\x0a\x20\x20✗\x20\x20'+w['message']+'\x0a'),process['exit'](0x1);}break;}if(sub==='submit'){((async()=>{try{const a=await feedbackSubmit['submitFeedback']({'project':projectVal,'all':allFlag,'persona':personaVal,'includePositive':includePositiveFlag,'dryRun':dryRunFlag,'yes':yesFlag,'limit':limitVal});a['cancelled']&&(console['log']('\x0a\x20\x20'+a['message']+'\x0a'),process['exit'](0x0));if(a['dryRun']&&a['payloads']){console['log']('\x0a──\x20Dry\x20run:\x20'+a['payloads']['length']+'\x20row(s)\x20─────────────────'),console['log']('\x20\x20\x20Endpoint:\x20'+a['endpoint']),console['log'](JSON['stringify'](a['payloads'][0x0],null,0x2));a['payloads']['length']>0x1&&console['log']('\x20\x20\x20…\x20and\x20'+(a['payloads']['length']-0x1)+'\x20more');console['log']('');return;}console['log']('\x0a✅\x20'+a['message']);if(a['endpoint'])console['log']('\x20\x20\x20Endpoint:\x20'+a['endpoint']);console['log']('');}catch(c){console['error']('\x0a\x20\x20✗\x20\x20'+c['message']+'\x0a'),process['exit'](0x1);}})());break;}if(sub==='status'){const st=feedbackSubmit['submitStatus']();console['log']('\x0a──\x20Feedback\x20submit\x20status\x20───────────────────────────'),console['log']('\x20\x20Consent:\x20\x20\x20\x20\x20'+st['consent']),console['log']('\x20\x20Endpoint:\x20\x20\x20\x20'+st['endpoint']),console['log']('\x20\x20Anon\x20key:\x20\x20\x20\x20'+st['anonKey']),console['log']('\x20\x20Unsent:\x20\x20\x20\x20\x20\x20'+st['unsentCount']+'\x20entr'+(st['unsentCount']===0x1?'y':'ies')),console['log']('\x20\x20Install\x20id:\x20\x20'+st['installId']+'\x20(anonymous)'),console['log']('\x20\x20Package:\x20\x20\x20\x20\x20'+st['packageVersion']),console['log']('');break;}if(sub==='revoke'){feedbackSubmit['revokeConsent'](),console['log']('\x0a🛑\x20Opt-in\x20consent\x20revoked.\x20Run\x20feedback\x20submit\x20again\x20to\x20re-consent.\x0a');break;}console['error']('\x0aUnknown\x20feedback\x20subcommand:\x20\x22'+sub+'\x22.\x20Use:\x20record\x20|\x20list\x20|\x20export\x20|\x20submit\x20|\x20status\x20|\x20revoke\x0a'),process['exit'](0x1);}case'export-training':{!personaVal&&(console['error']('\x0a\x20\x20✗\x20\x20--persona\x20is\x20required.\x20\x20Example:\x20npx\x20analyzthis_design\x20export-training\x20--persona\x20arjun\x0a'),process['exit'](0x1));try{const result=exportTraining({'persona':personaVal,'project':projectVal,'all':allFlag,'output':outputVal});console['log']('\x0a✅\x20Wrote\x20'+result['pairs']+'\x20accepted\x20training\x20pair(s)\x20for\x20\x22'+personaVal+'\x22\x20to\x20'+result['filePath']),!result['pairs']&&console['log']('\x20\x20\x20No\x20accepted\x20outputs\x20found.\x20Mark\x20one\x20first:\x20npx\x20analyzthis_design\x20session\x20accept\x20--persona\x20'+personaVal),console['log']('');}catch(x){console['error']('\x0a\x20\x20✗\x20\x20'+x['message']+'\x0a'),process['exit'](0x1);}break;}case'evolve':{const evolve=require('../lib/evolve'),windowArg=getFlag('window'),windowDays=windowArg?parseInt(windowArg,0xa):0x7;if(flags['includes']('--extract')){((async()=>{try{const a=await evolve['runEvolution']({'windowDays':windowDays,'dryRun':dryRunFlag});console['log']('\x0a──\x20Evolution\x20report\x20'+(dryRunFlag?'(dry\x20run)':'')+'\x20──'),console['log']('\x20\x20Lessons\x20extracted:\x20\x20'+a['extracted_lessons']),console['log']('\x20\x20Outcomes\x20inferred:\x20\x20'+a['inferred_outcomes']),console['log']('\x20\x20Prompt\x20patches:\x20\x20\x20\x20\x20'+a['prompt_patches']['length']),console['log']('\x20\x20Reference\x20proposals:'+a['reference_proposals']['length']),console['log']('\x20\x20Router\x20patches:\x20\x20\x20\x20\x20'+a['router_patches']['length']);for(const c of a['prompt_patches']){console['log']('\x0a\x20\x20Patch:\x20'+c['id']+'\x20—\x20'+c['persona']+'\x20—\x20'+c['description']);}for(const f of a['reference_proposals']){console['log']('\x0a\x20\x20Reference:\x20'+f['id']+'\x20—\x20'+f['persona']+'\x20—\x20'+f['description']);}for(const g of a['router_patches']){console['log']('\x0a\x20\x20Router:\x20'+g['id']+'\x20—\x20'+g['task_type']+'\x20→\x20'+g['suggested_route_to']['join'](',\x20'));}console['log']('');}catch(o){console['error']('\x0a\x20\x20✗\x20\x20'+o['message']+'\x0a'),process['exit'](0x1);}})());break;}if(flags['includes']('--apply')){const applyId=getFlag('apply');!applyId&&(console['error']('\x0a\x20\x20✗\x20\x20--apply\x20requires\x20a\x20patch\x20id\x0a'),process['exit'](0x1));try{const result=evolve['applyPatch']({'patchId':applyId,'dryRun':dryRunFlag});if(result['preview'])console['log']('\x0a──\x20Dry-run\x20patch\x20preview\x20──'),console['log']('\x20\x20Target:\x20'+result['targetFile']),console['log']('\x20\x20Preview:\x0a'+result['preview']['slice'](0x0,0x4b0));else{console['log']('\x0a✅\x20Patch\x20'+(result['applied']?'applied':'previewed')+':\x20'+applyId);if(result['targetFile'])console['log']('\x20\x20\x20Target:\x20'+result['targetFile']);if(result['message'])console['log']('\x20\x20\x20Note:\x20'+result['message']);}console['log']('');}catch(y){console['error']('\x0a\x20\x20✗\x20\x20'+y['message']+'\x0a'),process['exit'](0x1);}break;}console['log']('\x0a\x20\x20Usage:\x20evolve\x20--extract\x20[--window\x20N]\x20[--dry-run]\x20|\x20evolve\x20--apply\x20<patchId>\x20[--dry-run]\x0a');break;}case'outcome':{const outcome=require('../lib/outcome');if(flags['includes']('--infer')){const windowArg2=getFlag('window'),wd=windowArg2?parseInt(windowArg2,0xa):0x7;try{const result=outcome['inferAllOutcomes']({'windowDays':wd});console['log']('\x0a✅\x20Inferred\x20'+result['inferred']+'\x20outcome(s),\x20'+result['confirmed']+'\x20confirmed,\x20'+result['unknown']+'\x20unknown.\x0a');}catch(z){console['error']('\x0a\x20\x20✗\x20\x20'+z['message']+'\x0a'),process['exit'](0x1);}break;}if(flags['includes']('--pending')){const pending=outcome['listPendingConfirmations']();if(!pending['length'])console['log']('\x0a\x20\x20No\x20pending\x20outcome\x20confirmations.\x0a');else{console['log']('\x0a──\x20Pending\x20outcome\x20confirmations\x20('+pending['length']+')\x20──');for(const p of pending){console['log']('\x20\x20'+p['project']+'\x20/\x20'+p['persona']+':\x20'+p['inferred']+'\x20('+p['reason']+')');}console['log']('');}break;}if(flags['includes']('--confirm')){!personaVal&&(console['error']('\x0a\x20\x20✗\x20\x20--persona\x20is\x20required\x20for\x20--confirm\x0a'),process['exit'](0x1));const resultVal=getFlag('result');!resultVal&&(console['error']('\x0a\x20\x20✗\x20\x20--result\x20is\x20required\x20(shipped\x20|\x20revised\x20|\x20blocked_correctly\x20|\x20missed)\x0a'),process['exit'](0x1));try{outcome['confirmOutcome']({'project':projectVal,'persona':personaVal,'outcome':resultVal}),console['log']('\x0a✅\x20Outcome\x20confirmed:\x20'+personaVal+'\x20=\x20'+resultVal+'\x0a');}catch(A){console['error']('\x0a\x20\x20✗\x20\x20'+A['message']+'\x0a'),process['exit'](0x1);}break;}console['log']('\x0a\x20\x20Usage:\x20outcome\x20--infer\x20[--window\x20N]\x20|\x20outcome\x20--pending\x20|\x20outcome\x20--confirm\x20--persona\x20X\x20--result\x20Y\x0a');break;}case'--help':case'help':case'-h':console['log'](HELP);break;default:console['error']('\x0aUnknown\x20command:\x20\x22'+cmd+'\x22\x0a'),console['log'](HELP),process['exit'](0x1);}
2
+ 'use strict';
3
+
4
+ const path = require('path');
5
+ const os = require('os');
6
+ const fs = require('fs');
7
+ const { install, remove, SKILLS, TARGET_DIRS, printWelcomeBanner } = require('../lib/install');
8
+ const { resolveTargets, ALL_TARGET_IDS } = require('../lib/platforms');
9
+ const { connect, disconnect, sync, status } = require('../lib/knowledge');
10
+ const session = require('../lib/session');
11
+ const research = require('../lib/research');
12
+ const retrieve = require('../lib/retrieve');
13
+ const { exportTraining } = require('../lib/export');
14
+ const feedback = require('../lib/feedback');
15
+ const feedbackSubmit = require('../lib/feedback-submit');
16
+ const cost = require('../lib/cost');
17
+ const { collect } = require('../lib/collect');
18
+ const designSpec = require('../lib/design-spec');
19
+ const { run: orchestratorRun } = require('../lib/orchestrator/run');
20
+ const hostLlm = require('../lib/host-llm');
21
+ const moodboard = require('../lib/moodboard');
22
+
23
+ const HELP = `
24
+ Analyzthis_Design — 8 AI design personas with a personal knowledge bank
25
+
26
+ Usage:
27
+ npx analyzthis_design [command] [options]
28
+
29
+ ── Skill commands ───────────────────────────────────────────
30
+ install Copy all skills to the target AI tool's directory (default)
31
+ remove Delete installed skills from the target AI tool's directory
32
+ list Show installed skills for a target
33
+ welcome Print getting-started banner for your AI tool (--target)
34
+
35
+ ── Knowledge bank commands ──────────────────────────────────
36
+ connect Register a vault or knowledge folder as a source
37
+ sync Read all sources and build the knowledge-bank skill
38
+ disconnect Remove a source from the registry
39
+ status Show connected sources and last sync time
40
+ collect Kavi: scan codebase → Obsidian vault → enrich → sync knowledge bank
41
+ (--vault path, --dry-run, --no-enrich, --no-web, --no-discover,
42
+ --web-limit N, --target cursor|claude|codex|grok|windsurf|agents|all)
43
+
44
+ ── Design spec commands ─────────────────────────────────────
45
+ spec show Print design_spec from session state
46
+ spec validate Validate a DesignSpec JSON file (--file) or session
47
+ spec save Save DesignSpec JSON to session (--file required)
48
+ spec template Print empty DesignSpec template block
49
+
50
+ ── Session commands (agentic orchestrator) ──────────────────
51
+ session init Create a fresh session-state.json for this project
52
+ session show Print the current session-state.json
53
+ session reset Delete the session state for this project (--all for every project)
54
+ session accept Mark a persona's last output accepted, for training export
55
+ (--persona <id>, optional --reject to unmark)
56
+ Optional feedback: --comment, --correction, --rating 1-5, --tags a,b
57
+
58
+ ── Persona feedback commands ─────────────────────────────────
59
+ feedback record Record unhappiness or a correction for a persona output
60
+ (--persona <id>, --comment, --correction, --rating 1-5, --tags)
61
+ feedback list List feedback entries for this project (--all for every project)
62
+ feedback export Export rejected + correction JSONL pairs for training
63
+ (--persona <id>, --all, --output <path>, --include-positive)
64
+ feedback submit Opt-in: send anonymized corrections to community store (Supabase)
65
+ (--yes skip prompt, --dry-run preview, --all unsent across projects)
66
+ feedback status Show submit consent, endpoint config, unsent count
67
+ feedback revoke Revoke opt-in consent for community submit
68
+
69
+ ── Efficiency / cost commands ────────────────────────────────
70
+ metrics Print the last run's cost metrics (--all for every project)
71
+ cost Print the last run's $ cost from config.pricing (--all for every project)
72
+ export-training Write accepted-output JSONL pairs for LoRA prep
73
+ (--persona <id>, --all, --output <path>)
74
+ feedback export Write rejected + correction JSONL pairs (DPO / negative examples)
75
+
76
+ ── Research commands ────────────────────────────────────────
77
+ research --url <url> Fetch a URL and append to session web-context.md
78
+ research --query <text> Search stub (or provider) appended to web-context.md
79
+
80
+ ── Mood board commands ─────────────────────────────────────
81
+ moodboard create --task <text> Build a mood board from web + DS references
82
+ [--url <url> ...] [--auto]
83
+ moodboard critique --board <id> Run team deliberation over a board
84
+ moodboard add --board <id> Add a user reference and rerun critique
85
+ [--url <url>] [--title <t>] [--desc <d>]
86
+ [--tags a,b] [--note <text>]
87
+ moodboard list List mood boards for this project
88
+
89
+ ── Reference data (retrieve-on-demand) ───────────────────────
90
+ retrieve --file <csv> --column <col> --keywords a,b Filtered, citation-ready rows
91
+ --limit N (default 3)
92
+
93
+ ── Orchestrator (standalone runtime) ────────────────────────
94
+ run --task <text> DEFAULT v2.0: frontier planner → cheap chunk models → synthesis
95
+ --budget free only zero-cost models (Ollama, free APIs)
96
+ --budget cheap include cheap cloud models with user keys
97
+ --sequential run chunks sequentially (default)
98
+ --max-chunks N cap chunks (default 6)
99
+ --dry-run show planner output without executing chunks
100
+ --unchunked use the legacy single-pass orchestrator
101
+
102
+ run-unchunked --task <text> Legacy non-chunked orchestrator
103
+ --continue resume after /devi fills pending responses
104
+ --lite (default) MoE subset only | --full allow full chain
105
+ --experts a,b explicit override, skips the router entirely
106
+ --deliberate adversarial satisfaction loops (default on)
107
+ --no-deliberate legacy sequential pass-the-parcel mode
108
+ --max-rounds N cap deliberation rounds (default 3)
109
+ --satisfaction X satisfaction threshold 0.0-1.0 (default 0.4)
110
+
111
+ ── Devi (host LLM — no API keys) ────────────────────────────
112
+ devi status List pending persona prompts awaiting host LLM responses
113
+ (--run path to a specific run directory)
114
+ devi respond Submit a persona response file
115
+ (--run path, --step 001-arjun, --file response.md)
116
+
117
+ ── Options ──────────────────────────────────────────────────
118
+ --target Platform: cursor | claude | codex | grok | windsurf | agents | all (default: cursor)
119
+ --force Overwrite existing skills on install
120
+ --vault Path to Obsidian vault or markdown folder (connect command)
121
+ --tags Comma-separated tags to filter by, e.g. design,brand,ux
122
+ --include Comma-separated sub-folder names to include, e.g. Design,Brand
123
+ --project Project id override for session/research/run commands (default: derived from cwd)
124
+ --all With "session reset", clear every project's session state
125
+ --url URL to fetch (research command)
126
+ --query Search query (research command)
127
+ --task Task description (run command)
128
+ --figma Figma URL (run command)
129
+ --provider anthropic | openai | google | zai | ollama | groq | together | openrouter | deepseek | host (default: auto)
130
+ --model Model override (run / run-unchunked command)
131
+ --continue With "run-unchunked", resume host-mode run after devi respond
132
+ --dry-run Print routing + chain without calling any LLM (run / run-unchunked command); or show planner output
133
+ --lite Force MoE subset only, even for full_screen_review (run-unchunked command; default)
134
+ --full Allow the full design-critic chain for full_screen_review (run-unchunked command)
135
+ --experts Comma-separated persona ids, bypasses the router entirely (run-unchunked command)
136
+ --budget free | cheap | auto — chunk model budget (run command; default: auto)
137
+ --sequential Run chunks sequentially (run command; default on)
138
+ --max-chunks Cap number of planner chunks (run command; default 6)
139
+ --unchunked Force legacy single-pass orchestrator (run command)
140
+ --output Write final session-state.json to this path (run / run-unchunked command); or JSONL path (export-training)
141
+ --persona Persona id (session accept; export-training; feedback commands)
142
+ --reject With "session accept", mark the output rejected instead of accepted
143
+ --comment What was wrong or what you liked (session accept / feedback record)
144
+ --correction How you fixed it or what you wanted instead (session accept / feedback record)
145
+ --rating 1 (very unhappy) to 5 (very happy) — feedback record / session accept
146
+ --include-positive With "feedback export", include satisfied entries too
147
+ --yes With "feedback submit", accept consent prompt without asking again
148
+ --deliberate With "run", force adversarial deliberation loops
149
+ --no-deliberate With "run", legacy sequential handoff (no objection rounds)
150
+ --max-rounds With "run", cap deliberation rounds (default 3)
151
+ --satisfaction With "run", satisfaction threshold 0.0-1.0 (default 0.4)
152
+ --no-enrich With "collect", write draft vault + sync without LLM enrichment
153
+ --no-web With "collect", skip fetching URLs from config/PRDs/README
154
+ --no-discover With "collect", skip Obsidian/vault/knowledge-graph discovery
155
+ --web-limit Cap external URLs fetched during collect (default: 10)
156
+ --limit Cap notes enriched (collect) or retrieve rows (retrieve)
157
+ --board Mood board id (moodboard critique / add)
158
+ --title Reference title (moodboard add)
159
+ --desc Reference description (moodboard add)
160
+ --auto With moodboard create, discover references without explicit URLs
161
+ --help Show this help message
162
+
163
+ ── Examples ─────────────────────────────────────────────────
164
+ npx analyzthis_design # install for Cursor
165
+ npx analyzthis_design --target all # install for all tools
166
+ npx analyzthis_design welcome # re-print getting-started help
167
+ npx analyzthis_design welcome --target claude
168
+
169
+ npx analyzthis_design collect # Kavi: scan → vault → enrich → sync
170
+ npx analyzthis_design collect --dry-run # preview classification + web URLs
171
+ npx analyzthis_design collect --no-enrich --limit 50
172
+ npx analyzthis_design collect --no-web # skip external URL fetch
173
+ npx analyzthis_design collect --vault ~/Documents/MyVault --target all
174
+
175
+ npx analyzthis_design connect --vault ~/Documents/MyVault
176
+ npx analyzthis_design connect --vault ~/docs --tags design,brand,product
177
+ npx analyzthis_design connect --vault ~/vault --include Design,Research
178
+ npx analyzthis_design sync # sync to Cursor
179
+ npx analyzthis_design sync --target all # sync to all tools
180
+ npx analyzthis_design status # show sources
181
+ npx analyzthis_design disconnect --vault ~/Documents/MyVault
182
+
183
+ npx analyzthis_design session init # start a new session for this repo
184
+ npx analyzthis_design session show # inspect current session state
185
+ npx analyzthis_design session reset # clear session state for this repo
186
+
187
+ npx analyzthis_design research --url https://example.com/design-tokens
188
+ npx analyzthis_design research --query "EY design system tokens"
189
+
190
+ npx analyzthis_design moodboard create --task "B2B fintech dashboard, trustworthy, high-contrast" --auto
191
+ npx analyzthis_design moodboard critique --board <boardId>
192
+ npx analyzthis_design moodboard add --board <boardId> --url https://dribbble.com/shots/example --title "Alt hero" --tags "landing,trust"
193
+
194
+ npx analyzthis_design retrieve --file colors.csv --column "Product Type" --keywords saas,dashboard
195
+ npx analyzthis_design retrieve --file styles.csv --column "Best For" --keywords b2b --limit 3
196
+
197
+ npx analyzthis_design run --task "Fix contrast on landing page" --dry-run
198
+ npx analyzthis_design run --task "Review this screen" --budget free
199
+ npx analyzthis_design run --task "Review this screen" --budget cheap --sequential
200
+ npx analyzthis_design run-unchunked --task "Just check spacing" --experts arjun
201
+ npx analyzthis_design devi status
202
+ npx analyzthis_design devi respond --run ~/.analyzthis_design/runs/... --step 001-arjun --file out.md
203
+ npx analyzthis_design run-unchunked --task "Review this screen" --provider anthropic
204
+
205
+ npx analyzthis_design session accept --persona arjun
206
+ npx analyzthis_design session accept --persona arjun --reject \\
207
+ --comment "Invented tokens not in our DS" \\
208
+ --correction "Use --color-primary and spacing-4 from tokens.css" \\
209
+ --rating 2 --tags invented_tokens,missed_ds
210
+ npx analyzthis_design feedback record --persona arjun --rating 2 --comment "..." --correction "..."
211
+ npx analyzthis_design feedback list
212
+ npx analyzthis_design feedback export --persona arjun --all
213
+ npx analyzthis_design feedback submit --dry-run
214
+ npx analyzthis_design feedback submit --all --yes
215
+ npx analyzthis_design feedback status
216
+ npx analyzthis_design metrics
217
+ npx analyzthis_design cost
218
+ npx analyzthis_design export-training --persona arjun --all
219
+
220
+ ── Install paths ────────────────────────────────────────────
221
+ Cursor → ~/.cursor/skills/
222
+ Claude → ~/.claude/skills/ (+ legacy ~/.claude/commands/)
223
+ Codex → ~/.codex/skills/
224
+ Grok → ~/.grok/skills/
225
+ Windsurf → ~/.codeium/windsurf/skills/
226
+ agents → ~/.agents/skills/ (cross-tool discovery)
227
+
228
+ ── Knowledge bank config ────────────────────────────────────
229
+ Config → ~/.analyzthis_design/config.json
230
+
231
+ Docs: https://github.com/rishikeshjoshi/analyzthis_design
232
+ `;
233
+
234
+ // ─── Parse args ──────────────────────────────────────────────────────────────
235
+
236
+ const [,, cmd, ...flags] = process.argv;
237
+
238
+ function getFlag(name) {
239
+ // Supports both --flag=value and --flag value
240
+ const eq = flags.find(f => f.startsWith(`--${name}=`));
241
+ if (eq) return eq.split('=').slice(1).join('=');
242
+ const idx = flags.indexOf(`--${name}`);
243
+ if (idx !== -1 && flags[idx + 1] && !flags[idx + 1].startsWith('--')) return flags[idx + 1];
244
+ return null;
245
+ }
246
+
247
+ function parseFeedbackTags(raw) {
248
+ if (!raw) return [];
249
+ return raw.split(',').map((t) => t.trim().toLowerCase()).filter(Boolean);
250
+ }
251
+
252
+ const force = flags.includes('--force');
253
+ const targetVal = getFlag('target') || 'cursor';
254
+ const vaultVal = getFlag('vault');
255
+ const tagsVal = getFlag('tags');
256
+ const includeVal = getFlag('include');
257
+ const projectVal = getFlag('project');
258
+ const allFlag = flags.includes('--all');
259
+ const urlVal = getFlag('url');
260
+ const queryVal = getFlag('query');
261
+ const taskVal = getFlag('task');
262
+ const figmaVal = getFlag('figma');
263
+ const providerVal = getFlag('provider');
264
+ const modelVal = getFlag('model');
265
+ const outputVal = getFlag('output');
266
+ const dryRunFlag = flags.includes('--dry-run');
267
+ const liteFlag = flags.includes('--lite');
268
+ const fullFlag = flags.includes('--full');
269
+ const expertsVal = getFlag('experts');
270
+ const fileVal = getFlag('file');
271
+ const columnVal = getFlag('column');
272
+ const keywordsVal = getFlag('keywords');
273
+ const limitVal = getFlag('limit');
274
+ const personaVal = getFlag('persona');
275
+ const rejectFlag = flags.includes('--reject');
276
+ const commentVal = getFlag('comment');
277
+ const correctionVal = getFlag('correction');
278
+ const ratingVal = getFlag('rating');
279
+ const includePositiveFlag = flags.includes('--include-positive');
280
+ const yesFlag = flags.includes('--yes');
281
+ const deliberateFlag = flags.includes('--deliberate');
282
+ const noDeliberateFlag = flags.includes('--no-deliberate');
283
+ const maxRoundsVal = getFlag('max-rounds');
284
+ const satisfactionVal = getFlag('satisfaction');
285
+ const continueFlag = flags.includes('--continue');
286
+ const runDirVal = getFlag('run');
287
+ const stepVal = getFlag('step');
288
+ const noEnrichFlag = flags.includes('--no-enrich');
289
+ const noWebFlag = flags.includes('--no-web');
290
+ const noDiscoverFlag = flags.includes('--no-discover');
291
+ const webLimitVal = getFlag('web-limit');
292
+ const boardVal = getFlag('board');
293
+ const titleVal = getFlag('title');
294
+ const descVal = getFlag('desc');
295
+ const autoFlag = flags.includes('--auto');
296
+ const budgetVal = getFlag('budget');
297
+ const sequentialFlag = flags.includes('--sequential');
298
+ const maxChunksVal = getFlag('max-chunks');
299
+ const unchunkedFlag = flags.includes('--unchunked');
300
+
301
+ // ─── Commands ────────────────────────────────────────────────────────────────
302
+
303
+ switch (cmd) {
304
+ case undefined:
305
+ case 'install':
306
+ install({ force, target: targetVal });
307
+ break;
308
+
309
+ case 'remove':
310
+ case 'uninstall':
311
+ remove({ target: targetVal });
312
+ break;
313
+
314
+ case 'welcome': {
315
+ const targets = resolveTargets(targetVal) || ['cursor'];
316
+ for (const tId of targets) printWelcomeBanner(tId);
317
+ break;
318
+ }
319
+
320
+ case 'list': {
321
+ const { TARGETS } = require('../lib/platforms');
322
+ const targets = resolveTargets(targetVal);
323
+ if (!targets) {
324
+ console.error(`\n ✗ Unknown target "${targetVal}". Choose: ${ALL_TARGET_IDS.join(', ')}, all\n`);
325
+ process.exit(1);
326
+ }
327
+ for (const tId of targets) {
328
+ const t = TARGETS[tId];
329
+ console.log(`\nInstalled Analyzthis_Design skills [${t.label}] (${t.root}):\n`);
330
+ for (const skill of SKILLS) {
331
+ const asDir = path.join(t.root, skill);
332
+ const asFile = path.join(t.root, `${skill}.md`);
333
+ let exists = fs.existsSync(asDir) || fs.existsSync(asFile);
334
+ if (!exists && t.also) {
335
+ exists = fs.existsSync(path.join(t.also.root, skill)) ||
336
+ fs.existsSync(path.join(t.also.root, `${skill}.md`));
337
+ }
338
+ console.log(` ${exists ? '✅' : '✗ '} ${skill}`);
339
+ }
340
+ }
341
+ console.log('');
342
+ break;
343
+ }
344
+
345
+ // ── Knowledge bank ──────────────────────────────────────────────────────
346
+
347
+ case 'connect': {
348
+ if (!vaultVal) {
349
+ console.error('\n ✗ --vault is required. Example: npx analyzthis_design connect --vault ~/Documents/MyVault\n');
350
+ process.exit(1);
351
+ }
352
+ try {
353
+ const tags = tagsVal ? tagsVal.split(',').map(t => t.trim()) : [];
354
+ const include = includeVal ? includeVal.split(',').map(t => t.trim()) : [];
355
+ const abs = connect({ vaultPath: vaultVal, tags, include });
356
+ console.log(`\n✅ Connected: ${abs}`);
357
+ if (tags.length) console.log(` Tags filter: ${tags.join(', ')}`);
358
+ if (include.length) console.log(` Folder filter: ${include.join(', ')}`);
359
+ console.log(`\n Run "npx analyzthis_design sync" to build the knowledge bank.\n`);
360
+ } catch (err) {
361
+ console.error(`\n ✗ ${err.message}\n`);
362
+ process.exit(1);
363
+ }
364
+ break;
365
+ }
366
+
367
+ case 'disconnect': {
368
+ if (!vaultVal) {
369
+ console.error('\n ✗ --vault is required. Example: npx analyzthis_design disconnect --vault ~/Documents/MyVault\n');
370
+ process.exit(1);
371
+ }
372
+ disconnect(vaultVal);
373
+ console.log(`\n🗑 Disconnected: ${path.resolve(vaultVal)}\n`);
374
+ break;
375
+ }
376
+
377
+ case 'sync': {
378
+ const { resolveTargets, ALL_TARGET_IDS } = require('../lib/platforms');
379
+ const targets = resolveTargets(targetVal);
380
+ if (!targets) {
381
+ console.error(`\n ✗ Unknown target "${targetVal}". Choose: ${ALL_TARGET_IDS.join(', ')}, all\n`);
382
+ process.exit(1);
383
+ }
384
+ console.log('\n⏳ Syncing knowledge bank...\n');
385
+ try {
386
+ const result = sync({ targets });
387
+ if (result.message) {
388
+ console.log(` ⚠ ${result.message}\n`);
389
+ } else {
390
+ console.log(`✅ Synced ${result.synced} note(s) into the knowledge bank.`);
391
+ for (const t of result.copiedTo) console.log(` • ${t}`);
392
+ console.log(`\n💡 The knowledge bank is now active. All personas will read it first.\n`);
393
+ }
394
+ } catch (err) {
395
+ console.error(`\n ✗ Sync failed: ${err.message}\n`);
396
+ process.exit(1);
397
+ }
398
+ break;
399
+ }
400
+
401
+ case 'status': {
402
+ const cfg = status();
403
+ if (!cfg.sources || cfg.sources.length === 0) {
404
+ console.log('\n No knowledge sources connected.\n Run: npx analyzthis_design connect --vault /path/to/vault\n');
405
+ } else {
406
+ console.log(`\n📚 Knowledge bank sources (${cfg.sources.length}):\n`);
407
+ for (const s of cfg.sources) {
408
+ console.log(` • ${s.path}`);
409
+ if (s.tags.length) console.log(` Tags: ${s.tags.join(', ')}`);
410
+ if (s.include.length) console.log(` Folders: ${s.include.join(', ')}`);
411
+ console.log(` Added: ${s.addedAt}`);
412
+ }
413
+ if (cfg.lastSync) console.log(`\n Last sync: ${cfg.lastSync}`);
414
+ console.log('');
415
+ }
416
+ break;
417
+ }
418
+
419
+ // ── Session (agentic orchestrator) ──────────────────────────────────────
420
+
421
+ case 'session': {
422
+ const sub = flags.find(f => !f.startsWith('--'));
423
+ switch (sub) {
424
+ case 'init': {
425
+ const { projectId, filePath } = session.init({ project: projectVal });
426
+ console.log(`\n✅ Session initialized for project "${projectId}"`);
427
+ console.log(` ${filePath}\n`);
428
+ break;
429
+ }
430
+ case 'show': {
431
+ const state = session.show({ project: projectVal });
432
+ if (!state) {
433
+ console.log('\n No session found. Run: npx analyzthis_design session init\n');
434
+ } else {
435
+ console.log(JSON.stringify(state, null, 2));
436
+ }
437
+ break;
438
+ }
439
+ case 'reset': {
440
+ const result = session.reset({ project: projectVal, all: allFlag });
441
+ console.log(`\n🗑 Session reset: ${result.removed}\n`);
442
+ break;
443
+ }
444
+ case 'accept': {
445
+ if (!personaVal) {
446
+ console.error('\n ✗ --persona is required. Example: npx analyzthis_design session accept --persona arjun\n');
447
+ process.exit(1);
448
+ }
449
+ if (commentVal || correctionVal || ratingVal) {
450
+ try {
451
+ const fb = feedback.recordFeedback({
452
+ project: projectVal,
453
+ persona: personaVal,
454
+ satisfied: !rejectFlag,
455
+ rating: ratingVal != null ? Number(ratingVal) : undefined,
456
+ comment: commentVal || '',
457
+ correction: correctionVal || '',
458
+ tags: parseFeedbackTags(tagsVal),
459
+ markRejected: true,
460
+ });
461
+ console.log(`\n✅ Marked "${personaVal}" as ${rejectFlag ? 'rejected' : 'accepted'} with feedback (${fb.entry.id}).\n`);
462
+ } catch (err) {
463
+ console.error(`\n ✗ ${err.message}\n`);
464
+ process.exit(1);
465
+ }
466
+ } else {
467
+ const result = session.markAccepted({ project: projectVal, persona: personaVal, accepted: !rejectFlag });
468
+ if (!result.updated) {
469
+ console.log(`\n ⚠ ${result.reason}\n`);
470
+ } else {
471
+ console.log(`\n✅ Marked "${personaVal}" output as ${rejectFlag ? 'rejected' : 'accepted'}.\n`);
472
+ }
473
+ }
474
+ break;
475
+ }
476
+ default:
477
+ console.error(`\nUnknown session subcommand: "${sub || ''}". Use: init | show | reset | accept\n`);
478
+ process.exit(1);
479
+ }
480
+ break;
481
+ }
482
+
483
+ // ── Design spec ─────────────────────────────────────────────────────────
484
+
485
+ case 'spec': {
486
+ const sub = flags[0] || 'show';
487
+ if (sub === 'template') {
488
+ console.log('\n' + designSpec.templateMarkdown() + '\n');
489
+ break;
490
+ }
491
+ if (sub === 'show') {
492
+ const row = designSpec.showFromSession({ project: projectVal });
493
+ if (!row) {
494
+ console.log('\n No design_spec in session. Run /design-director or /ux-ideator Phase 7 first.\n');
495
+ break;
496
+ }
497
+ console.log('\n── design_spec ──────────────────────────────────────');
498
+ console.log(JSON.stringify(row.design_spec, null, 2));
499
+ console.log('');
500
+ break;
501
+ }
502
+ if (sub === 'save') {
503
+ if (!fileVal) {
504
+ console.error('\n ✗ spec save requires --file <path.json>\n');
505
+ process.exit(1);
506
+ }
507
+ try {
508
+ const raw = fs.readFileSync(path.resolve(fileVal), 'utf8');
509
+ const spec = JSON.parse(raw);
510
+ const validation = designSpec.validateDesignSpec(spec);
511
+ if (!validation.valid) {
512
+ console.log('\n✗ Cannot save invalid spec:\n');
513
+ for (const e of validation.errors) console.log(` • ${e}`);
514
+ console.log('');
515
+ process.exit(1);
516
+ }
517
+ const saved = designSpec.saveToSession(spec, { project: projectVal, merge: false });
518
+ console.log(`\n✅ Saved design_spec to session (${saved.projectId})\n`);
519
+ } catch (err) {
520
+ console.error(`\n ✗ ${err.message}\n`);
521
+ process.exit(1);
522
+ }
523
+ break;
524
+ }
525
+ if (sub === 'validate') {
526
+ try {
527
+ let result;
528
+ if (fileVal) {
529
+ result = designSpec.validateFile(fileVal);
530
+ } else {
531
+ const row = designSpec.showFromSession({ project: projectVal });
532
+ if (!row) {
533
+ console.error('\n ✗ No design_spec in session and no --file provided.\n');
534
+ process.exit(1);
535
+ }
536
+ result = { spec: row.design_spec, ...designSpec.validateDesignSpec(row.design_spec) };
537
+ }
538
+ if (result.valid) {
539
+ console.log('\n✅ DesignSpec is valid.\n');
540
+ if (result.spec && !fileVal) {
541
+ console.log(` status: ${result.spec.status} | screen: ${result.spec.screen_name}\n`);
542
+ }
543
+ } else {
544
+ console.log('\n✗ DesignSpec validation failed:\n');
545
+ for (const e of result.errors) console.log(` • ${e}`);
546
+ console.log('');
547
+ process.exit(1);
548
+ }
549
+ } catch (err) {
550
+ console.error(`\n ✗ ${err.message}\n`);
551
+ process.exit(1);
552
+ }
553
+ break;
554
+ }
555
+ console.error('\n ✗ Unknown spec subcommand. Use: spec show | validate | save | template\n');
556
+ process.exit(1);
557
+ }
558
+
559
+ // ── Collect knowledge (Kavi) ────────────────────────────────────────────
560
+
561
+ case 'collect': {
562
+ collect({
563
+ project: projectVal,
564
+ vault: vaultVal || undefined,
565
+ dryRun: dryRunFlag,
566
+ enrich: !noEnrichFlag,
567
+ web: !noWebFlag,
568
+ discoverSources: !noDiscoverFlag,
569
+ webLimit: webLimitVal ? parseInt(webLimitVal, 10) : null,
570
+ limit: limitVal ? parseInt(limitVal, 10) : null,
571
+ target: targetVal,
572
+ provider: providerVal,
573
+ model: modelVal,
574
+ }).catch((err) => {
575
+ console.error(`\n ✗ Collect failed: ${err.message}\n`);
576
+ process.exit(1);
577
+ });
578
+ break;
579
+ }
580
+
581
+ // ── Research ────────────────────────────────────────────────────────────
582
+
583
+ case 'research': {
584
+ (async () => {
585
+ try {
586
+ if (urlVal) {
587
+ console.log(`\n⏳ Fetching ${urlVal}...\n`);
588
+ const result = await research.researchUrl({ url: urlVal, project: projectVal });
589
+ console.log(`✅ Wrote ${result.chars} chars to ${result.filePath}\n`);
590
+ } else if (queryVal) {
591
+ console.log(`\n⏳ Researching "${queryVal}"...\n`);
592
+ const result = await research.researchQuery({ query: queryVal, project: projectVal });
593
+ if (result.mode === 'stub') {
594
+ console.log(`⚠ No research.provider configured — wrote a stub for the host IDE to fill.`);
595
+ console.log(` ${result.filePath}`);
596
+ console.log(` Tip: set research.provider in ~/.analyzthis_design/config.json, or use WebSearch in Cursor.\n`);
597
+ } else {
598
+ console.log(`✅ Wrote ${result.chars} chars to ${result.filePath}\n`);
599
+ }
600
+ } else {
601
+ console.error('\n ✗ Provide --url <url> or --query <text>\n');
602
+ process.exit(1);
603
+ }
604
+ } catch (err) {
605
+ console.error(`\n ✗ Research failed: ${err.message}\n`);
606
+ process.exit(1);
607
+ }
608
+ })();
609
+ break;
610
+ }
611
+
612
+ // ── Mood board ───────────────────────────────────────────────────────────
613
+
614
+ case 'moodboard': {
615
+ const msub = flags.find((f) => !f.startsWith('--')) || 'create';
616
+ if (msub === 'create') {
617
+ if (!taskVal) {
618
+ console.error('\n ✗ --task is required. Example: npx analyzthis_design moodboard create --task "B2B fintech dashboard" --auto\n');
619
+ process.exit(1);
620
+ }
621
+ (async () => {
622
+ try {
623
+ const urls = [];
624
+ const raw = flags.filter((f) => f.startsWith('--url=')).map((f) => f.split('=').slice(1).join('='));
625
+ for (let i = 0; i < flags.length; i++) {
626
+ if (flags[i] === '--url' && flags[i + 1] && !flags[i + 1].startsWith('--')) urls.push(flags[i + 1]);
627
+ }
628
+ for (const u of raw) if (urls.indexOf(u) === -1) urls.push(u);
629
+ const result = await moodboard.buildMoodBoard({
630
+ project: projectVal,
631
+ task: taskVal,
632
+ urls: urls,
633
+ discover: autoFlag || urls.length > 0,
634
+ dryRun: dryRunFlag,
635
+ });
636
+ console.log(`\n✅ Mood board created: ${result.board.board_id}`);
637
+ console.log(` References: ${result.board.references.length}`);
638
+ console.log(` Board dir: ${result.boardDir}`);
639
+ console.log(` Workspace: ${result.workspacePath}\n`);
640
+ if (dryRunFlag) {
641
+ console.log(JSON.stringify(result.board, null, 2).slice(0, 2000));
642
+ console.log('');
643
+ }
644
+ } catch (err) {
645
+ console.error(`\n ✗ Mood board create failed: ${err.message}\n`);
646
+ process.exit(1);
647
+ }
648
+ })();
649
+ break;
650
+ }
651
+ if (msub === 'critique') {
652
+ if (!boardVal) {
653
+ console.error('\n ✗ --board is required. Example: npx analyzthis_design moodboard critique --board <id>\n');
654
+ process.exit(1);
655
+ }
656
+ (async () => {
657
+ try {
658
+ const result = await moodboard.critiqueMoodBoard({
659
+ project: projectVal,
660
+ boardId: boardVal,
661
+ provider: providerVal,
662
+ model: modelVal,
663
+ dryRun: dryRunFlag,
664
+ noDeliberate: noDeliberateFlag,
665
+ maxRounds: maxRoundsVal,
666
+ satisfaction: satisfactionVal,
667
+ });
668
+ console.log(`\n✅ Mood board critique complete: ${result.board.board_id}`);
669
+ console.log(` Verdict: ${result.board.synthesis?.verdict || 'n/a'}`);
670
+ console.log(` Rounds: ${result.board.deliberation?.round || 0}`);
671
+ console.log(` Board: ${result.boardDir || path.join(session.sessionDir(projectVal || session.getProjectId()), 'moodboard', boardVal)}`);
672
+ console.log(` Workspace: ${result.workspacePath}\n`);
673
+ } catch (err) {
674
+ if (err.name === 'HostLlmPendingError') {
675
+ hostLlm.printDeviInstructions(err);
676
+ process.exit(2);
677
+ }
678
+ console.error(`\n ✗ Mood board critique failed: ${err.message}\n`);
679
+ process.exit(1);
680
+ }
681
+ })();
682
+ break;
683
+ }
684
+ if (msub === 'add') {
685
+ if (!boardVal) {
686
+ console.error('\n ✗ --board is required. Example: npx analyzthis_design moodboard add --board <id> --url <url>\n');
687
+ process.exit(1);
688
+ }
689
+ (async () => {
690
+ try {
691
+ const tags = tagsVal ? tagsVal.split(',').map((t) => t.trim()).filter(Boolean) : [];
692
+ const result = await moodboard.addUserReferenceAndRerun({
693
+ project: projectVal,
694
+ boardId: boardVal,
695
+ reference: {
696
+ url: urlVal || '',
697
+ title: titleVal || '',
698
+ description: descVal || '',
699
+ tags: tags,
700
+ note: commentVal || '',
701
+ },
702
+ provider: providerVal,
703
+ model: modelVal,
704
+ dryRun: dryRunFlag,
705
+ noDeliberate: noDeliberateFlag,
706
+ maxRounds: maxRoundsVal,
707
+ satisfaction: satisfactionVal,
708
+ });
709
+ console.log(`\n✅ Added reference to board ${result.board.board_id}: ${result.added.id}`);
710
+ console.log(` Total references: ${result.board.references.length}`);
711
+ console.log(` Verdict: ${result.board.synthesis?.verdict || 'n/a'}\n`);
712
+ } catch (err) {
713
+ if (err.name === 'HostLlmPendingError') {
714
+ hostLlm.printDeviInstructions(err);
715
+ process.exit(2);
716
+ }
717
+ console.error(`\n ✗ Mood board add failed: ${err.message}\n`);
718
+ process.exit(1);
719
+ }
720
+ })();
721
+ break;
722
+ }
723
+ if (msub === 'list') {
724
+ const boards = moodboard.listBoards(projectVal);
725
+ if (!boards.length) {
726
+ console.log('\n No mood boards found for this project.\n');
727
+ } else {
728
+ console.log(`\n── Mood boards (${boards.length}) ──`);
729
+ for (const b of boards) console.log(` • ${b}`);
730
+ console.log('');
731
+ }
732
+ break;
733
+ }
734
+ console.error('\n Unknown moodboard subcommand. Use: create | critique | add | list\n');
735
+ process.exit(1);
736
+ }
737
+
738
+ // ── Retrieve-on-demand reference rows ───────────────────────────────────
739
+
740
+ case 'retrieve': {
741
+ if (!fileVal) {
742
+ console.error('\n ✗ --file is required. Example: npx analyzthis_design retrieve --file colors.csv --column "Product Type" --keywords saas\n');
743
+ process.exit(1);
744
+ }
745
+ try {
746
+ const keywords = keywordsVal ? keywordsVal.split(',').map(s => s.trim()).filter(Boolean) : [];
747
+ const filters = columnVal && keywords.length ? [{ column: columnVal, anyOf: keywords }] : [];
748
+ const limit = limitVal ? parseInt(limitVal, 10) : 3;
749
+ const result = retrieve.retrieve({ file: fileVal, filters, limit });
750
+ if (!result.rows.length) {
751
+ console.log(`\n No rows matched in ${fileVal}${columnVal ? ` for column "${columnVal}"` : ''}${keywords.length ? ` with keywords: ${keywords.join(', ')}` : ''}.\n`);
752
+ } else {
753
+ console.log(`\n📋 ${result.rows.length}/${result.matched} matching row(s) in ${fileVal}${result.cacheHit ? ' (cache hit)' : ''}:\n`);
754
+ for (const row of result.rows) {
755
+ console.log(` Row ${row.__no}:`);
756
+ for (const [k, v] of Object.entries(row)) {
757
+ if (k.startsWith('__') || !v) continue;
758
+ console.log(` ${k}: ${v}`);
759
+ }
760
+ console.log('');
761
+ }
762
+ if (columnVal) console.log(` Citation format: [${fileVal}, row N: "${columnVal} value"]\n`);
763
+ }
764
+ } catch (err) {
765
+ console.error(`\n ✗ ${err.message}\n`);
766
+ process.exit(1);
767
+ }
768
+ break;
769
+ }
770
+
771
+ // ── Orchestrator run (chunked by default, v2.0) ───────────────────────────
772
+
773
+ case 'run': {
774
+ if (!taskVal) {
775
+ console.error('\n ✗ --task is required. Example: npx analyzthis_design run --task "Review onboarding flow" --budget free\n');
776
+ process.exit(1);
777
+ }
778
+ (async () => {
779
+ try {
780
+ const result = await orchestratorRun({
781
+ task: taskVal,
782
+ figma: figmaVal || '',
783
+ project: projectVal,
784
+ provider: providerVal,
785
+ model: modelVal,
786
+ dryRun: dryRunFlag,
787
+ budget: budgetVal || 'auto',
788
+ sequential: sequentialFlag || !flags.includes('--parallel'),
789
+ maxChunks: maxChunksVal ? parseInt(maxChunksVal, 10) : null,
790
+ unchunked: unchunkedFlag,
791
+ output: outputVal,
792
+ continueRun: continueFlag,
793
+ });
794
+ if (dryRunFlag) {
795
+ console.log('\n── Chunk plan (dry run) ──');
796
+ console.log(JSON.stringify(result.plan || result, null, 2).slice(0, 3000));
797
+ console.log('');
798
+ return;
799
+ }
800
+ if (result.mode === 'host_pending' || result.host_pending) {
801
+ const pending = result.host_pending;
802
+ console.log('\n╔══════════════════════════════════════════════════════════════════════╗');
803
+ console.log('║ DEVI — Host LLM pending (chunk planner) ║');
804
+ console.log('╚══════════════════════════════════════════════════════════════════════╝\n');
805
+ console.log(` Step: ${pending.step_id}`);
806
+ console.log(` Prompt file: ${path.join(pending.run_dir, 'pending', pending.step_id + '.json')}`);
807
+ console.log(` Run directory: ${pending.run_dir}`);
808
+ console.log('\n In Cursor, invoke: /devi');
809
+ console.log(' Or submit response:');
810
+ console.log(` npx analyzthis_design devi respond --run ${pending.run_dir} --step ${pending.step_id} --file response.md`);
811
+ console.log(' Then continue:');
812
+ console.log(` npx analyzthis_design run --continue --task "${taskVal}"\n`);
813
+ process.exit(2);
814
+ return;
815
+ }
816
+ } catch (err) {
817
+ if (err.name === 'HostLlmPendingError') {
818
+ hostLlm.printDeviInstructions(err);
819
+ process.exit(2);
820
+ }
821
+ console.error(`\n ✗ Run failed: ${err.message}\n`);
822
+ process.exit(1);
823
+ }
824
+ })();
825
+ break;
826
+ }
827
+
828
+ case 'run-unchunked': {
829
+ let runTask = taskVal;
830
+ if (!runTask && continueFlag) {
831
+ const st = session.show({ project: projectVal });
832
+ runTask = st?.host_run?.task || hostLlm.loadManifest(st?.host_run?.run_dir || '')?.task || st?.digest?.task_map_summary;
833
+ }
834
+ if (!runTask) {
835
+ console.error('\n ✗ --task is required. Example: npx analyzthis_design run-unchunked --task "Fix contrast" --dry-run\n');
836
+ process.exit(1);
837
+ }
838
+ orchestratorRun({
839
+ task: runTask,
840
+ figma: figmaVal || '',
841
+ provider: providerVal,
842
+ model: modelVal,
843
+ dryRun: dryRunFlag,
844
+ lite: liteFlag,
845
+ full: fullFlag,
846
+ deliberate: deliberateFlag ? true : null,
847
+ noDeliberate: noDeliberateFlag,
848
+ maxRounds: maxRoundsVal,
849
+ satisfaction: satisfactionVal,
850
+ continueRun: continueFlag,
851
+ experts: expertsVal ? expertsVal.split(',').map((s) => s.trim()).filter(Boolean) : null,
852
+ project: projectVal,
853
+ output: outputVal,
854
+ unchunked: true,
855
+ }).catch((err) => {
856
+ if (err.name === 'HostLlmPendingError') process.exit(2);
857
+ console.error(`\n ✗ Run failed: ${err.message}\n`);
858
+ process.exit(1);
859
+ });
860
+ break;
861
+ }
862
+
863
+ case 'devi': {
864
+ const sub = flags[0];
865
+ if (sub === 'status') {
866
+ let runDir = runDirVal;
867
+ if (!runDir) {
868
+ const st = session.show({ project: projectVal });
869
+ runDir = st?.host_run?.run_dir || hostLlm.findLatestRun(st?.project_id || session.getProjectId())?.runDir;
870
+ }
871
+ if (!runDir || !fs.existsSync(runDir)) {
872
+ console.log('\n No host run found. Start one: npx analyzthis_design run --task "..." --full\n');
873
+ break;
874
+ }
875
+ const pending = hostLlm.listPending(runDir);
876
+ console.log(`\n📋 Devi — host run: ${runDir}\n`);
877
+ for (const p of pending) {
878
+ console.log(` ${p.hasResponse ? '✅' : '⏳'} ${p.stepId} (${p.personaId})`);
879
+ }
880
+ const waiting = pending.filter((p) => !p.hasResponse);
881
+ if (waiting.length) {
882
+ console.log(`\n ${waiting.length} pending — invoke /devi in Cursor or devi respond for each step.\n`);
883
+ } else {
884
+ console.log('\n All responses present — run: npx analyzthis_design run --continue --task "..."\n');
885
+ }
886
+ break;
887
+ }
888
+ if (sub === 'respond') {
889
+ if (!runDirVal || !stepVal || !fileVal) {
890
+ console.error('\n ✗ devi respond requires --run, --step, and --file\n');
891
+ process.exit(1);
892
+ }
893
+ const text = fs.readFileSync(path.resolve(fileVal), 'utf8');
894
+ hostLlm.submitResponse(path.resolve(runDirVal), stepVal, text);
895
+ console.log(`\n✅ Wrote response for ${stepVal}\n`);
896
+ break;
897
+ }
898
+ console.log('\n Usage: devi status | devi respond --run <dir> --step <id> --file <path>\n');
899
+ break;
900
+ }
901
+
902
+ // ── Efficiency / cost metrics ────────────────────────────────────────────
903
+
904
+ case 'metrics': {
905
+ const projectIds = allFlag ? session.listProjects() : [projectVal || session.getProjectId()];
906
+ if (!projectIds.length) {
907
+ console.log('\n No sessions found.\n');
908
+ break;
909
+ }
910
+ console.log('\n📊 Last-run metrics\n');
911
+ for (const projectId of projectIds) {
912
+ const state = session.show({ project: projectId });
913
+ if (!state) continue;
914
+ const m = state.metrics || {};
915
+ console.log(` ${projectId}`);
916
+ console.log(` mode: ${m.mode ?? 'n/a'}`);
917
+ console.log(` llm_calls: ${m.llm_calls ?? 0}`);
918
+ console.log(` experts_run: ${(m.experts_run || []).join(', ') || 'none'}`);
919
+ console.log(` input_tokens_est: ${m.input_tokens_est ?? 0}`);
920
+ console.log(` output_tokens_est: ${m.output_tokens_est ?? 0}`);
921
+ console.log(` cache_hits: ${m.cache_hits ?? 0}`);
922
+ console.log(` deliberation_rounds: ${m.deliberation_rounds ?? 0}`);
923
+ console.log(` objections_raised: ${m.objections_raised ?? 0}`);
924
+ console.log(` objections_resolved: ${m.objections_resolved ?? 0}`);
925
+ console.log(` raj_escalations: ${m.raj_escalations ?? 0}`);
926
+ const d = state.deliberation;
927
+ if (d?.mode) {
928
+ console.log(` deliberation_mode: ${d.mode}, consensus=${d.consensus_reached}`);
929
+ }
930
+ console.log('');
931
+ }
932
+ break;
933
+ }
934
+
935
+ // ── $-cost report (v1.10) ────────────────────────────────────────────────
936
+
937
+ case 'cost': {
938
+ cost.report({ project: projectVal, all: allFlag });
939
+ break;
940
+ }
941
+
942
+ // ── Persona feedback (v1.16) ────────────────────────────────────────────
943
+
944
+ case 'feedback': {
945
+ const sub = flags[0] || 'record';
946
+ if (sub === 'record') {
947
+ if (!personaVal) {
948
+ console.error('\n ✗ --persona is required.\n');
949
+ console.error(' Example: npx analyzthis_design feedback record --persona arjun --rating 2 \\\n');
950
+ console.error(' --comment "Invented tokens" --correction "Use tokens.css primary + spacing-4"\n');
951
+ process.exit(1);
952
+ }
953
+ const ratingNum = ratingVal != null ? Number(ratingVal) : undefined;
954
+ const satisfied = ratingNum != null ? ratingNum >= 4 : false;
955
+ try {
956
+ const result = feedback.recordFeedback({
957
+ project: projectVal,
958
+ persona: personaVal,
959
+ satisfied,
960
+ rating: ratingNum,
961
+ comment: commentVal || '',
962
+ correction: correctionVal || '',
963
+ tags: parseFeedbackTags(tagsVal),
964
+ markRejected: !satisfied,
965
+ });
966
+ console.log(`\n📝 Feedback recorded for "${personaVal}" (${result.entry.id}).`);
967
+ console.log(` Global log: ${result.globalFile}\n`);
968
+ } catch (err) {
969
+ console.error(`\n ✗ ${err.message}\n`);
970
+ process.exit(1);
971
+ }
972
+ break;
973
+ }
974
+ if (sub === 'list') {
975
+ const items = feedback.listFeedback({ project: projectVal, all: allFlag });
976
+ if (!items.length) {
977
+ console.log('\n No feedback entries yet.\n');
978
+ console.log(' Record one: npx analyzthis_design feedback record --persona arjun --rating 2 --comment "..."\n');
979
+ break;
980
+ }
981
+ console.log(`\n── Feedback (${items.length}) ───────────────────────────────`);
982
+ for (const e of items) {
983
+ const mood = e.satisfied ? '✅' : '⚠️';
984
+ const rating = e.rating != null ? ` rating=${e.rating}` : '';
985
+ const tags = e.tags?.length ? ` [${e.tags.join(', ')}]` : '';
986
+ const sent = e.submitted_at ? ' 📤' : '';
987
+ console.log(`${mood} ${e.at} ${e.persona}${rating}${tags}${sent}`);
988
+ if (e.comment) console.log(` comment: ${e.comment.slice(0, 120)}${e.comment.length > 120 ? '…' : ''}`);
989
+ if (e.correction) console.log(` correction: ${e.correction.slice(0, 120)}${e.correction.length > 120 ? '…' : ''}`);
990
+ }
991
+ console.log('');
992
+ break;
993
+ }
994
+ if (sub === 'export') {
995
+ try {
996
+ const result = feedback.exportCorrections({
997
+ persona: personaVal,
998
+ project: projectVal,
999
+ all: allFlag,
1000
+ output: outputVal,
1001
+ includePositive: includePositiveFlag,
1002
+ });
1003
+ console.log(`\n✅ Wrote ${result.pairs} correction pair(s) to ${result.filePath}`);
1004
+ if (!result.pairs) {
1005
+ console.log(' No entries with comment/correction found. Record feedback first.');
1006
+ console.log(` Tags hint: ${feedback.ISSUE_TAG_HINTS.slice(0, 6).join(', ')}, …`);
1007
+ }
1008
+ console.log('');
1009
+ } catch (err) {
1010
+ console.error(`\n ✗ ${err.message}\n`);
1011
+ process.exit(1);
1012
+ }
1013
+ break;
1014
+ }
1015
+ if (sub === 'submit') {
1016
+ (async () => {
1017
+ try {
1018
+ const result = await feedbackSubmit.submitFeedback({
1019
+ project: projectVal,
1020
+ all: allFlag,
1021
+ persona: personaVal,
1022
+ includePositive: includePositiveFlag,
1023
+ dryRun: dryRunFlag,
1024
+ yes: yesFlag,
1025
+ limit: limitVal,
1026
+ });
1027
+ if (result.cancelled) {
1028
+ console.log(`\n ${result.message}\n`);
1029
+ process.exit(0);
1030
+ }
1031
+ if (result.dryRun && result.payloads) {
1032
+ console.log(`\n── Dry run: ${result.payloads.length} row(s) ─────────────────`);
1033
+ console.log(` Endpoint: ${result.endpoint}`);
1034
+ console.log(JSON.stringify(result.payloads[0], null, 2));
1035
+ if (result.payloads.length > 1) {
1036
+ console.log(` … and ${result.payloads.length - 1} more`);
1037
+ }
1038
+ console.log('');
1039
+ return;
1040
+ }
1041
+ console.log(`\n✅ ${result.message}`);
1042
+ if (result.endpoint) console.log(` Endpoint: ${result.endpoint}`);
1043
+ console.log('');
1044
+ } catch (err) {
1045
+ console.error(`\n ✗ ${err.message}\n`);
1046
+ process.exit(1);
1047
+ }
1048
+ })();
1049
+ break;
1050
+ }
1051
+ if (sub === 'status') {
1052
+ const st = feedbackSubmit.submitStatus();
1053
+ console.log('\n── Feedback submit status ───────────────────────────');
1054
+ console.log(` Consent: ${st.consent}`);
1055
+ console.log(` Endpoint: ${st.endpoint}`);
1056
+ console.log(` Anon key: ${st.anonKey}`);
1057
+ console.log(` Unsent: ${st.unsentCount} entr${st.unsentCount === 1 ? 'y' : 'ies'}`);
1058
+ console.log(` Install id: ${st.installId} (anonymous)`);
1059
+ console.log(` Package: ${st.packageVersion}`);
1060
+ console.log('');
1061
+ break;
1062
+ }
1063
+ if (sub === 'revoke') {
1064
+ feedbackSubmit.revokeConsent();
1065
+ console.log('\n🛑 Opt-in consent revoked. Run feedback submit again to re-consent.\n');
1066
+ break;
1067
+ }
1068
+ console.error(`\nUnknown feedback subcommand: "${sub}". Use: record | list | export | submit | status | revoke\n`);
1069
+ process.exit(1);
1070
+ }
1071
+
1072
+ // ── LoRA readiness: training-pair export (Phase 5, hook only) ──────────
1073
+
1074
+ case 'export-training': {
1075
+ if (!personaVal) {
1076
+ console.error('\n ✗ --persona is required. Example: npx analyzthis_design export-training --persona arjun\n');
1077
+ process.exit(1);
1078
+ }
1079
+ try {
1080
+ const result = exportTraining({ persona: personaVal, project: projectVal, all: allFlag, output: outputVal });
1081
+ console.log(`\n✅ Wrote ${result.pairs} accepted training pair(s) for "${personaVal}" to ${result.filePath}`);
1082
+ if (!result.pairs) {
1083
+ console.log(` No accepted outputs found. Mark one first: npx analyzthis_design session accept --persona ${personaVal}`);
1084
+ }
1085
+ console.log('');
1086
+ } catch (err) {
1087
+ console.error(`\n ✗ ${err.message}\n`);
1088
+ process.exit(1);
1089
+ }
1090
+ break;
1091
+ }
1092
+
1093
+ case 'evolve': {
1094
+ const evolve = require('../lib/evolve');
1095
+ const windowArg = getFlag('window');
1096
+ const windowDays = windowArg ? parseInt(windowArg, 10) : 7;
1097
+ if (flags.includes('--extract')) {
1098
+ (async () => {
1099
+ try {
1100
+ const report = await evolve.runEvolution({ windowDays, dryRun: dryRunFlag });
1101
+ console.log('\n── Evolution report ' + (dryRunFlag ? '(dry run)' : '') + ' ──');
1102
+ console.log(' Lessons extracted: ' + report.extracted_lessons);
1103
+ console.log(' Outcomes inferred: ' + report.inferred_outcomes);
1104
+ console.log(' Prompt patches: ' + report.prompt_patches.length);
1105
+ console.log(' Reference proposals:' + report.reference_proposals.length);
1106
+ console.log(' Router patches: ' + report.router_patches.length);
1107
+ for (const p of report.prompt_patches) {
1108
+ console.log('\n Patch: ' + p.id + ' — ' + p.persona + ' — ' + p.description);
1109
+ }
1110
+ for (const p of report.reference_proposals) {
1111
+ console.log('\n Reference: ' + p.id + ' — ' + p.persona + ' — ' + p.description);
1112
+ }
1113
+ for (const p of report.router_patches) {
1114
+ console.log('\n Router: ' + p.id + ' — ' + p.task_type + ' → ' + p.suggested_route_to.join(', '));
1115
+ }
1116
+ console.log('');
1117
+ } catch (err) {
1118
+ console.error(`\n ✗ ${err.message}\n`);
1119
+ process.exit(1);
1120
+ }
1121
+ })();
1122
+ break;
1123
+ }
1124
+ if (flags.includes('--apply')) {
1125
+ const applyId = getFlag('apply');
1126
+ if (!applyId) {
1127
+ console.error('\n �� --apply requires a patch id\n');
1128
+ process.exit(1);
1129
+ }
1130
+ try {
1131
+ const result = evolve.applyPatch({ patchId: applyId, dryRun: dryRunFlag });
1132
+ if (result.preview) {
1133
+ console.log('\n── Dry-run patch preview ──');
1134
+ console.log(' Target: ' + result.targetFile);
1135
+ console.log(' Preview:\n' + result.preview.slice(0, 1200));
1136
+ } else {
1137
+ console.log('\n��� Patch ' + (result.applied ? 'applied' : 'previewed') + ': ' + applyId);
1138
+ if (result.targetFile) console.log(' Target: ' + result.targetFile);
1139
+ if (result.message) console.log(' Note: ' + result.message);
1140
+ }
1141
+ console.log('');
1142
+ } catch (err) {
1143
+ console.error(`\n �� ${err.message}\n`);
1144
+ process.exit(1);
1145
+ }
1146
+ break;
1147
+ }
1148
+ if (flags.includes('--metrics')) {
1149
+ const em = require('../lib/evolution-metrics');
1150
+ const m = em.computeEvolutionMetrics(projectVal);
1151
+ console.log('\n' + em.formatEvolutionSummary(m));
1152
+ break;
1153
+ }
1154
+ if (flags.includes('--ready')) {
1155
+ const em = require('../lib/evolution-metrics');
1156
+ const ready = em.checkEvolutionReady(projectVal);
1157
+ console.log('\n' + (ready.ready ? '[READY] ' : '[PENDING] ') + ready.reason);
1158
+ console.log('');
1159
+ console.log(em.formatEvolutionSummary(ready.metrics));
1160
+ break;
1161
+ }
1162
+ console.log('\n Usage: evolve --extract [--window N] [--dry-run] | evolve --apply <patchId> [--dry-run] | evolve --metrics | evolve --ready\n');
1163
+ break;
1164
+ }
1165
+
1166
+ case 'outcome': {
1167
+ const outcome = require('../lib/outcome');
1168
+ if (flags.includes('--infer')) {
1169
+ const windowArg2 = getFlag('window');
1170
+ const wd = windowArg2 ? parseInt(windowArg2, 10) : 7;
1171
+ try {
1172
+ const result = outcome.inferAllOutcomes({ windowDays: wd });
1173
+ console.log('\n✅ Inferred ' + result.inferred + ' outcome(s), ' + result.confirmed + ' confirmed, ' + result.unknown + ' unknown.\n');
1174
+ } catch (err) {
1175
+ console.error(`\n ✗ ${err.message}\n`);
1176
+ process.exit(1);
1177
+ }
1178
+ break;
1179
+ }
1180
+ if (flags.includes('--pending')) {
1181
+ const pending = outcome.listPendingConfirmations();
1182
+ if (!pending.length) {
1183
+ console.log('\n No pending outcome confirmations.\n');
1184
+ } else {
1185
+ console.log('\n── Pending outcome confirmations (' + pending.length + ') ──');
1186
+ for (const p of pending) {
1187
+ console.log(' ' + p.project + ' / ' + p.persona + ': ' + p.inferred + ' (' + p.reason + ')');
1188
+ }
1189
+ console.log('');
1190
+ }
1191
+ break;
1192
+ }
1193
+ if (flags.includes('--confirm')) {
1194
+ if (!personaVal) {
1195
+ console.error('\n ✗ --persona is required for --confirm\n');
1196
+ process.exit(1);
1197
+ }
1198
+ const resultVal = getFlag('result');
1199
+ if (!resultVal) {
1200
+ console.error('\n ✗ --result is required (shipped | revised | blocked_correctly | missed)\n');
1201
+ process.exit(1);
1202
+ }
1203
+ try {
1204
+ outcome.confirmOutcome({ project: projectVal, persona: personaVal, outcome: resultVal });
1205
+ console.log('\n✅ Outcome confirmed: ' + personaVal + ' = ' + resultVal + '\n');
1206
+ } catch (err) {
1207
+ console.error(`\n ✗ ${err.message}\n`);
1208
+ process.exit(1);
1209
+ }
1210
+ break;
1211
+ }
1212
+ console.log('\n Usage: outcome --infer [--window N] | outcome --pending | outcome --confirm --persona X --result Y\n');
1213
+ break;
1214
+ }
1215
+
1216
+ case '--help':
1217
+ case 'help':
1218
+ case '-h':
1219
+ console.log(HELP);
1220
+ break;
1221
+
1222
+ default:
1223
+ console.error(`\nUnknown command: "${cmd}"\n`);
1224
+ console.log(HELP);
1225
+ process.exit(1);
1226
+ }