@fission-ai/openspec 0.23.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +111 -382
- package/dist/cli/index.js +120 -6
- package/dist/commands/workflow/index.d.ts +17 -0
- package/dist/commands/workflow/index.js +12 -0
- package/dist/commands/workflow/instructions.d.ts +29 -0
- package/dist/commands/workflow/instructions.js +381 -0
- package/dist/commands/workflow/new-change.d.ts +11 -0
- package/dist/commands/workflow/new-change.js +44 -0
- package/dist/commands/workflow/schemas.d.ts +10 -0
- package/dist/commands/workflow/schemas.js +34 -0
- package/dist/commands/workflow/shared.d.ts +52 -0
- package/dist/commands/workflow/shared.js +111 -0
- package/dist/commands/workflow/status.d.ts +14 -0
- package/dist/commands/workflow/status.js +58 -0
- package/dist/commands/workflow/templates.d.ts +16 -0
- package/dist/commands/workflow/templates.js +68 -0
- package/dist/core/artifact-graph/instruction-loader.d.ts +5 -1
- package/dist/core/artifact-graph/instruction-loader.js +8 -19
- package/dist/core/command-generation/adapters/amazon-q.d.ts +13 -0
- package/dist/core/command-generation/adapters/amazon-q.js +26 -0
- package/dist/core/command-generation/adapters/antigravity.d.ts +13 -0
- package/dist/core/command-generation/adapters/antigravity.js +26 -0
- package/dist/core/command-generation/adapters/auggie.d.ts +13 -0
- package/dist/core/command-generation/adapters/auggie.js +27 -0
- package/dist/core/command-generation/adapters/claude.d.ts +13 -0
- package/dist/core/command-generation/adapters/claude.js +50 -0
- package/dist/core/command-generation/adapters/cline.d.ts +14 -0
- package/dist/core/command-generation/adapters/cline.js +27 -0
- package/dist/core/command-generation/adapters/codebuddy.d.ts +13 -0
- package/dist/core/command-generation/adapters/codebuddy.js +28 -0
- package/dist/core/command-generation/adapters/codex.d.ts +13 -0
- package/dist/core/command-generation/adapters/codex.js +27 -0
- package/dist/core/command-generation/adapters/continue.d.ts +13 -0
- package/dist/core/command-generation/adapters/continue.js +28 -0
- package/dist/core/command-generation/adapters/costrict.d.ts +13 -0
- package/dist/core/command-generation/adapters/costrict.js +27 -0
- package/dist/core/command-generation/adapters/crush.d.ts +13 -0
- package/dist/core/command-generation/adapters/crush.js +30 -0
- package/dist/core/command-generation/adapters/cursor.d.ts +14 -0
- package/dist/core/command-generation/adapters/cursor.js +44 -0
- package/dist/core/command-generation/adapters/factory.d.ts +13 -0
- package/dist/core/command-generation/adapters/factory.js +27 -0
- package/dist/core/command-generation/adapters/gemini.d.ts +13 -0
- package/dist/core/command-generation/adapters/gemini.js +26 -0
- package/dist/core/command-generation/adapters/github-copilot.d.ts +13 -0
- package/dist/core/command-generation/adapters/github-copilot.js +26 -0
- package/dist/core/command-generation/adapters/iflow.d.ts +13 -0
- package/dist/core/command-generation/adapters/iflow.js +29 -0
- package/dist/core/command-generation/adapters/index.d.ts +27 -0
- package/dist/core/command-generation/adapters/index.js +27 -0
- package/dist/core/command-generation/adapters/kilocode.d.ts +14 -0
- package/dist/core/command-generation/adapters/kilocode.js +23 -0
- package/dist/core/command-generation/adapters/opencode.d.ts +13 -0
- package/dist/core/command-generation/adapters/opencode.js +26 -0
- package/dist/core/command-generation/adapters/qoder.d.ts +13 -0
- package/dist/core/command-generation/adapters/qoder.js +30 -0
- package/dist/core/command-generation/adapters/qwen.d.ts +13 -0
- package/dist/core/command-generation/adapters/qwen.js +26 -0
- package/dist/core/command-generation/adapters/roocode.d.ts +14 -0
- package/dist/core/command-generation/adapters/roocode.js +27 -0
- package/dist/core/command-generation/adapters/windsurf.d.ts +14 -0
- package/dist/core/command-generation/adapters/windsurf.js +51 -0
- package/dist/core/command-generation/generator.d.ts +21 -0
- package/dist/core/command-generation/generator.js +27 -0
- package/dist/core/command-generation/index.d.ts +22 -0
- package/dist/core/command-generation/index.js +24 -0
- package/dist/core/command-generation/registry.d.ts +36 -0
- package/dist/core/command-generation/registry.js +88 -0
- package/dist/core/command-generation/types.d.ts +55 -0
- package/dist/core/command-generation/types.js +8 -0
- package/dist/core/config.d.ts +1 -0
- package/dist/core/config.js +21 -21
- package/dist/core/init.d.ts +16 -36
- package/dist/core/init.js +323 -534
- package/dist/core/legacy-cleanup.d.ts +162 -0
- package/dist/core/legacy-cleanup.js +501 -0
- package/dist/core/shared/index.d.ts +8 -0
- package/dist/core/shared/index.js +8 -0
- package/dist/core/shared/skill-generation.d.ts +41 -0
- package/dist/core/shared/skill-generation.js +76 -0
- package/dist/core/shared/tool-detection.d.ts +66 -0
- package/dist/core/shared/tool-detection.js +140 -0
- package/dist/core/templates/index.d.ts +7 -16
- package/dist/core/templates/index.js +8 -36
- package/dist/core/templates/skill-templates.d.ts +13 -0
- package/dist/core/templates/skill-templates.js +627 -21
- package/dist/core/update.d.ts +38 -0
- package/dist/core/update.js +280 -62
- package/dist/prompts/searchable-multi-select.d.ts +27 -0
- package/dist/prompts/searchable-multi-select.js +149 -0
- package/dist/ui/ascii-patterns.d.ts +16 -0
- package/dist/ui/ascii-patterns.js +133 -0
- package/dist/ui/welcome-screen.d.ts +10 -0
- package/dist/ui/welcome-screen.js +146 -0
- package/dist/utils/file-system.d.ts +11 -0
- package/dist/utils/file-system.js +65 -2
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +2 -0
- package/package.json +1 -1
- package/dist/commands/artifact-workflow.d.ts +0 -17
- package/dist/commands/artifact-workflow.js +0 -915
- package/dist/core/configurators/agents.d.ts +0 -8
- package/dist/core/configurators/agents.js +0 -15
- package/dist/core/configurators/base.d.ts +0 -7
- package/dist/core/configurators/base.js +0 -2
- package/dist/core/configurators/claude.d.ts +0 -8
- package/dist/core/configurators/claude.js +0 -15
- package/dist/core/configurators/cline.d.ts +0 -8
- package/dist/core/configurators/cline.js +0 -15
- package/dist/core/configurators/codebuddy.d.ts +0 -8
- package/dist/core/configurators/codebuddy.js +0 -15
- package/dist/core/configurators/costrict.d.ts +0 -8
- package/dist/core/configurators/costrict.js +0 -15
- package/dist/core/configurators/iflow.d.ts +0 -8
- package/dist/core/configurators/iflow.js +0 -15
- package/dist/core/configurators/qoder.d.ts +0 -30
- package/dist/core/configurators/qoder.js +0 -42
- package/dist/core/configurators/qwen.d.ts +0 -24
- package/dist/core/configurators/qwen.js +0 -37
- package/dist/core/configurators/registry.d.ts +0 -9
- package/dist/core/configurators/registry.js +0 -43
- package/dist/core/configurators/slash/amazon-q.d.ts +0 -9
- package/dist/core/configurators/slash/amazon-q.js +0 -46
- package/dist/core/configurators/slash/antigravity.d.ts +0 -9
- package/dist/core/configurators/slash/antigravity.js +0 -23
- package/dist/core/configurators/slash/auggie.d.ts +0 -9
- package/dist/core/configurators/slash/auggie.js +0 -31
- package/dist/core/configurators/slash/base.d.ts +0 -19
- package/dist/core/configurators/slash/base.js +0 -69
- package/dist/core/configurators/slash/claude.d.ts +0 -9
- package/dist/core/configurators/slash/claude.js +0 -37
- package/dist/core/configurators/slash/cline.d.ts +0 -9
- package/dist/core/configurators/slash/cline.js +0 -23
- package/dist/core/configurators/slash/codebuddy.d.ts +0 -9
- package/dist/core/configurators/slash/codebuddy.js +0 -34
- package/dist/core/configurators/slash/codex.d.ts +0 -14
- package/dist/core/configurators/slash/codex.js +0 -109
- package/dist/core/configurators/slash/continue.d.ts +0 -9
- package/dist/core/configurators/slash/continue.js +0 -46
- package/dist/core/configurators/slash/costrict.d.ts +0 -9
- package/dist/core/configurators/slash/costrict.js +0 -31
- package/dist/core/configurators/slash/crush.d.ts +0 -9
- package/dist/core/configurators/slash/crush.js +0 -37
- package/dist/core/configurators/slash/cursor.d.ts +0 -9
- package/dist/core/configurators/slash/cursor.js +0 -37
- package/dist/core/configurators/slash/factory.d.ts +0 -10
- package/dist/core/configurators/slash/factory.js +0 -35
- package/dist/core/configurators/slash/gemini.d.ts +0 -9
- package/dist/core/configurators/slash/gemini.js +0 -22
- package/dist/core/configurators/slash/github-copilot.d.ts +0 -9
- package/dist/core/configurators/slash/github-copilot.js +0 -34
- package/dist/core/configurators/slash/iflow.d.ts +0 -9
- package/dist/core/configurators/slash/iflow.js +0 -37
- package/dist/core/configurators/slash/kilocode.d.ts +0 -9
- package/dist/core/configurators/slash/kilocode.js +0 -17
- package/dist/core/configurators/slash/opencode.d.ts +0 -12
- package/dist/core/configurators/slash/opencode.js +0 -72
- package/dist/core/configurators/slash/qoder.d.ts +0 -35
- package/dist/core/configurators/slash/qoder.js +0 -76
- package/dist/core/configurators/slash/qwen.d.ts +0 -32
- package/dist/core/configurators/slash/qwen.js +0 -49
- package/dist/core/configurators/slash/registry.d.ts +0 -8
- package/dist/core/configurators/slash/registry.js +0 -78
- package/dist/core/configurators/slash/roocode.d.ts +0 -9
- package/dist/core/configurators/slash/roocode.js +0 -23
- package/dist/core/configurators/slash/toml-base.d.ts +0 -10
- package/dist/core/configurators/slash/toml-base.js +0 -53
- package/dist/core/configurators/slash/windsurf.d.ts +0 -9
- package/dist/core/configurators/slash/windsurf.js +0 -23
- package/dist/core/templates/agents-root-stub.d.ts +0 -2
- package/dist/core/templates/agents-root-stub.js +0 -17
- package/dist/core/templates/agents-template.d.ts +0 -2
- package/dist/core/templates/agents-template.js +0 -458
- package/dist/core/templates/claude-template.d.ts +0 -2
- package/dist/core/templates/claude-template.js +0 -2
- package/dist/core/templates/cline-template.d.ts +0 -2
- package/dist/core/templates/cline-template.js +0 -2
- package/dist/core/templates/costrict-template.d.ts +0 -2
- package/dist/core/templates/costrict-template.js +0 -2
- package/dist/core/templates/project-template.d.ts +0 -8
- package/dist/core/templates/project-template.js +0 -32
- package/dist/core/templates/slash-command-templates.d.ts +0 -4
- package/dist/core/templates/slash-command-templates.js +0 -49
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ASCII art animation patterns for the welcome screen.
|
|
3
|
+
* OpenSpec logo animation - diamond/rhombus shape with hollow center "O".
|
|
4
|
+
*/
|
|
5
|
+
// Detect if full Unicode is supported
|
|
6
|
+
const supportsUnicode = process.platform !== 'win32' ||
|
|
7
|
+
!!process.env.WT_SESSION || // Windows Terminal
|
|
8
|
+
!!process.env.TERM_PROGRAM; // Modern terminal
|
|
9
|
+
// Character set based on Unicode support
|
|
10
|
+
// Block characters for pixel-art aesthetic
|
|
11
|
+
const CHARS = supportsUnicode
|
|
12
|
+
? { full: '██', dim: '░░', empty: ' ' }
|
|
13
|
+
: { full: '##', dim: '++', empty: ' ' };
|
|
14
|
+
const _ = CHARS.empty;
|
|
15
|
+
const F = CHARS.full;
|
|
16
|
+
const D = CHARS.dim;
|
|
17
|
+
/**
|
|
18
|
+
* Welcome animation frames - OpenSpec logo building from center
|
|
19
|
+
* 7 rows × 6 columns diamond with hollow center "O"
|
|
20
|
+
* Center bar is 2 cols × 3 rows (rows 3,4,5 cols 3,4)
|
|
21
|
+
* Each frame is an array of strings (lines of ASCII art)
|
|
22
|
+
* Grid: 6 cols × 2 chars = 12 chars wide
|
|
23
|
+
*/
|
|
24
|
+
export const WELCOME_ANIMATION = {
|
|
25
|
+
interval: 120,
|
|
26
|
+
frames: [
|
|
27
|
+
// Frame 1: Empty
|
|
28
|
+
[
|
|
29
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 1
|
|
30
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 2
|
|
31
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 3
|
|
32
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`,
|
|
33
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`,
|
|
34
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`,
|
|
35
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`,
|
|
36
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`,
|
|
37
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`,
|
|
38
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`,
|
|
39
|
+
],
|
|
40
|
+
// Frame 2: Center blocks appear (dim) - 2x3 center bar
|
|
41
|
+
[
|
|
42
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 1
|
|
43
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 2
|
|
44
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 3
|
|
45
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`,
|
|
46
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`,
|
|
47
|
+
`${_}${_}${_}${_}${D}${D}${_}${_}`,
|
|
48
|
+
`${_}${_}${_}${_}${D}${D}${_}${_}`,
|
|
49
|
+
`${_}${_}${_}${_}${D}${D}${_}${_}`,
|
|
50
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`,
|
|
51
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`,
|
|
52
|
+
],
|
|
53
|
+
// Frame 3: Center blocks solidify
|
|
54
|
+
[
|
|
55
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 1
|
|
56
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 2
|
|
57
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 3
|
|
58
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`,
|
|
59
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`,
|
|
60
|
+
`${_}${_}${_}${_}${F}${F}${_}${_}`,
|
|
61
|
+
`${_}${_}${_}${_}${F}${F}${_}${_}`,
|
|
62
|
+
`${_}${_}${_}${_}${F}${F}${_}${_}`,
|
|
63
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`,
|
|
64
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`,
|
|
65
|
+
],
|
|
66
|
+
// Frame 4: Top and bottom points appear
|
|
67
|
+
[
|
|
68
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 1
|
|
69
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 2
|
|
70
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 3
|
|
71
|
+
`${_}${_}${_}${_}${D}${D}${_}${_}`,
|
|
72
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`,
|
|
73
|
+
`${_}${_}${_}${_}${F}${F}${_}${_}`,
|
|
74
|
+
`${_}${_}${_}${_}${F}${F}${_}${_}`,
|
|
75
|
+
`${_}${_}${_}${_}${F}${F}${_}${_}`,
|
|
76
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`,
|
|
77
|
+
`${_}${_}${_}${_}${D}${D}${_}${_}`,
|
|
78
|
+
],
|
|
79
|
+
// Frame 5: Inner ring forming
|
|
80
|
+
[
|
|
81
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 1
|
|
82
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 2
|
|
83
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 3
|
|
84
|
+
`${_}${_}${_}${_}${F}${F}${_}${_}`,
|
|
85
|
+
`${_}${_}${_}${D}${_}${_}${D}${_}`,
|
|
86
|
+
`${_}${_}${_}${_}${F}${F}${_}${_}`,
|
|
87
|
+
`${_}${_}${_}${_}${F}${F}${_}${_}`,
|
|
88
|
+
`${_}${_}${_}${_}${F}${F}${_}${_}`,
|
|
89
|
+
`${_}${_}${_}${D}${_}${_}${D}${_}`,
|
|
90
|
+
`${_}${_}${_}${_}${F}${F}${_}${_}`,
|
|
91
|
+
],
|
|
92
|
+
// Frame 6: Outer ring appearing
|
|
93
|
+
[
|
|
94
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 1
|
|
95
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 2
|
|
96
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 3
|
|
97
|
+
`${_}${_}${_}${_}${F}${F}${_}${_}`,
|
|
98
|
+
`${_}${_}${_}${F}${_}${_}${F}${_}`,
|
|
99
|
+
`${_}${_}${D}${_}${F}${F}${_}${D}`,
|
|
100
|
+
`${_}${_}${D}${_}${F}${F}${_}${D}`,
|
|
101
|
+
`${_}${_}${D}${_}${F}${F}${_}${D}`,
|
|
102
|
+
`${_}${_}${_}${F}${_}${_}${F}${_}`,
|
|
103
|
+
`${_}${_}${_}${_}${F}${F}${_}${_}`,
|
|
104
|
+
],
|
|
105
|
+
// Frame 7: Full logo
|
|
106
|
+
[
|
|
107
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 1
|
|
108
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 2
|
|
109
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 3
|
|
110
|
+
`${_}${_}${_}${_}${F}${F}${_}${_}`,
|
|
111
|
+
`${_}${_}${_}${F}${_}${_}${F}${_}`,
|
|
112
|
+
`${_}${_}${F}${_}${F}${F}${_}${F}`,
|
|
113
|
+
`${_}${_}${F}${_}${F}${F}${_}${F}`,
|
|
114
|
+
`${_}${_}${F}${_}${F}${F}${_}${F}`,
|
|
115
|
+
`${_}${_}${_}${F}${_}${_}${F}${_}`,
|
|
116
|
+
`${_}${_}${_}${_}${F}${F}${_}${_}`,
|
|
117
|
+
],
|
|
118
|
+
// Frame 8: Hold complete logo
|
|
119
|
+
[
|
|
120
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 1
|
|
121
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 2
|
|
122
|
+
`${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 3
|
|
123
|
+
`${_}${_}${_}${_}${F}${F}${_}${_}`,
|
|
124
|
+
`${_}${_}${_}${F}${_}${_}${F}${_}`,
|
|
125
|
+
`${_}${_}${F}${_}${F}${F}${_}${F}`,
|
|
126
|
+
`${_}${_}${F}${_}${F}${F}${_}${F}`,
|
|
127
|
+
`${_}${_}${F}${_}${F}${F}${_}${F}`,
|
|
128
|
+
`${_}${_}${_}${F}${_}${_}${F}${_}`,
|
|
129
|
+
`${_}${_}${_}${_}${F}${F}${_}${_}`,
|
|
130
|
+
],
|
|
131
|
+
],
|
|
132
|
+
};
|
|
133
|
+
//# sourceMappingURL=ascii-patterns.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Animated welcome screen for the experimental artifact workflow setup.
|
|
3
|
+
* Shows side-by-side layout with animated ASCII art on left and welcome text on right.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Shows the animated welcome screen.
|
|
7
|
+
* Returns when user presses Enter.
|
|
8
|
+
*/
|
|
9
|
+
export declare function showWelcomeScreen(): Promise<void>;
|
|
10
|
+
//# sourceMappingURL=welcome-screen.d.ts.map
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Animated welcome screen for the experimental artifact workflow setup.
|
|
3
|
+
* Shows side-by-side layout with animated ASCII art on left and welcome text on right.
|
|
4
|
+
*/
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import { WELCOME_ANIMATION } from './ascii-patterns.js';
|
|
7
|
+
// Minimum terminal width for side-by-side layout
|
|
8
|
+
const MIN_WIDTH = 60;
|
|
9
|
+
// Width of the ASCII art column (with padding)
|
|
10
|
+
const ART_COLUMN_WIDTH = 24;
|
|
11
|
+
/**
|
|
12
|
+
* Welcome text content (right column)
|
|
13
|
+
*/
|
|
14
|
+
function getWelcomeText() {
|
|
15
|
+
return [
|
|
16
|
+
chalk.white.bold('Welcome to OpenSpec'),
|
|
17
|
+
chalk.dim('A lightweight spec-driven framework'),
|
|
18
|
+
'',
|
|
19
|
+
chalk.white('This setup will configure:'),
|
|
20
|
+
chalk.dim(' • Agent Skills for AI tools'),
|
|
21
|
+
chalk.dim(' • /opsx:* slash commands'),
|
|
22
|
+
'',
|
|
23
|
+
chalk.white('Quick start after setup:'),
|
|
24
|
+
` ${chalk.yellow('/opsx:new')} ${chalk.dim('Create a change')}`,
|
|
25
|
+
` ${chalk.yellow('/opsx:continue')} ${chalk.dim('Next artifact')}`,
|
|
26
|
+
` ${chalk.yellow('/opsx:apply')} ${chalk.dim('Implement tasks')}`,
|
|
27
|
+
'',
|
|
28
|
+
chalk.cyan('Press Enter to select tools...'),
|
|
29
|
+
];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Renders a single frame with side-by-side layout
|
|
33
|
+
*/
|
|
34
|
+
function renderFrame(artLines, textLines) {
|
|
35
|
+
const maxLines = Math.max(artLines.length, textLines.length);
|
|
36
|
+
const lines = [];
|
|
37
|
+
for (let i = 0; i < maxLines; i++) {
|
|
38
|
+
const artLine = artLines[i] || '';
|
|
39
|
+
const textLine = textLines[i] || '';
|
|
40
|
+
// Pad the art column to fixed width
|
|
41
|
+
const paddedArt = artLine.padEnd(ART_COLUMN_WIDTH);
|
|
42
|
+
// Color the ASCII art with cyan for visual appeal
|
|
43
|
+
const coloredArt = chalk.cyan(paddedArt);
|
|
44
|
+
// Clear line before writing to prevent residual characters
|
|
45
|
+
lines.push(`\x1b[2K${coloredArt}${textLine}`);
|
|
46
|
+
}
|
|
47
|
+
return lines.join('\n');
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Checks if the terminal supports animation
|
|
51
|
+
*/
|
|
52
|
+
function canAnimate() {
|
|
53
|
+
// Must be TTY
|
|
54
|
+
if (!process.stdout.isTTY)
|
|
55
|
+
return false;
|
|
56
|
+
// Respect NO_COLOR
|
|
57
|
+
if (process.env.NO_COLOR)
|
|
58
|
+
return false;
|
|
59
|
+
// Check terminal width
|
|
60
|
+
const columns = process.stdout.columns || 80;
|
|
61
|
+
if (columns < MIN_WIDTH)
|
|
62
|
+
return false;
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Wait for Enter key press
|
|
67
|
+
*/
|
|
68
|
+
function waitForEnter() {
|
|
69
|
+
return new Promise((resolve) => {
|
|
70
|
+
const { stdin } = process;
|
|
71
|
+
// Handle non-TTY gracefully
|
|
72
|
+
if (!stdin.isTTY) {
|
|
73
|
+
resolve();
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const wasRaw = stdin.isRaw;
|
|
77
|
+
stdin.setRawMode(true);
|
|
78
|
+
stdin.resume();
|
|
79
|
+
const onData = (data) => {
|
|
80
|
+
const char = data.toString();
|
|
81
|
+
// Enter key or Ctrl+C
|
|
82
|
+
if (char === '\r' || char === '\n' || char === '\u0003') {
|
|
83
|
+
stdin.removeListener('data', onData);
|
|
84
|
+
stdin.setRawMode(wasRaw);
|
|
85
|
+
stdin.pause();
|
|
86
|
+
// Handle Ctrl+C
|
|
87
|
+
if (char === '\u0003') {
|
|
88
|
+
process.stdout.write('\n');
|
|
89
|
+
process.exit(0);
|
|
90
|
+
}
|
|
91
|
+
resolve();
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
stdin.on('data', onData);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Shows the animated welcome screen.
|
|
99
|
+
* Returns when user presses Enter.
|
|
100
|
+
*/
|
|
101
|
+
export async function showWelcomeScreen() {
|
|
102
|
+
const textLines = getWelcomeText();
|
|
103
|
+
if (!canAnimate()) {
|
|
104
|
+
// Fallback: show static welcome
|
|
105
|
+
const frame = WELCOME_ANIMATION.frames[3]; // Peak frame
|
|
106
|
+
process.stdout.write('\n' + renderFrame(frame, textLines) + '\n\n');
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
let frameIndex = 0;
|
|
110
|
+
let running = true;
|
|
111
|
+
let isFirstRender = true;
|
|
112
|
+
// Content height for cursor movement between frames
|
|
113
|
+
const numContentLines = Math.max(WELCOME_ANIMATION.frames[0].length, textLines.length);
|
|
114
|
+
const frameHeight = numContentLines + 1; // internal newlines (11) + trailing newlines (2) = 13
|
|
115
|
+
// Total height including initial newline (for cleanup)
|
|
116
|
+
const totalHeight = frameHeight + 1; // 14
|
|
117
|
+
// Initial render
|
|
118
|
+
process.stdout.write('\n');
|
|
119
|
+
// Animation loop
|
|
120
|
+
const interval = setInterval(() => {
|
|
121
|
+
if (!running)
|
|
122
|
+
return;
|
|
123
|
+
const frame = WELCOME_ANIMATION.frames[frameIndex];
|
|
124
|
+
// Move cursor up to overwrite previous frame (always after first render)
|
|
125
|
+
if (!isFirstRender) {
|
|
126
|
+
process.stdout.write(`\x1b[${frameHeight}A`);
|
|
127
|
+
}
|
|
128
|
+
isFirstRender = false;
|
|
129
|
+
// Render current frame
|
|
130
|
+
process.stdout.write(renderFrame(frame, textLines) + '\n\n');
|
|
131
|
+
// Advance to next frame
|
|
132
|
+
frameIndex = (frameIndex + 1) % WELCOME_ANIMATION.frames.length;
|
|
133
|
+
}, WELCOME_ANIMATION.interval);
|
|
134
|
+
// Wait for Enter
|
|
135
|
+
await waitForEnter();
|
|
136
|
+
// Stop animation
|
|
137
|
+
running = false;
|
|
138
|
+
clearInterval(interval);
|
|
139
|
+
// Clear the welcome screen and move on
|
|
140
|
+
process.stdout.write(`\x1b[${totalHeight}A`);
|
|
141
|
+
for (let i = 0; i < totalHeight; i++) {
|
|
142
|
+
process.stdout.write('\x1b[2K\n'); // Clear line
|
|
143
|
+
}
|
|
144
|
+
process.stdout.write(`\x1b[${totalHeight}A`); // Move back up
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=welcome-screen.js.map
|
|
@@ -22,4 +22,15 @@ export declare class FileSystemUtils {
|
|
|
22
22
|
static updateFileWithMarkers(filePath: string, content: string, startMarker: string, endMarker: string): Promise<void>;
|
|
23
23
|
static ensureWritePermissions(dirPath: string): Promise<boolean>;
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Removes a marker block from file content.
|
|
27
|
+
* Only removes markers that are on their own lines (ignores inline mentions).
|
|
28
|
+
* Cleans up double blank lines that may result from removal.
|
|
29
|
+
*
|
|
30
|
+
* @param content - File content with markers
|
|
31
|
+
* @param startMarker - The start marker string
|
|
32
|
+
* @param endMarker - The end marker string
|
|
33
|
+
* @returns Content with marker block removed, or original content if markers not found/invalid
|
|
34
|
+
*/
|
|
35
|
+
export declare function removeMarkerBlock(content: string, startMarker: string, endMarker: string): string;
|
|
25
36
|
//# sourceMappingURL=file-system.d.ts.map
|
|
@@ -204,9 +204,28 @@ export class FileSystemUtils {
|
|
|
204
204
|
}
|
|
205
205
|
return await this.ensureWritePermissions(parentDir);
|
|
206
206
|
}
|
|
207
|
-
const testFile = path.join(dirPath, '.openspec-test-' + Date.now());
|
|
207
|
+
const testFile = path.join(dirPath, '.openspec-test-' + Date.now() + '-' + Math.random().toString(36).slice(2));
|
|
208
208
|
await fs.writeFile(testFile, '');
|
|
209
|
-
|
|
209
|
+
// On Windows, file may be temporarily locked by antivirus or indexing services.
|
|
210
|
+
// Retry unlink with a small delay if it fails.
|
|
211
|
+
const maxRetries = 3;
|
|
212
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
213
|
+
try {
|
|
214
|
+
await fs.unlink(testFile);
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
catch (unlinkError) {
|
|
218
|
+
if (attempt === maxRetries - 1) {
|
|
219
|
+
// Last attempt failed, but we successfully wrote the file, so permissions are OK
|
|
220
|
+
// Just log and continue - the temp file will be cleaned up eventually
|
|
221
|
+
console.debug(`Could not clean up test file ${testFile}: ${unlinkError.message}`);
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
// Wait briefly before retrying (Windows file lock release)
|
|
225
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
210
229
|
return true;
|
|
211
230
|
}
|
|
212
231
|
catch (error) {
|
|
@@ -215,4 +234,48 @@ export class FileSystemUtils {
|
|
|
215
234
|
}
|
|
216
235
|
}
|
|
217
236
|
}
|
|
237
|
+
/**
|
|
238
|
+
* Removes a marker block from file content.
|
|
239
|
+
* Only removes markers that are on their own lines (ignores inline mentions).
|
|
240
|
+
* Cleans up double blank lines that may result from removal.
|
|
241
|
+
*
|
|
242
|
+
* @param content - File content with markers
|
|
243
|
+
* @param startMarker - The start marker string
|
|
244
|
+
* @param endMarker - The end marker string
|
|
245
|
+
* @returns Content with marker block removed, or original content if markers not found/invalid
|
|
246
|
+
*/
|
|
247
|
+
export function removeMarkerBlock(content, startMarker, endMarker) {
|
|
248
|
+
const startIndex = findMarkerIndex(content, startMarker);
|
|
249
|
+
const endIndex = startIndex !== -1
|
|
250
|
+
? findMarkerIndex(content, endMarker, startIndex + startMarker.length)
|
|
251
|
+
: findMarkerIndex(content, endMarker);
|
|
252
|
+
if (startIndex === -1 || endIndex === -1 || endIndex <= startIndex) {
|
|
253
|
+
return content;
|
|
254
|
+
}
|
|
255
|
+
// Find the start of the line containing the start marker
|
|
256
|
+
let lineStart = startIndex;
|
|
257
|
+
while (lineStart > 0 && content[lineStart - 1] !== '\n') {
|
|
258
|
+
lineStart--;
|
|
259
|
+
}
|
|
260
|
+
// Find the end of the line containing the end marker
|
|
261
|
+
let lineEnd = endIndex + endMarker.length;
|
|
262
|
+
while (lineEnd < content.length && content[lineEnd] !== '\n') {
|
|
263
|
+
lineEnd++;
|
|
264
|
+
}
|
|
265
|
+
// Include the trailing newline if present
|
|
266
|
+
if (lineEnd < content.length && content[lineEnd] === '\n') {
|
|
267
|
+
lineEnd++;
|
|
268
|
+
}
|
|
269
|
+
const before = content.substring(0, lineStart);
|
|
270
|
+
const after = content.substring(lineEnd);
|
|
271
|
+
// Clean up double blank lines (handle both Unix \n and Windows \r\n)
|
|
272
|
+
let result = before + after;
|
|
273
|
+
result = result.replace(/(\r?\n){3,}/g, '\n\n');
|
|
274
|
+
// Trim trailing whitespace but preserve leading whitespace and original newline style
|
|
275
|
+
if (result.trimEnd() === '') {
|
|
276
|
+
return '';
|
|
277
|
+
}
|
|
278
|
+
const newline = content.includes('\r\n') ? '\r\n' : '\n';
|
|
279
|
+
return result.trimEnd() + newline;
|
|
280
|
+
}
|
|
218
281
|
//# sourceMappingURL=file-system.js.map
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { validateChangeName, createChange } from './change-utils.js';
|
|
2
2
|
export type { ValidationResult, CreateChangeOptions } from './change-utils.js';
|
|
3
3
|
export { readChangeMetadata, writeChangeMetadata, resolveSchemaForChange, validateSchemaName, ChangeMetadataError, } from './change-metadata.js';
|
|
4
|
+
export { FileSystemUtils, removeMarkerBlock } from './file-system.js';
|
|
4
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/utils/index.js
CHANGED
|
@@ -2,4 +2,6 @@
|
|
|
2
2
|
export { validateChangeName, createChange } from './change-utils.js';
|
|
3
3
|
// Change metadata utilities
|
|
4
4
|
export { readChangeMetadata, writeChangeMetadata, resolveSchemaForChange, validateSchemaName, ChangeMetadataError, } from './change-metadata.js';
|
|
5
|
+
// File system utilities
|
|
6
|
+
export { FileSystemUtils, removeMarkerBlock } from './file-system.js';
|
|
5
7
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Artifact Workflow CLI Commands (Experimental)
|
|
3
|
-
*
|
|
4
|
-
* This file contains all artifact workflow commands in isolation for easy removal.
|
|
5
|
-
* Commands expose the ArtifactGraph and InstructionLoader APIs to users and agents.
|
|
6
|
-
*
|
|
7
|
-
* To remove this feature:
|
|
8
|
-
* 1. Delete this file
|
|
9
|
-
* 2. Remove the registerArtifactWorkflowCommands() call from src/cli/index.ts
|
|
10
|
-
*/
|
|
11
|
-
import type { Command } from 'commander';
|
|
12
|
-
/**
|
|
13
|
-
* Registers all artifact workflow commands on the given program.
|
|
14
|
-
* All commands are marked as experimental in their help text.
|
|
15
|
-
*/
|
|
16
|
-
export declare function registerArtifactWorkflowCommands(program: Command): void;
|
|
17
|
-
//# sourceMappingURL=artifact-workflow.d.ts.map
|