@fission-ai/openspec 1.13.1 → 1.14.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 +15 -3
- package/dist/cli/index.js +39 -1
- package/dist/commands/spec.js +1 -0
- package/dist/commands/workflow/instructions.js +66 -18
- package/dist/commands/workflow/shared.d.ts +7 -0
- package/dist/commands/workflow/status.js +15 -2
- package/dist/core/archive.js +258 -78
- package/dist/core/artifact-graph/instruction-loader.d.ts +7 -0
- package/dist/core/artifact-graph/instruction-loader.js +18 -1
- package/dist/core/artifact-graph/outputs.d.ts +1 -1
- package/dist/core/artifact-graph/outputs.js +38 -8
- package/dist/core/change-metadata/schema.d.ts +3 -0
- package/dist/core/change-metadata/schema.js +10 -0
- package/dist/core/change-status-policy.d.ts +8 -0
- package/dist/core/change-status-policy.js +33 -2
- package/dist/core/command-generation/adapters/atomcode.d.ts +24 -0
- package/dist/core/command-generation/adapters/atomcode.js +46 -0
- package/dist/core/command-generation/adapters/codestudio.d.ts +13 -0
- package/dist/core/command-generation/adapters/codestudio.js +27 -0
- package/dist/core/command-generation/adapters/continue.js +4 -0
- package/dist/core/command-generation/adapters/easycode.d.ts +17 -0
- package/dist/core/command-generation/adapters/easycode.js +28 -0
- package/dist/core/command-generation/adapters/gemini.js +1 -35
- package/dist/core/command-generation/adapters/gigacode.d.ts +17 -0
- package/dist/core/command-generation/adapters/gigacode.js +31 -0
- package/dist/core/command-generation/adapters/index.d.ts +4 -0
- package/dist/core/command-generation/adapters/index.js +4 -0
- package/dist/core/command-generation/adapters/kilocode.d.ts +1 -1
- package/dist/core/command-generation/adapters/kilocode.js +2 -2
- package/dist/core/command-generation/registry.js +8 -0
- package/dist/core/command-generation/toml.d.ts +19 -0
- package/dist/core/command-generation/toml.js +39 -0
- package/dist/core/command-surface.js +1 -1
- package/dist/core/completions/command-registry.js +19 -0
- package/dist/core/completions/installers/zsh-installer.js +4 -2
- package/dist/core/config-prompts.js +6 -6
- package/dist/core/config.js +11 -1
- package/dist/core/init.js +44 -14
- package/dist/core/legacy-cleanup.d.ts +1 -1
- package/dist/core/legacy-cleanup.js +40 -11
- package/dist/core/list.d.ts +2 -0
- package/dist/core/list.js +49 -23
- package/dist/core/parsers/markdown-parser.js +5 -0
- package/dist/core/parsers/requirement-blocks.d.ts +40 -3
- package/dist/core/parsers/requirement-blocks.js +74 -25
- package/dist/core/project-config.js +45 -1
- package/dist/core/references.js +3 -1
- package/dist/core/root-selection.d.ts +6 -0
- package/dist/core/root-selection.js +16 -0
- package/dist/core/schemas/base.schema.d.ts +3 -0
- package/dist/core/schemas/base.schema.js +6 -0
- package/dist/core/schemas/change.schema.d.ts +8 -0
- package/dist/core/schemas/spec.schema.d.ts +2 -0
- package/dist/core/specs-apply.d.ts +20 -0
- package/dist/core/specs-apply.js +19 -6
- package/dist/core/templates/workflows/apply-change.js +5 -2
- package/dist/core/templates/workflows/archive-change.js +56 -20
- package/dist/core/templates/workflows/bulk-archive-change.js +34 -16
- package/dist/core/templates/workflows/continue-change.js +0 -2
- package/dist/core/templates/workflows/explore.js +2 -2
- package/dist/core/templates/workflows/ff-change.js +2 -2
- package/dist/core/templates/workflows/onboard.js +9 -4
- package/dist/core/templates/workflows/update-change.js +21 -9
- package/dist/core/templates/workflows/verify-change.js +115 -52
- package/dist/core/update.js +20 -7
- package/dist/core/validation/constants.d.ts +1 -1
- package/dist/core/validation/constants.js +1 -1
- package/dist/core/validation/purpose-placeholder.js +24 -9
- package/dist/core/validation/validator.js +15 -6
- package/dist/core/version-check.d.ts +23 -1
- package/dist/core/version-check.js +112 -26
- package/dist/core/view.d.ts +2 -0
- package/dist/core/view.js +62 -4
- package/dist/utils/change-metadata.d.ts +20 -1
- package/dist/utils/change-metadata.js +57 -1
- package/dist/utils/command-references.d.ts +1 -1
- package/dist/utils/command-references.js +2 -2
- package/dist/utils/file-system.js +20 -3
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/line-endings.d.ts +34 -0
- package/dist/utils/line-endings.js +46 -0
- package/package.json +2 -2
- package/schemas/spec-driven/schema.yaml +10 -1
- package/schemas/spec-driven/templates/proposal.md +6 -3
|
@@ -10,14 +10,45 @@ export function summarizePlanningHome(planningHome) {
|
|
|
10
10
|
};
|
|
11
11
|
}
|
|
12
12
|
export function buildActionContext(input) {
|
|
13
|
+
const scope = editScope(input);
|
|
14
|
+
// Keys stay in the published contract order.
|
|
13
15
|
return {
|
|
14
16
|
mode: 'repo-local',
|
|
15
17
|
sourceOfTruth: 'repo',
|
|
16
18
|
planningArtifacts: input.artifactIds,
|
|
17
19
|
linkedContext: [],
|
|
18
|
-
allowedEditRoots:
|
|
20
|
+
allowedEditRoots: scope.allowedEditRoots,
|
|
19
21
|
requiresAffectedAreaSelection: false,
|
|
20
|
-
constraints:
|
|
22
|
+
constraints: scope.constraints,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* A store holds planning artifacts only. The CLI does not route tasks to
|
|
27
|
+
* repos, so it names the declaring project on the current path as the edit
|
|
28
|
+
* root and has the agent ask before going anywhere else (#2013).
|
|
29
|
+
*/
|
|
30
|
+
function editScope(input) {
|
|
31
|
+
if (!input.store) {
|
|
32
|
+
return {
|
|
33
|
+
allowedEditRoots: [input.projectRoot],
|
|
34
|
+
constraints: ['Repo-local change artifacts and implementation edits are scoped to this project.'],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const planning = `Change artifacts live in store '${input.store.id}' (${input.projectRoot}).`;
|
|
38
|
+
const { implementationRoot } = input.store;
|
|
39
|
+
if (implementationRoot) {
|
|
40
|
+
return {
|
|
41
|
+
allowedEditRoots: [implementationRoot, input.projectRoot],
|
|
42
|
+
constraints: [
|
|
43
|
+
`${planning} Implementation edits go in ${implementationRoot}, the project on the current path that declares this store; ask the user before editing any other repository.`,
|
|
44
|
+
],
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
allowedEditRoots: [input.projectRoot],
|
|
49
|
+
constraints: [
|
|
50
|
+
`${planning} OpenSpec could not determine which repository implements this change; ask the user which repository to edit, and make implementation edits there.`,
|
|
51
|
+
],
|
|
21
52
|
};
|
|
22
53
|
}
|
|
23
54
|
export function resolveNextStep(input) {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AtomCode Command Adapter
|
|
3
|
+
*
|
|
4
|
+
* Formats project commands for AtomCode.
|
|
5
|
+
* https://github.com/atomgit-atomcode/atomcode#custom-commands
|
|
6
|
+
*/
|
|
7
|
+
import type { ToolCommandAdapter } from '../types.js';
|
|
8
|
+
/**
|
|
9
|
+
* AtomCode adapter for command generation.
|
|
10
|
+
* File path: .atomcode/commands/opsx-<id>.md
|
|
11
|
+
* Frontmatter: name, description, args
|
|
12
|
+
*
|
|
13
|
+
* AtomCode's custom-command parser reads name and args literally without YAML
|
|
14
|
+
* unquoting, so these controlled identifiers must stay unquoted.
|
|
15
|
+
* The command name matches the filename.
|
|
16
|
+
*
|
|
17
|
+
* `args` mirrors what the workflow actually accepts. AtomCode executes an
|
|
18
|
+
* `args: none` command straight from the slash menu, while `optional` completes
|
|
19
|
+
* to `/name ` and waits for a second Enter. Advertising arguments a workflow
|
|
20
|
+
* never reads would cost every user that extra keystroke, so only workflows
|
|
21
|
+
* carrying an `**Input**:` contract declare `optional` and receive $ARGUMENTS.
|
|
22
|
+
*/
|
|
23
|
+
export declare const atomcodeAdapter: ToolCommandAdapter;
|
|
24
|
+
//# sourceMappingURL=atomcode.d.ts.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AtomCode Command Adapter
|
|
3
|
+
*
|
|
4
|
+
* Formats project commands for AtomCode.
|
|
5
|
+
* https://github.com/atomgit-atomcode/atomcode#custom-commands
|
|
6
|
+
*/
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { stringify } from 'yaml';
|
|
9
|
+
/** A workflow declares its invocation input with an `**Input**:` heading. */
|
|
10
|
+
const INPUT_HEADING = /^\*\*Input\*\*:/m;
|
|
11
|
+
/**
|
|
12
|
+
* AtomCode adapter for command generation.
|
|
13
|
+
* File path: .atomcode/commands/opsx-<id>.md
|
|
14
|
+
* Frontmatter: name, description, args
|
|
15
|
+
*
|
|
16
|
+
* AtomCode's custom-command parser reads name and args literally without YAML
|
|
17
|
+
* unquoting, so these controlled identifiers must stay unquoted.
|
|
18
|
+
* The command name matches the filename.
|
|
19
|
+
*
|
|
20
|
+
* `args` mirrors what the workflow actually accepts. AtomCode executes an
|
|
21
|
+
* `args: none` command straight from the slash menu, while `optional` completes
|
|
22
|
+
* to `/name ` and waits for a second Enter. Advertising arguments a workflow
|
|
23
|
+
* never reads would cost every user that extra keystroke, so only workflows
|
|
24
|
+
* carrying an `**Input**:` contract declare `optional` and receive $ARGUMENTS.
|
|
25
|
+
*/
|
|
26
|
+
export const atomcodeAdapter = {
|
|
27
|
+
toolId: 'atomcode',
|
|
28
|
+
getFilePath(commandId) {
|
|
29
|
+
return path.join('.atomcode', 'commands', `opsx-${commandId}.md`);
|
|
30
|
+
},
|
|
31
|
+
formatFile(content) {
|
|
32
|
+
// Keep ordinary descriptions plain for the literal custom-command parser,
|
|
33
|
+
// while keeping special values valid YAML for frontmatter consumers.
|
|
34
|
+
const description = stringify({ description: content.description }, { lineWidth: 0, blockQuote: false });
|
|
35
|
+
const acceptsInput = INPUT_HEADING.test(content.body);
|
|
36
|
+
const argumentsBlock = acceptsInput ? '\n**Provided arguments**: $ARGUMENTS\n' : '';
|
|
37
|
+
return `---
|
|
38
|
+
name: opsx-${content.id}
|
|
39
|
+
${description}args: ${acceptsInput ? 'optional' : 'none'}
|
|
40
|
+
---
|
|
41
|
+
${argumentsBlock}
|
|
42
|
+
${content.body}
|
|
43
|
+
`;
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=atomcode.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code Studio Command Adapter
|
|
3
|
+
*
|
|
4
|
+
* Formats commands for Syncfusion Code Studio following its .prompt.md specification.
|
|
5
|
+
*/
|
|
6
|
+
import type { ToolCommandAdapter } from '../types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Code Studio adapter for command generation.
|
|
9
|
+
* File path: .codestudio/prompts/opsx-<id>.prompt.md
|
|
10
|
+
* Frontmatter: description
|
|
11
|
+
*/
|
|
12
|
+
export declare const codeStudioAdapter: ToolCommandAdapter;
|
|
13
|
+
//# sourceMappingURL=codestudio.d.ts.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code Studio Command Adapter
|
|
3
|
+
*
|
|
4
|
+
* Formats commands for Syncfusion Code Studio following its .prompt.md specification.
|
|
5
|
+
*/
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import { escapeYamlValue } from '../yaml.js';
|
|
8
|
+
/**
|
|
9
|
+
* Code Studio adapter for command generation.
|
|
10
|
+
* File path: .codestudio/prompts/opsx-<id>.prompt.md
|
|
11
|
+
* Frontmatter: description
|
|
12
|
+
*/
|
|
13
|
+
export const codeStudioAdapter = {
|
|
14
|
+
toolId: 'codestudio',
|
|
15
|
+
getFilePath(commandId) {
|
|
16
|
+
return path.join('.codestudio', 'prompts', `opsx-${commandId}.prompt.md`);
|
|
17
|
+
},
|
|
18
|
+
formatFile(content) {
|
|
19
|
+
return `---
|
|
20
|
+
description: ${escapeYamlValue(content.description)}
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
${content.body}
|
|
24
|
+
`;
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=codestudio.js.map
|
|
@@ -16,12 +16,16 @@ export const continueAdapter = {
|
|
|
16
16
|
return path.join('.continue', 'prompts', `opsx-${commandId}.prompt`);
|
|
17
17
|
},
|
|
18
18
|
formatFile(content) {
|
|
19
|
+
// Continue injects an invoked prompt into the model context. Smaller local
|
|
20
|
+
// models can otherwise mistake the workflow name for a tool to call (#925).
|
|
19
21
|
return `---
|
|
20
22
|
name: ${escapeYamlValue(`opsx-${content.id}`)}
|
|
21
23
|
description: ${escapeYamlValue(content.description)}
|
|
22
24
|
invokable: true
|
|
23
25
|
---
|
|
24
26
|
|
|
27
|
+
This workflow prompt is already active. Follow its instructions directly. Do not call a tool named after this workflow.
|
|
28
|
+
|
|
25
29
|
${content.body}
|
|
26
30
|
`;
|
|
27
31
|
},
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EasyCode Command Adapter
|
|
3
|
+
*
|
|
4
|
+
* Formats commands for OrionStarAI/EasyCode using its TOML command format.
|
|
5
|
+
* https://github.com/OrionStarAI/EasyCode
|
|
6
|
+
*/
|
|
7
|
+
import type { ToolCommandAdapter } from '../types.js';
|
|
8
|
+
/**
|
|
9
|
+
* EasyCode adapter for command generation.
|
|
10
|
+
* File path: .easycode/commands/opsx/<id>.toml
|
|
11
|
+
*
|
|
12
|
+
* Format:
|
|
13
|
+
* description = "<basic-string>" single-line, backslash/quote-safe
|
|
14
|
+
* prompt = """<multiline-string>""" multiline, backslash/triple-quote-safe
|
|
15
|
+
*/
|
|
16
|
+
export declare const easycodeAdapter: ToolCommandAdapter;
|
|
17
|
+
//# sourceMappingURL=easycode.d.ts.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EasyCode Command Adapter
|
|
3
|
+
*
|
|
4
|
+
* Formats commands for OrionStarAI/EasyCode using its TOML command format.
|
|
5
|
+
* https://github.com/OrionStarAI/EasyCode
|
|
6
|
+
*/
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { escapeTomlBasicString, escapeTomlMultilineBasicString } from '../toml.js';
|
|
9
|
+
/**
|
|
10
|
+
* EasyCode adapter for command generation.
|
|
11
|
+
* File path: .easycode/commands/opsx/<id>.toml
|
|
12
|
+
*
|
|
13
|
+
* Format:
|
|
14
|
+
* description = "<basic-string>" single-line, backslash/quote-safe
|
|
15
|
+
* prompt = """<multiline-string>""" multiline, backslash/triple-quote-safe
|
|
16
|
+
*/
|
|
17
|
+
export const easycodeAdapter = {
|
|
18
|
+
toolId: 'easycode',
|
|
19
|
+
getFilePath(commandId) {
|
|
20
|
+
return path.join('.easycode', 'commands', 'opsx', `${commandId}.toml`);
|
|
21
|
+
},
|
|
22
|
+
formatFile(content) {
|
|
23
|
+
const safeDesc = escapeTomlBasicString(content.description);
|
|
24
|
+
const safeBody = escapeTomlMultilineBasicString(content.body);
|
|
25
|
+
return `description = "${safeDesc}"\n\nprompt = """\n${safeBody}\n"""\n`;
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=easycode.js.map
|
|
@@ -4,41 +4,7 @@
|
|
|
4
4
|
* Formats commands for Gemini CLI following its TOML specification.
|
|
5
5
|
*/
|
|
6
6
|
import path from 'path';
|
|
7
|
-
|
|
8
|
-
* Control characters (C0 except tab/newline/carriage return, plus DEL) are
|
|
9
|
-
* invalid inside TOML strings and must be written as escapes.
|
|
10
|
-
*/
|
|
11
|
-
const TOML_CONTROL_CHARS = new RegExp('[\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f\\u007f]', 'g');
|
|
12
|
-
/**
|
|
13
|
-
* TOML basic strings are escape-active: a backslash or double quote in the
|
|
14
|
-
* value breaks the file if written raw. Newlines cannot appear in a
|
|
15
|
-
* single-line basic string at all, so they are escaped too.
|
|
16
|
-
*/
|
|
17
|
-
function escapeTomlBasicString(value) {
|
|
18
|
-
return value
|
|
19
|
-
.replace(/\\/g, '\\\\')
|
|
20
|
-
.replace(/"/g, '\\"')
|
|
21
|
-
.replace(/\n/g, '\\n')
|
|
22
|
-
.replace(/\r/g, '\\r')
|
|
23
|
-
.replace(/\t/g, '\\t')
|
|
24
|
-
.replace(TOML_CONTROL_CHARS, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, '0')}`);
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Multiline basic strings keep raw newlines and tabs, but backslashes are
|
|
28
|
-
* still escape-active, any run of three quotes would end the string, and the
|
|
29
|
-
* same control characters are invalid as in single-line basic strings — a
|
|
30
|
-
* lone carriage return included (only LF and CRLF may appear raw; CRLF is
|
|
31
|
-
* normalized away so the emitted file is single-convention). Escapes are
|
|
32
|
-
* introduced after backslash-doubling so they are not re-doubled.
|
|
33
|
-
*/
|
|
34
|
-
function escapeTomlMultilineBasicString(value) {
|
|
35
|
-
return value
|
|
36
|
-
.replace(/\r\n/g, '\n')
|
|
37
|
-
.replace(/\\/g, '\\\\')
|
|
38
|
-
.replace(/"""/g, '""\\"')
|
|
39
|
-
.replace(/\r/g, '\\r')
|
|
40
|
-
.replace(TOML_CONTROL_CHARS, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, '0')}`);
|
|
41
|
-
}
|
|
7
|
+
import { escapeTomlBasicString, escapeTomlMultilineBasicString } from '../toml.js';
|
|
42
8
|
/**
|
|
43
9
|
* Gemini adapter for command generation.
|
|
44
10
|
* File path: .gemini/commands/opsx/<id>.toml
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GigaCode Command Adapter
|
|
3
|
+
*
|
|
4
|
+
* Formats commands for GigaCode using its Markdown custom command format.
|
|
5
|
+
* Project commands live in `.gigacode/commands/` and accept an optional
|
|
6
|
+
* `description` field in YAML frontmatter.
|
|
7
|
+
*
|
|
8
|
+
* @see https://gitverse.ru/docs/ai/ai-assistant-gigacode/gigacode-cli/commands
|
|
9
|
+
*/
|
|
10
|
+
import type { ToolCommandAdapter } from '../types.js';
|
|
11
|
+
/**
|
|
12
|
+
* GigaCode adapter for command generation.
|
|
13
|
+
* File path: .gigacode/commands/opsx-<id>.md
|
|
14
|
+
* Format: Markdown with description frontmatter
|
|
15
|
+
*/
|
|
16
|
+
export declare const gigacodeAdapter: ToolCommandAdapter;
|
|
17
|
+
//# sourceMappingURL=gigacode.d.ts.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GigaCode Command Adapter
|
|
3
|
+
*
|
|
4
|
+
* Formats commands for GigaCode using its Markdown custom command format.
|
|
5
|
+
* Project commands live in `.gigacode/commands/` and accept an optional
|
|
6
|
+
* `description` field in YAML frontmatter.
|
|
7
|
+
*
|
|
8
|
+
* @see https://gitverse.ru/docs/ai/ai-assistant-gigacode/gigacode-cli/commands
|
|
9
|
+
*/
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import { escapeYamlValue } from '../yaml.js';
|
|
12
|
+
/**
|
|
13
|
+
* GigaCode adapter for command generation.
|
|
14
|
+
* File path: .gigacode/commands/opsx-<id>.md
|
|
15
|
+
* Format: Markdown with description frontmatter
|
|
16
|
+
*/
|
|
17
|
+
export const gigacodeAdapter = {
|
|
18
|
+
toolId: 'gigacode',
|
|
19
|
+
getFilePath(commandId) {
|
|
20
|
+
return path.join('.gigacode', 'commands', `opsx-${commandId}.md`);
|
|
21
|
+
},
|
|
22
|
+
formatFile(content) {
|
|
23
|
+
return `---
|
|
24
|
+
description: ${escapeYamlValue(content.description)}
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
${content.body}
|
|
28
|
+
`;
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=gigacode.js.map
|
|
@@ -5,20 +5,24 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export { amazonQAdapter } from './amazon-q.js';
|
|
7
7
|
export { antigravityAdapter } from './antigravity.js';
|
|
8
|
+
export { atomcodeAdapter } from './atomcode.js';
|
|
8
9
|
export { auggieAdapter } from './auggie.js';
|
|
9
10
|
export { bobAdapter } from './bob.js';
|
|
10
11
|
export { claudeAdapter } from './claude.js';
|
|
11
12
|
export { clineAdapter } from './cline.js';
|
|
12
13
|
export { commandCodeAdapter } from './command-code.js';
|
|
13
14
|
export { codebuddyAdapter } from './codebuddy.js';
|
|
15
|
+
export { codeStudioAdapter } from './codestudio.js';
|
|
14
16
|
export { continueAdapter } from './continue.js';
|
|
15
17
|
export { costrictAdapter } from './costrict.js';
|
|
16
18
|
export { crushAdapter } from './crush.js';
|
|
17
19
|
export { cursorAdapter } from './cursor.js';
|
|
18
20
|
export { devinAdapter } from './devin.js';
|
|
21
|
+
export { easycodeAdapter } from './easycode.js';
|
|
19
22
|
export { factoryAdapter } from './factory.js';
|
|
20
23
|
export { geminiAdapter } from './gemini.js';
|
|
21
24
|
export { githubCopilotAdapter } from './github-copilot.js';
|
|
25
|
+
export { gigacodeAdapter } from './gigacode.js';
|
|
22
26
|
export { iflowAdapter } from './iflow.js';
|
|
23
27
|
export { junieAdapter } from './junie.js';
|
|
24
28
|
export { kilocodeAdapter } from './kilocode.js';
|
|
@@ -5,20 +5,24 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export { amazonQAdapter } from './amazon-q.js';
|
|
7
7
|
export { antigravityAdapter } from './antigravity.js';
|
|
8
|
+
export { atomcodeAdapter } from './atomcode.js';
|
|
8
9
|
export { auggieAdapter } from './auggie.js';
|
|
9
10
|
export { bobAdapter } from './bob.js';
|
|
10
11
|
export { claudeAdapter } from './claude.js';
|
|
11
12
|
export { clineAdapter } from './cline.js';
|
|
12
13
|
export { commandCodeAdapter } from './command-code.js';
|
|
13
14
|
export { codebuddyAdapter } from './codebuddy.js';
|
|
15
|
+
export { codeStudioAdapter } from './codestudio.js';
|
|
14
16
|
export { continueAdapter } from './continue.js';
|
|
15
17
|
export { costrictAdapter } from './costrict.js';
|
|
16
18
|
export { crushAdapter } from './crush.js';
|
|
17
19
|
export { cursorAdapter } from './cursor.js';
|
|
18
20
|
export { devinAdapter } from './devin.js';
|
|
21
|
+
export { easycodeAdapter } from './easycode.js';
|
|
19
22
|
export { factoryAdapter } from './factory.js';
|
|
20
23
|
export { geminiAdapter } from './gemini.js';
|
|
21
24
|
export { githubCopilotAdapter } from './github-copilot.js';
|
|
25
|
+
export { gigacodeAdapter } from './gigacode.js';
|
|
22
26
|
export { iflowAdapter } from './iflow.js';
|
|
23
27
|
export { junieAdapter } from './junie.js';
|
|
24
28
|
export { kilocodeAdapter } from './kilocode.js';
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import type { ToolCommandAdapter } from '../types.js';
|
|
8
8
|
/**
|
|
9
9
|
* Kilo Code adapter for command generation.
|
|
10
|
-
* File path: .
|
|
10
|
+
* File path: .kilo/command/opsx-<id>.md
|
|
11
11
|
* Format: Plain markdown without frontmatter
|
|
12
12
|
*/
|
|
13
13
|
export declare const kilocodeAdapter: ToolCommandAdapter;
|
|
@@ -7,13 +7,13 @@
|
|
|
7
7
|
import path from 'path';
|
|
8
8
|
/**
|
|
9
9
|
* Kilo Code adapter for command generation.
|
|
10
|
-
* File path: .
|
|
10
|
+
* File path: .kilo/command/opsx-<id>.md
|
|
11
11
|
* Format: Plain markdown without frontmatter
|
|
12
12
|
*/
|
|
13
13
|
export const kilocodeAdapter = {
|
|
14
14
|
toolId: 'kilocode',
|
|
15
15
|
getFilePath(commandId) {
|
|
16
|
-
return path.join('.
|
|
16
|
+
return path.join('.kilo', 'command', `opsx-${commandId}.md`);
|
|
17
17
|
},
|
|
18
18
|
formatFile(content) {
|
|
19
19
|
return `${content.body}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { amazonQAdapter } from './adapters/amazon-q.js';
|
|
8
8
|
import { antigravityAdapter } from './adapters/antigravity.js';
|
|
9
|
+
import { atomcodeAdapter } from './adapters/atomcode.js';
|
|
9
10
|
import { auggieAdapter } from './adapters/auggie.js';
|
|
10
11
|
import { bobAdapter } from './adapters/bob.js';
|
|
11
12
|
import { claudeAdapter } from './adapters/claude.js';
|
|
@@ -13,13 +14,16 @@ import { clineAdapter } from './adapters/cline.js';
|
|
|
13
14
|
import { commandCodeAdapter } from './adapters/command-code.js';
|
|
14
15
|
import { devinAdapter } from './adapters/devin.js';
|
|
15
16
|
import { codebuddyAdapter } from './adapters/codebuddy.js';
|
|
17
|
+
import { codeStudioAdapter } from './adapters/codestudio.js';
|
|
16
18
|
import { continueAdapter } from './adapters/continue.js';
|
|
17
19
|
import { costrictAdapter } from './adapters/costrict.js';
|
|
18
20
|
import { crushAdapter } from './adapters/crush.js';
|
|
19
21
|
import { cursorAdapter } from './adapters/cursor.js';
|
|
22
|
+
import { easycodeAdapter } from './adapters/easycode.js';
|
|
20
23
|
import { factoryAdapter } from './adapters/factory.js';
|
|
21
24
|
import { geminiAdapter } from './adapters/gemini.js';
|
|
22
25
|
import { githubCopilotAdapter } from './adapters/github-copilot.js';
|
|
26
|
+
import { gigacodeAdapter } from './adapters/gigacode.js';
|
|
23
27
|
import { iflowAdapter } from './adapters/iflow.js';
|
|
24
28
|
import { junieAdapter } from './adapters/junie.js';
|
|
25
29
|
import { kilocodeAdapter } from './adapters/kilocode.js';
|
|
@@ -43,6 +47,7 @@ export class CommandAdapterRegistry {
|
|
|
43
47
|
static {
|
|
44
48
|
CommandAdapterRegistry.register(amazonQAdapter);
|
|
45
49
|
CommandAdapterRegistry.register(antigravityAdapter);
|
|
50
|
+
CommandAdapterRegistry.register(atomcodeAdapter);
|
|
46
51
|
CommandAdapterRegistry.register(auggieAdapter);
|
|
47
52
|
CommandAdapterRegistry.register(bobAdapter);
|
|
48
53
|
CommandAdapterRegistry.register(claudeAdapter);
|
|
@@ -50,13 +55,16 @@ export class CommandAdapterRegistry {
|
|
|
50
55
|
CommandAdapterRegistry.register(commandCodeAdapter);
|
|
51
56
|
CommandAdapterRegistry.register(devinAdapter);
|
|
52
57
|
CommandAdapterRegistry.register(codebuddyAdapter);
|
|
58
|
+
CommandAdapterRegistry.register(codeStudioAdapter);
|
|
53
59
|
CommandAdapterRegistry.register(continueAdapter);
|
|
54
60
|
CommandAdapterRegistry.register(costrictAdapter);
|
|
55
61
|
CommandAdapterRegistry.register(crushAdapter);
|
|
56
62
|
CommandAdapterRegistry.register(cursorAdapter);
|
|
63
|
+
CommandAdapterRegistry.register(easycodeAdapter);
|
|
57
64
|
CommandAdapterRegistry.register(factoryAdapter);
|
|
58
65
|
CommandAdapterRegistry.register(geminiAdapter);
|
|
59
66
|
CommandAdapterRegistry.register(githubCopilotAdapter);
|
|
67
|
+
CommandAdapterRegistry.register(gigacodeAdapter);
|
|
60
68
|
CommandAdapterRegistry.register(iflowAdapter);
|
|
61
69
|
CommandAdapterRegistry.register(junieAdapter);
|
|
62
70
|
CommandAdapterRegistry.register(kilocodeAdapter);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared TOML string escaping for command adapters.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* TOML basic strings are escape-active: a backslash or double quote in the
|
|
6
|
+
* value breaks the file if written raw. Newlines cannot appear in a
|
|
7
|
+
* single-line basic string at all, so they are escaped too.
|
|
8
|
+
*/
|
|
9
|
+
export declare function escapeTomlBasicString(value: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Multiline basic strings keep raw newlines and tabs, but backslashes are
|
|
12
|
+
* still escape-active, any run of three quotes would end the string, and the
|
|
13
|
+
* same control characters are invalid as in single-line basic strings — a
|
|
14
|
+
* lone carriage return included (only LF and CRLF may appear raw; CRLF is
|
|
15
|
+
* normalized away so the emitted file is single-convention). Escapes are
|
|
16
|
+
* introduced after backslash-doubling so they are not re-doubled.
|
|
17
|
+
*/
|
|
18
|
+
export declare function escapeTomlMultilineBasicString(value: string): string;
|
|
19
|
+
//# sourceMappingURL=toml.d.ts.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared TOML string escaping for command adapters.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Control characters (C0 except tab/newline/carriage return, plus DEL) are
|
|
6
|
+
* invalid inside TOML strings and must be written as escapes.
|
|
7
|
+
*/
|
|
8
|
+
const TOML_CONTROL_CHARS = new RegExp('[\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f\\u007f]', 'g');
|
|
9
|
+
/**
|
|
10
|
+
* TOML basic strings are escape-active: a backslash or double quote in the
|
|
11
|
+
* value breaks the file if written raw. Newlines cannot appear in a
|
|
12
|
+
* single-line basic string at all, so they are escaped too.
|
|
13
|
+
*/
|
|
14
|
+
export function escapeTomlBasicString(value) {
|
|
15
|
+
return value
|
|
16
|
+
.replace(/\\/g, '\\\\')
|
|
17
|
+
.replace(/"/g, '\\"')
|
|
18
|
+
.replace(/\n/g, '\\n')
|
|
19
|
+
.replace(/\r/g, '\\r')
|
|
20
|
+
.replace(/\t/g, '\\t')
|
|
21
|
+
.replace(TOML_CONTROL_CHARS, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, '0')}`);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Multiline basic strings keep raw newlines and tabs, but backslashes are
|
|
25
|
+
* still escape-active, any run of three quotes would end the string, and the
|
|
26
|
+
* same control characters are invalid as in single-line basic strings — a
|
|
27
|
+
* lone carriage return included (only LF and CRLF may appear raw; CRLF is
|
|
28
|
+
* normalized away so the emitted file is single-convention). Escapes are
|
|
29
|
+
* introduced after backslash-doubling so they are not re-doubled.
|
|
30
|
+
*/
|
|
31
|
+
export function escapeTomlMultilineBasicString(value) {
|
|
32
|
+
return value
|
|
33
|
+
.replace(/\r\n/g, '\n')
|
|
34
|
+
.replace(/\\/g, '\\\\')
|
|
35
|
+
.replace(/"""/g, '""\\"')
|
|
36
|
+
.replace(/\r/g, '\\r')
|
|
37
|
+
.replace(TOML_CONTROL_CHARS, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, '0')}`);
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=toml.js.map
|
|
@@ -13,7 +13,7 @@ export function resolveCommandSurfaceCapability(toolId) {
|
|
|
13
13
|
if (CommandAdapterRegistry.has(toolId)) {
|
|
14
14
|
return 'adapter-backed';
|
|
15
15
|
}
|
|
16
|
-
if (toolId === 'codex') {
|
|
16
|
+
if (toolId === 'codex' || toolId === 'warp') {
|
|
17
17
|
return 'skills-invocable';
|
|
18
18
|
}
|
|
19
19
|
return 'none';
|
|
@@ -54,6 +54,17 @@ export const COMMAND_REGISTRY = [
|
|
|
54
54
|
},
|
|
55
55
|
],
|
|
56
56
|
},
|
|
57
|
+
{
|
|
58
|
+
name: 'version',
|
|
59
|
+
description: 'Report the installed OpenSpec version and update availability',
|
|
60
|
+
flags: [
|
|
61
|
+
COMMON_FLAGS.json,
|
|
62
|
+
{
|
|
63
|
+
name: 'check',
|
|
64
|
+
description: 'Check the registry for a newer version',
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
},
|
|
57
68
|
{
|
|
58
69
|
name: 'list',
|
|
59
70
|
description: 'List items (changes by default, or specs with --specs)',
|
|
@@ -66,6 +77,14 @@ export const COMMAND_REGISTRY = [
|
|
|
66
77
|
name: 'changes',
|
|
67
78
|
description: 'List changes explicitly (default)',
|
|
68
79
|
},
|
|
80
|
+
{
|
|
81
|
+
name: 'archived',
|
|
82
|
+
description: 'Show only archived changes',
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: 'all',
|
|
86
|
+
description: 'Show both active and archived changes',
|
|
87
|
+
},
|
|
69
88
|
{
|
|
70
89
|
name: 'sort',
|
|
71
90
|
description: 'Sort order: "recent" (default) or "name"',
|
|
@@ -194,8 +194,10 @@ export class ZshInstaller {
|
|
|
194
194
|
}
|
|
195
195
|
// Remove lines between markers (inclusive)
|
|
196
196
|
lines.splice(startIndex, endIndex - startIndex + 1);
|
|
197
|
-
//
|
|
198
|
-
|
|
197
|
+
// Install puts the block at the top of the file followed by one blank
|
|
198
|
+
// separator line; drop that line too so the file reads as it did before.
|
|
199
|
+
// Everything else, including blank lines the user had at the top, is left as is.
|
|
200
|
+
if (startIndex === 0 && lines.length > 0 && lines[0].trim() === '') {
|
|
199
201
|
lines.shift();
|
|
200
202
|
}
|
|
201
203
|
// Write back
|
|
@@ -19,13 +19,13 @@ export function serializeConfig(config) {
|
|
|
19
19
|
else {
|
|
20
20
|
// Context section with comments
|
|
21
21
|
lines.push('# Project context (optional)');
|
|
22
|
-
lines.push('#
|
|
23
|
-
lines.push('#
|
|
22
|
+
lines.push('# Add only constraints that should guide OpenSpec artifacts and workflows.');
|
|
23
|
+
lines.push('# Include constraints an agent cannot infer by reading the code.');
|
|
24
|
+
lines.push('# Keep general project documentation and discoverable codebase facts out.');
|
|
24
25
|
lines.push('# Example:');
|
|
25
26
|
lines.push('# context: |');
|
|
26
|
-
lines.push('#
|
|
27
|
-
lines.push('#
|
|
28
|
-
lines.push('# Domain: e-commerce platform');
|
|
27
|
+
lines.push('# Designs and tasks must cover Windows, macOS, and Linux');
|
|
28
|
+
lines.push('# Write all artifacts in Spanish');
|
|
29
29
|
lines.push('');
|
|
30
30
|
}
|
|
31
31
|
// Rules section with comments
|
|
@@ -35,7 +35,7 @@ export function serializeConfig(config) {
|
|
|
35
35
|
lines.push('# rules:');
|
|
36
36
|
lines.push('# proposal:');
|
|
37
37
|
lines.push('# - Keep proposals under 500 words');
|
|
38
|
-
lines.push('# - Always
|
|
38
|
+
lines.push('# - Always state what is out of scope');
|
|
39
39
|
lines.push('# tasks:');
|
|
40
40
|
lines.push('# - Break tasks into chunks of max 2 hours');
|
|
41
41
|
lines.push('');
|