create-takt-sdd 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +16 -0
- package/dist/generated/takt-ref.js +2 -0
- package/dist/i18n.js +34 -16
- package/dist/install.js +134 -19
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -16,6 +16,8 @@ function parseArgs(argv) {
|
|
|
16
16
|
help: false,
|
|
17
17
|
version: false,
|
|
18
18
|
tag: undefined,
|
|
19
|
+
withoutSkills: false,
|
|
20
|
+
refsPath: "references/takt",
|
|
19
21
|
};
|
|
20
22
|
for (let i = 0; i < argv.length; i++) {
|
|
21
23
|
const arg = argv[i];
|
|
@@ -44,6 +46,18 @@ function parseArgs(argv) {
|
|
|
44
46
|
case "--dry-run":
|
|
45
47
|
args.dryRun = true;
|
|
46
48
|
break;
|
|
49
|
+
case "--without-skills":
|
|
50
|
+
args.withoutSkills = true;
|
|
51
|
+
break;
|
|
52
|
+
case "--refs-path": {
|
|
53
|
+
const value = argv[++i];
|
|
54
|
+
if (!value) {
|
|
55
|
+
console.error('Error: --refs-path requires a value (e.g. "references/takt")');
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
args.refsPath = value;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
47
61
|
case "-h":
|
|
48
62
|
case "--help":
|
|
49
63
|
args.help = true;
|
|
@@ -76,6 +90,8 @@ async function main() {
|
|
|
76
90
|
force: args.force,
|
|
77
91
|
dryRun: args.dryRun,
|
|
78
92
|
tag: args.tag,
|
|
93
|
+
withoutSkills: args.withoutSkills,
|
|
94
|
+
refsPath: args.refsPath,
|
|
79
95
|
cwd: process.cwd(),
|
|
80
96
|
});
|
|
81
97
|
}
|
package/dist/i18n.js
CHANGED
|
@@ -7,21 +7,30 @@ const en = {
|
|
|
7
7
|
dryRunHeader: "[dry-run] The following files would be installed:",
|
|
8
8
|
dryRunItem: (path) => ` ${path}`,
|
|
9
9
|
dryRunSkipped: "[dry-run] No files were written.",
|
|
10
|
-
taktNotFound: "Warning: takt is not installed. Install it first: https://github.com/nrslib/takt",
|
|
11
10
|
tarNotFound: "Error: tar command is required.",
|
|
12
11
|
archiveError: "Error: .takt/ not found in the downloaded archive.",
|
|
13
12
|
scriptsAdded: (count) => `Added ${count} npm scripts to package.json`,
|
|
14
13
|
scriptsSkipped: (keys) => `Skipped existing scripts: ${keys.join(", ")}`,
|
|
15
|
-
scriptsCreated: "Created package.json with npm scripts",
|
|
14
|
+
scriptsCreated: "Created package.json with npm scripts and devDependencies",
|
|
15
|
+
depsAdded: (keys) => `Added devDependencies: ${keys.join(", ")}`,
|
|
16
|
+
installingSkills: "Installing takt skills to .agent/skills/...",
|
|
17
|
+
skillInstalled: (name) => `Installed skill: ${name}`,
|
|
18
|
+
skillSymlinked: (name, target) => `Symlinked ${target}/${name} -> .agent/skills/${name}`,
|
|
19
|
+
downloadingTaktRefs: (refsPath) => `Downloading takt builtins to ${refsPath}/...`,
|
|
20
|
+
taktRefsInstalled: "Installed takt references (builtins, docs)",
|
|
21
|
+
taktRefsSkipped: "Takt references already exist, skipping",
|
|
22
|
+
taktRefsError: "Warning: Failed to download takt references. Skills may not find style guides.",
|
|
16
23
|
helpText: `Usage: npx create-takt-sdd [options]
|
|
17
24
|
|
|
18
25
|
Options:
|
|
19
|
-
--tag <version>
|
|
20
|
-
--lang <en|ja>
|
|
21
|
-
--force
|
|
22
|
-
--dry-run
|
|
23
|
-
-
|
|
24
|
-
-
|
|
26
|
+
--tag <version> Version to install ("latest", "0.2.0", default: installer version)
|
|
27
|
+
--lang <en|ja> Message language (default: en)
|
|
28
|
+
--force Overwrite existing .takt/ directory
|
|
29
|
+
--dry-run Preview without writing files
|
|
30
|
+
--without-skills Skip installing takt skills to .agent/skills/
|
|
31
|
+
--refs-path <path> Path for takt references (default: references/takt)
|
|
32
|
+
-h, --help Show this help
|
|
33
|
+
-v, --version Show version`,
|
|
25
34
|
usageExamples: `
|
|
26
35
|
Installed to: .takt/
|
|
27
36
|
|
|
@@ -45,21 +54,30 @@ const ja = {
|
|
|
45
54
|
dryRunHeader: "[dry-run] 以下のファイルがインストールされます:",
|
|
46
55
|
dryRunItem: (path) => ` ${path}`,
|
|
47
56
|
dryRunSkipped: "[dry-run] ファイルは書き込まれませんでした。",
|
|
48
|
-
taktNotFound: "警告: takt がインストールされていません。先にインストールしてください: https://github.com/nrslib/takt",
|
|
49
57
|
tarNotFound: "エラー: tar コマンドが必要です。",
|
|
50
58
|
archiveError: "エラー: ダウンロードしたアーカイブに .takt/ が見つかりません。",
|
|
51
59
|
scriptsAdded: (count) => `package.json に ${count} 個の npm scripts を追加しました`,
|
|
52
60
|
scriptsSkipped: (keys) => `既存のスクリプトをスキップしました: ${keys.join(", ")}`,
|
|
53
|
-
scriptsCreated: "npm scripts 付きの package.json を作成しました",
|
|
61
|
+
scriptsCreated: "npm scripts と devDependencies 付きの package.json を作成しました",
|
|
62
|
+
depsAdded: (keys) => `devDependencies を追加しました: ${keys.join(", ")}`,
|
|
63
|
+
installingSkills: ".agent/skills/ に takt スキルをインストール中...",
|
|
64
|
+
skillInstalled: (name) => `スキルをインストールしました: ${name}`,
|
|
65
|
+
skillSymlinked: (name, target) => `シンボリックリンク作成: ${target}/${name} -> .agent/skills/${name}`,
|
|
66
|
+
downloadingTaktRefs: (refsPath) => `${refsPath}/ に takt ビルトインをダウンロード中...`,
|
|
67
|
+
taktRefsInstalled: "takt リファレンスをインストールしました(builtins, docs)",
|
|
68
|
+
taktRefsSkipped: "takt リファレンスは既に存在するためスキップしました",
|
|
69
|
+
taktRefsError: "警告: takt リファレンスのダウンロードに失敗しました。スキルがスタイルガイドを参照できない可能性があります。",
|
|
54
70
|
helpText: `使い方: npx create-takt-sdd [オプション]
|
|
55
71
|
|
|
56
72
|
オプション:
|
|
57
|
-
--tag <version>
|
|
58
|
-
--lang <en|ja>
|
|
59
|
-
--force
|
|
60
|
-
--dry-run
|
|
61
|
-
-
|
|
62
|
-
-
|
|
73
|
+
--tag <version> インストールするバージョン ("latest", "0.2.0", デフォルト: インストーラのバージョン)
|
|
74
|
+
--lang <en|ja> メッセージ言語 (デフォルト: en)
|
|
75
|
+
--force 既存の .takt/ を上書き
|
|
76
|
+
--dry-run プレビューのみ(ファイル書き込みなし)
|
|
77
|
+
--without-skills takt スキルのインストールをスキップ
|
|
78
|
+
--refs-path <path> takt リファレンスのパス(デフォルト: references/takt)
|
|
79
|
+
-h, --help ヘルプを表示
|
|
80
|
+
-v, --version バージョンを表示`,
|
|
63
81
|
usageExamples: `
|
|
64
82
|
インストール先: .takt/
|
|
65
83
|
|
package/dist/install.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { execSync } from "node:child_process";
|
|
2
|
-
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, symlinkSync, statSync, writeFileSync } from "node:fs";
|
|
3
3
|
import https from "node:https";
|
|
4
4
|
import { createWriteStream } from "node:fs";
|
|
5
5
|
import { mkdtempSync } from "node:fs";
|
|
@@ -7,6 +7,7 @@ import { tmpdir } from "node:os";
|
|
|
7
7
|
import { dirname, join, relative, resolve } from "node:path";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
9
|
import { getMessages } from "./i18n.js";
|
|
10
|
+
import { TAKT_REF_HASH } from "./generated/takt-ref.js";
|
|
10
11
|
const __filename = fileURLToPath(import.meta.url);
|
|
11
12
|
const __dirname = dirname(__filename);
|
|
12
13
|
function getInstallerVersion() {
|
|
@@ -15,7 +16,9 @@ function getInstallerVersion() {
|
|
|
15
16
|
return pkg.version;
|
|
16
17
|
}
|
|
17
18
|
const REPO = "j5ik2o/takt-sdd";
|
|
19
|
+
const TAKT_REPO = "nrslib/takt";
|
|
18
20
|
const TARGET_DIR = ".takt";
|
|
21
|
+
const DEFAULT_REFS_PATH = "references/takt";
|
|
19
22
|
const FACET_DIRS = [
|
|
20
23
|
"pieces",
|
|
21
24
|
"personas",
|
|
@@ -24,6 +27,19 @@ const FACET_DIRS = [
|
|
|
24
27
|
"knowledge",
|
|
25
28
|
"output-contracts",
|
|
26
29
|
];
|
|
30
|
+
const TAKT_SKILLS = [
|
|
31
|
+
"takt-analyze",
|
|
32
|
+
"takt-facet",
|
|
33
|
+
"takt-optimize",
|
|
34
|
+
"takt-piece",
|
|
35
|
+
];
|
|
36
|
+
const SKILL_SYMLINK_TARGETS = [
|
|
37
|
+
".claude/skills",
|
|
38
|
+
".codex/skills",
|
|
39
|
+
];
|
|
40
|
+
const SDD_DEV_DEPENDENCIES = {
|
|
41
|
+
"takt": "^0.20.0",
|
|
42
|
+
};
|
|
27
43
|
const SDD_SCRIPTS = {
|
|
28
44
|
"sdd": "takt --pipeline --skip-git --create-worktree no -w sdd -t",
|
|
29
45
|
"sdd:requirements": "takt --pipeline --skip-git --create-worktree no -w sdd-requirements -t",
|
|
@@ -134,13 +150,6 @@ function collectFiles(dir, base) {
|
|
|
134
150
|
export async function install(options) {
|
|
135
151
|
const msg = getMessages(options.lang);
|
|
136
152
|
const targetPath = join(options.cwd, TARGET_DIR);
|
|
137
|
-
// takt の存在チェック
|
|
138
|
-
try {
|
|
139
|
-
execSync("which takt", { stdio: "ignore" });
|
|
140
|
-
}
|
|
141
|
-
catch {
|
|
142
|
-
warn(msg.taktNotFound);
|
|
143
|
-
}
|
|
144
153
|
// tar の存在チェック
|
|
145
154
|
try {
|
|
146
155
|
execSync("which tar", { stdio: "ignore" });
|
|
@@ -173,16 +182,27 @@ export async function install(options) {
|
|
|
173
182
|
if (options.dryRun) {
|
|
174
183
|
info(msg.dryRunHeader);
|
|
175
184
|
for (const dir of FACET_DIRS) {
|
|
176
|
-
const srcDir = join(extractedTakt, dir);
|
|
185
|
+
const srcDir = join(extractedTakt, options.lang, dir);
|
|
177
186
|
if (existsSync(srcDir)) {
|
|
178
|
-
for (const file of collectFiles(srcDir, extractedTakt)) {
|
|
187
|
+
for (const file of collectFiles(srcDir, join(extractedTakt, options.lang))) {
|
|
179
188
|
console.log(msg.dryRunItem(join(TARGET_DIR, file)));
|
|
180
189
|
}
|
|
181
190
|
}
|
|
182
191
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
192
|
+
if (!options.withoutSkills) {
|
|
193
|
+
for (const skill of TAKT_SKILLS) {
|
|
194
|
+
const skillSrc = join(extractedDir, ".agent", "skills", skill);
|
|
195
|
+
if (existsSync(skillSrc)) {
|
|
196
|
+
for (const file of collectFiles(skillSrc, join(extractedDir, ".agent", "skills"))) {
|
|
197
|
+
console.log(msg.dryRunItem(join(".agent", "skills", file)));
|
|
198
|
+
}
|
|
199
|
+
for (const target of SKILL_SYMLINK_TARGETS) {
|
|
200
|
+
console.log(msg.dryRunItem(`${target}/${skill} -> ../../.agent/skills/${skill}`));
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
console.log(msg.dryRunItem(`${options.refsPath}/builtins/`));
|
|
205
|
+
console.log(msg.dryRunItem(`${options.refsPath}/docs/`));
|
|
186
206
|
}
|
|
187
207
|
console.log("");
|
|
188
208
|
info(msg.dryRunSkipped);
|
|
@@ -192,7 +212,7 @@ export async function install(options) {
|
|
|
192
212
|
info(msg.installing);
|
|
193
213
|
mkdirSync(targetPath, { recursive: true });
|
|
194
214
|
for (const dir of FACET_DIRS) {
|
|
195
|
-
const srcDir = join(extractedTakt, dir);
|
|
215
|
+
const srcDir = join(extractedTakt, options.lang, dir);
|
|
196
216
|
if (existsSync(srcDir)) {
|
|
197
217
|
const destDir = join(targetPath, dir);
|
|
198
218
|
if (existsSync(destDir)) {
|
|
@@ -201,12 +221,94 @@ export async function install(options) {
|
|
|
201
221
|
cpSync(srcDir, destDir, { recursive: true });
|
|
202
222
|
}
|
|
203
223
|
}
|
|
204
|
-
// .gitignore
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
224
|
+
// .gitignore は takt が初回実行時に自動配置するため、インストーラでは生成しない
|
|
225
|
+
// takt スキルのインストール
|
|
226
|
+
const agentSkillsDir = join(options.cwd, ".agent", "skills");
|
|
227
|
+
const extractedSkillsDir = join(extractedDir, ".agent", "skills");
|
|
228
|
+
if (!options.withoutSkills && existsSync(extractedSkillsDir)) {
|
|
229
|
+
info(msg.installingSkills);
|
|
230
|
+
mkdirSync(agentSkillsDir, { recursive: true });
|
|
231
|
+
for (const skill of TAKT_SKILLS) {
|
|
232
|
+
const skillSrc = join(extractedSkillsDir, skill);
|
|
233
|
+
if (!existsSync(skillSrc))
|
|
234
|
+
continue;
|
|
235
|
+
const skillDest = join(agentSkillsDir, skill);
|
|
236
|
+
if (existsSync(skillDest)) {
|
|
237
|
+
rmSync(skillDest, { recursive: true });
|
|
238
|
+
}
|
|
239
|
+
cpSync(skillSrc, skillDest, { recursive: true });
|
|
240
|
+
// SKILL.md 内の references/takt パスを置換
|
|
241
|
+
if (options.refsPath !== DEFAULT_REFS_PATH) {
|
|
242
|
+
const skillMd = join(skillDest, "SKILL.md");
|
|
243
|
+
if (existsSync(skillMd)) {
|
|
244
|
+
const content = readFileSync(skillMd, "utf-8");
|
|
245
|
+
const updated = content.replaceAll(DEFAULT_REFS_PATH, options.refsPath);
|
|
246
|
+
writeFileSync(skillMd, updated, "utf-8");
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
info(msg.skillInstalled(skill));
|
|
250
|
+
}
|
|
251
|
+
// .claude/skills/ と .codex/skills/ にシンボリックリンクを作成
|
|
252
|
+
for (const target of SKILL_SYMLINK_TARGETS) {
|
|
253
|
+
const targetDir = join(options.cwd, target);
|
|
254
|
+
mkdirSync(targetDir, { recursive: true });
|
|
255
|
+
for (const skill of TAKT_SKILLS) {
|
|
256
|
+
if (!existsSync(join(agentSkillsDir, skill)))
|
|
257
|
+
continue;
|
|
258
|
+
const linkPath = join(targetDir, skill);
|
|
259
|
+
if (existsSync(linkPath)) {
|
|
260
|
+
rmSync(linkPath, { recursive: true });
|
|
261
|
+
}
|
|
262
|
+
symlinkSync(`../../.agent/skills/${skill}`, linkPath);
|
|
263
|
+
info(msg.skillSymlinked(skill, target));
|
|
264
|
+
}
|
|
265
|
+
}
|
|
208
266
|
}
|
|
209
|
-
//
|
|
267
|
+
// takt リファレンスのダウンロード(スキルが参照するbuiltins等)
|
|
268
|
+
if (!options.withoutSkills) {
|
|
269
|
+
const refsDir = join(options.cwd, options.refsPath);
|
|
270
|
+
if (!existsSync(join(refsDir, "builtins"))) {
|
|
271
|
+
info(msg.downloadingTaktRefs(options.refsPath));
|
|
272
|
+
const taktTmpDir = mkdtempSync(join(tmpdir(), "takt-refs-"));
|
|
273
|
+
try {
|
|
274
|
+
const taktArchive = join(taktTmpDir, "takt.tar.gz");
|
|
275
|
+
const taktTarball = `https://github.com/${TAKT_REPO}/archive/${TAKT_REF_HASH}.tar.gz`;
|
|
276
|
+
await download(taktTarball, taktArchive);
|
|
277
|
+
execSync(`tar -xzf "${taktArchive}" -C "${taktTmpDir}"`, { stdio: "ignore" });
|
|
278
|
+
// takt-{hash}/ ディレクトリを探す
|
|
279
|
+
const taktExtracted = readdirSync(taktTmpDir).find((d) => d.startsWith("takt-") && statSync(join(taktTmpDir, d)).isDirectory());
|
|
280
|
+
if (taktExtracted) {
|
|
281
|
+
const taktRoot = join(taktTmpDir, taktExtracted);
|
|
282
|
+
mkdirSync(refsDir, { recursive: true });
|
|
283
|
+
// builtins/ をコピー
|
|
284
|
+
const builtinsSrc = join(taktRoot, "builtins");
|
|
285
|
+
if (existsSync(builtinsSrc)) {
|
|
286
|
+
cpSync(builtinsSrc, join(refsDir, "builtins"), { recursive: true });
|
|
287
|
+
}
|
|
288
|
+
// docs/faceted-prompting.ja.md をコピー
|
|
289
|
+
const fpSrc = join(taktRoot, "docs", "faceted-prompting.ja.md");
|
|
290
|
+
if (existsSync(fpSrc)) {
|
|
291
|
+
mkdirSync(join(refsDir, "docs"), { recursive: true });
|
|
292
|
+
cpSync(fpSrc, join(refsDir, "docs", "faceted-prompting.ja.md"));
|
|
293
|
+
}
|
|
294
|
+
info(msg.taktRefsInstalled);
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
warn(msg.taktRefsError);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
catch {
|
|
301
|
+
warn(msg.taktRefsError);
|
|
302
|
+
}
|
|
303
|
+
finally {
|
|
304
|
+
rmSync(taktTmpDir, { recursive: true, force: true });
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
info(msg.taktRefsSkipped);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
// package.json に npm scripts と devDependencies を追加
|
|
210
312
|
const pkgPath = join(options.cwd, "package.json");
|
|
211
313
|
if (existsSync(pkgPath)) {
|
|
212
314
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
@@ -223,6 +325,15 @@ export async function install(options) {
|
|
|
223
325
|
}
|
|
224
326
|
}
|
|
225
327
|
pkg.scripts = scripts;
|
|
328
|
+
const devDeps = pkg.devDependencies ?? {};
|
|
329
|
+
const depsAdded = [];
|
|
330
|
+
for (const [key, value] of Object.entries(SDD_DEV_DEPENDENCIES)) {
|
|
331
|
+
if (devDeps[key] === undefined) {
|
|
332
|
+
devDeps[key] = value;
|
|
333
|
+
depsAdded.push(key);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
pkg.devDependencies = devDeps;
|
|
226
337
|
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf-8");
|
|
227
338
|
if (added.length > 0) {
|
|
228
339
|
info(msg.scriptsAdded(added.length));
|
|
@@ -230,11 +341,15 @@ export async function install(options) {
|
|
|
230
341
|
if (skipped.length > 0) {
|
|
231
342
|
warn(msg.scriptsSkipped(skipped));
|
|
232
343
|
}
|
|
344
|
+
if (depsAdded.length > 0) {
|
|
345
|
+
info(msg.depsAdded(depsAdded));
|
|
346
|
+
}
|
|
233
347
|
}
|
|
234
348
|
else {
|
|
235
349
|
const pkg = {
|
|
236
350
|
private: true,
|
|
237
351
|
scripts: { ...SDD_SCRIPTS },
|
|
352
|
+
devDependencies: { ...SDD_DEV_DEPENDENCIES },
|
|
238
353
|
};
|
|
239
354
|
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf-8");
|
|
240
355
|
info(msg.scriptsCreated);
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-takt-sdd",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Installer for takt-sdd: Spec-Driven Development workflow for takt",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"create-takt-sdd": "./dist/cli.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
|
-
"build": "tsc && node scripts/add-shebang.js",
|
|
10
|
+
"build": "node scripts/embed-takt-ref.js && tsc && node scripts/add-shebang.js",
|
|
11
11
|
"prepare": "npm run build"
|
|
12
12
|
},
|
|
13
13
|
"keywords": [
|