dijk-skills 1.0.4 → 1.0.8

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 CHANGED
@@ -15,27 +15,41 @@ npm install -g dijk-skills
15
15
  npx dijk-skills install [options]
16
16
  ```
17
17
 
18
+ ### CLI Alias
19
+
20
+ After `npm i -g dijk-skills`, both `dijk-skills` and the short alias `dijk` work: `dijk install`, `dijk -- openspec init`. Without a global install, use `npx -p dijk-skills dijk -- openspec init`, or plain `npx dijk-skills ...`.
21
+
22
+ > Caveat: bare `npx dijk` does NOT resolve to this package — npx would look for an unrelated npm package named `dijk`. Always use `-p dijk-skills` or a global/local install.
23
+
18
24
  ### Options
19
25
 
20
26
  | Option | Description | Default |
21
27
  |--------|-------------|---------|
22
- | `--modules <list>` | Comma-separated module names | `common` |
28
+ | `--modules <list>` | Comma-separated module names | `all` |
23
29
  | `--dir <path>` | Target installation directory | `~/.agents` |
24
30
 
25
31
  ### Modules
26
32
 
27
- | Module | Skills |
28
- |--------|--------|
29
- | `common` | caveman, grilling, handoff, humanizer-zh, i-have-adhd |
30
- | `writing` | grill-my-proposal, last30days, vibe-code-insight, vibe-opinion-insight |
31
- | `tools` | mcp-builder, skill-creator |
32
- | `coding` | *(empty, reserved for future skills)* |
33
+ | Module | Skill | Description |
34
+ |--------|-------|-------------|
35
+ | `common` | caveman | 超压缩交流模式,在保持技术准确性的同时大幅节省输出 token(分 lite/full/ultra 档) |
36
+ | `common` | grilling | 对计划、决策或想法进行不留情面的连环追问,压力测试你的思路 |
37
+ | `common` | humanizer-zh | 去除文本中的 AI 生成痕迹,使其更自然、更像人类书写 |
38
+ | `common` | i-have-adhd | 面向 ADHD 读者塑造输出:下一步行动置顶、多步任务编号、复述状态、抑制离题、给出时间预估 |
39
+ | `writing` | grill-my-proposal | 把方案往死里问——三阶段递进追问(宏观结构→逐章深挖→交叉验证),动手前压力测试方案 |
40
+ | `writing` | last30days | 研究任意话题近 30 天的真实讨论,覆盖 Reddit、X、YouTube、TikTok、Hacker News、Polymarket、GitHub 与全网 |
41
+ | `writing` | vibe-code-insight | 对软件项目做深度系统分析,产出 `design.md`(系统设计)与 `trend.md`(生态与趋势洞察) |
42
+ | `writing` | vibe-opinion-insight | Human 驱动的 AI Agent 技术洞察框架——Agent 是启发工具,Human 赋予意义并承担责任 |
43
+ | `tools` | handoff | 将当前会话压缩为交接文档,供另一个 agent 接续工作 |
44
+ | `tools` | mcp-builder | 构建高质量 MCP 服务器的指南,支持 Python(FastMCP)与 Node/TypeScript(MCP SDK) |
45
+ | `tools` | skill-creator | 创建、编辑、评测与优化 skill,含触发准确率的基准测试 |
46
+ | `coding` | *(reserved)* | 空——保留给未来的 skill |
33
47
 
34
48
  > Installing any module automatically includes `common`.
35
49
 
36
50
  ### Examples
37
51
 
38
- Install common skills to default location:
52
+ Install all skills to default location:
39
53
  ```bash
40
54
  npx dijk-skills install
41
55
  ```
@@ -50,6 +64,26 @@ Custom target directory:
50
64
  npx dijk-skills install --modules coding --dir ~/my-agents
51
65
  ```
52
66
 
67
+ ## OpenSpec Bootstrap
68
+
69
+ Bootstrap OpenSpec (`@fission-ai/openspec`) into a project for spec-driven development. Run it inside your project directory.
70
+
71
+ ```bash
72
+ npx dijk-skills -- openspec init # bootstrap the current project
73
+ npx dijk-skills -- openspec <args...> # any other openspec command (pure passthrough)
74
+ dijk -- openspec init # same, via the short alias
75
+ ```
76
+
77
+ - Passthrough — forwards to `@fission-ai/openspec@latest` via npx, exit codes propagated
78
+ - On `init` only: drops the customizable config template (`coding/openspec/config.yaml`) into `./openspec/` first (never overwrites an existing config) and defaults `--tools opencode --no-animation` unless you pass your own
79
+ - Idempotent — re-run anytime to refresh CLI-owned files
80
+
81
+ Default target is `opencode` (`.opencode/skills/openspec-*/` + `/opsx-*` commands). For the vendor-neutral shared target, pass `--tools agents` explicitly: writes `.agents/skills/openspec-*/` only (no `/opsx-*` command files; in opencode the skills are then invoked by name, e.g. `/openspec-propose`).
82
+
83
+ **Prerequisites:** Node >= 20.19, network access for npx.
84
+
85
+ **Customization:** edit the project's `openspec/config.yaml` (keys: `schema`, `context`, `rules`, `operations`), or edit the repo template (`coding/openspec/config.yaml`) to change defaults for future bootstraps.
86
+
53
87
  ## Installed Structure
54
88
 
55
89
  Skills are installed to `{dir}/skills/{skill-name}/`:
@@ -2,42 +2,59 @@
2
2
 
3
3
  import { parseArgs } from 'node:util';
4
4
  import { install } from '../lib/installer.js';
5
+ import { runOpenspec } from '../lib/openspec.js';
5
6
  import { dirname, resolve } from 'node:path';
6
7
  import { fileURLToPath } from 'node:url';
7
8
 
8
9
  const __dirname = dirname(fileURLToPath(import.meta.url));
9
10
  const packageRoot = resolve(__dirname, '..');
10
11
 
11
- const { values, positionals } = parseArgs({
12
- allowPositionals: true,
13
- options: {
14
- modules: {
15
- type: 'string',
16
- default: 'common'
17
- },
18
- dir: {
19
- type: 'string',
20
- default: '~/.agents'
21
- },
22
- help: {
23
- type: 'boolean',
24
- short: 'h'
12
+ // Everything after the first `--` (npx may consume it), or all of argv
13
+ const argv = process.argv.slice(2);
14
+ const sepIdx = argv.indexOf('--');
15
+ const effective = sepIdx !== -1 ? argv.slice(sepIdx + 1) : argv;
16
+
17
+ if (effective[0] === 'openspec') {
18
+ // Passthrough to the OpenSpec CLI; lib owns exitCode + init output
19
+ await runOpenspec({ packageRoot, args: effective.slice(1), cwd: process.cwd() });
20
+ } else {
21
+ const { values, positionals } = parseArgs({
22
+ args: effective,
23
+ allowPositionals: true,
24
+ options: {
25
+ modules: {
26
+ type: 'string',
27
+ default: 'all'
28
+ },
29
+ dir: {
30
+ type: 'string',
31
+ default: '~/.agents'
32
+ },
33
+ help: {
34
+ type: 'boolean',
35
+ short: 'h'
36
+ }
25
37
  }
26
- }
27
- });
38
+ });
28
39
 
29
- const command = positionals[0];
40
+ const command = positionals[0];
30
41
 
31
- if (values.help || !command) {
32
- console.log(`Usage: npx dijk-skills install [options]
42
+ if (values.help || !command) {
43
+ console.log(`Usage: npx dijk-skills <command> [options]
44
+ (short alias: dijk — after \`npm i -g dijk-skills\`, or \`npx -p dijk-skills dijk ...\`)
33
45
 
34
46
  Commands:
35
- install Install skills to target directory
47
+ install Install skills to target directory
48
+ openspec <args...> Run the OpenSpec CLI (passthrough via npx). Put it after
49
+ \`--\` to be npx-safe: npx dijk-skills -- openspec init
50
+ On \`init\`: drops the customizable coding/openspec/config.yaml
51
+ template into ./openspec/ (never overwrites an existing
52
+ config) and defaults --tools opencode --no-animation.
36
53
 
37
54
  Options:
38
55
  --modules <list> Comma-separated module names or "all"
39
56
  Values: coding,common,tools,writing,all
40
- Default: common
57
+ Default: all
41
58
  --dir <path> Target installation directory
42
59
  Default: ~/.agents
43
60
  -h, --help Show this help message
@@ -47,32 +64,40 @@ Examples:
47
64
  npx dijk-skills install --modules all
48
65
  npx dijk-skills install --modules writing,tools
49
66
  npx dijk-skills install --modules coding --dir ~/custom/path
67
+ npx dijk-skills -- openspec init
68
+ npx dijk-skills -- openspec update
69
+ npx dijk-skills -- openspec status
50
70
  `);
51
- process.exit(0);
52
- }
71
+ process.exit(0);
72
+ }
53
73
 
54
- if (command !== 'install') {
55
- console.error(`Unknown command: ${command}`);
56
- console.error('Available commands: install');
57
- process.exit(1);
58
- }
74
+ function expandTilde(path) {
75
+ return path.startsWith('~')
76
+ ? path.replace('~', process.env.HOME || process.env.USERPROFILE || '')
77
+ : path;
78
+ }
59
79
 
60
- const modules = values.modules === 'all'
61
- ? ['coding', 'common', 'tools', 'writing']
62
- : values.modules.split(',').map(m => m.trim()).filter(Boolean);
80
+ if (command !== 'install') {
81
+ console.error(`Unknown command: ${command}`);
82
+ console.error('Available commands: install, openspec');
83
+ process.exit(1);
84
+ }
63
85
 
64
- const targetDir = values.dir.startsWith('~')
65
- ? values.dir.replace('~', process.env.HOME || process.env.USERPROFILE || '')
66
- : values.dir;
86
+ const modules = values.modules === 'all'
87
+ ? ['coding', 'common', 'tools', 'writing']
88
+ : values.modules.split(',').map(m => m.trim()).filter(Boolean);
67
89
 
68
- try {
69
- await install({
70
- packageRoot,
71
- modules,
72
- targetDir: resolve(targetDir)
73
- });
74
- console.log('\n✓ Installation complete');
75
- } catch (err) {
76
- console.error('Installation failed:', err.message);
77
- process.exit(1);
90
+ const targetDir = expandTilde(values.dir);
91
+
92
+ try {
93
+ await install({
94
+ packageRoot,
95
+ modules,
96
+ targetDir: resolve(targetDir)
97
+ });
98
+ console.log('\n✓ Installation complete');
99
+ } catch (err) {
100
+ console.error('Installation failed:', err.message);
101
+ process.exit(1);
102
+ }
78
103
  }
@@ -0,0 +1,32 @@
1
+ schema: spec-driven
2
+
3
+ rules:
4
+ proposal:
5
+ - 保持简洁,不描述实现方式;
6
+ - 背景:必须,包括变更背景、目标、动机;
7
+ - 术语表:必须,表格,包括 [中文-英文-解释];
8
+ - 用户故事:必须,子章节,每一章包括 [> 叙事性描述]、[- 用户故事描述] 和 [**验收标准**];
9
+ - 功能清单:必须,子章节,每一章包括 [> 描述]、[- 规格]、[**使用方式** (如界面操作/后台接口等)]、[影响];
10
+ - 每一个功能对应一个 spec 文件;
11
+ - 修改 proposal 之后必须确保 proposal 其他章节以及 specs 和 design 同步满足;
12
+
13
+ specs:
14
+ - 保持简洁,不描述实现细节;
15
+ - 功能需求(FR):必须,包括ID、描述、1~N个用户场景(GIVEN/WHEN/THEN格式);
16
+ - 非功能需求(NFR):必须,包括ID、描述,范围包括可靠性、可用性、资源占用、性能、安全、容错、可观测等方面
17
+
18
+ design:
19
+ - 保持简洁;
20
+ - 上下文:必须,包括上游系统、下游系统、外部接口清单;
21
+ - 总体架构:必须,包括架构约束、各模块的逻辑架构和依赖关系、技术选型及理由;
22
+ - 必须包含设计决策记录(ADR),记录关键取舍及备选方案(为什么 X 而不是 Y);
23
+ - 必须考虑非功能性需求的应对方案;
24
+ - 必须识别技术风险,并列出已知限制和后续演进方向;
25
+
26
+ tasks:
27
+ - 每个 task 须包含:用例编号、用例名称、前置条件、步骤、预期结果、验证方法;
28
+ - 必须关联 FR-ID 和 NFR-ID,确保可追溯;
29
+ - 必须包含单元测试(覆盖率 ≥ 80%)、集成测试、冒烟测试(如有);
30
+ - 必须包含验收测试(与 specs 中的用户场景对应)、人工测试指导(如有)、构建与部署验证、数据准备方法、文档交付等;
31
+ - 缺陷必须分级(致命/重/一般/建议),并明确发布影响;
32
+
@@ -0,0 +1,83 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { copyFile, mkdir } from 'node:fs/promises';
3
+ import { existsSync } from 'node:fs';
4
+ import { join } from 'node:path';
5
+
6
+ /**
7
+ * Drop the user-owned OpenSpec config template into <cwd>/openspec/.
8
+ * Never overwrites an existing config.yaml / config.yml.
9
+ */
10
+ async function ensureConfigTemplate(cwd, packageRoot) {
11
+ await mkdir(join(cwd, 'openspec'), { recursive: true });
12
+
13
+ // Config is user-owned: only drop the template if no config exists yet
14
+ const configYaml = join(cwd, 'openspec', 'config.yaml');
15
+ const configYml = join(cwd, 'openspec', 'config.yml');
16
+
17
+ if (!existsSync(configYaml) && !existsSync(configYml)) {
18
+ await copyFile(join(packageRoot, 'coding', 'openspec', 'config.yaml'), configYaml);
19
+ console.log('✓ wrote openspec/config.yaml (template — customize freely)');
20
+ } else {
21
+ const existing = existsSync(configYaml) ? 'config.yaml' : 'config.yml';
22
+ console.log(`· openspec/${existing} exists — keeping it (never overwritten)`);
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Run the OpenSpec CLI (@fission-ai/openspec) via npx, forwarding args
28
+ * verbatim. On `init`: drops the config template first (never overwriting
29
+ * an existing config) and adds default flags `--tools opencode
30
+ * --no-animation` when the user didn't supply their own. Child exit codes
31
+ * propagate; this never throws.
32
+ */
33
+ export async function runOpenspec({ packageRoot, args, cwd = process.cwd() }) {
34
+ const isInit = args[0] === 'init';
35
+
36
+ if (isInit) {
37
+ // OpenSpec requires Node >= 20.19.0 — warn, but do not abort
38
+ const [major, minor] = process.versions.node.split('.').map(Number);
39
+ if (major < 20 || (major === 20 && minor < 19)) {
40
+ console.log(`⚠ OpenSpec requires Node >= 20.19.0 (current: ${process.versions.node}) — continuing anyway`);
41
+ }
42
+
43
+ console.log(`Target project: ${cwd}`);
44
+
45
+ await ensureConfigTemplate(cwd, packageRoot);
46
+
47
+ // Default flags, appended only when the user didn't supply their own
48
+ // (--tools also matches the equals form `--tools=<list>`)
49
+ const hasTools = args.some(a => a === '--tools' || a.startsWith('--tools='));
50
+ if (!hasTools) {
51
+ args = [...args, '--tools', 'opencode'];
52
+ }
53
+ if (!args.includes('--no-animation')) {
54
+ args = [...args, '--no-animation'];
55
+ }
56
+ }
57
+
58
+ const result = spawnSync('npx', ['-y', '@fission-ai/openspec@latest', ...args], {
59
+ cwd,
60
+ stdio: 'inherit',
61
+ shell: process.platform === 'win32'
62
+ });
63
+
64
+ if (result.error) {
65
+ console.error(`Failed to run openspec via npx: ${result.error.message}`);
66
+ process.exitCode = 1;
67
+ return;
68
+ }
69
+
70
+ if (result.status !== 0) {
71
+ process.exitCode = result.status ?? 1;
72
+ return;
73
+ }
74
+
75
+ if (isInit) {
76
+ console.log(`✓ OpenSpec bootstrap complete
77
+ - Project config: openspec/config.yaml (yours — openspec never overwrites it)
78
+ - Agent skills: .opencode/skills/openspec-*/
79
+ - Slash commands: .opencode/commands/opsx-*.md (/opsx-propose, /opsx-apply, ...)
80
+ - Vendor-neutral alternative: re-run with --tools agents for shared .agents/skills (skills only, no commands)
81
+ - Re-run anytime to refresh CLI-owned files; upgrade later with: npx @fission-ai/openspec@latest update`);
82
+ }
83
+ }
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "dijk-skills",
3
- "version": "1.0.4",
3
+ "version": "1.0.8",
4
4
  "description": "CLI installer for Dijk skills collection",
5
5
  "type": "module",
6
6
  "bin": {
7
- "dijk-skills": "./bin/dijk-skills.js"
7
+ "dijk-skills": "./bin/dijk-skills.js",
8
+ "dijk": "./bin/dijk-skills.js"
8
9
  },
9
10
  "files": [
10
11
  "bin/",
File without changes