@chenmk/superflow 0.1.3 → 0.2.1
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/app/cli.js +218 -0
- package/dist/app/cli.js.map +1 -0
- package/dist/app/commands/archive.js +6 -0
- package/dist/app/commands/archive.js.map +1 -0
- package/dist/app/commands/check.js +132 -0
- package/dist/app/commands/check.js.map +1 -0
- package/dist/app/commands/clarify.js +6 -0
- package/dist/app/commands/clarify.js.map +1 -0
- package/dist/app/commands/config.js +103 -0
- package/dist/app/commands/config.js.map +1 -0
- package/dist/app/commands/design.js +28 -0
- package/dist/app/commands/design.js.map +1 -0
- package/dist/app/commands/docs.js +6 -0
- package/dist/app/commands/docs.js.map +1 -0
- package/dist/app/commands/doctor.js +494 -0
- package/dist/app/commands/doctor.js.map +1 -0
- package/dist/app/commands/implement.js +6 -0
- package/dist/app/commands/implement.js.map +1 -0
- package/dist/app/commands/init.js +520 -0
- package/dist/app/commands/init.js.map +1 -0
- package/dist/app/commands/pipeline.js +6 -0
- package/dist/app/commands/pipeline.js.map +1 -0
- package/dist/app/commands/scan.js +63 -0
- package/dist/app/commands/scan.js.map +1 -0
- package/dist/app/commands/status.js +192 -0
- package/dist/app/commands/status.js.map +1 -0
- package/dist/app/commands/uninstall.js +214 -0
- package/dist/app/commands/uninstall.js.map +1 -0
- package/dist/app/commands/update.js +193 -0
- package/dist/app/commands/update.js.map +1 -0
- package/dist/app/commands/verify.js +6 -0
- package/dist/app/commands/verify.js.map +1 -0
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/archive.js +1 -1
- package/dist/commands/archive.js.map +1 -1
- package/dist/commands/clarify.js +1 -1
- package/dist/commands/clarify.js.map +1 -1
- package/dist/commands/design.js +1 -1
- package/dist/commands/design.js.map +1 -1
- package/dist/commands/docs.js +1 -1
- package/dist/commands/docs.js.map +1 -1
- package/dist/commands/doctor.js +4 -3
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/implement.js +1 -1
- package/dist/commands/implement.js.map +1 -1
- package/dist/commands/init.js +13 -12
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/pipeline.js +1 -1
- package/dist/commands/pipeline.js.map +1 -1
- package/dist/commands/scan.js +2 -2
- package/dist/commands/scan.js.map +1 -1
- package/dist/commands/status.js +1 -1
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/uninstall.js +6 -5
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +10 -9
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/verify.js +1 -1
- package/dist/commands/verify.js.map +1 -1
- package/dist/core/dependencies.js +1 -1
- package/dist/core/dependencies.js.map +1 -1
- package/dist/core/detect.js +0 -60
- package/dist/core/detect.js.map +1 -1
- package/dist/core/skill-check.js +3 -2
- package/dist/core/skill-check.js.map +1 -1
- package/dist/domains/agent.js +64 -0
- package/dist/domains/agent.js.map +1 -0
- package/dist/domains/config/cli-help.js +98 -0
- package/dist/domains/config/cli-help.js.map +1 -0
- package/dist/domains/config/context.js +126 -0
- package/dist/domains/config/context.js.map +1 -0
- package/dist/domains/config/i18n.js +105 -0
- package/dist/domains/config/i18n.js.map +1 -0
- package/dist/domains/config/manifest.js +21 -0
- package/dist/domains/config/manifest.js.map +1 -0
- package/dist/domains/deps.js +146 -0
- package/dist/domains/deps.js.map +1 -0
- package/dist/domains/hook.js +134 -0
- package/dist/domains/hook.js.map +1 -0
- package/dist/domains/intent.js +69 -0
- package/dist/domains/intent.js.map +1 -0
- package/dist/domains/run-state.js +47 -0
- package/dist/domains/run-state.js.map +1 -0
- package/dist/domains/skill/assets.js +27 -0
- package/dist/domains/skill/assets.js.map +1 -0
- package/dist/domains/skill/check.js +32 -0
- package/dist/domains/skill/check.js.map +1 -0
- package/dist/domains/skill/deploy.js +62 -0
- package/dist/domains/skill/deploy.js.map +1 -0
- package/dist/domains/skill/prompts.js +20 -0
- package/dist/domains/skill/prompts.js.map +1 -0
- package/dist/domains/skill/rules.js +17 -0
- package/dist/domains/skill/rules.js.map +1 -0
- package/dist/domains/skill/scripts.js +48 -0
- package/dist/domains/skill/scripts.js.map +1 -0
- package/dist/domains/state-events.js +32 -0
- package/dist/domains/state-events.js.map +1 -0
- package/dist/domains/state.js +54 -0
- package/dist/domains/state.js.map +1 -0
- package/dist/domains/workflow-state.js +47 -0
- package/dist/domains/workflow-state.js.map +1 -0
- package/dist/platform/fs.js +45 -0
- package/dist/platform/fs.js.map +1 -0
- package/dist/platform/os.js +14 -0
- package/dist/platform/os.js.map +1 -0
- package/dist/platform/paths.js +55 -0
- package/dist/platform/paths.js.map +1 -0
- package/dist/platform/process.js +29 -0
- package/dist/platform/process.js.map +1 -0
- package/dist/platform/version-check.js +45 -0
- package/dist/platform/version-check.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import manifestJson from '../../../assets/manifest.json' with { type: 'json' };
|
|
2
|
+
const manifest = manifestJson;
|
|
3
|
+
export function getManifest() {
|
|
4
|
+
return manifest;
|
|
5
|
+
}
|
|
6
|
+
export function getManifestSkillNames() {
|
|
7
|
+
return [...manifest.skills];
|
|
8
|
+
}
|
|
9
|
+
export function getManifestRules() {
|
|
10
|
+
return [...(manifest.rules ?? [])];
|
|
11
|
+
}
|
|
12
|
+
export function getManifestScripts(agent) {
|
|
13
|
+
return [...manifest.scripts, ...(manifest.agentScripts[agent] ?? [])];
|
|
14
|
+
}
|
|
15
|
+
export function getManifestHooks(agent) {
|
|
16
|
+
if (agent === 'opencode') {
|
|
17
|
+
return [...(manifest.agentHooks[agent] ?? [])];
|
|
18
|
+
}
|
|
19
|
+
return [...(manifest.agentHooks[agent] ?? []), ...manifest.hooks];
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../src/domains/config/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,+BAA+B,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAc/E,MAAM,QAAQ,GAAG,YAA2B,CAAC;AAE7C,MAAM,UAAU,WAAW;IACzB,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,OAAO,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,KAAY;IAC7C,OAAO,CAAC,GAAG,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAY;IAC3C,IAAI,KAAK,KAAK,UAAU,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;AACpE,CAAC"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import { homedir } from 'os';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import { runCommand } from '../platform/process.js';
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = path.dirname(__filename);
|
|
8
|
+
// dist/domains/deps.js → ../../../assets
|
|
9
|
+
const ASSETS_DIR = path.resolve(__dirname, '..', '..', '..', 'assets');
|
|
10
|
+
function alreadyInstalled(output) {
|
|
11
|
+
return /already\s+(installed|exists)|is\s+already\s+installed|already\s+added/i.test(output);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 安装 openspec CLI(npm 全局)
|
|
15
|
+
* 失败阻塞 init(核心依赖)
|
|
16
|
+
*/
|
|
17
|
+
export async function installOpenspec() {
|
|
18
|
+
const result = await runCommand('npm', ['install', '-g', '@fission-ai/openspec@latest']);
|
|
19
|
+
if (result.code !== 0) {
|
|
20
|
+
return { ok: false, error: `npm install failed: ${result.stderr}` };
|
|
21
|
+
}
|
|
22
|
+
return { ok: true };
|
|
23
|
+
}
|
|
24
|
+
export function openspecInitArgs(projectPath, agents, _scope, includeProfile = true) {
|
|
25
|
+
const args = ['init', projectPath, '--tools', agents.join(',')];
|
|
26
|
+
if (includeProfile) {
|
|
27
|
+
args.push('--profile', 'custom');
|
|
28
|
+
}
|
|
29
|
+
return args;
|
|
30
|
+
}
|
|
31
|
+
export async function initializeOpenspec(projectPath, agents, scope) {
|
|
32
|
+
const args = openspecInitArgs(projectPath, agents, scope);
|
|
33
|
+
const result = await runCommand('openspec', args, {
|
|
34
|
+
cwd: projectPath,
|
|
35
|
+
timeout: 120_000,
|
|
36
|
+
});
|
|
37
|
+
if (result.code === 0)
|
|
38
|
+
return { ok: true };
|
|
39
|
+
const stderr = result.stderr || result.stdout;
|
|
40
|
+
if (stderr.includes('unknown option') && stderr.includes('--profile')) {
|
|
41
|
+
const fallback = await runCommand('openspec', openspecInitArgs(projectPath, agents, scope, false), { cwd: projectPath, timeout: 120_000 });
|
|
42
|
+
if (fallback.code === 0)
|
|
43
|
+
return { ok: true };
|
|
44
|
+
return { ok: false, error: fallback.stderr || fallback.stdout };
|
|
45
|
+
}
|
|
46
|
+
return { ok: false, error: stderr };
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 安装 superpowers(claude 插件)
|
|
50
|
+
* 失败阻塞 init(核心 HOW/TDD 依赖;已装视为成功)
|
|
51
|
+
*/
|
|
52
|
+
export async function installSuperpowers() {
|
|
53
|
+
const result = await runCommand('claude', [
|
|
54
|
+
'plugin',
|
|
55
|
+
'install',
|
|
56
|
+
'superpowers@superpowers-marketplace',
|
|
57
|
+
]);
|
|
58
|
+
if (result.code !== 0) {
|
|
59
|
+
const output = `${result.stderr}\n${result.stdout}`;
|
|
60
|
+
if (alreadyInstalled(output))
|
|
61
|
+
return { ok: true };
|
|
62
|
+
return { ok: false, error: result.stderr };
|
|
63
|
+
}
|
|
64
|
+
return { ok: true };
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 安装 superpowers(Codex 插件)
|
|
68
|
+
* 失败阻塞 init(核心 HOW/TDD 依赖;已装视为成功)
|
|
69
|
+
*/
|
|
70
|
+
export async function installCodexSuperpowers() {
|
|
71
|
+
const result = await runCommand('codex', [
|
|
72
|
+
'plugin',
|
|
73
|
+
'add',
|
|
74
|
+
'superpowers@openai-curated',
|
|
75
|
+
]);
|
|
76
|
+
if (result.code !== 0) {
|
|
77
|
+
const output = `${result.stderr}\n${result.stdout}`;
|
|
78
|
+
if (alreadyInstalled(output))
|
|
79
|
+
return { ok: true };
|
|
80
|
+
return { ok: false, error: result.stderr || result.stdout };
|
|
81
|
+
}
|
|
82
|
+
return { ok: true };
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* 安装 understand-anything(claude 插件)
|
|
86
|
+
*/
|
|
87
|
+
export async function installUnderstand() {
|
|
88
|
+
const result = await runCommand('claude', [
|
|
89
|
+
'plugin',
|
|
90
|
+
'install',
|
|
91
|
+
'understand-anything@understand-anything',
|
|
92
|
+
]);
|
|
93
|
+
if (result.code !== 0) {
|
|
94
|
+
return { ok: false, error: result.stderr };
|
|
95
|
+
}
|
|
96
|
+
return { ok: true };
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* 安装 understand-anything(Codex / agents 技能链接)
|
|
100
|
+
*/
|
|
101
|
+
export async function installCodexUnderstand() {
|
|
102
|
+
const script = path.join(homedir(), '.understand-anything', 'repo', 'install.sh');
|
|
103
|
+
const result = await runCommand('bash', [script, 'codex']);
|
|
104
|
+
if (result.code !== 0) {
|
|
105
|
+
const fallback = await linkCodexUnderstandSkills();
|
|
106
|
+
if (fallback.ok)
|
|
107
|
+
return fallback;
|
|
108
|
+
return { ok: false, error: `${result.stderr || result.stdout}\n${fallback.error}` };
|
|
109
|
+
}
|
|
110
|
+
return { ok: true };
|
|
111
|
+
}
|
|
112
|
+
async function linkCodexUnderstandSkills() {
|
|
113
|
+
const sourceRoot = path.join(homedir(), '.understand-anything', 'repo', 'understand-anything-plugin', 'skills');
|
|
114
|
+
const targetRoot = path.join(homedir(), '.agents', 'skills');
|
|
115
|
+
try {
|
|
116
|
+
const entries = await fs.readdir(sourceRoot, { withFileTypes: true });
|
|
117
|
+
await fs.mkdir(targetRoot, { recursive: true });
|
|
118
|
+
for (const entry of entries) {
|
|
119
|
+
if (!entry.isDirectory())
|
|
120
|
+
continue;
|
|
121
|
+
const source = path.join(sourceRoot, entry.name);
|
|
122
|
+
const target = path.join(targetRoot, entry.name);
|
|
123
|
+
await fs.rm(target, { recursive: true, force: true });
|
|
124
|
+
await fs.symlink(source, target, process.platform === 'win32' ? 'junction' : 'dir');
|
|
125
|
+
}
|
|
126
|
+
return { ok: true };
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
return { ok: false, error: `understand-anything fallback failed: ${err.message}` };
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* 安装 api-doc-changelog(直接复制)
|
|
134
|
+
*/
|
|
135
|
+
export async function installApiDocChangelog(skillsDir = path.join(homedir(), '.claude', 'skills')) {
|
|
136
|
+
const source = path.join(ASSETS_DIR, 'skills', 'api-doc-changelog');
|
|
137
|
+
const dest = path.join(skillsDir, 'api-doc-changelog');
|
|
138
|
+
try {
|
|
139
|
+
await fs.cp(source, dest, { recursive: true, force: true });
|
|
140
|
+
return { ok: true };
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
return { ok: false, error: err.message };
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=deps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deps.js","sourceRoot":"","sources":["../../src/domains/deps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAGpD,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAC3C,yCAAyC;AACzC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;AAOvE,SAAS,gBAAgB,CAAC,MAAc;IACtC,OAAO,wEAAwE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC/F,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC,SAAS,EAAE,IAAI,EAAE,6BAA6B,CAAC,CAAC,CAAC;IACzF,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,uBAAuB,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;IACtE,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,WAAmB,EACnB,MAAe,EACf,MAAoB,EACpB,cAAc,GAAG,IAAI;IAErB,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAChE,IAAI,cAAc,EAAE,CAAC;QACnB,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,WAAmB,EACnB,MAAe,EACf,KAAmB;IAEnB,MAAM,IAAI,GAAG,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IAC1D,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,UAAU,EAAE,IAAI,EAAE;QAChD,GAAG,EAAE,WAAW;QAChB,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IACH,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IAE3C,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC;IAC9C,IAAI,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QACtE,MAAM,QAAQ,GAAG,MAAM,UAAU,CAC/B,UAAU,EACV,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,EACnD,EAAE,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,CACvC,CAAC;QACF,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;QAC7C,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;IAClE,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AACtC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,QAAQ,EAAE;QACxC,QAAQ;QACR,SAAS;QACT,qCAAqC;KACtC,CAAC,CAAC;IACH,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACtB,MAAM,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC;QACpD,IAAI,gBAAgB,CAAC,MAAM,CAAC;YAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;QAClD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;IAC7C,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AACtB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB;IAC3C,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,OAAO,EAAE;QACvC,QAAQ;QACR,KAAK;QACL,4BAA4B;KAC7B,CAAC,CAAC;IACH,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACtB,MAAM,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC;QACpD,IAAI,gBAAgB,CAAC,MAAM,CAAC;YAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;QAClD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;IAC9D,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AACtB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,QAAQ,EAAE;QACxC,QAAQ;QACR,SAAS;QACT,yCAAyC;KAC1C,CAAC,CAAC;IACH,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;IAC7C,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AACtB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB;IAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,sBAAsB,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC;IAClF,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC3D,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACtB,MAAM,QAAQ,GAAG,MAAM,yBAAyB,EAAE,CAAC;QACnD,IAAI,QAAQ,CAAC,EAAE;YAAE,OAAO,QAAQ,CAAC;QACjC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC;IACtF,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AACtB,CAAC;AAED,KAAK,UAAU,yBAAyB;IACtC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAC1B,OAAO,EAAE,EACT,sBAAsB,EACtB,MAAM,EACN,4BAA4B,EAC5B,QAAQ,CACT,CAAC;IACF,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;IAC7D,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QACtE,MAAM,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;gBAAE,SAAS;YACnC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACjD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACjD,MAAM,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACtD,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACtF,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,wCAAyC,GAAa,CAAC,OAAO,EAAE,EAAE,CAAC;IAChG,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,QAAQ,CAAC;IAErD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,mBAAmB,CAAC,CAAC;IACpE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;IACvD,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAC,CAAC,CAAC;QAC3D,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAG,GAAa,CAAC,OAAO,EAAE,CAAC;IACtD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
export const HOOK_MAP = {
|
|
4
|
+
'claude-auto-backup-hook.sh': { event: 'PostToolUse', matcher: 'Edit|Write|Bash' },
|
|
5
|
+
'codex-auto-backup-hook.sh': { event: 'PostToolUse', matcher: 'Edit|Write|Bash' },
|
|
6
|
+
'superflow-hook-guard.sh': { event: 'PreToolUse', matcher: 'Edit|Write|NotebookEdit' },
|
|
7
|
+
'superflow-enforce-hook.sh': { event: 'PreToolUse', matcher: 'Edit|Write|NotebookEdit' },
|
|
8
|
+
'superflow-contract-hooks.sh': { event: 'PreToolUse', matcher: 'Edit|Write|NotebookEdit' },
|
|
9
|
+
'superflow-dependency-update-hook.sh': { event: 'UserPromptSubmit' },
|
|
10
|
+
'superflow-sql-sync-hook.py': { event: 'PreToolUse', matcher: 'Edit|Write|NotebookEdit' },
|
|
11
|
+
'superflow-delivery-check.sh': { event: 'PreToolUse', matcher: 'Bash' },
|
|
12
|
+
'superflow-integration-evidence-hook.sh': { event: 'PreToolUse', matcher: 'Bash' },
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* 判定一个 command path 是否是 SuperBridge Flow 体系管理的 hook。
|
|
16
|
+
* - superflow-* 脚本:路径含 /scripts/superflow- 或 /hooks/superflow-
|
|
17
|
+
* - legacy sdd-* 脚本:用于清理旧版本安装残留
|
|
18
|
+
* - auto-backup-hook.sh:路径含 /scripts/ 或 /hooks/ 下的备份 hook
|
|
19
|
+
* 覆盖 `~` 路径和绝对路径两种写法。
|
|
20
|
+
*/
|
|
21
|
+
function isSuperflowManagedHook(command) {
|
|
22
|
+
if (!command)
|
|
23
|
+
return false;
|
|
24
|
+
return (command.includes('/scripts/superflow-') ||
|
|
25
|
+
command.includes('/hooks/superflow-') ||
|
|
26
|
+
command.includes('/scripts/sdd-') ||
|
|
27
|
+
command.includes('/hooks/sdd-') ||
|
|
28
|
+
command.includes('/scripts/claude-auto-backup-hook.sh') ||
|
|
29
|
+
command.includes('/scripts/claude-auto-backup-hook') ||
|
|
30
|
+
command.includes('/hooks/claude-auto-backup-hook.sh') ||
|
|
31
|
+
command.includes('/hooks/claude-auto-backup-hook') ||
|
|
32
|
+
command.includes('/scripts/codex-auto-backup-hook.sh') ||
|
|
33
|
+
command.includes('/scripts/codex-auto-backup-hook') ||
|
|
34
|
+
command.includes('/hooks/codex-auto-backup-hook.sh') ||
|
|
35
|
+
command.includes('/hooks/codex-auto-backup-hook'));
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 清理 settings.json 中所有 SuperBridge Flow 体系管理的 hook。
|
|
39
|
+
* - 保留非 superflow hook(用户手写、UserPromptSubmit system 提示等)
|
|
40
|
+
* - 保留所有其他顶层 key(env / enabledPlugins / extraKnownMarketplaces / statusLine / model / skipDangerousModePermissionPrompt)
|
|
41
|
+
* - 修改前自动备份到 .sdd-backup-<ts>
|
|
42
|
+
* - 返回清理掉的 hook command 数(用于日志)
|
|
43
|
+
*
|
|
44
|
+
* 修法理由:init 之前可能用 `~` 路径注册过,本 CLI 用绝对路径;
|
|
45
|
+
* registerHook 跳过逻辑只比较 command 字符串严格相等,会导致新旧并存。
|
|
46
|
+
* 用"全量覆盖"策略:先清所有 superflow/legacy sdd hook,再注册新 hook。
|
|
47
|
+
*/
|
|
48
|
+
export function clearSddHooks(settingsFile) {
|
|
49
|
+
if (!existsSync(settingsFile)) {
|
|
50
|
+
mkdirSync(path.dirname(settingsFile), { recursive: true });
|
|
51
|
+
writeFileSync(settingsFile, JSON.stringify({}, null, 2), 'utf-8');
|
|
52
|
+
return 0;
|
|
53
|
+
}
|
|
54
|
+
const settings = JSON.parse(readFileSync(settingsFile, 'utf-8'));
|
|
55
|
+
if (!settings.hooks)
|
|
56
|
+
return 0;
|
|
57
|
+
// 1. 备份
|
|
58
|
+
const backupPath = settingsFile + '.sdd-backup-' + Date.now();
|
|
59
|
+
writeFileSync(backupPath, JSON.stringify(settings, null, 2), 'utf-8');
|
|
60
|
+
// 2. 清理所有 SuperBridge Flow 体系管理的 hook
|
|
61
|
+
let removed = 0;
|
|
62
|
+
for (const event of Object.keys(settings.hooks)) {
|
|
63
|
+
const entries = settings.hooks[event];
|
|
64
|
+
if (!Array.isArray(entries))
|
|
65
|
+
continue;
|
|
66
|
+
const filtered = entries.filter((entry) => {
|
|
67
|
+
const cmds = (entry?.hooks ?? []).map((h) => h.command).filter(Boolean);
|
|
68
|
+
const allSuperflow = cmds.length > 0 && cmds.every((c) => isSuperflowManagedHook(c));
|
|
69
|
+
if (allSuperflow) {
|
|
70
|
+
removed += cmds.length;
|
|
71
|
+
return false; // 整条 entry 全删
|
|
72
|
+
}
|
|
73
|
+
return true;
|
|
74
|
+
});
|
|
75
|
+
if (filtered.length === 0) {
|
|
76
|
+
delete settings.hooks[event];
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
settings.hooks[event] = filtered;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// 3. 保留所有其他顶层 key
|
|
83
|
+
writeFileSync(settingsFile, JSON.stringify(settings, null, 2), 'utf-8');
|
|
84
|
+
return removed;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* 注册一个 hook 到 settings.json(read-merge-write)
|
|
88
|
+
* - 备份 settings.json 到 .sdd-backup-<ts>
|
|
89
|
+
* - 保留所有现有 key
|
|
90
|
+
* - 跳过已存在的 hook
|
|
91
|
+
* - 支持 matcherOverride 用于同脚本注册到多 matcher(superflow-sql-sync-hook.py)
|
|
92
|
+
*
|
|
93
|
+
* 注意:本函数只检查精确字符串相等,不会清理 `~` 路径的旧 hook。
|
|
94
|
+
* 配合 clearSddHooks() 使用(init 阶段先 clear 后 register)可避免重复。
|
|
95
|
+
*/
|
|
96
|
+
export function registerHook(settingsFile, scriptName, commandPath, options = {}) {
|
|
97
|
+
if (!existsSync(settingsFile)) {
|
|
98
|
+
mkdirSync(path.dirname(settingsFile), { recursive: true });
|
|
99
|
+
writeFileSync(settingsFile, JSON.stringify({}, null, 2), 'utf-8');
|
|
100
|
+
}
|
|
101
|
+
const settings = JSON.parse(readFileSync(settingsFile, 'utf-8'));
|
|
102
|
+
const map = HOOK_MAP[scriptName];
|
|
103
|
+
if (!map) {
|
|
104
|
+
throw new Error(`Unknown hook script: ${scriptName}. Expected one of: ${Object.keys(HOOK_MAP).join(', ')}`);
|
|
105
|
+
}
|
|
106
|
+
const finalMatcher = options.matcherOverride ?? map.matcher;
|
|
107
|
+
const finalEvent = map.event; // event 不可 override(同一脚本绑定同一 event 不同 matcher)
|
|
108
|
+
// 1. 备份
|
|
109
|
+
const backupPath = settingsFile + '.sdd-backup-' + Date.now();
|
|
110
|
+
writeFileSync(backupPath, JSON.stringify(settings, null, 2), 'utf-8');
|
|
111
|
+
// 2. 合并 hooks
|
|
112
|
+
if (!settings.hooks)
|
|
113
|
+
settings.hooks = {};
|
|
114
|
+
if (!settings.hooks[finalEvent])
|
|
115
|
+
settings.hooks[finalEvent] = [];
|
|
116
|
+
// 3. 跳过已存在(同 command + 同 matcher)
|
|
117
|
+
const exists = settings.hooks[finalEvent].some((entry) => {
|
|
118
|
+
const matcherMatches = finalMatcher === undefined
|
|
119
|
+
? entry.matcher === undefined
|
|
120
|
+
: entry.matcher === finalMatcher;
|
|
121
|
+
return entry.hooks?.some((h) => h.command === commandPath) && matcherMatches;
|
|
122
|
+
});
|
|
123
|
+
if (!exists) {
|
|
124
|
+
const entry = {
|
|
125
|
+
hooks: [{ type: 'command', command: commandPath, timeout: options.timeout ?? 120 }],
|
|
126
|
+
};
|
|
127
|
+
if (finalMatcher !== undefined)
|
|
128
|
+
entry.matcher = finalMatcher;
|
|
129
|
+
settings.hooks[finalEvent].push(entry);
|
|
130
|
+
}
|
|
131
|
+
// 4. 保留所有现有 key
|
|
132
|
+
writeFileSync(settingsFile, JSON.stringify(settings, null, 2), 'utf-8');
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=hook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook.js","sourceRoot":"","sources":["../../src/domains/hook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,IAAI,MAAM,MAAM,CAAC;AAOxB,MAAM,CAAC,MAAM,QAAQ,GAAiC;IACpD,4BAA4B,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,iBAAiB,EAAE;IAClF,2BAA2B,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,iBAAiB,EAAE;IACjF,yBAAyB,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,yBAAyB,EAAE;IACtF,2BAA2B,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,yBAAyB,EAAE;IACxF,6BAA6B,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,yBAAyB,EAAE;IAC1F,qCAAqC,EAAE,EAAE,KAAK,EAAE,kBAAkB,EAAE;IACpE,4BAA4B,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,yBAAyB,EAAE;IACzF,6BAA6B,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE;IACvE,wCAAwC,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE;CACnF,CAAC;AAIF;;;;;;GAMG;AACH,SAAS,sBAAsB,CAAC,OAA2B;IACzD,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAC3B,OAAO,CACL,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC;QACvC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC;QACrC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC;QACjC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC;QAC/B,OAAO,CAAC,QAAQ,CAAC,qCAAqC,CAAC;QACvD,OAAO,CAAC,QAAQ,CAAC,kCAAkC,CAAC;QACpD,OAAO,CAAC,QAAQ,CAAC,mCAAmC,CAAC;QACrD,OAAO,CAAC,QAAQ,CAAC,gCAAgC,CAAC;QAClD,OAAO,CAAC,QAAQ,CAAC,oCAAoC,CAAC;QACtD,OAAO,CAAC,QAAQ,CAAC,iCAAiC,CAAC;QACnD,OAAO,CAAC,QAAQ,CAAC,kCAAkC,CAAC;QACpD,OAAO,CAAC,QAAQ,CAAC,+BAA+B,CAAC,CAClD,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa,CAAC,YAAoB;IAChD,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC9B,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3D,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QAClE,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;IACjE,IAAI,CAAC,QAAQ,CAAC,KAAK;QAAE,OAAO,CAAC,CAAC;IAE9B,QAAQ;IACR,MAAM,UAAU,GAAG,YAAY,GAAG,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC9D,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAEtE,sCAAsC;IACtC,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAChD,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;YAAE,SAAS;QACtC,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,KAAU,EAAE,EAAE;YAC7C,MAAM,IAAI,GAAa,CAAC,KAAK,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACvF,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC;YACrF,IAAI,YAAY,EAAE,CAAC;gBACjB,OAAO,IAAI,IAAI,CAAC,MAAM,CAAC;gBACvB,OAAO,KAAK,CAAC,CAAE,cAAc;YAC/B,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;QACH,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC/B,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC;QACnC,CAAC;IACH,CAAC;IAED,kBAAkB;IAClB,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACxE,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,YAAY,CAC1B,YAAoB,EACpB,UAAkB,EAClB,WAAmB,EACnB,UAA0D,EAAE;IAE5D,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC9B,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3D,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACpE,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;IACjE,MAAM,GAAG,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;IACjC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,wBAAwB,UAAU,sBAAsB,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC9G,CAAC;IAED,MAAM,YAAY,GAAG,OAAO,CAAC,eAAe,IAAI,GAAG,CAAC,OAAO,CAAC;IAC5D,MAAM,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC,CAAE,+CAA+C;IAE9E,QAAQ;IACR,MAAM,UAAU,GAAG,YAAY,GAAG,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC9D,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAEtE,cAAc;IACd,IAAI,CAAC,QAAQ,CAAC,KAAK;QAAE,QAAQ,CAAC,KAAK,GAAG,EAAE,CAAC;IACzC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC;QAAE,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC;IAEjE,kCAAkC;IAClC,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,KAAU,EAAE,EAAE;QAC5D,MAAM,cAAc,GAAG,YAAY,KAAK,SAAS;YAC/C,CAAC,CAAC,KAAK,CAAC,OAAO,KAAK,SAAS;YAC7B,CAAC,CAAC,KAAK,CAAC,OAAO,KAAK,YAAY,CAAC;QACnC,OAAO,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,WAAW,CAAC,IAAI,cAAc,CAAC;IACpF,CAAC,CAAC,CAAC;IACH,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,KAAK,GAA4B;YACrC,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,GAAG,EAAE,CAAC;SACpF,CAAC;QACF,IAAI,YAAY,KAAK,SAAS;YAAE,KAAK,CAAC,OAAO,GAAG,YAAY,CAAC;QAC7D,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzC,CAAC;IAED,gBAAgB;IAChB,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AAC1E,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/** 触发 hotfix 的关键词(中文 + 英文) */
|
|
2
|
+
const HOTFIX_SIGNALS = [
|
|
3
|
+
'修复', '修', 'fix', 'hotfix', 'bug', '缺陷', '补丁', 'patch',
|
|
4
|
+
'紧急', 'urgent', '崩溃', 'crash', '报错', 'error',
|
|
5
|
+
];
|
|
6
|
+
/** 触发 tweak 的关键词(纯文档/配置类改动) */
|
|
7
|
+
const TWEAK_SIGNALS = [
|
|
8
|
+
'文档', 'doc', 'readme', '注释', 'comment', '文案', 'copy',
|
|
9
|
+
'配置', 'config', '格式', 'format', 'lint', '排版',
|
|
10
|
+
'changelog', 'news',
|
|
11
|
+
];
|
|
12
|
+
/** 触发 resume 的关键词 */
|
|
13
|
+
const RESUME_SIGNALS = [
|
|
14
|
+
'继续', '恢复', 'resume', '接着', '往下', '下一步', 'next',
|
|
15
|
+
];
|
|
16
|
+
/**
|
|
17
|
+
* 基于用户输入文本检测意图。
|
|
18
|
+
* 规则优先级:hotfix > tweak > resume > full
|
|
19
|
+
*/
|
|
20
|
+
export function detectIntent(input) {
|
|
21
|
+
const lower = input.toLowerCase();
|
|
22
|
+
// 1. hotfix 信号
|
|
23
|
+
const hotfixHit = HOTFIX_SIGNALS.filter((s) => lower.includes(s.toLowerCase()));
|
|
24
|
+
if (hotfixHit.length >= 2 || (hotfixHit.length >= 1 && lower.length < 40)) {
|
|
25
|
+
return { intent: 'hotfix', profile: 'hotfix', reason: `检测到修复信号: ${hotfixHit.join(', ')}` };
|
|
26
|
+
}
|
|
27
|
+
// 2. tweak 信号
|
|
28
|
+
const tweakHit = TWEAK_SIGNALS.filter((s) => lower.includes(s.toLowerCase()));
|
|
29
|
+
if (tweakHit.length >= 2 && !containsCodeSignals(lower)) {
|
|
30
|
+
return { intent: 'tweak', profile: 'tweak', reason: `检测到轻量改动信号: ${tweakHit.join(', ')}` };
|
|
31
|
+
}
|
|
32
|
+
// 3. resume 信号
|
|
33
|
+
const resumeHit = RESUME_SIGNALS.filter((s) => lower.includes(s.toLowerCase()));
|
|
34
|
+
if (resumeHit.length >= 1 && lower.length < 60) {
|
|
35
|
+
return { intent: 'resume', profile: 'full', reason: '检测到恢复信号,尝试继续上次中断的任务' };
|
|
36
|
+
}
|
|
37
|
+
// 4. ambiguous:太短无法判断
|
|
38
|
+
if (lower.length < 10) {
|
|
39
|
+
return { intent: 'ambiguous', profile: 'full', reason: '输入过短,无法自动判断意图' };
|
|
40
|
+
}
|
|
41
|
+
// 5. 默认 full
|
|
42
|
+
return { intent: 'full', profile: 'full', reason: '默认为完整工作流' };
|
|
43
|
+
}
|
|
44
|
+
/** 检查是否包含代码改动信号 */
|
|
45
|
+
function containsCodeSignals(input) {
|
|
46
|
+
const codeWords = [
|
|
47
|
+
'函数', 'function', '类', 'class', '接口', 'interface',
|
|
48
|
+
'模块', 'module', '组件', 'component', 'api', 'sql',
|
|
49
|
+
'数据库', 'database', '实现', 'implement', '开发',
|
|
50
|
+
'添加', '新增', 'add', 'feature', 'feat',
|
|
51
|
+
];
|
|
52
|
+
return codeWords.some((w) => input.includes(w));
|
|
53
|
+
}
|
|
54
|
+
/** 获取意图对应的工作流阶段列表 */
|
|
55
|
+
export function phasesForIntent(intent) {
|
|
56
|
+
switch (intent) {
|
|
57
|
+
case 'full':
|
|
58
|
+
return ['docs', 'design', 'implement', 'verify', 'archive'];
|
|
59
|
+
case 'hotfix':
|
|
60
|
+
return ['implement', 'verify', 'archive'];
|
|
61
|
+
case 'tweak':
|
|
62
|
+
return ['implement', 'verify'];
|
|
63
|
+
case 'resume':
|
|
64
|
+
return []; // 从 run-state 恢复,不预设阶段
|
|
65
|
+
case 'ambiguous':
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=intent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intent.js","sourceRoot":"","sources":["../../src/domains/intent.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
const RUN_STATE_FILE = '.sdd/run-state.json';
|
|
4
|
+
export function loadRunState(changeDir) {
|
|
5
|
+
const file = path.join(changeDir, RUN_STATE_FILE);
|
|
6
|
+
if (!existsSync(file))
|
|
7
|
+
return null;
|
|
8
|
+
try {
|
|
9
|
+
return JSON.parse(readFileSync(file, 'utf-8'));
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export function saveRunState(changeDir, state) {
|
|
16
|
+
const file = path.join(changeDir, RUN_STATE_FILE);
|
|
17
|
+
const dir = path.dirname(file);
|
|
18
|
+
if (!existsSync(dir))
|
|
19
|
+
mkdirSync(dir, { recursive: true });
|
|
20
|
+
writeFileSync(file, JSON.stringify({ ...state, updatedAt: new Date().toISOString() }, null, 2), 'utf-8');
|
|
21
|
+
}
|
|
22
|
+
export function initRunState(skill) {
|
|
23
|
+
return {
|
|
24
|
+
runId: `run-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
25
|
+
skill,
|
|
26
|
+
currentStep: null,
|
|
27
|
+
iteration: 0,
|
|
28
|
+
retries: {},
|
|
29
|
+
status: 'running',
|
|
30
|
+
updatedAt: new Date().toISOString(),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/** 增加指定步骤的重试计数 */
|
|
34
|
+
export function recordRetry(state, stepId) {
|
|
35
|
+
const retries = { ...state.retries };
|
|
36
|
+
retries[stepId] = (retries[stepId] ?? 0) + 1;
|
|
37
|
+
return { ...state, retries };
|
|
38
|
+
}
|
|
39
|
+
/** 更新当前步骤并增加迭代计数 */
|
|
40
|
+
export function advanceStep(state, step) {
|
|
41
|
+
return {
|
|
42
|
+
...state,
|
|
43
|
+
currentStep: step,
|
|
44
|
+
iteration: state.iteration + 1,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=run-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-state.js","sourceRoot":"","sources":["../../src/domains/run-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,IAAI,MAAM,MAAM,CAAC;AAuBxB,MAAM,cAAc,GAAG,qBAAqB,CAAC;AAE7C,MAAM,UAAU,YAAY,CAAC,SAAiB;IAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IAClD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAa,CAAC;IAC7D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,SAAiB,EAAE,KAAe;IAC7D,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IAClD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AAC3G,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,OAAO;QACL,KAAK,EAAE,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;QACpE,KAAK;QACL,WAAW,EAAE,IAAI;QACjB,SAAS,EAAE,CAAC;QACZ,OAAO,EAAE,EAAE;QACX,MAAM,EAAE,SAAS;QACjB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;AACJ,CAAC;AAED,kBAAkB;AAClB,MAAM,UAAU,WAAW,CAAC,KAAe,EAAE,MAAc;IACzD,MAAM,OAAO,GAAG,EAAE,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC;IACrC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IAC7C,OAAO,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,CAAC;AAC/B,CAAC;AAED,oBAAoB;AACpB,MAAM,UAAU,WAAW,CAAC,KAAe,EAAE,IAAY;IACvD,OAAO;QACL,GAAG,KAAK;QACR,WAAW,EAAE,IAAI;QACjB,SAAS,EAAE,KAAK,CAAC,SAAS,GAAG,CAAC;KAC/B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { getManifestHooks, getManifestRules, getManifestScripts, getManifestSkillNames, } from '../config/manifest.js';
|
|
2
|
+
export const ALL_SKILLS = getManifestSkillNames();
|
|
3
|
+
export const ALL_RULES = getManifestRules();
|
|
4
|
+
export const CODEX_PROMPTS = [
|
|
5
|
+
'superflow-pipeline.md',
|
|
6
|
+
'superflow-clarify.md',
|
|
7
|
+
'superflow-docs.md',
|
|
8
|
+
'superflow-design.md',
|
|
9
|
+
'superflow-implement.md',
|
|
10
|
+
'superflow-verify.md',
|
|
11
|
+
'superflow-archive.md',
|
|
12
|
+
];
|
|
13
|
+
export const LEGACY_CODEX_PROMPTS = [
|
|
14
|
+
'sdd.md',
|
|
15
|
+
'sdd-spec-pipeline.md',
|
|
16
|
+
];
|
|
17
|
+
export const COMMON_SCRIPTS = getManifestScripts('codex')
|
|
18
|
+
.filter((script) => script !== 'codex-auto-backup-hook.sh');
|
|
19
|
+
export const COMMON_HOOK_SCRIPTS = getManifestHooks('codex')
|
|
20
|
+
.filter((script) => script !== 'codex-auto-backup-hook.sh');
|
|
21
|
+
export function scriptsForAgent(agent) {
|
|
22
|
+
return getManifestScripts(agent);
|
|
23
|
+
}
|
|
24
|
+
export function hookScriptsForAgent(agent) {
|
|
25
|
+
return getManifestHooks(agent);
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=assets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assets.js","sourceRoot":"","sources":["../../../src/domains/skill/assets.ts"],"names":[],"mappings":"AACA,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAE/B,MAAM,CAAC,MAAM,UAAU,GAAG,qBAAqB,EAAE,CAAC;AAClD,MAAM,CAAC,MAAM,SAAS,GAAG,gBAAgB,EAAE,CAAC;AAE5C,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,uBAAuB;IACvB,sBAAsB;IACtB,mBAAmB;IACnB,qBAAqB;IACrB,wBAAwB;IACxB,qBAAqB;IACrB,sBAAsB;CACvB,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,QAAQ;IACR,sBAAsB;CACvB,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,kBAAkB,CAAC,OAAO,CAAC;KACtD,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,KAAK,2BAA2B,CAAC,CAAC;AAE9D,MAAM,CAAC,MAAM,mBAAmB,GAAG,gBAAgB,CAAC,OAAO,CAAC;KACzD,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,KAAK,2BAA2B,CAAC,CAAC;AAE9D,MAAM,UAAU,eAAe,CAAC,KAAY;IAC1C,OAAO,kBAAkB,CAAC,KAAK,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAAY;IAC9C,OAAO,gBAAgB,CAAC,KAAK,CAAC,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { computeDirHash } from '../../platform/fs.js';
|
|
4
|
+
import { getPlatformPaths } from '../../platform/paths.js';
|
|
5
|
+
import { parseAgentSelection, resolveAgents } from '../agent.js';
|
|
6
|
+
export function checkSkillDeployment(skillName, options = {}) {
|
|
7
|
+
const agents = resolveAgents(parseAgentSelection(options.agent));
|
|
8
|
+
const readyPaths = [];
|
|
9
|
+
for (const agent of agents) {
|
|
10
|
+
const platform = getPlatformPaths(agent);
|
|
11
|
+
const skillPath = path.join(platform.skillsDir, skillName);
|
|
12
|
+
const skillFile = path.join(skillPath, 'SKILL.md');
|
|
13
|
+
if (!existsSync(skillFile)) {
|
|
14
|
+
console.error(`Error: ${skillName} not deployed for ${platform.name}. Run: superflow init --agent ${agent}`);
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
computeDirHash(skillPath);
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
console.error(`[FAIL] ${platform.name} integrity check failed: ${err.message}`);
|
|
22
|
+
process.exit(2);
|
|
23
|
+
}
|
|
24
|
+
readyPaths.push(` ${platform.name}: ${skillFile}`);
|
|
25
|
+
}
|
|
26
|
+
console.log(`✓ ${skillName} ready at:`);
|
|
27
|
+
for (const readyPath of readyPaths) {
|
|
28
|
+
console.log(readyPath);
|
|
29
|
+
}
|
|
30
|
+
console.log(`\n→ Agent should load this skill via description matching.`);
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../../../src/domains/skill/check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAMjE,MAAM,UAAU,oBAAoB,CAClC,SAAiB,EACjB,UAA6B,EAAE;IAE/B,MAAM,MAAM,GAAG,aAAa,CAAC,mBAAmB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IACjE,MAAM,UAAU,GAAa,EAAE,CAAC;IAEhC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;QACzC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QAC3D,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;QACnD,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC3B,OAAO,CAAC,KAAK,CAAC,UAAU,SAAS,qBAAqB,QAAQ,CAAC,IAAI,iCAAiC,KAAK,EAAE,CAAC,CAAC;YAC7G,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,IAAI,CAAC;YACH,cAAc,CAAC,SAAS,CAAC,CAAC;QAC5B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,UAAU,QAAQ,CAAC,IAAI,4BAA6B,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;YAC3F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,UAAU,CAAC,IAAI,CAAC,KAAK,QAAQ,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,SAAS,YAAY,CAAC,CAAC;IACxC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACzB,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,4DAA4D,CAAC,CAAC;AAC5E,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import { existsSync } from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
export async function deploySkill(name, assetsDir, skillsDir, options = {}) {
|
|
5
|
+
const source = path.join(assetsDir, name);
|
|
6
|
+
const dest = path.join(skillsDir, name);
|
|
7
|
+
if (existsSync(dest)) {
|
|
8
|
+
if (options.skipExisting)
|
|
9
|
+
return;
|
|
10
|
+
if (options.overwrite !== true) {
|
|
11
|
+
const ts = Date.now();
|
|
12
|
+
const backup = path.join(skillsDir, `${name}.backup-${ts}`);
|
|
13
|
+
await fs.cp(dest, backup, { recursive: true });
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
await fs.rm(dest, { recursive: true, force: true });
|
|
17
|
+
await copySkillTree(source, dest, options.agent ?? 'codex');
|
|
18
|
+
}
|
|
19
|
+
export async function listDeployedSkills(skillsDir) {
|
|
20
|
+
if (!existsSync(skillsDir))
|
|
21
|
+
return [];
|
|
22
|
+
const entries = await fs.readdir(skillsDir, { withFileTypes: true });
|
|
23
|
+
return entries
|
|
24
|
+
.filter((e) => e.isDirectory() && !e.name.startsWith('.'))
|
|
25
|
+
.map((e) => e.name);
|
|
26
|
+
}
|
|
27
|
+
async function copySkillTree(source, dest, agent) {
|
|
28
|
+
const stat = await fs.stat(source);
|
|
29
|
+
if (stat.isDirectory()) {
|
|
30
|
+
await fs.mkdir(dest, { recursive: true });
|
|
31
|
+
const entries = await fs.readdir(source, { withFileTypes: true });
|
|
32
|
+
for (const entry of entries) {
|
|
33
|
+
await copySkillTree(path.join(source, entry.name), path.join(dest, entry.name), agent);
|
|
34
|
+
}
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
await fs.mkdir(path.dirname(dest), { recursive: true });
|
|
38
|
+
if (shouldRewriteSkillFile(source)) {
|
|
39
|
+
const content = await fs.readFile(source, 'utf-8');
|
|
40
|
+
await fs.writeFile(dest, rewriteSkillContent(content, agent), 'utf-8');
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
await fs.copyFile(source, dest);
|
|
44
|
+
}
|
|
45
|
+
function shouldRewriteSkillFile(file) {
|
|
46
|
+
return /\.(md|yaml|yml|json)$/i.test(file);
|
|
47
|
+
}
|
|
48
|
+
function rewriteSkillContent(content, agent) {
|
|
49
|
+
if (agent === 'codex')
|
|
50
|
+
return content;
|
|
51
|
+
if (agent === 'opencode') {
|
|
52
|
+
return content
|
|
53
|
+
.replaceAll('~/.codex/hooks', '~/.opencode/scripts')
|
|
54
|
+
.replaceAll('~/.codex/skills', '~/.opencode/skills')
|
|
55
|
+
.replaceAll('Codex Hooks', 'OpenCode Commands');
|
|
56
|
+
}
|
|
57
|
+
return content
|
|
58
|
+
.replaceAll('~/.codex/hooks', '~/.claude/scripts')
|
|
59
|
+
.replaceAll('~/.codex/skills', '~/.claude/skills')
|
|
60
|
+
.replaceAll('Codex Hooks', 'Claude Code Hooks');
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=deploy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deploy.js","sourceRoot":"","sources":["../../../src/domains/skill/deploy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
export async function deployPrompts(promptNames, assetsDir, promptsDir, options = {}) {
|
|
4
|
+
await fs.mkdir(promptsDir, { recursive: true });
|
|
5
|
+
for (const name of promptNames) {
|
|
6
|
+
const source = path.join(assetsDir, name);
|
|
7
|
+
const dest = path.join(promptsDir, name);
|
|
8
|
+
if (options.skipExisting) {
|
|
9
|
+
try {
|
|
10
|
+
await fs.access(dest);
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
// prompt does not exist; deploy it below.
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
await fs.cp(source, dest, { recursive: false, force: true });
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../../src/domains/skill/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,WAAqB,EACrB,SAAiB,EACjB,UAAkB,EAClB,UAAsC,EAAE;IAExC,MAAM,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEhD,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QACzC,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;YACzB,IAAI,CAAC;gBACH,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBACtB,SAAS;YACX,CAAC;YAAC,MAAM,CAAC;gBACP,0CAA0C;YAC5C,CAAC;QACH,CAAC;QACD,MAAM,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/D,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import { existsSync } from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
export async function deployRules(ruleNames, assetsDir, rulesDir, options = {}) {
|
|
5
|
+
await fs.mkdir(rulesDir, { recursive: true });
|
|
6
|
+
for (const name of ruleNames) {
|
|
7
|
+
const source = path.join(assetsDir, name);
|
|
8
|
+
const dest = path.join(rulesDir, name);
|
|
9
|
+
if (options.skipExisting && existsSync(dest))
|
|
10
|
+
continue;
|
|
11
|
+
await fs.cp(source, dest, { recursive: false, force: true });
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function rulePath(rulesDir, ruleName) {
|
|
15
|
+
return path.join(rulesDir, ruleName);
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=rules.js.map
|