@spekn/cli 1.0.1 → 1.0.2
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/dist/main.js +34806 -29538
- package/dist/prompts/governance-analysis.prompt.md +109 -0
- package/dist/resources/prompts/repo-analysis.prompt.md +28 -136
- package/dist/resources/prompts/repo-sync-analysis.prompt.md +31 -68
- package/dist/tui/app.d.ts +7 -0
- package/dist/tui/app.js +122 -0
- package/dist/tui/args.d.ts +8 -0
- package/dist/tui/args.js +57 -0
- package/dist/tui/capabilities/policy.d.ts +7 -0
- package/dist/tui/capabilities/policy.js +64 -0
- package/dist/tui/chunk-4WEASLXY.mjs +3444 -0
- package/dist/tui/chunk-755CADEG.mjs +3401 -0
- package/dist/tui/chunk-BUJQVTY5.mjs +3409 -0
- package/dist/tui/chunk-BZKKMGFB.mjs +1959 -0
- package/dist/tui/chunk-DJYOBCNM.mjs +3159 -0
- package/dist/tui/chunk-GTFTFDY4.mjs +3417 -0
- package/dist/tui/chunk-IMEBD2KA.mjs +3444 -0
- package/dist/tui/chunk-IX6DR5SW.mjs +3433 -0
- package/dist/tui/chunk-JKFOY4IF.mjs +2003 -0
- package/dist/tui/chunk-OXXZ3O5L.mjs +3378 -0
- package/dist/tui/chunk-SHJNIAAJ.mjs +1697 -0
- package/dist/tui/chunk-V4SNDRUS.mjs +1666 -0
- package/dist/tui/chunk-VXVHNZST.mjs +1666 -0
- package/dist/tui/chunk-WCTSFKTA.mjs +3459 -0
- package/dist/tui/chunk-X2XP5ACW.mjs +3443 -0
- package/dist/tui/chunk-YUYJ7VBG.mjs +2029 -0
- package/dist/tui/chunk-ZM3EI5IA.mjs +3384 -0
- package/dist/tui/chunk-ZYOX64HP.mjs +1653 -0
- package/dist/tui/components/frame.d.ts +8 -0
- package/dist/tui/components/frame.js +8 -0
- package/dist/tui/components/status-bar.d.ts +8 -0
- package/dist/tui/components/status-bar.js +8 -0
- package/dist/tui/index.d.ts +2 -0
- package/dist/tui/index.js +23 -0
- package/dist/tui/index.mjs +6999 -6938
- package/dist/tui/keymap/use-global-keymap.d.ts +19 -0
- package/dist/tui/keymap/use-global-keymap.js +82 -0
- package/dist/tui/navigation/nav-items.d.ts +3 -0
- package/dist/tui/navigation/nav-items.js +18 -0
- package/dist/tui/prompts/spec-creation-system.prompt.md +47 -0
- package/dist/tui/prompts/spec-refinement-system.prompt.md +72 -0
- package/dist/tui/screens/bridge.d.ts +8 -0
- package/dist/tui/screens/bridge.js +19 -0
- package/dist/tui/screens/decisions.d.ts +5 -0
- package/dist/tui/screens/decisions.js +28 -0
- package/dist/tui/screens/export.d.ts +5 -0
- package/dist/tui/screens/export.js +16 -0
- package/dist/tui/screens/home.d.ts +5 -0
- package/dist/tui/screens/home.js +33 -0
- package/dist/tui/screens/locked.d.ts +5 -0
- package/dist/tui/screens/locked.js +9 -0
- package/dist/tui/screens/specs.d.ts +5 -0
- package/dist/tui/screens/specs.js +31 -0
- package/dist/tui/services/client.d.ts +1 -0
- package/dist/tui/services/client.js +18 -0
- package/dist/tui/services/context-service.d.ts +19 -0
- package/dist/tui/services/context-service.js +246 -0
- package/dist/tui/shared-enums.d.ts +16 -0
- package/dist/tui/shared-enums.js +19 -0
- package/dist/tui/state/use-app-state.d.ts +35 -0
- package/dist/tui/state/use-app-state.js +177 -0
- package/dist/tui/types.d.ts +77 -0
- package/dist/tui/types.js +2 -0
- package/dist/tui/use-session-store-63YUGUFA.mjs +8 -0
- package/dist/tui/use-session-store-ACO2SMJC.mjs +8 -0
- package/dist/tui/use-session-store-BVFDAWOB.mjs +8 -0
- package/dist/tui/use-session-store-DJIZ3FQZ.mjs +9 -0
- package/dist/tui/use-session-store-EAIQA4UG.mjs +9 -0
- package/dist/tui/use-session-store-EFBAXC3G.mjs +8 -0
- package/dist/tui/use-session-store-FJOR4KTG.mjs +8 -0
- package/dist/tui/use-session-store-IJE5KVOC.mjs +8 -0
- package/dist/tui/use-session-store-KGAFXCKI.mjs +8 -0
- package/dist/tui/use-session-store-KS4DPNDY.mjs +8 -0
- package/dist/tui/use-session-store-MMHJENNL.mjs +8 -0
- package/dist/tui/use-session-store-OZ6HC4I2.mjs +9 -0
- package/dist/tui/use-session-store-PTMWISNJ.mjs +8 -0
- package/dist/tui/use-session-store-VCDECQMW.mjs +8 -0
- package/dist/tui/use-session-store-VOK5ML5J.mjs +9 -0
- package/package.json +6 -3
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
You are a governance analyst evaluating a repository's governance health. You have full access to the repository filesystem.
|
|
2
|
+
|
|
3
|
+
## Repository Context:
|
|
4
|
+
- Path: {{REPO_PATH}}{{LANG_CONTEXT}}{{SIZE_CONTEXT}}
|
|
5
|
+
- **Static baseline score: {{STATIC_SCORE}}/100**
|
|
6
|
+
- Per-check static scores:
|
|
7
|
+
{{CHECK_SCORES}}
|
|
8
|
+
|
|
9
|
+
## Governance Dimensions
|
|
10
|
+
|
|
11
|
+
Evaluate the repository across these 6 governance dimensions. For each, read the relevant files and score independently.
|
|
12
|
+
|
|
13
|
+
### 1. Agent Context Depth (`agent-context-depth`, maxScore: 143, weight: {{WEIGHT_AGENT_CONTEXT}})
|
|
14
|
+
Evaluates how well the repo provides context to AI coding agents — regardless of which agent tools are used. Discover and read any agent context files present (common examples: AGENTS.md, CLAUDE.md, .cursorrules, .github/copilot-instructions.md, GEMINI.md, or similar). Then evaluate the **quality of the context provided**, not which specific files exist:
|
|
15
|
+
- Build/test/lint commands with runnable code blocks
|
|
16
|
+
- Project structure / module map with annotated directories
|
|
17
|
+
- Debugging / troubleshooting / known issues guidance
|
|
18
|
+
- Current phase or focus indicator
|
|
19
|
+
- Per-subsystem verification commands (not just one global test command)
|
|
20
|
+
- Machine-parseable structure (headings, code blocks, YAML frontmatter)
|
|
21
|
+
- Multi-directory coverage: does context mention all major source directories?
|
|
22
|
+
- Modular context: is guidance split into focused files/sections, or one monolithic blob?
|
|
23
|
+
- Nested/per-package context for monorepo subdirectories
|
|
24
|
+
- Low content duplication across files (repeated sentences waste tokens)
|
|
25
|
+
- Reasonable total size (avoid bloating agent context windows)
|
|
26
|
+
|
|
27
|
+
Do NOT prescribe specific filenames, directory layouts, or tool-specific features. Evaluate what IS there and how useful it would be to any AI coding agent.
|
|
28
|
+
|
|
29
|
+
### 2. Spec-Driven Traceability (`spec-traceability`, maxScore: 75, weight: {{WEIGHT_SPEC_TRACEABILITY}})
|
|
30
|
+
Evaluates how well specifications drive development. Look for:
|
|
31
|
+
- specs/ directory with markdown specification documents
|
|
32
|
+
- Spec anchors (structured references like `auth.login.requirements`)
|
|
33
|
+
- Code referencing spec anchors in comments
|
|
34
|
+
- Spec generations (integer generation number in frontmatter)
|
|
35
|
+
- Spec-to-code traceability links
|
|
36
|
+
|
|
37
|
+
### 3. Governance Structure (`governance-structure`, maxScore: 70, weight: {{WEIGHT_GOVERNANCE_STRUCTURE}})
|
|
38
|
+
Evaluates structural governance patterns. Look for:
|
|
39
|
+
- .speknrc.json or equivalent config
|
|
40
|
+
- CI/CD governance hooks (pre-commit, PR checks)
|
|
41
|
+
- CODEOWNERS or equivalent ownership definitions
|
|
42
|
+
- Contribution guidelines (CONTRIBUTING.md)
|
|
43
|
+
- License file
|
|
44
|
+
- Well-organized directory structure
|
|
45
|
+
|
|
46
|
+
### 4. Decision Governance (`decision-governance`, maxScore: 60, weight: {{WEIGHT_DECISION_GOVERNANCE}})
|
|
47
|
+
Evaluates architectural decision tracking. Look for:
|
|
48
|
+
- decisions/ directory with decision records (ADRs/DRs)
|
|
49
|
+
- Decision index file
|
|
50
|
+
- Proper decision status tracking (proposed/accepted/deprecated)
|
|
51
|
+
- Decision dating (createdAt, decidedAt timestamps)
|
|
52
|
+
- Cross-references between decisions and specs
|
|
53
|
+
- Decision templates
|
|
54
|
+
|
|
55
|
+
### 5. Terminology Consistency (`terminology`, maxScore: 100, weight: {{WEIGHT_TERMINOLOGY}})
|
|
56
|
+
Evaluates naming consistency across docs and code. Look for:
|
|
57
|
+
- Consistent product name usage
|
|
58
|
+
- No spelling/casing variants of key terms
|
|
59
|
+
- Consistent component naming across docs and code
|
|
60
|
+
- Code comments using correct terminology
|
|
61
|
+
|
|
62
|
+
### 6. Specification Frontmatter Quality (`frontmatter-quality`, maxScore: 50, weight: {{WEIGHT_FRONTMATTER}})
|
|
63
|
+
Evaluates the quality of YAML frontmatter in spec files. Look for:
|
|
64
|
+
- Required fields: title, type
|
|
65
|
+
- Optional: generation (positive integer)
|
|
66
|
+
- Valid type values (intent, capability, architectural, workflow, operational, decision)
|
|
67
|
+
- Valid status values (draft, review, active, archived)
|
|
68
|
+
- Content hints (constraints, requirements, technical, guidance)
|
|
69
|
+
- Relationships (dependsOn, extends, compatibleWith, conflictsWith)
|
|
70
|
+
|
|
71
|
+
## Task
|
|
72
|
+
|
|
73
|
+
1. Discover and read the repository's governance files — agent context files, specs/, decisions/, and any other governance artifacts
|
|
74
|
+
2. Score each dimension independently (0 to maxScore)
|
|
75
|
+
3. For each dimension, list specific findings with severity (error/warning/info) and actionable messages
|
|
76
|
+
4. Provide strategic recommendations
|
|
77
|
+
|
|
78
|
+
Respond ONLY with valid JSON (no markdown fences, no explanation outside JSON):
|
|
79
|
+
{
|
|
80
|
+
"checkScores": [
|
|
81
|
+
{
|
|
82
|
+
"checkId": "string (one of the 6 IDs above)",
|
|
83
|
+
"score": "number (0 to maxScore for that check)",
|
|
84
|
+
"maxScore": "number (the maxScore listed above)",
|
|
85
|
+
"weight": "number (the weight listed above)",
|
|
86
|
+
"summary": "string (1-2 sentence assessment)",
|
|
87
|
+
"findings": [
|
|
88
|
+
{
|
|
89
|
+
"checkId": "string (same as parent)",
|
|
90
|
+
"severity": "error|warning|info",
|
|
91
|
+
"message": "string (specific, actionable finding)",
|
|
92
|
+
"file": "string (optional, relative file path)",
|
|
93
|
+
"autoFixable": false,
|
|
94
|
+
"speknCta": "string (optional, how Spekn helps)"
|
|
95
|
+
}
|
|
96
|
+
]
|
|
97
|
+
}
|
|
98
|
+
],
|
|
99
|
+
"rootCauses": "string (2-3 sentences: why do these governance gaps exist?)",
|
|
100
|
+
"priorities": [{"finding": "string", "reason": "string", "files": ["string"], "timeEstimate": "string", "scoreImpact": "string"}],
|
|
101
|
+
"quickWins": [{"action": "string", "steps": ["string"], "timeEstimate": "string", "scoreImpact": "string"}],
|
|
102
|
+
"architecturalRec": {"recommendation": "string", "implementation": ["string"], "scoreImpact": "string"},
|
|
103
|
+
"governanceImpact": {"currentScore": {{STATIC_SCORE}}, "potentialScore": "number (0-100 projected score after ALL recommended fixes)", "improvement": "number (potentialScore minus currentScore)"}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
IMPORTANT:
|
|
107
|
+
- governanceImpact.currentScore is FIXED at {{STATIC_SCORE}} (the actual static baseline). Do NOT recompute it.
|
|
108
|
+
- governanceImpact.potentialScore should reflect your realistic estimate after all recommended fixes are applied. Must be 0-100.
|
|
109
|
+
- Each check is normalized (score/maxScore) then weighted, so the headline score is a weighted average percentage, NOT a sum of raw scores.
|
|
@@ -1,151 +1,43 @@
|
|
|
1
1
|
You are analyzing a repository to register it with a Spekn project.
|
|
2
|
-
You have
|
|
2
|
+
You have Spekn MCP tools available to create specifications and decisions.
|
|
3
3
|
|
|
4
4
|
PROJECT ID: {{PROJECT_ID}}{{ORG_INSTRUCTION}}
|
|
5
5
|
REPO PATH: {{REPO_PATH}}
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
{{
|
|
9
|
-
|
|
10
|
-
STEP 0 — VERIFY TOOLS:
|
|
11
|
-
Before doing anything else, list the available MCP tools to confirm you have
|
|
12
|
-
access to spekn_spec_create, spekn_spec_list, and spekn_decision_create. If these tools are NOT available,
|
|
13
|
-
output "ERROR: Spekn MCP tools not available. Cannot proceed with analysis." and stop.
|
|
7
|
+
DETECTED TECH STACK:
|
|
8
|
+
{{TECH_STACK}}
|
|
14
9
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
(package.json, Cargo.toml, pyproject.toml, etc.), and key source directories
|
|
18
|
-
to understand what this project does, its tech stack, and architecture.
|
|
19
|
-
|
|
20
|
-
STEP 2 — CREATE MAIN PROJECT SPECIFICATION:
|
|
21
|
-
Use spekn_spec_create to create a main project overview spec:
|
|
22
|
-
- Title: "Project Overview" — short, no repo name prefix
|
|
23
|
-
- Content MUST start with a YAML frontmatter block:
|
|
24
|
-
---
|
|
25
|
-
title: "Project Overview"
|
|
26
|
-
type: intent
|
|
27
|
-
version: "1.0.0"
|
|
28
|
-
status: draft
|
|
29
|
-
author: "repo ingestor"
|
|
30
|
-
tags: [overview, project]
|
|
31
|
-
hints:
|
|
32
|
-
constraints: ["Key project invariants and boundaries"]
|
|
33
|
-
requirements: ["Core project goals and capabilities"]
|
|
34
|
-
technical: ["Tech stack, architecture patterns, build system"]
|
|
35
|
-
guidance: ["Development conventions and contribution guidelines"]
|
|
36
|
-
---
|
|
37
|
-
- After the frontmatter, include a comprehensive explanation of what the project does,
|
|
38
|
-
tech stack, directory structure, build system, development conventions, and key decisions
|
|
39
|
-
- This becomes the primary context for the engineering manager agent
|
|
10
|
+
DISCOVERED DOCUMENTATION FILES:
|
|
11
|
+
{{FILE_LIST}}
|
|
40
12
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
- Use spekn_spec_create to create a Specification record
|
|
45
|
-
- Use the first # heading as the title (must be unique, 3-100 chars)
|
|
46
|
-
- If the file already has a YAML frontmatter block (---), preserve it but ensure author is set:
|
|
47
|
-
- author: "repo ingestor" (add it when missing)
|
|
48
|
-
- If no frontmatter exists, prepend one with:
|
|
49
|
-
- type: "capability"
|
|
50
|
-
- version: "1.0.0"
|
|
51
|
-
- author: "repo ingestor"
|
|
52
|
-
- hints: populate from the file content (constraints, requirements, technical, guidance)
|
|
53
|
-
- Set version to "1.0.0"
|
|
13
|
+
NOTE: The list above contains only governance, spec, decision, and documentation files.
|
|
14
|
+
You MUST explore source code directories yourself using your filesystem tools (ls, Glob, Read).
|
|
15
|
+
The source code is your PRIMARY input for understanding the project and creating domain specs.
|
|
54
16
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
- Then perform ACP DECISION DETECTION before creating records:
|
|
59
|
-
- Extract one normalized decision object per explicit decision/ADR entry
|
|
60
|
-
- Ignore vague notes that do not state a concrete choice
|
|
61
|
-
- If one file contains multiple explicit ADR entries, create one decision record per entry
|
|
62
|
-
- Use this normalized structure for each extracted decision:
|
|
63
|
-
{
|
|
64
|
-
"title": "<3-100 chars, imperative/statement form>",
|
|
65
|
-
"description": "<what was decided, specific and concrete>",
|
|
66
|
-
"rationale": "<why this option was chosen>",
|
|
67
|
-
"alternatives": ["<rejected option 1>", "<rejected option 2>"]
|
|
68
|
-
}
|
|
69
|
-
- Formatting requirements:
|
|
70
|
-
- title must NOT include prefixes like "Decision:", "ADR-001:", markdown symbols, or file names
|
|
71
|
-
- description and rationale must be plain text (no markdown headings/bullets)
|
|
72
|
-
- alternatives must be plain option strings; use [] when none are explicit
|
|
73
|
-
- If rationale is missing, infer a concise rationale from nearby context (trade-offs/constraints)
|
|
74
|
-
- Create each record with spekn_decision_create using:
|
|
75
|
-
- projectId: PROJECT ID
|
|
76
|
-
- specificationId: parent decision specification ID
|
|
77
|
-
- title, description, rationale, alternatives from normalized object
|
|
17
|
+
────────────────────────────────────────────────────────────────────────
|
|
18
|
+
INSTRUCTIONS
|
|
19
|
+
────────────────────────────────────────────────────────────────────────
|
|
78
20
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
- Check whether you have a tool that can read or extract text from PDF files
|
|
82
|
-
(e.g. `read_file` with PDF support, a `pdf` skill, or any PDF extraction tool)
|
|
83
|
-
- If you DO have PDF capability:
|
|
84
|
-
- Read each PDF file to extract its text content
|
|
85
|
-
- Determine what the document covers (architecture diagrams, requirements, RFCs,
|
|
86
|
-
compliance docs, contracts, design documents, etc.)
|
|
87
|
-
- For each PDF that contains specification-worthy content, use spekn_spec_create:
|
|
88
|
-
- Title: short descriptive name derived from the PDF content (NOT the filename)
|
|
89
|
-
- Content MUST start with a YAML frontmatter block:
|
|
90
|
-
- type: choose the best fit ("capability", "architectural", "intent", "operational")
|
|
91
|
-
- status: "draft"
|
|
92
|
-
- author: "repo ingestor"
|
|
93
|
-
- tags: ["pdf-import", ...relevant tags]
|
|
94
|
-
- hints: summarize key content in each layer
|
|
95
|
-
- After frontmatter, include the extracted content reformatted as clean markdown
|
|
96
|
-
- For PDFs containing decision records or ADRs, create decisions following STEP 3 rules
|
|
97
|
-
- If you do NOT have PDF capability:
|
|
98
|
-
- Log: "PDF files found but no PDF reading tool available — skipping PDF analysis"
|
|
99
|
-
- List the PDF files that were skipped so the user knows
|
|
100
|
-
- Do NOT fail the entire analysis if PDF reading is unavailable
|
|
21
|
+
Before starting work, load the Spekn specification format and workflow
|
|
22
|
+
instructions from the MCP server. Load each of these prompts in order:
|
|
101
23
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
- Descriptive title (e.g. "CI/CD Pipeline", "Testing Strategy")
|
|
107
|
-
- Content MUST start with a YAML frontmatter block:
|
|
108
|
-
- type: "capability" for new features, "operational" for ops/process improvements
|
|
109
|
-
- status: "draft"
|
|
110
|
-
- author: "repo ingestor"
|
|
111
|
-
- tags: reflecting the gap area (e.g., [ci-cd, automation] or [testing, quality])
|
|
112
|
-
- hints: summarize what the spec covers in each context layer
|
|
113
|
-
- After frontmatter, describe what the repo SHOULD have (best practices)
|
|
114
|
-
- Focus on quality over quantity — only create specs for real gaps
|
|
24
|
+
1. spekn-spec-format — full specification format reference (frontmatter, body, YAML rules)
|
|
25
|
+
2. spekn-anchor-format — anchor heading rules and per-anchor required fields
|
|
26
|
+
3. spekn-quality-scoring — self-scoring checklist and quality rules
|
|
27
|
+
4. spekn-repo-analysis (with args: { "projectId": "{{PROJECT_ID}}" }) — 6-step repo analysis workflow
|
|
115
28
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
- implementation evidence in code (routers/services/components/tests)
|
|
121
|
-
- a corresponding feature document in specs/features/
|
|
122
|
-
- an implementation plan (IMPLEMENTATION_PLAN.md) when feature status implies planning/active build
|
|
123
|
-
- For missing or weakly-covered items, create improvement specs with spekn_spec_create:
|
|
124
|
-
- Title: short descriptive name of the feature gap (e.g. "Flatpak Governance Enforcement", "Network Egress Policy")
|
|
125
|
-
- Do NOT prefix titles with the repo name, "Gap:", or any other prefix
|
|
126
|
-
- type: "capability" for product/runtime gaps, "operational" for process/governance gaps
|
|
127
|
-
- tags must include "feature-coverage" and "plan-gap"
|
|
128
|
-
- hints must explicitly include missing code surfaces and missing planning artifacts
|
|
129
|
-
- Do not duplicate if an equivalent gap spec already exists; update existing draft instead when possible
|
|
29
|
+
HOW TO LOAD PROMPTS (try in order):
|
|
30
|
+
A) Use the MCP prompts protocol: prompts/get with name "spekn-spec-format", etc.
|
|
31
|
+
B) If prompts are not available, call the tool: spekn_prompt_get(name: "spekn-spec-format"), etc.
|
|
32
|
+
C) If both fail, report the failure and continue — do NOT stop the workflow entirely.
|
|
130
33
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
- Number of specs imported from PDF documents (or skipped if no PDF tool)
|
|
135
|
-
- Number of decisions created from decision files
|
|
136
|
-
- Number of improvement specs created
|
|
137
|
-
- Overall governance assessment (strengths and gaps)
|
|
138
|
-
- Feature coverage summary (implemented vs partial vs missing)
|
|
139
|
-
- Missing plan features summary
|
|
140
|
-
- Include a "FEATURE_COVERAGE" section in this exact line format:
|
|
141
|
-
- FEATURE | <id-or-name> | <status> | <evidence-or-missing>
|
|
142
|
-
- Include a "MISSING_PLAN_FEATURES" section in this exact line format:
|
|
143
|
-
- PLAN_GAP | <id-or-name> | <missing-artifact> | <recommended-spec-title>
|
|
144
|
-
- Include a "DECISIONS_CREATED" section in this exact line format:
|
|
145
|
-
- DECISION | <source-file> | <title> | <specificationId>
|
|
34
|
+
Read and internalize each prompt's content, then follow the workflow
|
|
35
|
+
steps from spekn-repo-analysis using the runtime context above (tech
|
|
36
|
+
stack, discovered files, repo path) as your input data.
|
|
146
37
|
|
|
147
38
|
RULES:
|
|
148
|
-
- ALWAYS use
|
|
149
|
-
-
|
|
150
|
-
-
|
|
39
|
+
- ALWAYS use MCP tools (spekn_spec_create / spekn_decision_create) — never just describe what you would create
|
|
40
|
+
- Every spec MUST follow the format from spekn-spec-format
|
|
41
|
+
- Every spec MUST score at least B (75+) per the spekn-quality-scoring checklist
|
|
151
42
|
- If a tool call fails, report the error and continue with the next item
|
|
43
|
+
- Do NOT create specs for governance files (CLAUDE.md, AGENTS.md, .cursorrules)
|
|
@@ -3,83 +3,46 @@ Your role is to detect drift, decide what to update, and avoid duplicate specs.
|
|
|
3
3
|
|
|
4
4
|
PROJECT ID: {{PROJECT_ID}}{{ORG_INSTRUCTION}}
|
|
5
5
|
REPO PATH: {{REPO_PATH}}
|
|
6
|
+
|
|
6
7
|
COMMIT CONTEXT:
|
|
7
8
|
{{COMMIT_CONTEXT}}
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
{{
|
|
11
|
-
|
|
12
|
-
STEP 0 — VERIFY TOOLS:
|
|
13
|
-
List available tools and confirm you have:
|
|
14
|
-
- spekn_spec_list
|
|
15
|
-
- spekn_spec_create
|
|
16
|
-
- spekn_spec_update
|
|
17
|
-
- spekn_decision_create
|
|
18
|
-
- spekn_decision_update
|
|
19
|
-
If missing critical tools, output an error and stop.
|
|
10
|
+
DETECTED TECH STACK:
|
|
11
|
+
{{TECH_STACK}}
|
|
20
12
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
1. Call spekn_spec_list for the project using pagination.
|
|
24
|
-
- API limit is max 100 items per page.
|
|
25
|
-
- Use `limit <= 100` and increment `offset` until no more items are returned.
|
|
26
|
-
2. Build a map of existing specs by:
|
|
27
|
-
- exact title
|
|
28
|
-
- normalized title (case/spacing/punctuation insensitive)
|
|
29
|
-
3. Treat locked specs as canonical. Never create a duplicate just because content differs.
|
|
13
|
+
DISCOVERED DOCUMENTATION FILES:
|
|
14
|
+
{{FILE_LIST}}
|
|
30
15
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
Only use them as evidence for drift, not as direct create input.
|
|
16
|
+
NOTE: The list above contains only governance, spec, decision, and documentation files.
|
|
17
|
+
You have full filesystem access — use ls, Glob, and Read to explore source code directories
|
|
18
|
+
when you need to understand code changes, detect new modules, or verify drift.
|
|
35
19
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
- UPDATE_EXISTING: matching spec exists and should be updated
|
|
40
|
-
- CREATE_NEW: truly new capability/intent/decision area with no equivalent existing spec
|
|
20
|
+
────────────────────────────────────────────────────────────────────────
|
|
21
|
+
INSTRUCTIONS
|
|
22
|
+
────────────────────────────────────────────────────────────────────────
|
|
41
23
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
- CREATE_NEW only when no reasonable existing target exists.
|
|
45
|
-
- Never create a “repo ingestor import ...” duplicate of an existing locked/canonical spec.
|
|
46
|
-
- If uncertain between update and create, choose update and explain rationale.
|
|
47
|
-
- Give extra weight to commit-range changes since LAST_SYNC_COMMIT when deciding drift.
|
|
48
|
-
- If code/protocol files changed, verify corresponding specs/decisions were updated; if not, propose targeted updates.
|
|
24
|
+
Before starting work, load the Spekn specification format and workflow
|
|
25
|
+
instructions from the MCP server. Load each of these prompts in order:
|
|
49
26
|
|
|
50
|
-
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
- Keep titles stable for existing specs; avoid generating near-duplicate titles.
|
|
55
|
-
- For UPDATE_EXISTING calls, include version/history intent:
|
|
56
|
-
- prefer `changeType: "patch"` for small clarifications
|
|
57
|
-
- use `changeType: "minor"` for new requirements/constraints
|
|
58
|
-
- set concise `changeDescription` referencing commit-range drift rationale
|
|
27
|
+
1. spekn-spec-format — full specification format reference (frontmatter, body, YAML rules)
|
|
28
|
+
2. spekn-anchor-format — anchor heading rules and per-anchor required fields
|
|
29
|
+
3. spekn-quality-scoring — self-scoring checklist and quality rules
|
|
30
|
+
4. spekn-repo-sync (with args: { "projectId": "{{PROJECT_ID}}" }) — 5-step repo sync workflow
|
|
59
31
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
- skip
|
|
65
|
-
- if approval is not explicit, skip the low-confidence change
|
|
66
|
-
- mention each prompted item again in REVIEW_NOTES
|
|
32
|
+
HOW TO LOAD PROMPTS (try in order):
|
|
33
|
+
A) Use the MCP prompts protocol: prompts/get with name "spekn-spec-format", etc.
|
|
34
|
+
B) If prompts are not available, call the tool: spekn_prompt_get(name: "spekn-spec-format"), etc.
|
|
35
|
+
C) If both fail, report the failure and continue — do NOT stop the workflow entirely.
|
|
67
36
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
- file, drift type, severity, target spec (if any)
|
|
72
|
-
2. SYNC_ACTION_PLAN
|
|
73
|
-
- ACTION | SKIP/UPDATE_EXISTING/CREATE_NEW | file | target/new title | reason
|
|
74
|
-
3. SYNC_APPLIED
|
|
75
|
-
- APPLIED | update/create/skip | entity type | id/title
|
|
76
|
-
4. REVIEW_NOTES
|
|
77
|
-
- low-confidence updates that should be human-reviewed
|
|
78
|
-
- missing spec/decision coverage for changed code/protocol files
|
|
37
|
+
Read and internalize each prompt's content, then follow the workflow
|
|
38
|
+
steps from spekn-repo-sync using the runtime context above (tech stack,
|
|
39
|
+
discovered files, repo path, commit context) as your input data.
|
|
79
40
|
|
|
80
41
|
RULES:
|
|
81
|
-
-
|
|
82
|
-
-
|
|
83
|
-
-
|
|
84
|
-
-
|
|
85
|
-
-
|
|
42
|
+
- ALWAYS use MCP tools (spekn_spec_create / spekn_spec_update / spekn_decision_create) — never just describe what you would create
|
|
43
|
+
- Every spec MUST follow the format from spekn-spec-format
|
|
44
|
+
- Every spec MUST score at least B (75+) per the spekn-quality-scoring checklist
|
|
45
|
+
- Frontmatter MUST stay under 2048 bytes — if a tool call fails with size limit, trim and retry
|
|
46
|
+
- Minimize churn — prefer updates over new specs
|
|
47
|
+
- Respect existing canonical spec set
|
|
48
|
+
- If a tool call fails for other reasons, report the error and continue with the next item
|
package/dist/tui/app.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TuiApp = TuiApp;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const ink_1 = require("ink");
|
|
6
|
+
const ui_1 = require("@inkjs/ui");
|
|
7
|
+
const use_app_state_1 = require("./state/use-app-state");
|
|
8
|
+
const use_global_keymap_1 = require("./keymap/use-global-keymap");
|
|
9
|
+
const frame_1 = require("./components/frame");
|
|
10
|
+
const status_bar_1 = require("./components/status-bar");
|
|
11
|
+
const home_1 = require("./screens/home");
|
|
12
|
+
const specs_1 = require("./screens/specs");
|
|
13
|
+
const export_1 = require("./screens/export");
|
|
14
|
+
const decisions_1 = require("./screens/decisions");
|
|
15
|
+
const bridge_1 = require("./screens/bridge");
|
|
16
|
+
const locked_1 = require("./screens/locked");
|
|
17
|
+
/** Brand-aligned theme: Electric Indigo spinner, semantic colors via component defaults */
|
|
18
|
+
const speknTheme = (0, ui_1.extendTheme)(ui_1.defaultTheme, {
|
|
19
|
+
components: {
|
|
20
|
+
Spinner: {
|
|
21
|
+
styles: {
|
|
22
|
+
frame: () => ({ color: '#6366F1' }),
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
function renderMainScreen(screen, state) {
|
|
28
|
+
if (screen === 'home')
|
|
29
|
+
return (0, jsx_runtime_1.jsx)(home_1.HomeScreen, { state: state });
|
|
30
|
+
if (screen === 'specs')
|
|
31
|
+
return (0, jsx_runtime_1.jsx)(specs_1.SpecsScreen, { state: state });
|
|
32
|
+
if (screen === 'export')
|
|
33
|
+
return (0, jsx_runtime_1.jsx)(export_1.ExportScreen, { state: state });
|
|
34
|
+
if (screen === 'decisions')
|
|
35
|
+
return (0, jsx_runtime_1.jsx)(decisions_1.DecisionsScreen, { state: state });
|
|
36
|
+
if (screen === 'bridge')
|
|
37
|
+
return (0, jsx_runtime_1.jsx)(bridge_1.BridgeScreen, { state: state });
|
|
38
|
+
const nav = state.navPolicy.find((item) => item.id === screen);
|
|
39
|
+
return (0, jsx_runtime_1.jsx)(locked_1.LockedScreen, { item: nav });
|
|
40
|
+
}
|
|
41
|
+
function TuiApp({ apiUrl, initialScreen, projectId }) {
|
|
42
|
+
const { state, refresh, setScreen, toggleHelp, setSearchQuery, setCommandMode, setExportFormat, previewExport, generateExport, bridgeStart, bridgeStop, appendLog, } = (0, use_app_state_1.useAppState)(apiUrl, initialScreen, projectId);
|
|
43
|
+
(0, use_global_keymap_1.useGlobalKeymap)({
|
|
44
|
+
screen: state.screen,
|
|
45
|
+
navPolicy: state.navPolicy,
|
|
46
|
+
commandMode: state.commandMode,
|
|
47
|
+
showHelp: state.showHelp,
|
|
48
|
+
onNavigate: setScreen,
|
|
49
|
+
onHelpToggle: toggleHelp,
|
|
50
|
+
onSearchToggle: () => setSearchQuery(state.searchQuery ? '' : '*'),
|
|
51
|
+
onSearchClear: () => setSearchQuery(''),
|
|
52
|
+
onCommandModeToggle: setCommandMode,
|
|
53
|
+
onRefresh: () => {
|
|
54
|
+
void refresh();
|
|
55
|
+
},
|
|
56
|
+
onExportPreview: () => {
|
|
57
|
+
void previewExport();
|
|
58
|
+
},
|
|
59
|
+
onExportGenerate: () => {
|
|
60
|
+
void generateExport();
|
|
61
|
+
},
|
|
62
|
+
onBridgeStart: bridgeStart,
|
|
63
|
+
onBridgeStop: () => {
|
|
64
|
+
void bridgeStop();
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
const handleCommandSubmit = (command) => {
|
|
68
|
+
const normalized = command.trim().toLowerCase();
|
|
69
|
+
setCommandMode(false);
|
|
70
|
+
if (!normalized)
|
|
71
|
+
return;
|
|
72
|
+
if (normalized === 'help') {
|
|
73
|
+
toggleHelp();
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (normalized === 'refresh' || normalized === 'r') {
|
|
77
|
+
void refresh();
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (normalized.startsWith('goto ')) {
|
|
81
|
+
const target = normalized.replace('goto ', '').trim();
|
|
82
|
+
setScreen(target);
|
|
83
|
+
appendLog(`[nav] goto ${target}`);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (normalized === 'show specs') {
|
|
87
|
+
setScreen('specs');
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (normalized === 'show export') {
|
|
91
|
+
setScreen('export');
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (normalized === 'run export') {
|
|
95
|
+
void generateExport();
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (normalized === 'format claude') {
|
|
99
|
+
setExportFormat('claude-md');
|
|
100
|
+
appendLog('[export] Format switched to claude-md');
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (normalized === 'format cursor') {
|
|
104
|
+
setExportFormat('cursorrules');
|
|
105
|
+
appendLog('[export] Format switched to cursorrules');
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (normalized === 'bridge start') {
|
|
109
|
+
bridgeStart();
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (normalized === 'bridge stop') {
|
|
113
|
+
void bridgeStop();
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
appendLog(`[command] Unknown: ${command}`);
|
|
117
|
+
};
|
|
118
|
+
const left = `${state.boot?.organizationName ?? '...'} / ${state.boot?.projectName ?? '...'}`;
|
|
119
|
+
const center = state.loading ? 'Loading...' : state.statusLine;
|
|
120
|
+
const right = `${state.screen} | phase:${state.workflow.currentPhase ?? 'n/a'} | role:${state.boot?.role ?? 'n/a'} | tier:${state.boot?.plan ?? 'n/a'}`;
|
|
121
|
+
return ((0, jsx_runtime_1.jsx)(ui_1.ThemeProvider, { theme: speknTheme, children: (0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "column", children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { bold: true, color: "cyan", children: "Spekn TUI - Technical Cockpit" }), (0, jsx_runtime_1.jsx)(ink_1.Text, { color: "gray", children: "Shortcuts: j/k/h/l nav, : commands, ? help, r refresh, Ctrl+C quit" }), state.error ? ((0, jsx_runtime_1.jsx)(ink_1.Box, { marginTop: 1, children: (0, jsx_runtime_1.jsx)(ui_1.Alert, { variant: "error", children: state.error }) })) : null, (0, jsx_runtime_1.jsxs)(ink_1.Box, { marginTop: 1, children: [(0, jsx_runtime_1.jsx)(ink_1.Box, { width: "28%", flexDirection: "column", children: (0, jsx_runtime_1.jsx)(frame_1.Frame, { title: "Navigation", children: state.navPolicy.map((item, index) => ((0, jsx_runtime_1.jsxs)(ink_1.Text, { color: state.screen === item.id ? 'green' : item.state === 'locked' ? 'yellow' : item.state === 'disabled' ? 'gray' : undefined, children: [state.screen === item.id ? '>' : ' ', " ", index + 1, ". ", item.label, item.state === 'locked' ? ' (locked)' : item.state === 'disabled' ? ' (disabled)' : ''] }, item.id))) }) }), (0, jsx_runtime_1.jsx)(ink_1.Box, { width: "52%", flexDirection: "column", children: (0, jsx_runtime_1.jsx)(frame_1.Frame, { title: "Context", children: renderMainScreen(state.screen, state) }) }), (0, jsx_runtime_1.jsx)(ink_1.Box, { width: "20%", flexDirection: "column", children: (0, jsx_runtime_1.jsx)(frame_1.Frame, { title: "Event Log", dim: true, children: (state.logs.length === 0 ? ['[system] ready'] : state.logs.slice(0, 7)).map((line, index) => ((0, jsx_runtime_1.jsx)(ink_1.Text, { color: "gray", children: line }, `log-${index}`))) }) })] }), state.showHelp ? ((0, jsx_runtime_1.jsx)(ink_1.Box, { marginTop: 1, children: (0, jsx_runtime_1.jsx)(ui_1.Alert, { variant: "info", children: "Help: j/k/h/l navigate | :help | :goto specs | :run export | format claude/cursor | bridge start/stop" }) })) : null, state.commandMode ? ((0, jsx_runtime_1.jsxs)(ink_1.Box, { marginTop: 1, children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: "green", children: ":" }), (0, jsx_runtime_1.jsx)(ui_1.TextInput, { placeholder: "command...", onSubmit: handleCommandSubmit })] })) : null, (0, jsx_runtime_1.jsx)(status_bar_1.StatusBar, { left: left, center: center, right: right })] }) }));
|
|
122
|
+
}
|
package/dist/tui/args.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseTuiArgs = parseTuiArgs;
|
|
4
|
+
const VIEW_ALIASES = {
|
|
5
|
+
home: 'home',
|
|
6
|
+
specs: 'specs',
|
|
7
|
+
export: 'export',
|
|
8
|
+
decisions: 'decisions',
|
|
9
|
+
bridge: 'bridge',
|
|
10
|
+
};
|
|
11
|
+
function parseTuiArgs(args) {
|
|
12
|
+
let projectId;
|
|
13
|
+
let apiUrl = process.env.SPEKN_API_URL ?? 'http://localhost:3000';
|
|
14
|
+
let initialView = 'home';
|
|
15
|
+
let noColor = false;
|
|
16
|
+
for (let i = 0; i < args.length; i++) {
|
|
17
|
+
const arg = args[i];
|
|
18
|
+
if ((arg === '--project-id' || arg === '--project') && args[i + 1]) {
|
|
19
|
+
projectId = args[++i];
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (arg.startsWith('--project-id=')) {
|
|
23
|
+
projectId = arg.slice('--project-id='.length);
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (arg === '--api-url' && args[i + 1]) {
|
|
27
|
+
apiUrl = args[++i];
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (arg.startsWith('--api-url=')) {
|
|
31
|
+
apiUrl = arg.slice('--api-url='.length);
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (arg === '--view' && args[i + 1]) {
|
|
35
|
+
const candidate = VIEW_ALIASES[String(args[++i]).toLowerCase()];
|
|
36
|
+
if (candidate)
|
|
37
|
+
initialView = candidate;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (arg.startsWith('--view=')) {
|
|
41
|
+
const candidate = VIEW_ALIASES[arg.slice('--view='.length).toLowerCase()];
|
|
42
|
+
if (candidate)
|
|
43
|
+
initialView = candidate;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (arg === '--no-color') {
|
|
47
|
+
noColor = true;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
projectId,
|
|
53
|
+
apiUrl,
|
|
54
|
+
initialView,
|
|
55
|
+
noColor,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { OrganizationPlan } from '../shared-enums';
|
|
2
|
+
import type { CapabilityContext, NavItemPolicy } from '../types';
|
|
3
|
+
type OrganizationPlanType = (typeof OrganizationPlan)[keyof typeof OrganizationPlan];
|
|
4
|
+
export declare function meetsMinimumTier(current: OrganizationPlanType, required: OrganizationPlanType): boolean;
|
|
5
|
+
export declare function resolveNavPolicy(ctx: CapabilityContext): NavItemPolicy[];
|
|
6
|
+
export declare function isActionAllowed(policy: NavItemPolicy): boolean;
|
|
7
|
+
export {};
|