sillyspec 3.20.3 → 3.20.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/sillyspec-archive/SKILL.md +21 -17
- package/.claude/skills/sillyspec-auto/SKILL.md +83 -77
- package/.claude/skills/sillyspec-brainstorm/SKILL.md +44 -17
- package/.claude/skills/sillyspec-commit/SKILL.md +106 -105
- package/.claude/skills/sillyspec-continue/SKILL.md +45 -44
- package/.claude/skills/sillyspec-doctor/SKILL.md +31 -22
- package/.claude/skills/sillyspec-execute/SKILL.md +30 -17
- package/.claude/skills/sillyspec-explore/SKILL.md +109 -96
- package/.claude/skills/sillyspec-knowledge/SKILL.md +270 -0
- package/.claude/skills/sillyspec-plan/SKILL.md +21 -52
- package/.claude/skills/sillyspec-propose/SKILL.md +21 -17
- package/.claude/skills/sillyspec-quick/SKILL.md +21 -17
- package/.claude/skills/sillyspec-resume/SKILL.md +68 -111
- package/.claude/skills/sillyspec-scan/SKILL.md +21 -17
- package/.claude/skills/sillyspec-state/SKILL.md +54 -54
- package/.claude/skills/sillyspec-status/SKILL.md +21 -17
- package/.claude/skills/sillyspec-verify/SKILL.md +21 -17
- package/.claude/skills/sillyspec-workspace/SKILL.md +157 -149
- package/.husky/pre-push +13 -0
- package/CLAUDE.md +18 -0
- package/README.md +198 -186
- package/SKILL.md +90 -87
- package/bin/sillyspec.js +2 -2
- package/docs/brainstorm-plan-contract.md +64 -0
- package/docs/plan-execute-contract.md +123 -0
- package/docs/platform-scan-protocol.md +298 -0
- package/docs/revision-mode.md +115 -0
- package/docs/sillyspec/file-lifecycle/known-implementation-gaps.md +99 -0
- package/docs/sillyspec/file-lifecycle/platform-workflows-sync.md +218 -0
- package/docs/sillyspec/file-lifecycle/stage-artifacts.md +167 -0
- package/docs/sillyspec/file-lifecycle/storage-and-state.md +148 -0
- package/docs/sillyspec/file-lifecycle/worktree-and-guard.md +211 -0
- package/docs/sillyspec/file-lifecycle.md +131 -0
- package/docs/workflow-contract-regression.md +106 -0
- package/docs/worktree-isolation.md +252 -0
- package/package.json +40 -34
- package/packages/dashboard/dist/assets/{index-D1EVTLmc.js → index-Bq_Z2hne.js} +7446 -7446
- package/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -0
- package/packages/dashboard/dist/index.html +16 -16
- package/packages/dashboard/dist/prototype-dashboard.html +836 -0
- package/packages/dashboard/dist/prototype-overview.html +256 -0
- package/packages/dashboard/index.html +15 -15
- package/packages/dashboard/package-lock.json +2384 -2384
- package/packages/dashboard/package.json +25 -25
- package/packages/dashboard/public/prototype-dashboard.html +836 -0
- package/packages/dashboard/public/prototype-overview.html +256 -0
- package/packages/dashboard/server/executor.js +86 -86
- package/packages/dashboard/server/index.js +588 -508
- package/packages/dashboard/server/parser.js +526 -458
- package/packages/dashboard/server/watcher.js +350 -342
- package/packages/dashboard/src/App.vue +558 -325
- package/packages/dashboard/src/components/ActionBar.vue +93 -84
- package/packages/dashboard/src/components/CommandPalette.vue +96 -92
- package/packages/dashboard/src/components/DetailPanel.vue +137 -137
- package/packages/dashboard/src/components/DocPreview.vue +105 -8
- package/packages/dashboard/src/components/DocTree.vue +75 -19
- package/packages/dashboard/src/components/HResizeHandle.vue +48 -0
- package/packages/dashboard/src/components/LogStream.vue +65 -65
- package/packages/dashboard/src/components/PipelineStage.vue +95 -75
- package/packages/dashboard/src/components/PipelineView.vue +156 -129
- package/packages/dashboard/src/components/ProjectCard.vue +187 -0
- package/packages/dashboard/src/components/ProjectList.vue +210 -210
- package/packages/dashboard/src/components/ProjectOverview.vue +113 -139
- package/packages/dashboard/src/components/StageBadge.vue +67 -53
- package/packages/dashboard/src/components/StepCard.vue +94 -89
- package/packages/dashboard/src/components/VResizeHandle.vue +61 -0
- package/packages/dashboard/src/components/detail/DocsDetail.vue +48 -48
- package/packages/dashboard/src/components/detail/GitDetail.vue +61 -61
- package/packages/dashboard/src/components/detail/TechDetail.vue +43 -43
- package/packages/dashboard/src/composables/useDashboard.js +192 -164
- package/packages/dashboard/src/composables/useKeyboard.js +119 -119
- package/packages/dashboard/src/composables/useLayout.js +131 -0
- package/packages/dashboard/src/composables/useWebSocket.js +129 -129
- package/packages/dashboard/src/main.js +8 -8
- package/packages/dashboard/src/style.css +132 -132
- package/packages/dashboard/vite.config.js +18 -18
- package/src/brainstorm-postcheck.js +158 -0
- package/src/change-list.js +52 -0
- package/src/change-risk-profile.js +352 -0
- package/src/classify-change.js +73 -0
- package/src/constants.js +70 -0
- package/src/contract-matrix.js +278 -0
- package/src/db.js +201 -0
- package/src/endpoint-extractor.js +315 -0
- package/src/hooks/claude-pre-tool-use.cjs +125 -0
- package/src/hooks/worktree-guard.js +761 -0
- package/src/index.js +922 -252
- package/src/init.js +470 -375
- package/src/knowledge-match.js +130 -0
- package/src/migrate.js +117 -117
- package/src/modules.js +482 -0
- package/src/progress.js +1734 -508
- package/src/run.js +3465 -652
- package/src/scan-postcheck.js +387 -0
- package/src/setup.js +398 -460
- package/src/stage-contract.js +700 -0
- package/src/stages/archive.js +160 -54
- package/src/stages/brainstorm-auto.js +229 -0
- package/src/stages/brainstorm.js +645 -239
- package/src/stages/doctor.js +365 -312
- package/src/stages/execute.js +634 -264
- package/src/stages/explore.js +34 -0
- package/src/stages/index.js +29 -35
- package/src/stages/knowledge.js +498 -0
- package/src/stages/plan-postcheck.js +518 -0
- package/src/stages/plan.js +582 -279
- package/src/stages/propose.js +174 -115
- package/src/stages/quick.js +102 -63
- package/src/stages/scan.js +558 -141
- package/src/stages/status.js +65 -65
- package/src/stages/verify.js +322 -135
- package/src/sync.js +497 -0
- package/src/task-review.js +346 -0
- package/src/workflow.js +785 -0
- package/src/worktree-apply.js +549 -0
- package/src/worktree-deps.js +185 -0
- package/src/worktree.js +982 -0
- package/templates/workflows/archive-impact.yaml +79 -0
- package/templates/workflows/scan-docs.yaml +132 -0
- package/test/brainstorm-plan-contract.test.mjs +273 -0
- package/test/check-syntax.mjs +26 -0
- package/test/cli-top-level-aliases.test.mjs +174 -0
- package/test/contract-artifacts.test.mjs +323 -0
- package/test/decision-supersede.test.mjs +277 -0
- package/test/knowledge-match.test.mjs +231 -0
- package/test/plan-execute-contract.test.mjs +357 -0
- package/test/plan-optimization.test.mjs +572 -0
- package/test/platform-artifacts.test.mjs +190 -0
- package/test/platform-failure-samples.test.mjs +199 -0
- package/test/platform-recovery-chain.test.mjs +179 -0
- package/test/platform-recovery.test.mjs +167 -0
- package/test/platform-scan-p0.test.mjs +175 -0
- package/test/revision-v1.test.mjs +1145 -0
- package/test/run-sanitize-project-name.test.mjs +51 -0
- package/test/run-scan-postcheck-fail.test.mjs +64 -0
- package/test/run-scan-project-parse.test.mjs +200 -0
- package/test/run-tests.mjs +48 -0
- package/test/runtime-cleanup-keeps-worktree.test.mjs +107 -0
- package/test/scan-docs-yaml-placeholders.test.mjs +84 -0
- package/test/scan-knowledge.test.mjs +175 -0
- package/test/scan-paths.test.mjs +68 -0
- package/test/scan-postcheck-project-priority.test.mjs +85 -0
- package/test/scan-postcheck.test.mjs +197 -0
- package/test/scan-workflow-anyfailed-block.test.mjs +52 -0
- package/test/spec-dir.test.mjs +206 -0
- package/test/stage-contract-failed-post-check.test.mjs +102 -0
- package/test/stage-contract.test.mjs +299 -0
- package/test/stage-definitions.test.mjs +39 -0
- package/test/wait-gates.test.mjs +501 -0
- package/test/workflow-spec-base.test.mjs +142 -0
- package/test/worktree-deps-provision.test.mjs +148 -0
- package/test/worktree-guard.test.mjs +136 -0
- package/test/worktree-native-overlay.test.mjs +188 -0
- package/.sillyspec/changes/archive/2026-04-08-derive-state/design.md +0 -97
- package/.sillyspec/changes/archive/2026-04-08-derive-state/plan.md +0 -51
- package/.sillyspec/changes/archive/2026-04-08-derive-state/proposal.md +0 -29
- package/.sillyspec/changes/archive/2026-04-08-derive-state/requirements.md +0 -34
- package/.sillyspec/changes/archive/2026-04-08-derive-state/tasks.md +0 -13
- package/.sillyspec/changes/archive/2026-04-08-derive-state/verify-result.md +0 -43
- package/.sillyspec/changes/auto-mode/design.md +0 -50
- package/.sillyspec/changes/auto-mode/proposal.md +0 -19
- package/.sillyspec/changes/auto-mode/requirements.md +0 -21
- package/.sillyspec/changes/auto-mode/tasks.md +0 -7
- package/.sillyspec/changes/brainstorm-archive/2026-04-05-dashboard-design.md +0 -206
- package/.sillyspec/changes/brainstorm-archive/2026-04-05-unified-docs-design.md +0 -199
- package/.sillyspec/changes/dashboard/design.md +0 -219
- package/.sillyspec/changes/dashboard/design.md.braindraft +0 -206
- package/.sillyspec/changes/run-command-design/design.md +0 -1230
- package/.sillyspec/changes/unified-docs-design/design.md +0 -199
- package/.sillyspec/docs/sillyspec/scan/.gitkeep +0 -0
- package/.sillyspec/knowledge/INDEX.md +0 -8
- package/.sillyspec/knowledge/uncategorized.md +0 -3
- package/.sillyspec/plans/2026-04-05-dashboard.md +0 -737
- package/.sillyspec/projects/sillyspec.yaml +0 -3
- package/dist/steps/brainstorm/01-load-context.md +0 -30
- package/dist/steps/brainstorm/02-reuse-check.md +0 -6
- package/dist/steps/brainstorm/03-prototype-analysis.md +0 -11
- package/dist/steps/brainstorm/04-module-split.md +0 -23
- package/dist/steps/brainstorm/05-dialog-explore.md +0 -8
- package/dist/steps/brainstorm/06-propose-approaches.md +0 -3
- package/dist/steps/brainstorm/07-present-design.md +0 -3
- package/dist/steps/brainstorm/08-write-design.md +0 -21
- package/dist/steps/brainstorm/09-self-review.md +0 -15
- package/dist/steps/brainstorm/10-user-confirm.md +0 -3
- package/dist/steps/brainstorm/11-output-spec.md +0 -7
- package/dist/steps/brainstorm/manifest.yaml +0 -26
- package/dist/steps/execute/01-load-context.md +0 -41
- package/dist/steps/execute/02-scan-conventions.md +0 -47
- package/dist/steps/execute/03-skill-mcp.md +0 -19
- package/dist/steps/execute/04-assign-task.md +0 -22
- package/dist/steps/execute/04b-prompt-template.md +0 -54
- package/dist/steps/execute/05-write-test.md +0 -7
- package/dist/steps/execute/06-write-code.md +0 -8
- package/dist/steps/execute/07-run-test.md +0 -26
- package/dist/steps/execute/08-fix-issues.md +0 -28
- package/dist/steps/execute/09-next-task.md +0 -33
- package/dist/steps/execute/manifest.yaml +0 -28
- package/dist/steps/plan/01-load-context.md +0 -22
- package/dist/steps/plan/02-anchor-confirm.md +0 -1
- package/dist/steps/plan/03-expand-tasks.md +0 -33
- package/dist/steps/plan/04-mark-order.md +0 -15
- package/dist/steps/plan/05-e2e-planning.md +0 -17
- package/dist/steps/plan/06-self-check.md +0 -16
- package/dist/steps/plan/07-save.md +0 -1
- package/dist/steps/plan/manifest.yaml +0 -18
- package/dist/steps/scan/01-env-detect.md +0 -51
- package/dist/steps/scan/02-tech-stack.md +0 -16
- package/dist/steps/scan/03-conventions.md +0 -16
- package/dist/steps/scan/04-structure.md +0 -19
- package/dist/steps/scan/05-quality.md +0 -18
- package/dist/steps/scan/06-complete.md +0 -49
- package/dist/steps/scan/manifest.yaml +0 -16
- package/dist/steps/verify/01-load-specs.md +0 -28
- package/dist/steps/verify/02-check-tasks.md +0 -1
- package/dist/steps/verify/03-check-design.md +0 -6
- package/dist/steps/verify/04-run-tests.md +0 -7
- package/dist/steps/verify/05-e2e-tests.md +0 -27
- package/dist/steps/verify/05b-e2e-fix.md +0 -33
- package/dist/steps/verify/06-code-quality.md +0 -25
- package/dist/steps/verify/07-lint-check.md +0 -27
- package/dist/steps/verify/08-output-report.md +0 -14
- package/dist/steps/verify/manifest.yaml +0 -22
- package/packages/dashboard/dist/assets/index-DGe8CqeP.css +0 -1
- package/src/derive.js +0 -147
- package/src/step.js +0 -543
|
@@ -1,121 +1,121 @@
|
|
|
1
|
-
import { reactive, computed } from 'vue'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Dashboard state management composable
|
|
5
|
-
* @returns {object} Dashboard state and methods
|
|
6
|
-
*/
|
|
7
|
-
export function useDashboard() {
|
|
8
|
-
// Reactive state
|
|
9
|
-
const state = reactive({
|
|
10
|
-
projects: [],
|
|
11
|
-
activeProject: null,
|
|
12
|
-
activeStep: null,
|
|
13
|
-
logs: [],
|
|
14
|
-
isPanelOpen: true,
|
|
15
|
-
executingProject: null,
|
|
16
|
-
isLoading: true,
|
|
17
|
-
activeTab: 'pipeline',
|
|
18
|
-
docs: { groups: [] },
|
|
19
|
-
selectedDocFile: null,
|
|
20
|
-
docContent: '',
|
|
21
|
-
docLoading: false
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Get project by name
|
|
26
|
-
* @param {string} name - Project name
|
|
27
|
-
* @returns {object|null} Project or null
|
|
28
|
-
*/
|
|
29
|
-
function getProject(path) {
|
|
30
|
-
return state.projects.find(p => p.path === path) || null
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Select a project as active
|
|
35
|
-
* @param {object|string} project - Project object or path
|
|
36
|
-
*/
|
|
37
|
-
function selectProject(project) {
|
|
38
|
-
const proj = typeof project === 'string'
|
|
39
|
-
? getProject(project)
|
|
40
|
-
: project
|
|
41
|
-
|
|
42
|
-
if (proj) {
|
|
43
|
-
state.activeProject = proj
|
|
44
|
-
state.activeStep = null
|
|
45
|
-
state.logs = []
|
|
46
|
-
state.selectedDocFile = null
|
|
47
|
-
state.docContent = ''
|
|
48
|
-
|
|
49
|
-
// Load initial logs from project state if available
|
|
50
|
-
if (proj.state?.progress?.currentLogs) {
|
|
51
|
-
appendLog(proj.state.progress.currentLogs)
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Select a step within active project
|
|
58
|
-
* @param {object} step - Step object
|
|
59
|
-
*/
|
|
60
|
-
function selectStep(step) {
|
|
61
|
-
state.activeStep = step
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Append log lines to logs buffer
|
|
66
|
-
* @param {string|string[]} lines - Log line(s) to append
|
|
67
|
-
*/
|
|
68
|
-
function appendLog(lines) {
|
|
69
|
-
const newLines = Array.isArray(lines) ? lines : [lines]
|
|
70
|
-
|
|
71
|
-
for (const line of newLines) {
|
|
72
|
-
const timestamp = new Date().toISOString()
|
|
73
|
-
state.logs.push({
|
|
74
|
-
id: `${timestamp}-${Math.random().toString(36).substr(2, 9)}`,
|
|
75
|
-
timestamp,
|
|
76
|
-
content: line,
|
|
77
|
-
type: 'info'
|
|
78
|
-
})
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Keep only last 500 lines
|
|
82
|
-
if (state.logs.length > 500) {
|
|
83
|
-
state.logs = state.logs.slice(-500)
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Clear logs buffer
|
|
89
|
-
*/
|
|
90
|
-
function clearLogs() {
|
|
91
|
-
state.logs = []
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Toggle detail panel open/closed
|
|
96
|
-
*/
|
|
97
|
-
function togglePanel() {
|
|
98
|
-
state.isPanelOpen = !state.isPanelOpen
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Open detail panel
|
|
103
|
-
*/
|
|
104
|
-
function openPanel() {
|
|
105
|
-
state.isPanelOpen = true
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Close detail panel
|
|
110
|
-
*/
|
|
111
|
-
function closePanel() {
|
|
112
|
-
state.isPanelOpen = false
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Update projects list
|
|
117
|
-
* @param {array} projects - New projects array
|
|
118
|
-
*/
|
|
1
|
+
import { reactive, computed } from 'vue'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Dashboard state management composable
|
|
5
|
+
* @returns {object} Dashboard state and methods
|
|
6
|
+
*/
|
|
7
|
+
export function useDashboard() {
|
|
8
|
+
// Reactive state
|
|
9
|
+
const state = reactive({
|
|
10
|
+
projects: [],
|
|
11
|
+
activeProject: null,
|
|
12
|
+
activeStep: null,
|
|
13
|
+
logs: [],
|
|
14
|
+
isPanelOpen: true,
|
|
15
|
+
executingProject: null,
|
|
16
|
+
isLoading: true,
|
|
17
|
+
activeTab: 'pipeline',
|
|
18
|
+
docs: { groups: [] },
|
|
19
|
+
selectedDocFile: null,
|
|
20
|
+
docContent: '',
|
|
21
|
+
docLoading: false
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Get project by name
|
|
26
|
+
* @param {string} name - Project name
|
|
27
|
+
* @returns {object|null} Project or null
|
|
28
|
+
*/
|
|
29
|
+
function getProject(path) {
|
|
30
|
+
return state.projects.find(p => p.path === path) || null
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Select a project as active
|
|
35
|
+
* @param {object|string} project - Project object or path
|
|
36
|
+
*/
|
|
37
|
+
function selectProject(project) {
|
|
38
|
+
const proj = typeof project === 'string'
|
|
39
|
+
? getProject(project)
|
|
40
|
+
: project
|
|
41
|
+
|
|
42
|
+
if (proj) {
|
|
43
|
+
state.activeProject = proj
|
|
44
|
+
state.activeStep = null
|
|
45
|
+
state.logs = []
|
|
46
|
+
state.selectedDocFile = null
|
|
47
|
+
state.docContent = ''
|
|
48
|
+
|
|
49
|
+
// Load initial logs from project state if available
|
|
50
|
+
if (proj.state?.progress?.currentLogs) {
|
|
51
|
+
appendLog(proj.state.progress.currentLogs)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Select a step within active project
|
|
58
|
+
* @param {object} step - Step object
|
|
59
|
+
*/
|
|
60
|
+
function selectStep(step) {
|
|
61
|
+
state.activeStep = step
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Append log lines to logs buffer
|
|
66
|
+
* @param {string|string[]} lines - Log line(s) to append
|
|
67
|
+
*/
|
|
68
|
+
function appendLog(lines) {
|
|
69
|
+
const newLines = Array.isArray(lines) ? lines : [lines]
|
|
70
|
+
|
|
71
|
+
for (const line of newLines) {
|
|
72
|
+
const timestamp = new Date().toISOString()
|
|
73
|
+
state.logs.push({
|
|
74
|
+
id: `${timestamp}-${Math.random().toString(36).substr(2, 9)}`,
|
|
75
|
+
timestamp,
|
|
76
|
+
content: line,
|
|
77
|
+
type: 'info'
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Keep only last 500 lines
|
|
82
|
+
if (state.logs.length > 500) {
|
|
83
|
+
state.logs = state.logs.slice(-500)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Clear logs buffer
|
|
89
|
+
*/
|
|
90
|
+
function clearLogs() {
|
|
91
|
+
state.logs = []
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Toggle detail panel open/closed
|
|
96
|
+
*/
|
|
97
|
+
function togglePanel() {
|
|
98
|
+
state.isPanelOpen = !state.isPanelOpen
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Open detail panel
|
|
103
|
+
*/
|
|
104
|
+
function openPanel() {
|
|
105
|
+
state.isPanelOpen = true
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Close detail panel
|
|
110
|
+
*/
|
|
111
|
+
function closePanel() {
|
|
112
|
+
state.isPanelOpen = false
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Update projects list
|
|
117
|
+
* @param {array} projects - New projects array
|
|
118
|
+
*/
|
|
119
119
|
function updateProjects(projects) {
|
|
120
120
|
state.isLoading = false
|
|
121
121
|
state.projects = projects
|
|
@@ -125,61 +125,89 @@ export function useDashboard() {
|
|
|
125
125
|
const updated = getProject(state.activeProject.path)
|
|
126
126
|
if (updated) {
|
|
127
127
|
state.activeProject = updated
|
|
128
|
+
return
|
|
128
129
|
}
|
|
129
130
|
}
|
|
130
|
-
}
|
|
131
131
|
|
|
132
|
-
|
|
133
|
-
* Set executing project state
|
|
134
|
-
* @param {string|null} projectName - Project name or null
|
|
135
|
-
*/
|
|
136
|
-
function setExecuting(projectName) {
|
|
137
|
-
state.executingProject = projectName
|
|
132
|
+
state.activeProject = state.projects[0] || null
|
|
138
133
|
}
|
|
139
134
|
|
|
140
135
|
/**
|
|
141
|
-
*
|
|
142
|
-
* @param {
|
|
143
|
-
* @returns {boolean}
|
|
136
|
+
* Merge a single project update into the current project list.
|
|
137
|
+
* @param {object} project - Partial project payload containing at least path
|
|
144
138
|
*/
|
|
145
|
-
function
|
|
146
|
-
|
|
147
|
-
}
|
|
139
|
+
function updateProject(project) {
|
|
140
|
+
if (!project?.path) return
|
|
148
141
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const activeProjectPath = computed(() => state.activeProject?.path || null)
|
|
152
|
-
const activeProjectStage = computed(() => state.activeProject?.state?.currentStage || null)
|
|
153
|
-
const hasProjects = computed(() => state.projects.length > 0)
|
|
154
|
-
const activeProjectSteps = computed(() => {
|
|
155
|
-
if (!state.activeProject?.state?.progress?.stages) return []
|
|
156
|
-
const currentStage = state.activeProject.state.currentStage
|
|
157
|
-
const stageData = state.activeProject.state.progress.stages[currentStage]
|
|
158
|
-
return stageData?.steps || []
|
|
159
|
-
})
|
|
142
|
+
const index = state.projects.findIndex(p => p.path === project.path)
|
|
143
|
+
if (index === -1) return
|
|
160
144
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
145
|
+
const updated = {
|
|
146
|
+
...state.projects[index],
|
|
147
|
+
...project,
|
|
148
|
+
state: project.state ?? state.projects[index].state,
|
|
149
|
+
overview: project.overview ?? state.projects[index].overview
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
state.projects.splice(index, 1, updated)
|
|
153
|
+
|
|
154
|
+
if (state.activeProject?.path === project.path) {
|
|
155
|
+
state.activeProject = updated
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Set executing project state
|
|
161
|
+
* @param {string|null} projectName - Project name or null
|
|
162
|
+
*/
|
|
163
|
+
function setExecuting(projectName) {
|
|
164
|
+
state.executingProject = projectName
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Check if a project is currently executing
|
|
169
|
+
* @param {string} projectName - Project name
|
|
170
|
+
* @returns {boolean}
|
|
171
|
+
*/
|
|
172
|
+
function isExecuting(projectName) {
|
|
173
|
+
return state.executingProject === projectName
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Computed properties
|
|
177
|
+
const activeProjectName = computed(() => state.activeProject?.name || null)
|
|
178
|
+
const activeProjectPath = computed(() => state.activeProject?.path || null)
|
|
179
|
+
const activeProjectStage = computed(() => state.activeProject?.state?.currentStage || null)
|
|
180
|
+
const hasProjects = computed(() => state.projects.length > 0)
|
|
181
|
+
const activeProjectSteps = computed(() => {
|
|
182
|
+
if (!state.activeProject?.state?.progress?.stages) return []
|
|
183
|
+
const currentStage = state.activeProject.state.currentStage
|
|
184
|
+
const stageData = state.activeProject.state.progress.stages[currentStage]
|
|
185
|
+
return stageData?.steps || []
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
return {
|
|
189
|
+
state,
|
|
190
|
+
getProject,
|
|
191
|
+
selectProject,
|
|
192
|
+
selectStep,
|
|
193
|
+
appendLog,
|
|
194
|
+
clearLogs,
|
|
195
|
+
togglePanel,
|
|
196
|
+
openPanel,
|
|
170
197
|
closePanel,
|
|
171
198
|
updateProjects,
|
|
199
|
+
updateProject,
|
|
172
200
|
setExecuting,
|
|
173
|
-
isExecuting,
|
|
174
|
-
activeProjectName,
|
|
175
|
-
activeProjectPath,
|
|
176
|
-
activeProjectStage,
|
|
177
|
-
hasProjects,
|
|
178
|
-
activeProjectSteps,
|
|
179
|
-
setActiveTab(tab) { state.activeTab = tab },
|
|
180
|
-
updateDocs(docs) { state.docs = docs },
|
|
181
|
-
selectDocFile(file) { state.selectedDocFile = file },
|
|
182
|
-
setDocContent(content) { state.docContent = content },
|
|
183
|
-
setDocLoading(loading) { state.docLoading = loading }
|
|
184
|
-
}
|
|
185
|
-
}
|
|
201
|
+
isExecuting,
|
|
202
|
+
activeProjectName,
|
|
203
|
+
activeProjectPath,
|
|
204
|
+
activeProjectStage,
|
|
205
|
+
hasProjects,
|
|
206
|
+
activeProjectSteps,
|
|
207
|
+
setActiveTab(tab) { state.activeTab = tab },
|
|
208
|
+
updateDocs(docs) { state.docs = docs },
|
|
209
|
+
selectDocFile(file) { state.selectedDocFile = file },
|
|
210
|
+
setDocContent(content) { state.docContent = content },
|
|
211
|
+
setDocLoading(loading) { state.docLoading = loading }
|
|
212
|
+
}
|
|
213
|
+
}
|
|
@@ -1,119 +1,119 @@
|
|
|
1
|
-
import { onMounted, onUnmounted } from 'vue'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Keyboard shortcuts composable
|
|
5
|
-
* @param {object} options - Configuration options
|
|
6
|
-
* @returns {object} Keyboard API
|
|
7
|
-
*/
|
|
8
|
-
export function useKeyboard(options = {}) {
|
|
9
|
-
const {
|
|
10
|
-
onCmdK = null,
|
|
11
|
-
onJ = null,
|
|
12
|
-
onK = null,
|
|
13
|
-
onEscape = null,
|
|
14
|
-
onEnter = null,
|
|
15
|
-
onArrowUp = null,
|
|
16
|
-
onArrowDown = null,
|
|
17
|
-
disabled: initialDisabled = false
|
|
18
|
-
} = options
|
|
19
|
-
|
|
20
|
-
let isDisabled = initialDisabled
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Handle keyboard events
|
|
24
|
-
* @param {KeyboardEvent} event
|
|
25
|
-
*/
|
|
26
|
-
function handleKeyDown(event) {
|
|
27
|
-
if (isDisabled) return
|
|
28
|
-
|
|
29
|
-
// Ignore if in input field
|
|
30
|
-
const target = event.target
|
|
31
|
-
if (target.tagName === 'INPUT' ||
|
|
32
|
-
target.tagName === 'TEXTAREA' ||
|
|
33
|
-
target.contentEditable === 'true') {
|
|
34
|
-
return
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0
|
|
38
|
-
const cmdOrCtrl = isMac ? event.metaKey : event.ctrlKey
|
|
39
|
-
|
|
40
|
-
// Cmd/Ctrl + K
|
|
41
|
-
if (cmdOrCtrl && event.key === 'k') {
|
|
42
|
-
event.preventDefault()
|
|
43
|
-
if (onCmdK) onCmdK()
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// J - navigate down
|
|
47
|
-
if (event.key === 'j' && !cmdOrCtrl) {
|
|
48
|
-
event.preventDefault()
|
|
49
|
-
if (onJ) onJ()
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// K - navigate up
|
|
53
|
-
if (event.key === 'k' && !cmdOrCtrl) {
|
|
54
|
-
event.preventDefault()
|
|
55
|
-
if (onK) onK()
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Escape
|
|
59
|
-
if (event.key === 'Escape') {
|
|
60
|
-
event.preventDefault()
|
|
61
|
-
if (onEscape) onEscape()
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Enter
|
|
65
|
-
if (event.key === 'Enter' && !cmdOrCtrl) {
|
|
66
|
-
event.preventDefault()
|
|
67
|
-
if (onEnter) onEnter()
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Arrow Up
|
|
71
|
-
if (event.key === 'ArrowUp' && !cmdOrCtrl) {
|
|
72
|
-
event.preventDefault()
|
|
73
|
-
if (onArrowUp) onArrowUp()
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Arrow Down
|
|
77
|
-
if (event.key === 'ArrowDown' && !cmdOrCtrl) {
|
|
78
|
-
event.preventDefault()
|
|
79
|
-
if (onArrowDown) onArrowDown()
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
onMounted(() => {
|
|
84
|
-
window.addEventListener('keydown', handleKeyDown)
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
onUnmounted(() => {
|
|
88
|
-
window.removeEventListener('keydown', handleKeyDown)
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
return {
|
|
92
|
-
disable: () => { isDisabled = true },
|
|
93
|
-
enable: () => { isDisabled = false }
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Global keyboard shortcuts for dashboard
|
|
99
|
-
* @param {object} callbacks - Callback functions for each shortcut
|
|
100
|
-
* @returns {object} Keyboard API
|
|
101
|
-
*/
|
|
102
|
-
export function useDashboardKeyboard(callbacks = {}) {
|
|
103
|
-
const {
|
|
104
|
-
onOpenCommandPalette,
|
|
105
|
-
onNavigateDown,
|
|
106
|
-
onNavigateUp,
|
|
107
|
-
onClose,
|
|
108
|
-
onSelect,
|
|
109
|
-
onPanelToggle
|
|
110
|
-
} = callbacks
|
|
111
|
-
|
|
112
|
-
return useKeyboard({
|
|
113
|
-
onCmdK: onOpenCommandPalette,
|
|
114
|
-
onJ: onNavigateDown,
|
|
115
|
-
onK: onNavigateUp,
|
|
116
|
-
onEscape: onClose,
|
|
117
|
-
onEnter: onSelect
|
|
118
|
-
})
|
|
119
|
-
}
|
|
1
|
+
import { onMounted, onUnmounted } from 'vue'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Keyboard shortcuts composable
|
|
5
|
+
* @param {object} options - Configuration options
|
|
6
|
+
* @returns {object} Keyboard API
|
|
7
|
+
*/
|
|
8
|
+
export function useKeyboard(options = {}) {
|
|
9
|
+
const {
|
|
10
|
+
onCmdK = null,
|
|
11
|
+
onJ = null,
|
|
12
|
+
onK = null,
|
|
13
|
+
onEscape = null,
|
|
14
|
+
onEnter = null,
|
|
15
|
+
onArrowUp = null,
|
|
16
|
+
onArrowDown = null,
|
|
17
|
+
disabled: initialDisabled = false
|
|
18
|
+
} = options
|
|
19
|
+
|
|
20
|
+
let isDisabled = initialDisabled
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Handle keyboard events
|
|
24
|
+
* @param {KeyboardEvent} event
|
|
25
|
+
*/
|
|
26
|
+
function handleKeyDown(event) {
|
|
27
|
+
if (isDisabled) return
|
|
28
|
+
|
|
29
|
+
// Ignore if in input field
|
|
30
|
+
const target = event.target
|
|
31
|
+
if (target.tagName === 'INPUT' ||
|
|
32
|
+
target.tagName === 'TEXTAREA' ||
|
|
33
|
+
target.contentEditable === 'true') {
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0
|
|
38
|
+
const cmdOrCtrl = isMac ? event.metaKey : event.ctrlKey
|
|
39
|
+
|
|
40
|
+
// Cmd/Ctrl + K
|
|
41
|
+
if (cmdOrCtrl && event.key === 'k') {
|
|
42
|
+
event.preventDefault()
|
|
43
|
+
if (onCmdK) onCmdK()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// J - navigate down
|
|
47
|
+
if (event.key === 'j' && !cmdOrCtrl) {
|
|
48
|
+
event.preventDefault()
|
|
49
|
+
if (onJ) onJ()
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// K - navigate up
|
|
53
|
+
if (event.key === 'k' && !cmdOrCtrl) {
|
|
54
|
+
event.preventDefault()
|
|
55
|
+
if (onK) onK()
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Escape
|
|
59
|
+
if (event.key === 'Escape') {
|
|
60
|
+
event.preventDefault()
|
|
61
|
+
if (onEscape) onEscape()
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Enter
|
|
65
|
+
if (event.key === 'Enter' && !cmdOrCtrl) {
|
|
66
|
+
event.preventDefault()
|
|
67
|
+
if (onEnter) onEnter()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Arrow Up
|
|
71
|
+
if (event.key === 'ArrowUp' && !cmdOrCtrl) {
|
|
72
|
+
event.preventDefault()
|
|
73
|
+
if (onArrowUp) onArrowUp()
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Arrow Down
|
|
77
|
+
if (event.key === 'ArrowDown' && !cmdOrCtrl) {
|
|
78
|
+
event.preventDefault()
|
|
79
|
+
if (onArrowDown) onArrowDown()
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
onMounted(() => {
|
|
84
|
+
window.addEventListener('keydown', handleKeyDown)
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
onUnmounted(() => {
|
|
88
|
+
window.removeEventListener('keydown', handleKeyDown)
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
disable: () => { isDisabled = true },
|
|
93
|
+
enable: () => { isDisabled = false }
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Global keyboard shortcuts for dashboard
|
|
99
|
+
* @param {object} callbacks - Callback functions for each shortcut
|
|
100
|
+
* @returns {object} Keyboard API
|
|
101
|
+
*/
|
|
102
|
+
export function useDashboardKeyboard(callbacks = {}) {
|
|
103
|
+
const {
|
|
104
|
+
onOpenCommandPalette,
|
|
105
|
+
onNavigateDown,
|
|
106
|
+
onNavigateUp,
|
|
107
|
+
onClose,
|
|
108
|
+
onSelect,
|
|
109
|
+
onPanelToggle
|
|
110
|
+
} = callbacks
|
|
111
|
+
|
|
112
|
+
return useKeyboard({
|
|
113
|
+
onCmdK: onOpenCommandPalette,
|
|
114
|
+
onJ: onNavigateDown,
|
|
115
|
+
onK: onNavigateUp,
|
|
116
|
+
onEscape: onClose,
|
|
117
|
+
onEnter: onSelect
|
|
118
|
+
})
|
|
119
|
+
}
|