@fission-ai/openspec 1.8.0 → 1.10.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/dist/cli/index.d.ts +32 -0
- package/dist/cli/index.js +80 -9
- package/dist/commands/change.js +1 -0
- package/dist/commands/config.d.ts +5 -0
- package/dist/commands/config.js +19 -4
- package/dist/commands/feedback.js +28 -7
- package/dist/commands/schema.js +193 -28
- package/dist/commands/validate.d.ts +23 -0
- package/dist/commands/validate.js +148 -4
- package/dist/commands/workflow/schemas.d.ts +2 -0
- package/dist/commands/workflow/schemas.js +9 -2
- package/dist/core/archive.js +74 -10
- package/dist/core/artifact-graph/instruction-loader.js +2 -7
- package/dist/core/artifact-graph/outputs.d.ts +4 -0
- package/dist/core/artifact-graph/outputs.js +7 -0
- package/dist/core/artifact-graph/resolver.d.ts +0 -12
- package/dist/core/artifact-graph/resolver.js +14 -0
- package/dist/core/command-generation/adapters/command-code.d.ts +19 -0
- package/dist/core/command-generation/adapters/command-code.js +34 -0
- package/dist/core/command-generation/adapters/index.d.ts +1 -0
- package/dist/core/command-generation/adapters/index.js +1 -0
- package/dist/core/command-generation/adapters/opencode.d.ts +2 -1
- package/dist/core/command-generation/adapters/opencode.js +13 -2
- package/dist/core/command-generation/registry.js +2 -0
- package/dist/core/completion-tip.d.ts +15 -0
- package/dist/core/completion-tip.js +133 -0
- package/dist/core/completions/command-registry.js +10 -0
- package/dist/core/completions/factory.d.ts +11 -0
- package/dist/core/completions/installers/bash-installer.d.ts +7 -0
- package/dist/core/completions/installers/bash-installer.js +15 -0
- package/dist/core/completions/installers/fish-installer.d.ts +7 -0
- package/dist/core/completions/installers/fish-installer.js +15 -0
- package/dist/core/completions/installers/powershell-installer.d.ts +7 -0
- package/dist/core/completions/installers/powershell-installer.js +15 -0
- package/dist/core/config-prompts.js +19 -10
- package/dist/core/config-schema.d.ts +1 -0
- package/dist/core/config-schema.js +2 -0
- package/dist/core/config.d.ts +1 -0
- package/dist/core/config.js +17 -15
- package/dist/core/global-config.d.ts +2 -0
- package/dist/core/init.d.ts +5 -0
- package/dist/core/init.js +110 -14
- package/dist/core/legacy-cleanup.d.ts +10 -0
- package/dist/core/legacy-cleanup.js +48 -26
- package/dist/core/parsers/requirement-blocks.js +41 -9
- package/dist/core/parsers/requirement-text.d.ts +8 -0
- package/dist/core/parsers/requirement-text.js +4 -3
- package/dist/core/profiles.d.ts +1 -1
- package/dist/core/profiles.js +11 -2
- package/dist/core/root-selection.d.ts +1 -1
- package/dist/core/shared-skill-target.d.ts +15 -0
- package/dist/core/shared-skill-target.js +30 -0
- package/dist/core/specs-apply.js +11 -4
- package/dist/core/templates/workflows/apply-change.js +3 -0
- package/dist/core/templates/workflows/feedback.js +1 -0
- package/dist/core/templates/workflows/onboard.js +4 -4
- package/dist/core/templates/workflows/propose.js +2 -2
- package/dist/core/templates/workflows/store-selection.d.ts +1 -1
- package/dist/core/templates/workflows/store-selection.js +1 -1
- package/dist/core/templates/workflows/update-change.js +4 -4
- package/dist/core/update.js +49 -11
- package/dist/core/validation/task-numbering.d.ts +16 -0
- package/dist/core/validation/task-numbering.js +57 -0
- package/dist/core/validation/validator.d.ts +5 -2
- package/dist/core/validation/validator.js +57 -3
- package/dist/telemetry/index.d.ts +3 -1
- package/dist/telemetry/index.js +10 -3
- package/dist/utils/change-metadata.js +17 -13
- package/dist/utils/change-utils.js +5 -0
- package/dist/utils/interactive.d.ts +30 -1
- package/dist/utils/interactive.js +105 -2
- package/dist/utils/task-progress.d.ts +34 -1
- package/dist/utils/task-progress.js +52 -28
- package/package.json +3 -6
- package/schemas/spec-driven/schema.yaml +17 -7
- package/scripts/postinstall.js +0 -83
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* First-run hint pointing users at opt-in shell completions.
|
|
3
|
+
*
|
|
4
|
+
* This hint used to be an npm `postinstall` script. Printing it from the CLI
|
|
5
|
+
* instead lets the package ship with no install scripts at all, so `npm install`
|
|
6
|
+
* no longer emits an `allow-scripts` warning. Completions stay opt-in: the tip
|
|
7
|
+
* only names the command, it never installs anything.
|
|
8
|
+
*
|
|
9
|
+
* The tip goes to stderr, never stdout, so it cannot contaminate piped command
|
|
10
|
+
* output.
|
|
11
|
+
*
|
|
12
|
+
* The tip is suppressed when:
|
|
13
|
+
* - CI is set (any value npm/telemetry would treat as CI)
|
|
14
|
+
* - OPENSPEC_NO_COMPLETIONS=1
|
|
15
|
+
* - completions are already installed, or the shell is one the installer would
|
|
16
|
+
* reject
|
|
17
|
+
* - the caller passes `silent` — JSON runs, `openspec completion ...`, and
|
|
18
|
+
* non-TTY runs, which are deferred rather than consumed (see `silent`)
|
|
19
|
+
*/
|
|
20
|
+
import * as fs from 'node:fs';
|
|
21
|
+
import * as path from 'node:path';
|
|
22
|
+
import { getGlobalConfigPath } from './global-config.js';
|
|
23
|
+
import { isCiEnvironment } from '../utils/ci.js';
|
|
24
|
+
import { detectShell } from '../utils/shell-detection.js';
|
|
25
|
+
import { CompletionFactory } from './completions/factory.js';
|
|
26
|
+
export const COMPLETION_TIP_MESSAGE = "Tip: Run 'openspec completion install' for shell completions";
|
|
27
|
+
function isSuppressedByEnv() {
|
|
28
|
+
// isCiEnvironment, not a CI==='true' string check: providers set CI to "True",
|
|
29
|
+
// "yes", "on", and the tip should be as quiet in those builds as telemetry is.
|
|
30
|
+
return isCiEnvironment() || process.env.OPENSPEC_NO_COMPLETIONS === '1';
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Whether the tip is worth showing, once we know it is owed and readable.
|
|
34
|
+
*
|
|
35
|
+
* "retire" consumes the tip without printing: the user either already has
|
|
36
|
+
* completions, or is on a shell `openspec completion install` would refuse.
|
|
37
|
+
*
|
|
38
|
+
* Without the installed check the tip tells people to install completions they
|
|
39
|
+
* installed long ago — including on the run right after `completion install`,
|
|
40
|
+
* whose own run only defers the tip. An undetected or unsupported shell retires
|
|
41
|
+
* it too: `completion install` exits 1 for those users, so pointing them at it
|
|
42
|
+
* is a dead end, and this tip is the only message about completions they would
|
|
43
|
+
* ever get.
|
|
44
|
+
*
|
|
45
|
+
* Not free: detectShell() forks `ps` to read the parent process (except on
|
|
46
|
+
* Windows), so this costs a spawn plus a stat. It runs only on interactive runs
|
|
47
|
+
* that still owe the tip, which is normally exactly one — but a config that
|
|
48
|
+
* cannot be written never records the flag, and then every interactive run pays
|
|
49
|
+
* it. On any unexpected error we show the tip rather than swallow it.
|
|
50
|
+
*/
|
|
51
|
+
async function decideTip() {
|
|
52
|
+
try {
|
|
53
|
+
const { shell } = detectShell();
|
|
54
|
+
if (!shell) {
|
|
55
|
+
return 'retire';
|
|
56
|
+
}
|
|
57
|
+
return (await CompletionFactory.createInstaller(shell).isInstalled())
|
|
58
|
+
? 'retire'
|
|
59
|
+
: 'show';
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return 'show';
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Read the global config exactly as it sits on disk.
|
|
67
|
+
*
|
|
68
|
+
* Deliberately NOT `getGlobalConfig()`: that merges in defaults, and writing the
|
|
69
|
+
* merged result back would stamp `profile`/`delivery` into a file the user never
|
|
70
|
+
* set them in. `migrateIfNeeded` treats a raw `profile` as "already migrated",
|
|
71
|
+
* so that stamp would permanently suppress the one-time profile migration and
|
|
72
|
+
* cost users their installed workflow skills.
|
|
73
|
+
*
|
|
74
|
+
* Returns null when the file exists but cannot be read or parsed — a config we
|
|
75
|
+
* cannot understand is left strictly alone rather than overwritten.
|
|
76
|
+
*/
|
|
77
|
+
function readRawConfig() {
|
|
78
|
+
const configPath = getGlobalConfigPath();
|
|
79
|
+
if (!fs.existsSync(configPath)) {
|
|
80
|
+
return {};
|
|
81
|
+
}
|
|
82
|
+
const parsed = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
83
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
return parsed;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Record the flag, re-reading the config first and replacing the file by rename.
|
|
90
|
+
*
|
|
91
|
+
* Deciding whether to show the tip costs a `ps` spawn and a stat, and a sibling
|
|
92
|
+
* `openspec` process can write the same file in that window — on a first run
|
|
93
|
+
* that is exactly when telemetry mints `anonymousId`. Re-reading here keeps the
|
|
94
|
+
* write down to this one key, and the rename keeps a reader from ever seeing a
|
|
95
|
+
* half-written config.
|
|
96
|
+
*/
|
|
97
|
+
function markTipSeen() {
|
|
98
|
+
const configPath = getGlobalConfigPath();
|
|
99
|
+
const current = readRawConfig() ?? {};
|
|
100
|
+
const tempPath = `${configPath}.${process.pid}.tmp`;
|
|
101
|
+
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
102
|
+
fs.writeFileSync(tempPath, JSON.stringify({ ...current, completionTipSeen: true }, null, 2) + '\n', 'utf-8');
|
|
103
|
+
fs.renameSync(tempPath, configPath);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Print the completion tip once, the first time the CLI runs.
|
|
107
|
+
* Never throws — a hint must not break a command.
|
|
108
|
+
*/
|
|
109
|
+
export async function maybeShowCompletionTip(options = {}) {
|
|
110
|
+
if (isSuppressedByEnv()) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
const raw = readRawConfig();
|
|
115
|
+
if (raw === null || raw.completionTipSeen === true) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (options.silent) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const decision = await decideTip();
|
|
122
|
+
// Record before printing: if the flag cannot be persisted, staying quiet
|
|
123
|
+
// beats reprinting the tip on every future run.
|
|
124
|
+
markTipSeen();
|
|
125
|
+
if (decision === 'show') {
|
|
126
|
+
console.error(`\n${COMPLETION_TIP_MESSAGE}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
// Silent failure - a hint should never break the CLI.
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=completion-tip.js.map
|
|
@@ -12,6 +12,11 @@ export const COMMAND_REGISTRY = [
|
|
|
12
12
|
description: 'Configure AI tools non-interactively (e.g., "all", "none", or comma-separated tool IDs)',
|
|
13
13
|
takesValue: true,
|
|
14
14
|
},
|
|
15
|
+
{
|
|
16
|
+
name: 'language',
|
|
17
|
+
description: 'Write new OpenSpec artifacts in this language',
|
|
18
|
+
takesValue: true,
|
|
19
|
+
},
|
|
15
20
|
{
|
|
16
21
|
name: 'force',
|
|
17
22
|
description: 'Auto-cleanup legacy files without prompting',
|
|
@@ -97,6 +102,10 @@ export const COMMAND_REGISTRY = [
|
|
|
97
102
|
name: 'specs',
|
|
98
103
|
description: 'Validate all specs',
|
|
99
104
|
},
|
|
105
|
+
{
|
|
106
|
+
name: 'archived',
|
|
107
|
+
description: 'Validate that archived changes have all tasks completed (for pre-commit linting)',
|
|
108
|
+
},
|
|
100
109
|
COMMON_FLAGS.type,
|
|
101
110
|
COMMON_FLAGS.strict,
|
|
102
111
|
COMMON_FLAGS.jsonValidation,
|
|
@@ -226,6 +235,7 @@ export const COMMAND_REGISTRY = [
|
|
|
226
235
|
description: 'List available workflow schemas with descriptions',
|
|
227
236
|
flags: [
|
|
228
237
|
COMMON_FLAGS.json,
|
|
238
|
+
COMMON_FLAGS.store,
|
|
229
239
|
],
|
|
230
240
|
},
|
|
231
241
|
{
|
|
@@ -24,6 +24,17 @@ export interface CompletionInstaller {
|
|
|
24
24
|
success: boolean;
|
|
25
25
|
message: string;
|
|
26
26
|
}>;
|
|
27
|
+
/**
|
|
28
|
+
* True when a completion script file is present at the install path.
|
|
29
|
+
*
|
|
30
|
+
* Deliberately just the script: bash and PowerShell also need a sourcing
|
|
31
|
+
* line in the user's profile, and `install()` adds that on a best-effort
|
|
32
|
+
* basis (it is skipped by OPENSPEC_NO_AUTO_CONFIG=1 or an unwritable
|
|
33
|
+
* profile, printing manual instructions instead). Someone in that state has
|
|
34
|
+
* already met the installer, so callers that use this to decide whether to
|
|
35
|
+
* *advertise* completions should not advertise again.
|
|
36
|
+
*/
|
|
37
|
+
isInstalled(): Promise<boolean>;
|
|
27
38
|
}
|
|
28
39
|
/**
|
|
29
40
|
* Factory for creating completion generators and installers
|
|
@@ -22,6 +22,13 @@ export declare class BashInstaller {
|
|
|
22
22
|
* @returns Installation path
|
|
23
23
|
*/
|
|
24
24
|
getInstallationPath(): Promise<string>;
|
|
25
|
+
/**
|
|
26
|
+
* Check if a completion script is currently installed.
|
|
27
|
+
* Mirrors ZshInstaller.isInstalled so callers can ask any installer.
|
|
28
|
+
*
|
|
29
|
+
* @returns true if the completion script exists
|
|
30
|
+
*/
|
|
31
|
+
isInstalled(): Promise<boolean>;
|
|
25
32
|
/**
|
|
26
33
|
* Backup an existing completion file if it exists
|
|
27
34
|
*
|
|
@@ -55,6 +55,21 @@ export class BashInstaller {
|
|
|
55
55
|
// For user installation, use local directory
|
|
56
56
|
return path.join(localCompletionDir, 'openspec');
|
|
57
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Check if a completion script is currently installed.
|
|
60
|
+
* Mirrors ZshInstaller.isInstalled so callers can ask any installer.
|
|
61
|
+
*
|
|
62
|
+
* @returns true if the completion script exists
|
|
63
|
+
*/
|
|
64
|
+
async isInstalled() {
|
|
65
|
+
try {
|
|
66
|
+
// stat, not access: a directory at the install path is not a script.
|
|
67
|
+
return (await fs.stat(await this.getInstallationPath())).isFile();
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
58
73
|
/**
|
|
59
74
|
* Backup an existing completion file if it exists
|
|
60
75
|
*
|
|
@@ -12,6 +12,13 @@ export declare class FishInstaller {
|
|
|
12
12
|
* @returns Installation path
|
|
13
13
|
*/
|
|
14
14
|
getInstallationPath(): string;
|
|
15
|
+
/**
|
|
16
|
+
* Check if a completion script is currently installed.
|
|
17
|
+
* Mirrors ZshInstaller.isInstalled so callers can ask any installer.
|
|
18
|
+
*
|
|
19
|
+
* @returns true if the completion script exists
|
|
20
|
+
*/
|
|
21
|
+
isInstalled(): Promise<boolean>;
|
|
15
22
|
/**
|
|
16
23
|
* Backup an existing completion file if it exists
|
|
17
24
|
*
|
|
@@ -19,6 +19,21 @@ export class FishInstaller {
|
|
|
19
19
|
getInstallationPath() {
|
|
20
20
|
return path.join(this.homeDir, '.config', 'fish', 'completions', 'openspec.fish');
|
|
21
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Check if a completion script is currently installed.
|
|
24
|
+
* Mirrors ZshInstaller.isInstalled so callers can ask any installer.
|
|
25
|
+
*
|
|
26
|
+
* @returns true if the completion script exists
|
|
27
|
+
*/
|
|
28
|
+
async isInstalled() {
|
|
29
|
+
try {
|
|
30
|
+
// stat, not access: a directory at the install path is not a script.
|
|
31
|
+
return (await fs.stat(this.getInstallationPath())).isFile();
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
22
37
|
/**
|
|
23
38
|
* Backup an existing completion file if it exists
|
|
24
39
|
*
|
|
@@ -43,6 +43,13 @@ export declare class PowerShellInstaller {
|
|
|
43
43
|
* @returns Installation path
|
|
44
44
|
*/
|
|
45
45
|
getInstallationPath(): string;
|
|
46
|
+
/**
|
|
47
|
+
* Check if a completion script is currently installed.
|
|
48
|
+
* Mirrors ZshInstaller.isInstalled so callers can ask any installer.
|
|
49
|
+
*
|
|
50
|
+
* @returns true if the completion script exists
|
|
51
|
+
*/
|
|
52
|
+
isInstalled(): Promise<boolean>;
|
|
46
53
|
/**
|
|
47
54
|
* Backup an existing completion file if it exists
|
|
48
55
|
*
|
|
@@ -110,6 +110,21 @@ export class PowerShellInstaller {
|
|
|
110
110
|
const profileDir = path.dirname(profilePath);
|
|
111
111
|
return path.join(profileDir, 'OpenSpecCompletion.ps1');
|
|
112
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Check if a completion script is currently installed.
|
|
115
|
+
* Mirrors ZshInstaller.isInstalled so callers can ask any installer.
|
|
116
|
+
*
|
|
117
|
+
* @returns true if the completion script exists
|
|
118
|
+
*/
|
|
119
|
+
async isInstalled() {
|
|
120
|
+
try {
|
|
121
|
+
// stat, not access: a directory at the install path is not a script.
|
|
122
|
+
return (await fs.stat(this.getInstallationPath())).isFile();
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
113
128
|
/**
|
|
114
129
|
* Backup an existing completion file if it exists
|
|
115
130
|
*
|
|
@@ -9,16 +9,25 @@ export function serializeConfig(config) {
|
|
|
9
9
|
// Schema (required)
|
|
10
10
|
lines.push(`schema: ${config.schema}`);
|
|
11
11
|
lines.push('');
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
12
|
+
if (config.context !== undefined) {
|
|
13
|
+
lines.push('context: |');
|
|
14
|
+
for (const line of config.context.split('\n')) {
|
|
15
|
+
lines.push(` ${line}`);
|
|
16
|
+
}
|
|
17
|
+
lines.push('');
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
// Context section with comments
|
|
21
|
+
lines.push('# Project context (optional)');
|
|
22
|
+
lines.push('# This is shown to AI when creating artifacts.');
|
|
23
|
+
lines.push('# Add your tech stack, conventions, style guides, domain knowledge, etc.');
|
|
24
|
+
lines.push('# Example:');
|
|
25
|
+
lines.push('# context: |');
|
|
26
|
+
lines.push('# Tech stack: TypeScript, React, Node.js');
|
|
27
|
+
lines.push('# We use conventional commits');
|
|
28
|
+
lines.push('# Domain: e-commerce platform');
|
|
29
|
+
lines.push('');
|
|
30
|
+
}
|
|
22
31
|
// Rules section with comments
|
|
23
32
|
lines.push('# Per-artifact rules (optional)');
|
|
24
33
|
lines.push('# Add custom rules for specific artifacts.');
|
|
@@ -19,6 +19,7 @@ export declare const GlobalConfigSchema: z.ZodObject<{
|
|
|
19
19
|
telemetry: z.ZodOptional<z.ZodObject<{
|
|
20
20
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
21
21
|
}, z.core.$loose>>;
|
|
22
|
+
completionTipSeen: z.ZodOptional<z.ZodBoolean>;
|
|
22
23
|
}, z.core.$loose>;
|
|
23
24
|
export type GlobalConfigType = z.infer<typeof GlobalConfigSchema>;
|
|
24
25
|
/**
|
package/dist/core/config.d.ts
CHANGED
package/dist/core/config.js
CHANGED
|
@@ -18,41 +18,43 @@ export const OPENSPEC_MARKERS = {
|
|
|
18
18
|
end: '<!-- OPENSPEC:END -->'
|
|
19
19
|
};
|
|
20
20
|
export const AI_TOOLS = [
|
|
21
|
-
{ name: 'Amazon Q Developer', value: 'amazon-q', available: true, successLabel: 'Amazon Q Developer', skillsDir: '.amazonq' },
|
|
22
|
-
{ name: 'Antigravity', value: 'antigravity', available: true, successLabel: 'Antigravity', skillsDir: '.agent' },
|
|
21
|
+
{ name: 'Amazon Q Developer', value: 'amazon-q', available: true, successLabel: 'Amazon Q Developer', skillsDir: '.amazonq', requiresIdeRestart: true },
|
|
22
|
+
{ name: 'Antigravity', value: 'antigravity', available: true, successLabel: 'Antigravity', skillsDir: '.agent', requiresIdeRestart: true },
|
|
23
23
|
{ name: 'Auggie (Augment CLI)', value: 'auggie', available: true, successLabel: 'Auggie', skillsDir: '.augment' },
|
|
24
24
|
{ name: 'Bob Shell', value: 'bob', available: true, successLabel: 'Bob Shell', skillsDir: '.bob' },
|
|
25
25
|
{ name: 'Claude Code', value: 'claude', available: true, successLabel: 'Claude Code', skillsDir: '.claude' },
|
|
26
|
-
{ name: 'Cline', value: 'cline', available: true, successLabel: 'Cline', skillsDir: '.cline' },
|
|
26
|
+
{ name: 'Cline', value: 'cline', available: true, successLabel: 'Cline', skillsDir: '.cline', requiresIdeRestart: true },
|
|
27
|
+
{ name: 'Command Code', value: 'command-code', available: true, successLabel: 'Command Code', skillsDir: '.commandcode' },
|
|
27
28
|
{ name: 'CodeArts', value: 'codeartsagent', available: true, successLabel: 'CodeArts', skillsDir: '.codeartsdoer' },
|
|
28
29
|
{ name: 'Codex', value: 'codex', available: true, successLabel: 'Codex', skillsDir: '.agents', legacySkillsDirs: ['.codex'], detectionPaths: ['.agents/skills', '.codex/skills'] },
|
|
29
|
-
{ name: 'Devin Desktop (formerly Windsurf)', value: 'devin', available: true, successLabel: 'Devin Desktop', skillsDir: '.devin', detectionPaths: ['.devin', '.windsurf'] },
|
|
30
|
+
{ name: 'Devin Desktop (formerly Windsurf)', value: 'devin', available: true, successLabel: 'Devin Desktop', skillsDir: '.devin', detectionPaths: ['.devin', '.windsurf'], requiresIdeRestart: true },
|
|
30
31
|
{ name: 'ForgeCode', value: 'forgecode', available: true, successLabel: 'ForgeCode', skillsDir: '.forge' },
|
|
31
32
|
{ name: 'CodeBuddy Code (CLI)', value: 'codebuddy', available: true, successLabel: 'CodeBuddy Code', skillsDir: '.codebuddy' },
|
|
32
|
-
{ name: 'Continue', value: 'continue', available: true, successLabel: 'Continue (VS Code / JetBrains / Cli)', skillsDir: '.continue' },
|
|
33
|
-
{ name: 'CoStrict', value: 'costrict', available: true, successLabel: 'CoStrict', skillsDir: '.cospec' },
|
|
33
|
+
{ name: 'Continue', value: 'continue', available: true, successLabel: 'Continue (VS Code / JetBrains / Cli)', skillsDir: '.continue', requiresIdeRestart: true },
|
|
34
|
+
{ name: 'CoStrict', value: 'costrict', available: true, successLabel: 'CoStrict', skillsDir: '.cospec', requiresIdeRestart: true },
|
|
34
35
|
{ name: 'Crush', value: 'crush', available: true, successLabel: 'Crush', skillsDir: '.crush' },
|
|
35
|
-
{ name: 'Cursor', value: 'cursor', available: true, successLabel: 'Cursor', skillsDir: '.cursor' },
|
|
36
|
+
{ name: 'Cursor', value: 'cursor', available: true, successLabel: 'Cursor', skillsDir: '.cursor', requiresIdeRestart: true },
|
|
36
37
|
{ name: 'Factory Droid', value: 'factory', available: true, successLabel: 'Factory Droid', skillsDir: '.factory' },
|
|
37
38
|
{ name: 'Gemini CLI', value: 'gemini', available: true, successLabel: 'Gemini CLI', skillsDir: '.gemini' },
|
|
38
|
-
{ name: 'GitHub Copilot', value: 'github-copilot', available: true, successLabel: 'GitHub Copilot', skillsDir: '.github', detectionPaths: ['.github/copilot-instructions.md', '.github/instructions', '.github/workflows/copilot-setup-steps.yml', '.github/prompts', '.github/agents', '.github/skills', '.github/.mcp.json'] },
|
|
39
|
+
{ name: 'GitHub Copilot', value: 'github-copilot', available: true, successLabel: 'GitHub Copilot', skillsDir: '.github', detectionPaths: ['.github/copilot-instructions.md', '.github/instructions', '.github/workflows/copilot-setup-steps.yml', '.github/prompts', '.github/agents', '.github/skills', '.github/.mcp.json'], requiresIdeRestart: true },
|
|
39
40
|
{ name: 'Hermes Agent', value: 'hermes', available: true, successLabel: 'Hermes Agent', skillsDir: '.hermes', detectionPaths: ['.hermes', 'HERMES.md', '.hermes.md'], setupNote: "Hermes only loads skills from ~/.hermes/skills by default. Add this project's .hermes/skills directory to skills.external_dirs in ~/.hermes/config.yaml so Hermes picks up the generated OpenSpec skills." },
|
|
40
41
|
{ name: 'iFlow', value: 'iflow', available: true, successLabel: 'iFlow', skillsDir: '.iflow' },
|
|
41
|
-
{ name: 'Junie', value: 'junie', available: true, successLabel: 'Junie', skillsDir: '.junie' },
|
|
42
|
-
{ name: 'Kilo Code', value: 'kilocode', available: true, successLabel: 'Kilo Code', skillsDir: '.kilocode' },
|
|
42
|
+
{ name: 'Junie', value: 'junie', available: true, successLabel: 'Junie', skillsDir: '.junie', requiresIdeRestart: true },
|
|
43
|
+
{ name: 'Kilo Code', value: 'kilocode', available: true, successLabel: 'Kilo Code', skillsDir: '.kilocode', requiresIdeRestart: true },
|
|
43
44
|
{ name: 'Kimi Code', value: 'kimi', available: true, successLabel: 'Kimi Code', skillsDir: '.kimi-code', detectionPaths: ['.kimi-code', '.kimi'] },
|
|
44
|
-
{ name: 'Kiro', value: 'kiro', available: true, successLabel: 'Kiro', skillsDir: '.kiro' },
|
|
45
|
-
{ name: 'Lingma', value: 'lingma', available: true, successLabel: 'Lingma', skillsDir: '.lingma' },
|
|
45
|
+
{ name: 'Kiro', value: 'kiro', available: true, successLabel: 'Kiro', skillsDir: '.kiro', requiresIdeRestart: true },
|
|
46
|
+
{ name: 'Lingma', value: 'lingma', available: true, successLabel: 'Lingma', skillsDir: '.lingma', requiresIdeRestart: true },
|
|
46
47
|
{ name: 'MiniMax Code', value: 'minimax-code', available: true, successLabel: 'MiniMax Code', globalSkillsDir: '.minimax' },
|
|
47
48
|
{ name: 'Mistral Vibe', value: 'vibe', available: true, successLabel: 'Mistral Vibe', skillsDir: '.vibe' },
|
|
48
49
|
{ name: 'Oh My Pi', value: 'oh-my-pi', available: true, successLabel: 'Oh My Pi', skillsDir: '.omp' },
|
|
49
50
|
{ name: 'OpenCode', value: 'opencode', available: true, successLabel: 'OpenCode', skillsDir: '.opencode' },
|
|
50
51
|
{ name: 'Pi', value: 'pi', available: true, successLabel: 'Pi', skillsDir: '.pi' },
|
|
51
|
-
{ name: 'Qoder', value: 'qoder', available: true, successLabel: 'Qoder', skillsDir: '.qoder' },
|
|
52
|
+
{ name: 'Qoder', value: 'qoder', available: true, successLabel: 'Qoder', skillsDir: '.qoder', requiresIdeRestart: true },
|
|
52
53
|
{ name: 'Qwen Code', value: 'qwen', available: true, successLabel: 'Qwen Code', skillsDir: '.qwen' },
|
|
53
54
|
{ name: 'Rovo Dev CLI', value: 'rovodev', available: true, successLabel: 'Rovo Dev CLI', skillsDir: '.rovodev', detectionPaths: ['.rovodev/skills', '.rovodev'] },
|
|
54
|
-
{ name: 'Zoo Code', value: 'roocode', available: true, successLabel: 'Zoo Code', skillsDir: '.roo' },
|
|
55
|
-
{ name: 'Trae', value: 'trae', available: true, successLabel: 'Trae', skillsDir: '.trae' },
|
|
55
|
+
{ name: 'Zoo Code', value: 'roocode', available: true, successLabel: 'Zoo Code', skillsDir: '.roo', requiresIdeRestart: true },
|
|
56
|
+
{ name: 'Trae', value: 'trae', available: true, successLabel: 'Trae', skillsDir: '.trae', requiresIdeRestart: true },
|
|
57
|
+
{ name: 'Zed Agent', value: 'zed', available: true, successLabel: 'Zed Agent', skillsDir: '.agents', detectionPaths: ['.zed', '.agents/skills'] },
|
|
56
58
|
{ name: 'ZCode', value: 'zcode', available: true, successLabel: 'ZCode', skillsDir: '.zcode' },
|
|
57
59
|
// Vendor-neutral target for assistants that read the shared `.agents` root.
|
|
58
60
|
// Detection keys off `.agents/skills` rather than the bare root: frameworks use
|
|
@@ -26,6 +26,8 @@ export interface GlobalConfig {
|
|
|
26
26
|
openers?: unknown;
|
|
27
27
|
/** Anonymous usage analytics settings and identity. */
|
|
28
28
|
telemetry?: TelemetryConfig;
|
|
29
|
+
/** Whether the first-run shell-completions tip has been shown. */
|
|
30
|
+
completionTipSeen?: boolean;
|
|
29
31
|
}
|
|
30
32
|
/**
|
|
31
33
|
* Gets the global configuration directory path following XDG Base Directory Specification.
|
package/dist/core/init.d.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
type InitCommandOptions = {
|
|
8
8
|
tools?: string;
|
|
9
|
+
language?: string;
|
|
9
10
|
force?: boolean;
|
|
10
11
|
interactive?: boolean;
|
|
11
12
|
profile?: string;
|
|
@@ -20,6 +21,7 @@ type InitCommandOptions = {
|
|
|
20
21
|
};
|
|
21
22
|
export declare class InitCommand {
|
|
22
23
|
private readonly toolsArg?;
|
|
24
|
+
private readonly language?;
|
|
23
25
|
private readonly force;
|
|
24
26
|
private readonly interactiveOption?;
|
|
25
27
|
private readonly profileOverride?;
|
|
@@ -85,6 +87,9 @@ export declare class InitCommand {
|
|
|
85
87
|
* @returns Created, refreshed, and failed tools plus removed artifact counts
|
|
86
88
|
*/
|
|
87
89
|
private generateSkillsAndCommands;
|
|
90
|
+
private normalizeLanguage;
|
|
91
|
+
private languageContext;
|
|
92
|
+
private assertLanguageCanBeApplied;
|
|
88
93
|
private createConfig;
|
|
89
94
|
private displaySuccessMessage;
|
|
90
95
|
private startSpinner;
|