@superkou/openspec 1.4.1 → 1.4.3

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.
@@ -28,5 +28,7 @@ export { qoderAdapter } from './qoder.js';
28
28
  export { lingmaAdapter } from './lingma.js';
29
29
  export { qwenAdapter } from './qwen.js';
30
30
  export { roocodeAdapter } from './roocode.js';
31
+ export { traeAdapter } from './trae.js';
31
32
  export { windsurfAdapter } from './windsurf.js';
33
+ export { zcodeAdapter } from './zcode.js';
32
34
  //# sourceMappingURL=index.d.ts.map
@@ -28,5 +28,7 @@ export { qoderAdapter } from './qoder.js';
28
28
  export { lingmaAdapter } from './lingma.js';
29
29
  export { qwenAdapter } from './qwen.js';
30
30
  export { roocodeAdapter } from './roocode.js';
31
+ export { traeAdapter } from './trae.js';
31
32
  export { windsurfAdapter } from './windsurf.js';
33
+ export { zcodeAdapter } from './zcode.js';
32
34
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Trae Command Adapter
3
+ *
4
+ * Formats commands for Trae following its command specification.
5
+ * Docs: Trae IDE 官方文档 - 命令功能
6
+ *
7
+ * Trae 支持项目级命令(.trae/commands/)和全局命令(~/.trae/commands/),
8
+ * 支持最多 3 层目录嵌套。本 adapter 生成项目级命令,路径为
9
+ * .trae/commands/opsx/<id>.md(2 层嵌套,在 3 层限制内)。
10
+ */
11
+ import type { ToolCommandAdapter } from '../types.js';
12
+ /**
13
+ * Trae adapter for command generation.
14
+ * File path: .trae/commands/opsx/<id>.md
15
+ * Frontmatter: name, description
16
+ */
17
+ export declare const traeAdapter: ToolCommandAdapter;
18
+ //# sourceMappingURL=trae.d.ts.map
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Trae Command Adapter
3
+ *
4
+ * Formats commands for Trae following its command specification.
5
+ * Docs: Trae IDE 官方文档 - 命令功能
6
+ *
7
+ * Trae 支持项目级命令(.trae/commands/)和全局命令(~/.trae/commands/),
8
+ * 支持最多 3 层目录嵌套。本 adapter 生成项目级命令,路径为
9
+ * .trae/commands/opsx/<id>.md(2 层嵌套,在 3 层限制内)。
10
+ */
11
+ import path from 'path';
12
+ /**
13
+ * Trae adapter for command generation.
14
+ * File path: .trae/commands/opsx/<id>.md
15
+ * Frontmatter: name, description
16
+ */
17
+ export const traeAdapter = {
18
+ toolId: 'trae',
19
+ getFilePath(commandId) {
20
+ return path.join('.trae', 'commands', 'opsx', `${commandId}.md`);
21
+ },
22
+ formatFile(content) {
23
+ return `---
24
+ name: ${content.name}
25
+ description: "${content.description}"
26
+ ---
27
+
28
+ ${content.body}
29
+ `;
30
+ },
31
+ };
32
+ //# sourceMappingURL=trae.js.map
@@ -0,0 +1,15 @@
1
+ /**
2
+ * ZCode Command Adapter
3
+ *
4
+ * Formats commands for ZCode CLI following its command specification.
5
+ * ZCode 在 .zcode/commands/ 下使用扁平的 opsx-<id>.md 命令文件,
6
+ * frontmatter 含 description 与可选的 argument-hint。
7
+ */
8
+ import type { ToolCommandAdapter } from '../types.js';
9
+ /**
10
+ * ZCode adapter for command generation.
11
+ * File path: .zcode/commands/opsx-<id>.md
12
+ * Frontmatter: description, argument-hint
13
+ */
14
+ export declare const zcodeAdapter: ToolCommandAdapter;
15
+ //# sourceMappingURL=zcode.d.ts.map
@@ -0,0 +1,29 @@
1
+ /**
2
+ * ZCode Command Adapter
3
+ *
4
+ * Formats commands for ZCode CLI following its command specification.
5
+ * ZCode 在 .zcode/commands/ 下使用扁平的 opsx-<id>.md 命令文件,
6
+ * frontmatter 含 description 与可选的 argument-hint。
7
+ */
8
+ import path from 'path';
9
+ /**
10
+ * ZCode adapter for command generation.
11
+ * File path: .zcode/commands/opsx-<id>.md
12
+ * Frontmatter: description, argument-hint
13
+ */
14
+ export const zcodeAdapter = {
15
+ toolId: 'zcode',
16
+ getFilePath(commandId) {
17
+ return path.join('.zcode', 'commands', `opsx-${commandId}.md`);
18
+ },
19
+ formatFile(content) {
20
+ return `---
21
+ description: ${content.description}
22
+ argument-hint: command arguments
23
+ ---
24
+
25
+ ${content.body}
26
+ `;
27
+ },
28
+ };
29
+ //# sourceMappingURL=zcode.js.map
@@ -29,7 +29,9 @@ import { qoderAdapter } from './adapters/qoder.js';
29
29
  import { lingmaAdapter } from './adapters/lingma.js';
30
30
  import { qwenAdapter } from './adapters/qwen.js';
31
31
  import { roocodeAdapter } from './adapters/roocode.js';
32
+ import { traeAdapter } from './adapters/trae.js';
32
33
  import { windsurfAdapter } from './adapters/windsurf.js';
34
+ import { zcodeAdapter } from './adapters/zcode.js';
33
35
  /**
34
36
  * Registry for looking up tool command adapters.
35
37
  */
@@ -62,7 +64,9 @@ export class CommandAdapterRegistry {
62
64
  CommandAdapterRegistry.register(lingmaAdapter);
63
65
  CommandAdapterRegistry.register(qwenAdapter);
64
66
  CommandAdapterRegistry.register(roocodeAdapter);
67
+ CommandAdapterRegistry.register(traeAdapter);
65
68
  CommandAdapterRegistry.register(windsurfAdapter);
69
+ CommandAdapterRegistry.register(zcodeAdapter);
66
70
  }
67
71
  /**
68
72
  * Register a tool command adapter.
@@ -32,8 +32,9 @@ export const AI_TOOLS = [
32
32
  { name: 'Qoder', value: 'qoder', available: true, successLabel: 'Qoder', skillsDir: '.qoder' },
33
33
  { name: 'Qwen Code', value: 'qwen', available: true, successLabel: 'Qwen Code', skillsDir: '.qwen' },
34
34
  { name: 'RooCode', value: 'roocode', available: true, successLabel: 'RooCode', skillsDir: '.roo' },
35
- { name: 'Trae', value: 'trae', available: true, successLabel: 'Trae', skillsDir: '.trae' },
35
+ { name: 'Trae', value: 'trae', available: true, successLabel: 'Trae', skillsDir: '.trae', detectionPaths: ['.trae/commands', '.trae/skills'] },
36
36
  { name: 'Windsurf', value: 'windsurf', available: true, successLabel: 'Windsurf', skillsDir: '.windsurf' },
37
+ { name: 'ZCode', value: 'zcode', available: true, successLabel: 'ZCode', skillsDir: '.zcode', detectionPaths: ['.zcode/commands', '.zcode/skills'] },
37
38
  { name: 'AGENTS.md (works with Amp, VS Code, …)', value: 'agents', available: false, successLabel: 'your AGENTS.md-compatible assistant' }
38
39
  ];
39
40
  //# sourceMappingURL=config.js.map
@@ -31,18 +31,24 @@ export interface ValidationResult {
31
31
  /**
32
32
  * Validates that a change name follows kebab-case conventions.
33
33
  *
34
- * Valid names:
35
- * - Start with a lowercase letter
34
+ * Valid names (two accepted forms):
35
+ * - Classic kebab-case: starts with a lowercase letter
36
+ * (e.g., `add-auth`, `refactor-db`)
37
+ * - MMDD-prefixed kebab-case: starts with a 4-digit date (MMDD) followed by `-`
38
+ * and a kebab-case suffix (e.g., `0628-add-auth`)
39
+ *
40
+ * Both forms:
36
41
  * - Contain only lowercase letters, numbers, and hyphens
37
- * - Do not start or end with a hyphen
42
+ * - Do not start or end with a hyphen (the MMDD prefix's hyphen is part of the prefix)
38
43
  * - Do not contain consecutive hyphens
39
44
  *
40
45
  * @param name - The change name to validate
41
46
  * @returns Validation result with `valid: true` or `valid: false` with an error message
42
47
  *
43
48
  * @example
44
- * validateChangeName('add-auth') // { valid: true }
45
- * validateChangeName('Add-Auth') // { valid: false, error: '...' }
49
+ * validateChangeName('add-auth') // { valid: true }
50
+ * validateChangeName('0628-add-auth') // { valid: true }
51
+ * validateChangeName('Add-Auth') // { valid: false, error: '...' }
46
52
  */
47
53
  export declare function validateChangeName(name: string): ValidationResult;
48
54
  /**
@@ -6,23 +6,30 @@ const DEFAULT_SCHEMA = 'spec-driven';
6
6
  /**
7
7
  * Validates that a change name follows kebab-case conventions.
8
8
  *
9
- * Valid names:
10
- * - Start with a lowercase letter
9
+ * Valid names (two accepted forms):
10
+ * - Classic kebab-case: starts with a lowercase letter
11
+ * (e.g., `add-auth`, `refactor-db`)
12
+ * - MMDD-prefixed kebab-case: starts with a 4-digit date (MMDD) followed by `-`
13
+ * and a kebab-case suffix (e.g., `0628-add-auth`)
14
+ *
15
+ * Both forms:
11
16
  * - Contain only lowercase letters, numbers, and hyphens
12
- * - Do not start or end with a hyphen
17
+ * - Do not start or end with a hyphen (the MMDD prefix's hyphen is part of the prefix)
13
18
  * - Do not contain consecutive hyphens
14
19
  *
15
20
  * @param name - The change name to validate
16
21
  * @returns Validation result with `valid: true` or `valid: false` with an error message
17
22
  *
18
23
  * @example
19
- * validateChangeName('add-auth') // { valid: true }
20
- * validateChangeName('Add-Auth') // { valid: false, error: '...' }
24
+ * validateChangeName('add-auth') // { valid: true }
25
+ * validateChangeName('0628-add-auth') // { valid: true }
26
+ * validateChangeName('Add-Auth') // { valid: false, error: '...' }
21
27
  */
22
28
  export function validateChangeName(name) {
23
- // Pattern: starts with lowercase letter, followed by lowercase letters/numbers,
24
- // optionally followed by hyphen + lowercase letters/numbers (repeatable)
25
- const kebabCasePattern = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
29
+ // Pattern: two accepted forms.
30
+ // Form 1 (classic): ^[a-z][a-z0-9]*(-[a-z0-9]+)*$
31
+ // Form 2 (MMDD-prefixed): ^\d{4}-[a-z][a-z0-9]*(-[a-z0-9]+)*$
32
+ const kebabCasePattern = /^(?:[a-z][a-z0-9]*(?:-[a-z0-9]+)*|\d{4}-[a-z][a-z0-9]*(?:-[a-z0-9]+)*)$/;
26
33
  if (!name) {
27
34
  return { valid: false, error: 'Change name cannot be empty' };
28
35
  }
@@ -49,10 +56,14 @@ export function validateChangeName(name) {
49
56
  if (/[^a-z0-9-]/.test(name)) {
50
57
  return { valid: false, error: 'Change name can only contain lowercase letters, numbers, and hyphens' };
51
58
  }
52
- if (/^[0-9]/.test(name)) {
53
- return { valid: false, error: 'Change name must start with a letter' };
59
+ // Numeric-prefixed name that didn't match Form 2: diagnose the date prefix shape
60
+ if (/^\d/.test(name)) {
61
+ if (!/^\d{4}-[a-z]/.test(name)) {
62
+ return { valid: false, error: 'Numeric-prefixed change name must use MMDD-<kebab> form (e.g., 0628-add-auth)' };
63
+ }
64
+ return { valid: false, error: 'Change name with MMDD prefix must be followed by kebab-case (e.g., 0628-add-auth)' };
54
65
  }
55
- return { valid: false, error: 'Change name must follow kebab-case convention (e.g., add-auth, refactor-db)' };
66
+ return { valid: false, error: 'Change name must follow kebab-case convention (e.g., add-auth, 0628-add-auth)' };
56
67
  }
57
68
  return { valid: true };
58
69
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@superkou/openspec",
3
- "version": "1.4.1",
3
+ "version": "1.4.3",
4
4
  "description": "AI-native system for spec-driven development",
5
5
  "keywords": [
6
6
  "openspec",
@@ -9,10 +9,10 @@
9
9
  "ai",
10
10
  "development"
11
11
  ],
12
- "homepage": "https://github.com/Fission-AI/OpenSpec",
12
+ "homepage": "https://github.com/sevensky/OpenSpec",
13
13
  "repository": {
14
14
  "type": "git",
15
- "url": "https://github.com/Fission-AI/OpenSpec"
15
+ "url": "git+https://github.com/sevensky/OpenSpec.git"
16
16
  },
17
17
  "license": "MIT",
18
18
  "author": "OpenSpec Contributors",
@@ -28,7 +28,7 @@
28
28
  }
29
29
  },
30
30
  "bin": {
31
- "openspec": "./bin/openspec.js"
31
+ "openspec": "bin/openspec.js"
32
32
  },
33
33
  "files": [
34
34
  "dist",
@@ -1,3 +1,8 @@
1
+ <!--
2
+ 命名约定:change 目录名用 MMDD-<kebab> 前缀(如 0628-add-auth),便于按日期排序与追溯。
3
+ 校验已支持两种形式:经典 kebab(add-auth)与 MMDD- 前缀(0628-add-auth),优先用后者。
4
+ -->
5
+
1
6
  ## Why
2
7
 
3
8
  <!-- 说明此变更的动机。解决什么问题?为什么现在做? -->
@@ -9,13 +14,17 @@
9
14
  ## Capabilities
10
15
 
11
16
  ### New Capabilities
12
- <!-- 引入的新能力。将 <name> 替换为 kebab-case 标识符(例如 user-auth、data-export、api-rate-limiting)。每个将创建 specs/<name>/spec.md -->
17
+ <!--
18
+ 引入的新能力。将 <name> 替换为 kebab-case 标识符(例如 user-auth、data-export、api-rate-limiting)。每个将创建 specs/<name>/spec.md
19
+ -->
13
20
  - `<name>`: <此能力覆盖范围的简要描述>
14
21
 
15
22
  ### Modified Capabilities
16
- <!-- 需求发生变化的既有能力(不涉及实现细节)。
17
- 仅当 spec 级别行为变化时列出。每个需要 delta spec 文件。
18
- 使用 openspec/specs/ 中的既有 spec 名称。如无需求变更则留空。 -->
23
+ <!--
24
+ 需求发生变化的既有能力(不涉及实现细节)。
25
+ 仅当 spec 级别行为变化时列出。每个需要 delta spec 文件。
26
+ 使用 openspec/specs/ 中的既有 spec 名称。如无需求变更则留空。
27
+ -->
19
28
  - `<existing-name>`: <哪些需求正在变化>
20
29
 
21
30
  ## Impact