arkaos 4.22.0 → 4.23.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 (252) hide show
  1. package/THE-ARKAOS-GUIDE.md +72 -0
  2. package/VERSION +1 -1
  3. package/arka/SKILL.md +28 -6
  4. package/arka/skills/bootstrap-agent/SKILL.md +3 -2
  5. package/arka/skills/flow/SKILL.md +3 -2
  6. package/arka/skills/forge/SKILL.md +3 -2
  7. package/arka/skills/recipes/SKILL.md +3 -2
  8. package/arka/skills/refine/SKILL.md +3 -2
  9. package/arka/skills/research/SKILL.md +3 -2
  10. package/bin/arka-doctor +8 -0
  11. package/core/cognition/insights/store.py +15 -4
  12. package/core/forge/persistence.py +27 -9
  13. package/core/forge/schema.py +45 -22
  14. package/core/governance/evidence_checks.py +101 -9
  15. package/core/governance/kb_cite_check.py +16 -6
  16. package/core/governance/stop_lint.py +38 -11
  17. package/core/governance/stop_lint_telemetry.py +11 -2
  18. package/core/hooks/user_prompt_submit.py +21 -23
  19. package/core/synapse/engine.py +46 -16
  20. package/core/synapse/graph_context_layer.py +7 -2
  21. package/core/synapse/kb_cache.py +63 -16
  22. package/core/synapse/layers.py +93 -30
  23. package/core/synapse/layers_base.py +16 -0
  24. package/core/synapse/layers_kb.py +325 -19
  25. package/dashboard/app/layouts/default.vue +7 -0
  26. package/dashboard/app/pages/plan-canvas.vue +630 -0
  27. package/departments/brand/SKILL.md +3 -2
  28. package/departments/brand/skills/archetype-finder/SKILL.md +3 -2
  29. package/departments/brand/skills/colors/SKILL.md +3 -2
  30. package/departments/brand/skills/design-system/SKILL.md +3 -2
  31. package/departments/brand/skills/identity-system/SKILL.md +3 -2
  32. package/departments/brand/skills/logo-brief/SKILL.md +3 -2
  33. package/departments/brand/skills/mockup-generate/SKILL.md +3 -2
  34. package/departments/brand/skills/naming-evaluate/SKILL.md +3 -2
  35. package/departments/brand/skills/positioning-statement/SKILL.md +3 -2
  36. package/departments/brand/skills/primal-audit/SKILL.md +3 -2
  37. package/departments/brand/skills/ux-audit/SKILL.md +3 -2
  38. package/departments/brand/skills/voice-guide/SKILL.md +3 -2
  39. package/departments/brand/skills/wireframe/SKILL.md +3 -2
  40. package/departments/community/SKILL.md +3 -2
  41. package/departments/community/skills/ai-community/SKILL.md +3 -2
  42. package/departments/community/skills/betting-setup/SKILL.md +3 -2
  43. package/departments/community/skills/business-model/SKILL.md +3 -2
  44. package/departments/community/skills/content-calendar/SKILL.md +3 -2
  45. package/departments/community/skills/events-plan/SKILL.md +3 -2
  46. package/departments/community/skills/gamification-design/SKILL.md +3 -2
  47. package/departments/community/skills/growth-plan/SKILL.md +3 -2
  48. package/departments/community/skills/metrics-track/SKILL.md +3 -2
  49. package/departments/community/skills/moderation/SKILL.md +3 -2
  50. package/departments/community/skills/monetize-plan/SKILL.md +3 -2
  51. package/departments/community/skills/niche-setup/SKILL.md +3 -2
  52. package/departments/community/skills/onboarding-flow/SKILL.md +3 -2
  53. package/departments/community/skills/platform-select/SKILL.md +3 -2
  54. package/departments/content/SKILL.md +3 -2
  55. package/departments/content/skills/ai-workflow/SKILL.md +3 -2
  56. package/departments/content/skills/analytics/SKILL.md +3 -2
  57. package/departments/content/skills/calendar/SKILL.md +3 -2
  58. package/departments/content/skills/content-system/SKILL.md +3 -2
  59. package/departments/content/skills/monetization-plan/SKILL.md +3 -2
  60. package/departments/content/skills/newsletter-write/SKILL.md +3 -2
  61. package/departments/content/skills/platform-optimize/SKILL.md +3 -2
  62. package/departments/content/skills/repurpose-plan/SKILL.md +3 -2
  63. package/departments/content/skills/research-compile/SKILL.md +3 -2
  64. package/departments/content/skills/script-structure/SKILL.md +3 -2
  65. package/departments/content/skills/short-form/SKILL.md +3 -2
  66. package/departments/content/skills/thumbnail-package/SKILL.md +3 -2
  67. package/departments/content/skills/trend-hunt/SKILL.md +3 -2
  68. package/departments/content/skills/video-produce/SKILL.md +3 -2
  69. package/departments/content/skills/video-setup/SKILL.md +3 -2
  70. package/departments/content/skills/viral-design/SKILL.md +3 -2
  71. package/departments/content/skills/youtube-strategy/SKILL.md +3 -2
  72. package/departments/dev/SKILL.md +3 -2
  73. package/departments/dev/skills/ai-assisted-dev/SKILL.md +3 -2
  74. package/departments/dev/skills/animated-website/SKILL.md +7 -0
  75. package/departments/dev/skills/architecture-design/SKILL.md +3 -2
  76. package/departments/dev/skills/code-review/SKILL.md +3 -2
  77. package/departments/dev/skills/db-design/SKILL.md +3 -2
  78. package/departments/dev/skills/ddd-model/SKILL.md +3 -2
  79. package/departments/dev/skills/demo-gif/SKILL.md +3 -2
  80. package/departments/dev/skills/deploy/SKILL.md +3 -2
  81. package/departments/dev/skills/devops-pipeline/SKILL.md +3 -2
  82. package/departments/dev/skills/docs/SKILL.md +3 -2
  83. package/departments/dev/skills/mcp/SKILL.md +3 -2
  84. package/departments/dev/skills/performance-audit/SKILL.md +3 -2
  85. package/departments/dev/skills/refactor-plan/SKILL.md +3 -2
  86. package/departments/dev/skills/research/SKILL.md +3 -2
  87. package/departments/dev/skills/security-compliance/SKILL.md +3 -2
  88. package/departments/dev/skills/stack-check/SKILL.md +3 -2
  89. package/departments/ecom/SKILL.md +3 -2
  90. package/departments/ecom/skills/analytics/SKILL.md +3 -2
  91. package/departments/ecom/skills/browse-competitor/SKILL.md +3 -2
  92. package/departments/ecom/skills/cart-recovery/SKILL.md +3 -2
  93. package/departments/ecom/skills/cro-optimize/SKILL.md +3 -2
  94. package/departments/ecom/skills/customer-journey/SKILL.md +3 -2
  95. package/departments/ecom/skills/fulfillment-plan/SKILL.md +3 -2
  96. package/departments/ecom/skills/marketplace-manage/SKILL.md +3 -2
  97. package/departments/ecom/skills/pricing-strategy/SKILL.md +3 -2
  98. package/departments/ecom/skills/product-launch/SKILL.md +3 -2
  99. package/departments/ecom/skills/rfm-segment/SKILL.md +3 -2
  100. package/departments/ecom/skills/social-commerce/SKILL.md +3 -2
  101. package/departments/ecom/skills/store-audit/SKILL.md +3 -2
  102. package/departments/ecom/skills/subscription-model/SKILL.md +3 -2
  103. package/departments/finance/SKILL.md +3 -2
  104. package/departments/finance/skills/budget-plan/SKILL.md +3 -2
  105. package/departments/finance/skills/cashflow-forecast/SKILL.md +3 -2
  106. package/departments/finance/skills/ciso-advisor/SKILL.md +3 -2
  107. package/departments/finance/skills/financial-model/SKILL.md +3 -2
  108. package/departments/finance/skills/pitch-deck/SKILL.md +3 -2
  109. package/departments/finance/skills/scenario-analysis/SKILL.md +3 -2
  110. package/departments/finance/skills/unit-economics/SKILL.md +3 -2
  111. package/departments/finance/skills/valuation-model/SKILL.md +3 -2
  112. package/departments/kb/SKILL.md +3 -2
  113. package/departments/kb/skills/ai-research/SKILL.md +3 -2
  114. package/departments/kb/skills/competitive-intel/SKILL.md +3 -2
  115. package/departments/kb/skills/doc-extraction/SKILL.md +3 -2
  116. package/departments/kb/skills/doc-redaction/SKILL.md +3 -2
  117. package/departments/kb/skills/knowledge-ops/SKILL.md +3 -2
  118. package/departments/kb/skills/knowledge-review/SKILL.md +3 -2
  119. package/departments/kb/skills/learn-content/SKILL.md +3 -2
  120. package/departments/kb/skills/moc-create/SKILL.md +3 -2
  121. package/departments/kb/skills/persona-build/SKILL.md +3 -2
  122. package/departments/kb/skills/research-plan/SKILL.md +3 -2
  123. package/departments/kb/skills/search-kb/SKILL.md +3 -2
  124. package/departments/kb/skills/source-evaluate/SKILL.md +3 -2
  125. package/departments/kb/skills/taxonomy-manage/SKILL.md +3 -2
  126. package/departments/kb/skills/write-as-persona/SKILL.md +3 -2
  127. package/departments/landing/SKILL.md +3 -2
  128. package/departments/landing/skills/ab-test/SKILL.md +3 -2
  129. package/departments/landing/skills/affiliate-bridge/SKILL.md +3 -2
  130. package/departments/landing/skills/awareness-diagnose/SKILL.md +3 -2
  131. package/departments/landing/skills/email-sequence/SKILL.md +3 -2
  132. package/departments/landing/skills/funnel-metrics/SKILL.md +3 -2
  133. package/departments/landing/skills/headline-write/SKILL.md +3 -2
  134. package/departments/landing/skills/launch-sequence/SKILL.md +3 -2
  135. package/departments/landing/skills/offer-create/SKILL.md +3 -2
  136. package/departments/landing/skills/optimize-page/SKILL.md +3 -2
  137. package/departments/landing/skills/page-architect/SKILL.md +3 -2
  138. package/departments/landing/skills/persuasion-apply/SKILL.md +3 -2
  139. package/departments/landing/skills/webinar-funnel/SKILL.md +3 -2
  140. package/departments/leadership/SKILL.md +3 -2
  141. package/departments/leadership/skills/change-manage/SKILL.md +3 -2
  142. package/departments/leadership/skills/conflict-resolve/SKILL.md +3 -2
  143. package/departments/leadership/skills/culture-audit/SKILL.md +3 -2
  144. package/departments/leadership/skills/delegation-matrix/SKILL.md +3 -2
  145. package/departments/leadership/skills/disc-assess/SKILL.md +3 -2
  146. package/departments/leadership/skills/feedback-give/SKILL.md +3 -2
  147. package/departments/leadership/skills/hiring-plan/SKILL.md +3 -2
  148. package/departments/leadership/skills/performance-review/SKILL.md +3 -2
  149. package/departments/marketing/SKILL.md +3 -2
  150. package/departments/marketing/skills/ab-test/SKILL.md +3 -2
  151. package/departments/marketing/skills/analytics-report/SKILL.md +3 -2
  152. package/departments/marketing/skills/audience-segment/SKILL.md +3 -2
  153. package/departments/marketing/skills/calendar-plan/SKILL.md +3 -2
  154. package/departments/marketing/skills/competitor-analysis/SKILL.md +3 -2
  155. package/departments/marketing/skills/content-audit/SKILL.md +3 -2
  156. package/departments/marketing/skills/email-sequence/SKILL.md +3 -2
  157. package/departments/marketing/skills/growth-loop/SKILL.md +3 -2
  158. package/departments/marketing/skills/marketing-automation/SKILL.md +3 -2
  159. package/departments/marketing/skills/paid-campaign/SKILL.md +3 -2
  160. package/departments/marketing/skills/programmatic-seo/SKILL.md +3 -2
  161. package/departments/marketing/skills/seo-audit/SKILL.md +3 -2
  162. package/departments/marketing/skills/social-strategy/SKILL.md +3 -2
  163. package/departments/ops/SKILL.md +3 -2
  164. package/departments/ops/skills/bottleneck-find/SKILL.md +3 -2
  165. package/departments/ops/skills/dashboard-build/SKILL.md +3 -2
  166. package/departments/ops/skills/gdpr-compliance/SKILL.md +3 -2
  167. package/departments/ops/skills/github-ops/SKILL.md +3 -2
  168. package/departments/ops/skills/gtd-setup/SKILL.md +3 -2
  169. package/departments/ops/skills/integration-design/SKILL.md +3 -2
  170. package/departments/ops/skills/iso27001/SKILL.md +3 -2
  171. package/departments/ops/skills/lean-audit/SKILL.md +3 -2
  172. package/departments/ops/skills/metrics-dashboard/SKILL.md +3 -2
  173. package/departments/ops/skills/n8n-flow/SKILL.md +3 -2
  174. package/departments/ops/skills/quality-management/SKILL.md +3 -2
  175. package/departments/ops/skills/risk-management/SKILL.md +3 -2
  176. package/departments/ops/skills/soc2-compliance/SKILL.md +3 -2
  177. package/departments/ops/skills/sop-create/SKILL.md +3 -2
  178. package/departments/ops/skills/terminal-ops/SKILL.md +3 -2
  179. package/departments/ops/skills/workflow-automate/SKILL.md +3 -2
  180. package/departments/ops/skills/zapier-flow/SKILL.md +3 -2
  181. package/departments/org/SKILL.md +3 -2
  182. package/departments/org/skills/compensation-plan/SKILL.md +3 -2
  183. package/departments/org/skills/culture-define/SKILL.md +3 -2
  184. package/departments/org/skills/decision-framework/SKILL.md +3 -2
  185. package/departments/org/skills/hiring-plan/SKILL.md +3 -2
  186. package/departments/org/skills/meeting-optimize/SKILL.md +3 -2
  187. package/departments/org/skills/onboarding-design/SKILL.md +3 -2
  188. package/departments/org/skills/org-design/SKILL.md +3 -2
  189. package/departments/org/skills/remote-setup/SKILL.md +3 -2
  190. package/departments/org/skills/sop-process/SKILL.md +3 -2
  191. package/departments/org/skills/team-assess/SKILL.md +3 -2
  192. package/departments/pm/SKILL.md +3 -2
  193. package/departments/pm/skills/backlog-groom/SKILL.md +3 -2
  194. package/departments/pm/skills/discovery-plan/SKILL.md +3 -2
  195. package/departments/pm/skills/estimate-forecast/SKILL.md +3 -2
  196. package/departments/pm/skills/impact-map/SKILL.md +3 -2
  197. package/departments/pm/skills/kanban-setup/SKILL.md +3 -2
  198. package/departments/pm/skills/risk-register/SKILL.md +3 -2
  199. package/departments/pm/skills/roadmap-build/SKILL.md +3 -2
  200. package/departments/pm/skills/sprint-plan/SKILL.md +3 -2
  201. package/departments/pm/skills/stakeholder-map/SKILL.md +3 -2
  202. package/departments/pm/skills/standup-run/SKILL.md +3 -2
  203. package/departments/pm/skills/story-write/SKILL.md +3 -2
  204. package/departments/saas/SKILL.md +3 -2
  205. package/departments/saas/skills/benchmark-compare/SKILL.md +3 -2
  206. package/departments/saas/skills/churn-analysis/SKILL.md +3 -2
  207. package/departments/saas/skills/customer-success/SKILL.md +3 -2
  208. package/departments/saas/skills/growth-plan/SKILL.md +3 -2
  209. package/departments/saas/skills/gtm-strategy/SKILL.md +3 -2
  210. package/departments/saas/skills/launch-execute/SKILL.md +3 -2
  211. package/departments/saas/skills/metrics-dashboard/SKILL.md +3 -2
  212. package/departments/saas/skills/micro-saas-stack/SKILL.md +3 -2
  213. package/departments/saas/skills/mvp-build/SKILL.md +3 -2
  214. package/departments/saas/skills/niche-evaluate/SKILL.md +3 -2
  215. package/departments/saas/skills/onboarding-optimize/SKILL.md +3 -2
  216. package/departments/saas/skills/plg-setup/SKILL.md +3 -2
  217. package/departments/saas/skills/pricing-strategy/SKILL.md +3 -2
  218. package/departments/saas/skills/validate-idea/SKILL.md +3 -2
  219. package/departments/sales/SKILL.md +3 -2
  220. package/departments/sales/skills/challenger-sell/SKILL.md +3 -2
  221. package/departments/sales/skills/deal-qualify/SKILL.md +3 -2
  222. package/departments/sales/skills/discovery-call/SKILL.md +3 -2
  223. package/departments/sales/skills/forecast-revenue/SKILL.md +3 -2
  224. package/departments/sales/skills/negotiate-plan/SKILL.md +3 -2
  225. package/departments/sales/skills/objection-handle/SKILL.md +3 -2
  226. package/departments/sales/skills/pipeline-manage/SKILL.md +3 -2
  227. package/departments/sales/skills/pricing-negotiate/SKILL.md +3 -2
  228. package/departments/strategy/SKILL.md +3 -2
  229. package/departments/strategy/skills/blue-ocean/SKILL.md +3 -2
  230. package/departments/strategy/skills/bmc/SKILL.md +3 -2
  231. package/departments/strategy/skills/board-advisor/SKILL.md +3 -2
  232. package/departments/strategy/skills/cto-advisor/SKILL.md +3 -2
  233. package/departments/strategy/skills/extract-data/SKILL.md +3 -2
  234. package/departments/strategy/skills/five-forces/SKILL.md +3 -2
  235. package/departments/strategy/skills/growth-strategy/SKILL.md +3 -2
  236. package/departments/strategy/skills/moat-analysis/SKILL.md +3 -2
  237. package/departments/strategy/skills/position/SKILL.md +3 -2
  238. package/departments/strategy/skills/scenario-plan/SKILL.md +3 -2
  239. package/installer/config-seed.js +81 -25
  240. package/installer/graphify.js +340 -0
  241. package/installer/index.js +8 -1
  242. package/installer/keys.js +18 -3
  243. package/installer/update.js +8 -1
  244. package/knowledge/skills-manifest.json +1 -1
  245. package/mcps/registry.json +9 -9
  246. package/mcps/scripts/apply-mcps.sh +6 -2
  247. package/package.json +2 -1
  248. package/pyproject.toml +1 -1
  249. package/scripts/dashboard-api.py +336 -124
  250. package/scripts/guide_gen.py +139 -0
  251. package/scripts/migrate_skills_kb_first.py +3 -2
  252. package/scripts/synapse-bridge.py +9 -1
@@ -0,0 +1,630 @@
1
+ <script setup lang="ts">
2
+ // Plan Canvas — review and decide on Forge plans (design direction
3
+ // validated by brand 2026-07-20: master-detail, Decision Rail as the
4
+ // page's single EKG-family signature, green budget = awaiting-review
5
+ // accent + approved badge + Approve button, keyboard-first).
6
+
7
+ interface PlanSummary {
8
+ id: string
9
+ name: string
10
+ status: string
11
+ tier: string
12
+ confidence: number
13
+ created_at: string
14
+ }
15
+
16
+ interface PlanPhase {
17
+ name: string
18
+ department: string
19
+ agents: string[]
20
+ deliverables: string[]
21
+ acceptance_criteria: string[]
22
+ depends_on: string[]
23
+ }
24
+
25
+ interface PlanDetail {
26
+ id: string
27
+ name: string
28
+ created_at: string
29
+ forged_by: string
30
+ goal: string
31
+ status: string
32
+ approved_at: string | null
33
+ approved_by: string | null
34
+ rejected_at: string | null
35
+ rejected_by: string | null
36
+ executed_at: string | null
37
+ review_note: string | null
38
+ plan_phases: PlanPhase[]
39
+ complexity: { score: number, tier: string }
40
+ critic: {
41
+ confidence: number
42
+ // IdentifiedRisk serializes risk/mitigation/severity, not description.
43
+ risks: { risk?: string, mitigation?: string, severity?: string }[]
44
+ rejected_elements: { element?: string, reason?: string }[]
45
+ }
46
+ governance: {
47
+ constitution_check: string
48
+ violations: string[]
49
+ quality_gate_required: boolean
50
+ }
51
+ execution_path: { type: string, target: string, departments: string[] }
52
+ degraded: boolean
53
+ }
54
+
55
+ const { fetchApi, apiBase } = useApi()
56
+ const toast = useToast()
57
+ const confirm = useConfirmDialog()
58
+
59
+ const { data, status, error, refresh } = await fetchApi<{
60
+ plans: PlanSummary[]
61
+ active_id: string | null
62
+ }>('/api/plans')
63
+
64
+ const plans = computed(() => data.value?.plans ?? [])
65
+ const activeId = computed(() => data.value?.active_id ?? null)
66
+ const awaiting = computed(() =>
67
+ plans.value.filter(p => ['draft', 'reviewing'].includes(p.status)).length
68
+ )
69
+ const executing = computed(() =>
70
+ plans.value.filter(p => p.status === 'executing').length
71
+ )
72
+
73
+ const selectedId = ref<string | null>(null)
74
+ const detailPath = computed(() =>
75
+ selectedId.value ? `/api/plans/${selectedId.value}` : ''
76
+ )
77
+ const {
78
+ data: detailData,
79
+ status: detailStatus,
80
+ refresh: refreshDetail
81
+ } = await fetchApi<{ plan?: PlanDetail, legacy?: boolean, error?: string }>(
82
+ () => detailPath.value,
83
+ { immediate: false, watch: false }
84
+ )
85
+ // Explicit over reactive-URL magic: with immediate:false the watcher
86
+ // chain proved unreliable in the production build — refetch on select.
87
+ watch(selectedId, (id) => {
88
+ if (id) refreshDetail()
89
+ })
90
+ const plan = computed(() => detailData.value?.plan ?? null)
91
+ const legacy = computed(() => detailData.value?.legacy === true)
92
+
93
+ // ── status vocabulary (green stays scarce: approved only) ──────────────
94
+ type BadgeColor = 'error' | 'primary' | 'info' | 'warning' | 'neutral'
95
+ type BadgeVariant = 'outline' | 'subtle'
96
+ const STATUS_BADGE: Record<string, { color: BadgeColor, variant: BadgeVariant }> = {
97
+ draft: { color: 'neutral', variant: 'outline' },
98
+ reviewing: { color: 'warning', variant: 'subtle' },
99
+ approved: { color: 'primary', variant: 'subtle' },
100
+ executing: { color: 'info', variant: 'subtle' },
101
+ completed: { color: 'neutral', variant: 'subtle' },
102
+ rejected: { color: 'error', variant: 'subtle' },
103
+ cancelled: { color: 'neutral', variant: 'outline' },
104
+ archived: { color: 'neutral', variant: 'outline' }
105
+ }
106
+ const badgeFor = (s: string) => STATUS_BADGE[s] ?? STATUS_BADGE.draft!
107
+
108
+ const decidable = computed(() =>
109
+ plan.value && !legacy.value
110
+ ? ['draft', 'reviewing'].includes(plan.value.status)
111
+ : false
112
+ )
113
+
114
+ // ── selection + keyboard (j/k/enter/esc/a/r; inputs are guarded by
115
+ // Nuxt UI's default usingInput=false) ─────────────────────────────────
116
+ const cursor = ref(0)
117
+ watch(plans, (list) => {
118
+ if (cursor.value >= list.length) cursor.value = Math.max(0, list.length - 1)
119
+ })
120
+ const select = (id: string) => {
121
+ selectedId.value = id
122
+ cursor.value = plans.value.findIndex(p => p.id === id)
123
+ }
124
+ defineShortcuts({
125
+ j: () => {
126
+ if (plans.value.length) {
127
+ cursor.value = Math.min(cursor.value + 1, plans.value.length - 1)
128
+ }
129
+ },
130
+ k: () => {
131
+ if (plans.value.length) cursor.value = Math.max(cursor.value - 1, 0)
132
+ },
133
+ enter: () => {
134
+ const target = plans.value[cursor.value]
135
+ if (target) select(target.id)
136
+ },
137
+ escape: () => { selectedId.value = null },
138
+ a: () => { if (decidable.value) decide('approve') },
139
+ r: () => { if (decidable.value) decide('reject') }
140
+ })
141
+
142
+ // ── tabs + raw escape-hatch ────────────────────────────────────────────
143
+ const tab = ref<'phases' | 'forge'>('phases')
144
+ const showRaw = ref(false)
145
+ watch(selectedId, () => {
146
+ tab.value = 'phases'
147
+ showRaw.value = false
148
+ })
149
+
150
+ // ── decision ───────────────────────────────────────────────────────────
151
+ const note = ref('')
152
+ const deciding = ref(false)
153
+ watch(selectedId, () => {
154
+ note.value = ''
155
+ })
156
+
157
+ async function decide(action: 'approve' | 'reject') {
158
+ if (!plan.value || deciding.value) return
159
+ if (action === 'reject') {
160
+ const ok = await confirm({
161
+ title: `Reject "${plan.value.name}"`,
162
+ description: 'The plan moves to rejected — a terminal state. '
163
+ + 'Your note stays on the record as the rationale.',
164
+ confirmLabel: 'Reject plan',
165
+ variant: 'danger'
166
+ })
167
+ if (!ok) return
168
+ }
169
+ deciding.value = true
170
+ try {
171
+ const result = await $fetch<{ status?: string, error?: string }>(
172
+ `${apiBase}/api/plans/${plan.value.id}/decision`,
173
+ { method: 'POST', body: { action, note: note.value } }
174
+ )
175
+ if (result.error) {
176
+ toast.add({ title: 'Decision refused', description: result.error, color: 'error' })
177
+ } else {
178
+ toast.add({
179
+ title: action === 'approve' ? 'Plan approved' : 'Plan rejected',
180
+ color: action === 'approve' ? 'primary' : 'neutral'
181
+ })
182
+ note.value = ''
183
+ await Promise.all([refresh(), refreshDetail()])
184
+ }
185
+ } catch {
186
+ toast.add({ title: 'Decision failed', description: 'API unreachable.', color: 'error' })
187
+ } finally {
188
+ deciding.value = false
189
+ }
190
+ }
191
+
192
+ // ── Decision Rail (the signature): static line, real trail only ────────
193
+ const RAIL = ['draft', 'reviewing', 'approved', 'executing', 'completed']
194
+ const NEGATIVE = ['rejected', 'cancelled']
195
+ const railStations = computed(() => {
196
+ if (!plan.value) return []
197
+ const p = plan.value
198
+ const negative = NEGATIVE.includes(p.status)
199
+ const reachedIndex = negative
200
+ ? RAIL.indexOf('reviewing')
201
+ : RAIL.indexOf(p.status === 'archived' ? 'completed' : p.status)
202
+ return RAIL.map((stage, i) => ({
203
+ stage,
204
+ reached: i <= reachedIndex,
205
+ current: !negative && stage === (p.status === 'archived' ? 'completed' : p.status),
206
+ detail: stage === 'draft' && p.created_at
207
+ ? `forged ${formatWhen(p.created_at)}${p.forged_by ? ` · ${p.forged_by}` : ''}`
208
+ : stage === 'approved' && p.approved_at
209
+ ? `${formatWhen(p.approved_at)}${p.approved_by ? ` · ${p.approved_by}` : ''}`
210
+ : stage === 'executing' && p.executed_at
211
+ ? formatWhen(p.executed_at)
212
+ : '',
213
+ note: stage === 'approved' && p.status !== 'rejected' ? p.review_note : null
214
+ }))
215
+ })
216
+ const negativeTerminal = computed(() => {
217
+ if (!plan.value || !NEGATIVE.includes(plan.value.status)) return null
218
+ const p = plan.value
219
+ const trail = p.rejected_at
220
+ ? `${formatWhen(p.rejected_at)}${p.rejected_by ? ` · ${p.rejected_by}` : ''}`
221
+ : ''
222
+ return {
223
+ stage: p.status,
224
+ detail: trail,
225
+ note: p.review_note
226
+ }
227
+ })
228
+
229
+ function formatWhen(iso: string): string {
230
+ const d = new Date(iso)
231
+ return Number.isNaN(d.getTime())
232
+ ? iso
233
+ : d.toLocaleDateString('en-GB', { day: '2-digit', month: 'short' })
234
+ + ' ' + d.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' })
235
+ }
236
+
237
+ // ── polling (ArkaLiveFeed cadence; paused when the tab is hidden) ──────
238
+ const visibility = useDocumentVisibility()
239
+ let poll: ReturnType<typeof setInterval> | undefined
240
+ onMounted(() => {
241
+ poll = setInterval(() => {
242
+ if (visibility.value === 'visible') refresh()
243
+ }, 15_000)
244
+ })
245
+ onBeforeUnmount(() => {
246
+ if (poll) clearInterval(poll)
247
+ })
248
+ </script>
249
+
250
+ <template>
251
+ <UDashboardPanel id="plan-canvas">
252
+ <template #header>
253
+ <UDashboardNavbar title="Plan Canvas">
254
+ <template #leading>
255
+ <UDashboardSidebarCollapse />
256
+ </template>
257
+ <template #right>
258
+ <UButton
259
+ icon="i-lucide-refresh-cw"
260
+ color="neutral"
261
+ variant="ghost"
262
+ aria-label="Refresh plans"
263
+ @click="() => refresh()"
264
+ />
265
+ </template>
266
+ </UDashboardNavbar>
267
+ </template>
268
+
269
+ <template #body>
270
+ <DashboardState
271
+ :status="status"
272
+ :error="error"
273
+ :empty="!plans.length"
274
+ empty-title="No forge plans yet"
275
+ empty-description="Plans land here when The Forge persists them — run /arka forge on a task."
276
+ empty-icon="i-lucide-drafting-compass"
277
+ :on-retry="() => refresh()"
278
+ >
279
+ <div class="mx-auto w-full max-w-6xl space-y-10 py-2">
280
+ <ArkaPageHero
281
+ numeral="I"
282
+ label="plan canvas"
283
+ title="The plan is the contract."
284
+ subtitle="Read deeply, decide once, leave a trail — approval is an operator act, not a formality."
285
+ >
286
+ <template #stats>
287
+ <div class="mt-4 grid grid-cols-1 gap-4 sm:grid-cols-2">
288
+ <ArkaStatCard
289
+ label="awaiting review"
290
+ :value="awaiting"
291
+ accent
292
+ hint="draft + reviewing — the number that changes your next action"
293
+ />
294
+ <ArkaStatCard
295
+ label="executing"
296
+ :value="executing"
297
+ hint="approved and in motion"
298
+ />
299
+ </div>
300
+ </template>
301
+ </ArkaPageHero>
302
+
303
+ <ArkaSection numeral="II" label="queue · review">
304
+ <div class="grid grid-cols-1 gap-6 lg:grid-cols-5">
305
+ <!-- master: the queue -->
306
+ <div class="lg:col-span-2 space-y-1" role="listbox" aria-label="Forge plans">
307
+ <button
308
+ v-for="(p, i) in plans"
309
+ :key="p.id"
310
+ type="button"
311
+ role="option"
312
+ :aria-selected="selectedId === p.id"
313
+ class="w-full rounded-md border px-3 py-2.5 text-left transition-colors duration-150 focus-visible:outline-2 focus-visible:outline-primary"
314
+ :class="[
315
+ selectedId === p.id
316
+ ? 'border-[var(--ui-border-accented)] bg-[var(--ui-bg-elevated)]'
317
+ : 'border-transparent hover:bg-[var(--ui-bg-elevated)]',
318
+ cursor === i ? 'ring-1 ring-[var(--ui-border-accented)]' : ''
319
+ ]"
320
+ @click="select(p.id)"
321
+ >
322
+ <div class="flex items-center justify-between gap-2">
323
+ <span class="truncate text-sm font-medium">
324
+ {{ p.name || p.id }}
325
+ </span>
326
+ <UBadge
327
+ :color="badgeFor(p.status).color"
328
+ :variant="badgeFor(p.status).variant"
329
+ size="sm"
330
+ class="shrink-0 capitalize"
331
+ >
332
+ <UIcon
333
+ v-if="p.status === 'completed'"
334
+ name="i-lucide-check"
335
+ class="size-3"
336
+ />
337
+ {{ p.status }}
338
+ </UBadge>
339
+ </div>
340
+ <div class="mt-1 flex items-center gap-3 text-xs text-muted">
341
+ <span class="arka-data">{{ p.tier }}</span>
342
+ <span class="arka-data">conf {{ (p.confidence ?? 0).toFixed(2) }}</span>
343
+ <span v-if="p.id === activeId" class="arka-eyebrow">active</span>
344
+ </div>
345
+ </button>
346
+ <p class="px-3 pt-2 text-[11px] text-muted">
347
+ <kbd>j</kbd>/<kbd>k</kbd> navigate · <kbd>↵</kbd> open ·
348
+ <kbd>esc</kbd> close · <kbd>a</kbd> approve · <kbd>r</kbd> reject
349
+ </p>
350
+ </div>
351
+
352
+ <!-- detail: review pane + Decision Rail -->
353
+ <div class="lg:col-span-3">
354
+ <ArkaGlowCard v-if="plan" :live="decidable">
355
+ <div class="grid grid-cols-1 gap-6 xl:grid-cols-[1fr_215px]">
356
+ <div class="min-w-0 space-y-4">
357
+ <header class="space-y-1">
358
+ <div class="flex items-start justify-between gap-3">
359
+ <h2 class="arka-serif-title text-2xl leading-tight">
360
+ {{ plan.name || plan.id }}
361
+ </h2>
362
+ <UButton
363
+ :label="showRaw ? 'hide raw' : 'raw'"
364
+ color="neutral"
365
+ variant="ghost"
366
+ size="xs"
367
+ icon="i-lucide-braces"
368
+ :aria-expanded="showRaw"
369
+ @click="showRaw = !showRaw"
370
+ />
371
+ </div>
372
+ <p class="arka-data text-xs text-muted">
373
+ {{ plan.id }}
374
+ </p>
375
+ <p v-if="plan.goal" class="text-sm text-muted">
376
+ {{ plan.goal }}
377
+ </p>
378
+ <UBadge
379
+ v-if="plan.degraded"
380
+ color="warning"
381
+ variant="subtle"
382
+ size="sm"
383
+ >
384
+ degraded forge — constitution phases only
385
+ </UBadge>
386
+ <UBadge
387
+ v-if="legacy"
388
+ color="neutral"
389
+ variant="outline"
390
+ size="sm"
391
+ >
392
+ legacy format — read-only
393
+ </UBadge>
394
+ </header>
395
+
396
+ <pre
397
+ v-if="showRaw"
398
+ class="arka-data max-h-72 overflow-auto rounded-md border border-[var(--ui-border)] bg-[var(--ui-bg)] p-3 text-[11px] leading-relaxed"
399
+ >{{ JSON.stringify(plan, null, 2) }}</pre>
400
+
401
+ <nav class="flex gap-1 border-b border-[var(--ui-border)]" aria-label="Plan views">
402
+ <button
403
+ v-for="t in (['phases', 'forge'] as const)"
404
+ :key="t"
405
+ type="button"
406
+ class="arka-eyebrow px-3 py-2 transition-colors duration-150"
407
+ :class="tab === t
408
+ ? 'border-b-2 border-primary text-[var(--ui-text)]'
409
+ : 'text-muted hover:text-[var(--ui-text)]'"
410
+ :aria-current="tab === t ? 'true' : undefined"
411
+ @click="tab = t"
412
+ >
413
+ {{ t }}
414
+ </button>
415
+ </nav>
416
+
417
+ <!-- phases: stacked cards to READ (the rail is the
418
+ page's only vertical stepper) -->
419
+ <div v-if="tab === 'phases'" class="space-y-3">
420
+ <div
421
+ v-for="(phase, i) in plan.plan_phases"
422
+ :key="phase.name"
423
+ class="rounded-md border border-[var(--ui-border)] p-3"
424
+ >
425
+ <div class="flex items-center justify-between gap-2">
426
+ <p class="text-sm font-medium">
427
+ <span class="arka-numeral mr-1.5">{{ i + 1 }}</span>
428
+ {{ phase.name }}
429
+ </p>
430
+ <span class="arka-eyebrow shrink-0">{{ phase.department }}</span>
431
+ </div>
432
+ <ul
433
+ v-if="phase.deliverables.length"
434
+ class="mt-2 space-y-1 text-xs text-muted"
435
+ >
436
+ <li v-for="d in phase.deliverables" :key="d" class="flex gap-2">
437
+ <span aria-hidden="true">—</span><span>{{ d }}</span>
438
+ </li>
439
+ </ul>
440
+ <p
441
+ v-if="phase.acceptance_criteria.length"
442
+ class="mt-2 text-[11px] text-muted"
443
+ >
444
+ <span class="arka-eyebrow">accepts</span>
445
+ {{ phase.acceptance_criteria.join(' · ') }}
446
+ </p>
447
+ </div>
448
+ <p v-if="!plan.plan_phases.length" class="text-sm text-muted">
449
+ This plan carries no phases — inspect the raw payload.
450
+ </p>
451
+ </div>
452
+
453
+ <!-- forge: complexity, critic, governance -->
454
+ <div v-else class="space-y-4 text-sm">
455
+ <div class="grid grid-cols-2 gap-3">
456
+ <div class="rounded-md border border-[var(--ui-border)] p-3">
457
+ <p class="arka-eyebrow">
458
+ complexity
459
+ </p>
460
+ <p class="mt-1">
461
+ <span class="arka-data text-lg">{{ plan.complexity.score }}</span>
462
+ <span class="ml-2 text-xs text-muted">{{ plan.complexity.tier }}</span>
463
+ </p>
464
+ </div>
465
+ <div class="rounded-md border border-[var(--ui-border)] p-3">
466
+ <p class="arka-eyebrow">
467
+ critic confidence
468
+ </p>
469
+ <p class="arka-data mt-1 text-lg">
470
+ {{ (plan.critic.confidence ?? 0).toFixed(2) }}
471
+ </p>
472
+ </div>
473
+ </div>
474
+ <div v-if="plan.critic.risks.length">
475
+ <p class="arka-eyebrow mb-1.5">
476
+ risks identified
477
+ </p>
478
+ <ul class="space-y-1 text-xs text-muted">
479
+ <li v-for="(risk, i) in plan.critic.risks" :key="i" class="flex flex-col gap-0.5">
480
+ <span>
481
+ <span class="mr-1.5 uppercase">{{ risk.severity || 'risk' }}</span>
482
+ {{ risk.risk || '—' }}
483
+ </span>
484
+ <span v-if="risk.mitigation" class="pl-1 italic">
485
+ → {{ risk.mitigation }}
486
+ </span>
487
+ </li>
488
+ </ul>
489
+ </div>
490
+ <div>
491
+ <p class="arka-eyebrow mb-1.5">
492
+ governance
493
+ </p>
494
+ <p class="text-xs text-muted">
495
+ constitution: {{ plan.governance.constitution_check }}
496
+ · quality gate:
497
+ {{ plan.governance.quality_gate_required ? 'required' : 'not required' }}
498
+ · path: {{ plan.execution_path.type }}
499
+ <template v-if="plan.execution_path.target">
500
+ → {{ plan.execution_path.target }}
501
+ </template>
502
+ </p>
503
+ <p
504
+ v-if="plan.governance.violations.length"
505
+ class="mt-1 text-xs text-error"
506
+ >
507
+ violations: {{ plan.governance.violations.join('; ') }}
508
+ </p>
509
+ </div>
510
+ </div>
511
+ </div>
512
+
513
+ <!-- The Decision Rail: static line, stations, real trail.
514
+ Only the current station pulses. -->
515
+ <aside aria-label="Plan lifecycle and decision">
516
+ <ol class="relative ml-2 border-l border-[var(--ui-border)] pl-5">
517
+ <li
518
+ v-for="station in railStations"
519
+ :key="station.stage"
520
+ class="relative pb-5 last:pb-0"
521
+ >
522
+ <span
523
+ class="absolute -left-[27px] top-0.5 flex size-3 items-center justify-center"
524
+ aria-hidden="true"
525
+ >
526
+ <span v-if="station.current" class="arka-live-dot" />
527
+ <span
528
+ v-else
529
+ class="size-1.5 rounded-full"
530
+ :class="station.reached
531
+ ? 'bg-[var(--ui-text-muted)]'
532
+ : 'bg-[var(--ui-border)]'"
533
+ />
534
+ </span>
535
+ <p
536
+ class="arka-eyebrow"
537
+ :class="station.current
538
+ ? 'text-[var(--ui-text)]'
539
+ : station.reached ? '' : 'opacity-40'"
540
+ >
541
+ {{ station.stage }}
542
+ </p>
543
+ <p v-if="station.detail" class="arka-data mt-0.5 text-[10px] text-muted">
544
+ {{ station.detail }}
545
+ </p>
546
+ <p
547
+ v-if="station.note"
548
+ class="mt-1 border-l-2 border-[var(--ui-border)] pl-2 text-[11px] italic text-muted"
549
+ >
550
+ {{ station.note }}
551
+ </p>
552
+ </li>
553
+ </ol>
554
+
555
+ <!-- negative terminal leaves the line (deviation IS
556
+ the meaning) -->
557
+ <div
558
+ v-if="negativeTerminal"
559
+ class="ml-6 mt-3 rounded-md border border-dashed border-[var(--ui-border)] p-2.5"
560
+ >
561
+ <p class="arka-eyebrow capitalize text-muted">
562
+ {{ negativeTerminal.stage }}
563
+ </p>
564
+ <p
565
+ v-if="negativeTerminal.detail"
566
+ class="arka-data mt-0.5 text-[10px] text-muted"
567
+ >
568
+ {{ negativeTerminal.detail }}
569
+ </p>
570
+ <p
571
+ v-if="negativeTerminal.note"
572
+ class="mt-1 text-[11px] italic text-muted"
573
+ >
574
+ {{ negativeTerminal.note }}
575
+ </p>
576
+ </div>
577
+
578
+ <!-- decision zone: anchored at the rail, one primary CTA -->
579
+ <div v-if="decidable" class="mt-5 space-y-2.5">
580
+ <UTextarea
581
+ v-model="note"
582
+ placeholder="Decision note (lands on the record)"
583
+ :rows="3"
584
+ class="w-full"
585
+ aria-label="Decision note"
586
+ />
587
+ <div class="flex flex-col gap-2">
588
+ <UButton
589
+ label="Approve plan"
590
+ color="primary"
591
+ icon="i-lucide-check"
592
+ block
593
+ :loading="deciding"
594
+ @click="decide('approve')"
595
+ />
596
+ <UButton
597
+ label="Reject"
598
+ color="neutral"
599
+ variant="outline"
600
+ icon="i-lucide-x"
601
+ block
602
+ :disabled="deciding"
603
+ @click="decide('reject')"
604
+ />
605
+ </div>
606
+ </div>
607
+ </aside>
608
+ </div>
609
+ </ArkaGlowCard>
610
+
611
+ <div
612
+ v-else
613
+ class="flex h-full min-h-48 items-center justify-center rounded-md border border-dashed border-[var(--ui-border)]"
614
+ >
615
+ <p v-if="detailStatus === 'pending'" class="text-sm text-muted" role="status">
616
+ <UIcon name="i-lucide-loader-2" class="mr-1 inline size-4 animate-spin" />
617
+ loading plan…
618
+ </p>
619
+ <p v-else class="max-w-56 text-center text-sm text-muted">
620
+ Select a plan to review — the queue stays in sight while you read.
621
+ </p>
622
+ </div>
623
+ </div>
624
+ </div>
625
+ </ArkaSection>
626
+ </div>
627
+ </DashboardState>
628
+ </template>
629
+ </UDashboardPanel>
630
+ </template>
@@ -8,8 +8,9 @@ allowed-tools: [Read, Write, Edit, Bash, Grep, Glob, Agent, WebFetch, WebSearch]
8
8
  ---
9
9
 
10
10
  <!-- arka:kb-first-prefix begin -->
11
- > **KB-first:** query `mcp__obsidian__search_notes` and cite
12
- > `[[wikilinks]]` — or declare the gap — BEFORE any external research.
11
+ > **KB-first:** query `mcp__obsidian__search_notes` (and
12
+ > `mcp__graphify__query_graph` when configured) and cite `[[wikilinks]]`
13
+ > or graph nodes — or declare the gap — BEFORE any external research.
13
14
  > Full doctrine: `arka/SKILL.md` (KB-First Research).
14
15
  <!-- arka:kb-first-prefix end -->
15
16
 
@@ -12,8 +12,9 @@ allowed-tools: [Read, Write, Edit, Bash, Grep, Glob, Agent, WebFetch, WebSearch]
12
12
  ---
13
13
 
14
14
  <!-- arka:kb-first-prefix begin -->
15
- > **KB-first:** query `mcp__obsidian__search_notes` and cite
16
- > `[[wikilinks]]` — or declare the gap — BEFORE any external research.
15
+ > **KB-first:** query `mcp__obsidian__search_notes` (and
16
+ > `mcp__graphify__query_graph` when configured) and cite `[[wikilinks]]`
17
+ > or graph nodes — or declare the gap — BEFORE any external research.
17
18
  > Full doctrine: `arka/SKILL.md` (KB-First Research).
18
19
  <!-- arka:kb-first-prefix end -->
19
20
 
@@ -12,8 +12,9 @@ allowed-tools: [Read, Write, Edit, Bash, Grep, Glob, Agent, WebFetch, WebSearch]
12
12
  ---
13
13
 
14
14
  <!-- arka:kb-first-prefix begin -->
15
- > **KB-first:** query `mcp__obsidian__search_notes` and cite
16
- > `[[wikilinks]]` — or declare the gap — BEFORE any external research.
15
+ > **KB-first:** query `mcp__obsidian__search_notes` (and
16
+ > `mcp__graphify__query_graph` when configured) and cite `[[wikilinks]]`
17
+ > or graph nodes — or declare the gap — BEFORE any external research.
17
18
  > Full doctrine: `arka/SKILL.md` (KB-First Research).
18
19
  <!-- arka:kb-first-prefix end -->
19
20
 
@@ -14,8 +14,9 @@ allowed-tools: [Read, Write, Edit, Bash, Grep, Glob, Agent, WebFetch, WebSearch]
14
14
  ---
15
15
 
16
16
  <!-- arka:kb-first-prefix begin -->
17
- > **KB-first:** query `mcp__obsidian__search_notes` and cite
18
- > `[[wikilinks]]` — or declare the gap — BEFORE any external research.
17
+ > **KB-first:** query `mcp__obsidian__search_notes` (and
18
+ > `mcp__graphify__query_graph` when configured) and cite `[[wikilinks]]`
19
+ > or graph nodes — or declare the gap — BEFORE any external research.
19
20
  > Full doctrine: `arka/SKILL.md` (KB-First Research).
20
21
  <!-- arka:kb-first-prefix end -->
21
22