create-takt-sdd 0.15.0 → 0.16.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 +0 -16
- package/dist/i18n.js +0 -18
- package/dist/install.js +18 -215
- package/package.json +2 -2
- package/dist/generated/takt-ref.js +0 -2
package/dist/cli.js
CHANGED
|
@@ -19,8 +19,6 @@ function parseArgs(argv) {
|
|
|
19
19
|
help: false,
|
|
20
20
|
version: false,
|
|
21
21
|
tag: undefined,
|
|
22
|
-
withoutSkills: false,
|
|
23
|
-
refsPath: "references/takt",
|
|
24
22
|
layout: "auto",
|
|
25
23
|
};
|
|
26
24
|
for (let i = 0; i < argv.length; i++) {
|
|
@@ -50,18 +48,6 @@ function parseArgs(argv) {
|
|
|
50
48
|
case "--dry-run":
|
|
51
49
|
args.dryRun = true;
|
|
52
50
|
break;
|
|
53
|
-
case "--without-skills":
|
|
54
|
-
args.withoutSkills = true;
|
|
55
|
-
break;
|
|
56
|
-
case "--refs-path": {
|
|
57
|
-
const value = argv[++i];
|
|
58
|
-
if (!value) {
|
|
59
|
-
console.error('Error: --refs-path requires a value (e.g. "references/takt")');
|
|
60
|
-
process.exit(1);
|
|
61
|
-
}
|
|
62
|
-
args.refsPath = value;
|
|
63
|
-
break;
|
|
64
|
-
}
|
|
65
51
|
case "--layout": {
|
|
66
52
|
const value = argv[++i];
|
|
67
53
|
if (!value || !isLayout(value)) {
|
|
@@ -103,8 +89,6 @@ async function main() {
|
|
|
103
89
|
force: args.force,
|
|
104
90
|
dryRun: args.dryRun,
|
|
105
91
|
tag: args.tag,
|
|
106
|
-
withoutSkills: args.withoutSkills,
|
|
107
|
-
refsPath: args.refsPath,
|
|
108
92
|
layout: args.layout,
|
|
109
93
|
cwd: process.cwd(),
|
|
110
94
|
});
|
package/dist/i18n.js
CHANGED
|
@@ -16,13 +16,6 @@ const en = {
|
|
|
16
16
|
scriptsCreated: "Created package.json with npm scripts and devDependencies",
|
|
17
17
|
depsAdded: (keys) => `Added devDependencies: ${keys.join(", ")}`,
|
|
18
18
|
depsUpdated: (keys) => `Updated devDependencies: ${keys.join(", ")}`,
|
|
19
|
-
installingSkills: "Installing takt skills to .agents/skills/...",
|
|
20
|
-
skillInstalled: (name) => `Installed skill: ${name}`,
|
|
21
|
-
skillSymlinked: (name, target) => `Symlinked ${target}/${name} -> .agents/skills/${name}`,
|
|
22
|
-
downloadingTaktRefs: (refsPath) => `Downloading takt builtins to ${refsPath}/...`,
|
|
23
|
-
taktRefsInstalled: "Installed takt references (builtins, docs)",
|
|
24
|
-
taktRefsSkipped: "Takt references already exist, skipping",
|
|
25
|
-
taktRefsError: "Warning: Failed to download takt references. Skills may not find style guides.",
|
|
26
19
|
layoutDetected: (layout) => `Using ${layout} layout`,
|
|
27
20
|
fileAdded: (path) => `Added: ${path}`,
|
|
28
21
|
fileUpdated: (path) => `Updated: ${path}`,
|
|
@@ -35,9 +28,7 @@ Options:
|
|
|
35
28
|
--lang <en|ja> Message language (default: en)
|
|
36
29
|
--force Overwrite existing .takt/ directory (ignored if manifest exists)
|
|
37
30
|
--dry-run Preview without writing files
|
|
38
|
-
--without-skills Skip installing takt skills to .agents/skills/
|
|
39
31
|
--layout <mode> Directory layout: auto, modern, legacy (default: auto)
|
|
40
|
-
--refs-path <path> Path for takt references (default: references/takt)
|
|
41
32
|
-h, --help Show this help
|
|
42
33
|
-v, --version Show version`,
|
|
43
34
|
usageExamples: `
|
|
@@ -79,13 +70,6 @@ const ja = {
|
|
|
79
70
|
scriptsCreated: "npm scripts と devDependencies 付きの package.json を作成しました",
|
|
80
71
|
depsAdded: (keys) => `devDependencies を追加しました: ${keys.join(", ")}`,
|
|
81
72
|
depsUpdated: (keys) => `devDependencies を更新しました: ${keys.join(", ")}`,
|
|
82
|
-
installingSkills: ".agents/skills/ に takt スキルをインストール中...",
|
|
83
|
-
skillInstalled: (name) => `スキルをインストールしました: ${name}`,
|
|
84
|
-
skillSymlinked: (name, target) => `シンボリックリンク作成: ${target}/${name} -> .agents/skills/${name}`,
|
|
85
|
-
downloadingTaktRefs: (refsPath) => `${refsPath}/ に takt ビルトインをダウンロード中...`,
|
|
86
|
-
taktRefsInstalled: "takt リファレンスをインストールしました(builtins, docs)",
|
|
87
|
-
taktRefsSkipped: "takt リファレンスは既に存在するためスキップしました",
|
|
88
|
-
taktRefsError: "警告: takt リファレンスのダウンロードに失敗しました。スキルがスタイルガイドを参照できない可能性があります。",
|
|
89
73
|
layoutDetected: (layout) => `${layout} レイアウトを使用します`,
|
|
90
74
|
fileAdded: (path) => `追加: ${path}`,
|
|
91
75
|
fileUpdated: (path) => `更新: ${path}`,
|
|
@@ -98,9 +82,7 @@ const ja = {
|
|
|
98
82
|
--lang <en|ja> メッセージ言語 (デフォルト: en)
|
|
99
83
|
--force 既存の .takt/ を上書き(マニフェストがある場合は無視)
|
|
100
84
|
--dry-run プレビューのみ(ファイル書き込みなし)
|
|
101
|
-
--without-skills takt スキルのインストールをスキップ
|
|
102
85
|
--layout <mode> ディレクトリレイアウト: auto, modern, legacy(デフォルト: auto)
|
|
103
|
-
--refs-path <path> takt リファレンスのパス(デフォルト: references/takt)
|
|
104
86
|
-h, --help ヘルプを表示
|
|
105
87
|
-v, --version バージョンを表示`,
|
|
106
88
|
usageExamples: `
|
package/dist/install.js
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { execSync } from "node:child_process";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
|
-
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync,
|
|
3
|
+
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
4
4
|
import https from "node:https";
|
|
5
|
-
import { createWriteStream } from "node:fs";
|
|
6
|
-
import { mkdtempSync } from "node:fs";
|
|
5
|
+
import { createWriteStream, mkdtempSync } from "node:fs";
|
|
7
6
|
import { tmpdir } from "node:os";
|
|
8
7
|
import { dirname, join, relative, resolve } from "node:path";
|
|
9
8
|
import { fileURLToPath } from "node:url";
|
|
10
9
|
import { getMessages } from "./i18n.js";
|
|
11
|
-
import { TAKT_REF_HASH } from "./generated/takt-ref.js";
|
|
12
10
|
const __filename = fileURLToPath(import.meta.url);
|
|
13
11
|
const __dirname = dirname(__filename);
|
|
14
12
|
function getInstallerVersion() {
|
|
@@ -17,9 +15,7 @@ function getInstallerVersion() {
|
|
|
17
15
|
return pkg.version;
|
|
18
16
|
}
|
|
19
17
|
const REPO = "j5ik2o/takt-sdd";
|
|
20
|
-
const TAKT_REPO = "nrslib/takt";
|
|
21
18
|
const TARGET_DIR = ".takt";
|
|
22
|
-
const DEFAULT_REFS_PATH = "references/takt";
|
|
23
19
|
const PIECE_DIR = "pieces";
|
|
24
20
|
const FACET_TYPES = [
|
|
25
21
|
"personas",
|
|
@@ -54,7 +50,7 @@ function detectLayout() {
|
|
|
54
50
|
function rewritePiecePathsForLegacy(piecesDir) {
|
|
55
51
|
if (!existsSync(piecesDir))
|
|
56
52
|
return;
|
|
57
|
-
for (const file of readdirSync(piecesDir).filter(f => f.endsWith(".yaml"))) {
|
|
53
|
+
for (const file of readdirSync(piecesDir).filter((f) => f.endsWith(".yaml"))) {
|
|
58
54
|
const filePath = join(piecesDir, file);
|
|
59
55
|
let content = readFileSync(filePath, "utf-8");
|
|
60
56
|
for (const type of FACET_TYPES) {
|
|
@@ -63,33 +59,22 @@ function rewritePiecePathsForLegacy(piecesDir) {
|
|
|
63
59
|
writeFileSync(filePath, content, "utf-8");
|
|
64
60
|
}
|
|
65
61
|
}
|
|
66
|
-
const TAKT_SKILLS = [
|
|
67
|
-
"takt-analyze",
|
|
68
|
-
"takt-facet",
|
|
69
|
-
"takt-optimize",
|
|
70
|
-
"takt-piece",
|
|
71
|
-
"takt-task",
|
|
72
|
-
];
|
|
73
|
-
const SKILL_SYMLINK_TARGETS = [
|
|
74
|
-
".claude/skills",
|
|
75
|
-
".codex/skills",
|
|
76
|
-
];
|
|
77
62
|
const SDD_SCRIPTS = {
|
|
78
|
-
"cc-sdd:full": "takt --pipeline --skip-git
|
|
79
|
-
"cc-sdd:requirements": "takt --pipeline --skip-git
|
|
80
|
-
"cc-sdd:validate-gap": "takt --pipeline --skip-git
|
|
81
|
-
"cc-sdd:design": "takt --pipeline --skip-git
|
|
82
|
-
"cc-sdd:validate-design": "takt --pipeline --skip-git
|
|
83
|
-
"cc-sdd:tasks": "takt --pipeline --skip-git
|
|
84
|
-
"cc-sdd:impl": "takt --pipeline --skip-git
|
|
85
|
-
"cc-sdd:validate-impl": "takt --pipeline --skip-git
|
|
86
|
-
"cc-sdd:steering": "takt --pipeline --skip-git
|
|
87
|
-
"cc-sdd:steering-custom": "takt --pipeline --skip-git
|
|
88
|
-
"opsx:full": "takt --pipeline --skip-git
|
|
89
|
-
"opsx:propose": "takt --pipeline --skip-git
|
|
90
|
-
"opsx:apply": "takt --pipeline --skip-git
|
|
91
|
-
"opsx:archive": "takt --pipeline --skip-git
|
|
92
|
-
"opsx:explore": "takt --skip-git
|
|
63
|
+
"cc-sdd:full": "takt --pipeline --skip-git -w cc-sdd-full -t",
|
|
64
|
+
"cc-sdd:requirements": "takt --pipeline --skip-git -w cc-sdd-requirements -t",
|
|
65
|
+
"cc-sdd:validate-gap": "takt --pipeline --skip-git -w cc-sdd-validate-gap -t",
|
|
66
|
+
"cc-sdd:design": "takt --pipeline --skip-git -w cc-sdd-design -t",
|
|
67
|
+
"cc-sdd:validate-design": "takt --pipeline --skip-git -w cc-sdd-validate-design -t",
|
|
68
|
+
"cc-sdd:tasks": "takt --pipeline --skip-git -w cc-sdd-tasks -t",
|
|
69
|
+
"cc-sdd:impl": "takt --pipeline --skip-git -w cc-sdd-impl -t",
|
|
70
|
+
"cc-sdd:validate-impl": "takt --pipeline --skip-git -w cc-sdd-validate-impl -t",
|
|
71
|
+
"cc-sdd:steering": "takt --pipeline --skip-git -w cc-sdd-steering -t",
|
|
72
|
+
"cc-sdd:steering-custom": "takt --pipeline --skip-git -w cc-sdd-steering-custom -t",
|
|
73
|
+
"opsx:full": "takt --pipeline --skip-git -w opsx-full -t",
|
|
74
|
+
"opsx:propose": "takt --pipeline --skip-git -w opsx-propose -t",
|
|
75
|
+
"opsx:apply": "takt --pipeline --skip-git -w opsx-apply -t",
|
|
76
|
+
"opsx:archive": "takt --pipeline --skip-git -w opsx-archive -t",
|
|
77
|
+
"opsx:explore": "takt --skip-git -w opsx-explore",
|
|
93
78
|
};
|
|
94
79
|
function info(msg) {
|
|
95
80
|
console.log(`\x1b[1;34m==>\x1b[0m ${msg}`);
|
|
@@ -144,7 +129,6 @@ function resolveTag(tagOption, installerVersion) {
|
|
|
144
129
|
if (tagOption === "latest") {
|
|
145
130
|
return fetchLatestTag();
|
|
146
131
|
}
|
|
147
|
-
// Accept both "v0.1.0" and "0.1.0"
|
|
148
132
|
return tagOption.startsWith("v") ? tagOption : `v${tagOption}`;
|
|
149
133
|
}
|
|
150
134
|
function download(url, dest) {
|
|
@@ -217,7 +201,6 @@ function syncDirectory(srcDir, destDir, srcBase, destBase, manifest, msg, cwd) {
|
|
|
217
201
|
const srcHash = computeFileHash(srcPath);
|
|
218
202
|
files[manifestKey] = srcHash;
|
|
219
203
|
if (!existsSync(destPath)) {
|
|
220
|
-
// New file — copy
|
|
221
204
|
mkdirSync(dirname(destPath), { recursive: true });
|
|
222
205
|
cpSync(srcPath, destPath);
|
|
223
206
|
info(msg.fileAdded(manifestKey));
|
|
@@ -225,24 +208,20 @@ function syncDirectory(srcDir, destDir, srcBase, destBase, manifest, msg, cwd) {
|
|
|
225
208
|
else if (manifest !== null) {
|
|
226
209
|
const recordedHash = manifest.files[manifestKey];
|
|
227
210
|
if (recordedHash === undefined) {
|
|
228
|
-
// File exists but not in manifest (pre-manifest environment)
|
|
229
211
|
warn(msg.fileSkippedCustomized(manifestKey));
|
|
230
212
|
}
|
|
231
213
|
else {
|
|
232
214
|
const currentHash = computeFileHash(destPath);
|
|
233
215
|
if (currentHash === recordedHash) {
|
|
234
|
-
// User has not modified — safe to overwrite
|
|
235
216
|
cpSync(srcPath, destPath);
|
|
236
217
|
info(msg.fileUpdated(manifestKey));
|
|
237
218
|
}
|
|
238
219
|
else {
|
|
239
|
-
// User has customized — skip
|
|
240
220
|
warn(msg.fileSkippedCustomized(manifestKey));
|
|
241
221
|
}
|
|
242
222
|
}
|
|
243
223
|
}
|
|
244
224
|
else {
|
|
245
|
-
// No manifest, fresh install or force — overwrite
|
|
246
225
|
cpSync(srcPath, destPath);
|
|
247
226
|
}
|
|
248
227
|
}
|
|
@@ -252,21 +231,18 @@ export async function install(options) {
|
|
|
252
231
|
const msg = getMessages(options.lang);
|
|
253
232
|
const targetPath = join(options.cwd, TARGET_DIR);
|
|
254
233
|
const manifestPath = join(targetPath, MANIFEST_FILE);
|
|
255
|
-
// tar の存在チェック
|
|
256
234
|
try {
|
|
257
235
|
execSync("which tar", { stdio: "ignore" });
|
|
258
236
|
}
|
|
259
237
|
catch {
|
|
260
238
|
errorExit(msg.tarNotFound);
|
|
261
239
|
}
|
|
262
|
-
// マニフェスト読み込み&モード判定
|
|
263
240
|
const manifest = loadManifest(manifestPath);
|
|
264
241
|
const isUpdate = manifest !== null;
|
|
265
242
|
const piecesExist = existsSync(join(targetPath, "pieces"));
|
|
266
243
|
if (!isUpdate && piecesExist && !options.force) {
|
|
267
244
|
errorExit(msg.existsError("npx create-takt-sdd"));
|
|
268
245
|
}
|
|
269
|
-
// ダウンロード
|
|
270
246
|
info(msg.downloading);
|
|
271
247
|
const tmpDir = mkdtempSync(join(tmpdir(), "takt-sdd-"));
|
|
272
248
|
const archivePath = join(tmpDir, "archive.tar.gz");
|
|
@@ -285,17 +261,14 @@ export async function install(options) {
|
|
|
285
261
|
}
|
|
286
262
|
const resolvedLayout = options.layout === "auto" ? detectLayout() : options.layout;
|
|
287
263
|
info(msg.layoutDetected(resolvedLayout));
|
|
288
|
-
// dry-run: ファイル一覧のみ表示
|
|
289
264
|
if (options.dryRun) {
|
|
290
265
|
info(msg.dryRunHeader);
|
|
291
|
-
// pieces
|
|
292
266
|
const piecesSrcDry = join(extractedTakt, options.lang, PIECE_DIR);
|
|
293
267
|
if (existsSync(piecesSrcDry)) {
|
|
294
268
|
for (const file of collectFiles(piecesSrcDry, piecesSrcDry)) {
|
|
295
269
|
console.log(msg.dryRunItem(join(TARGET_DIR, PIECE_DIR, file)));
|
|
296
270
|
}
|
|
297
271
|
}
|
|
298
|
-
// facets
|
|
299
272
|
for (const facetType of FACET_TYPES) {
|
|
300
273
|
const srcDir = join(extractedTakt, options.lang, srcFacetPath(facetType));
|
|
301
274
|
if (existsSync(srcDir)) {
|
|
@@ -305,33 +278,13 @@ export async function install(options) {
|
|
|
305
278
|
}
|
|
306
279
|
}
|
|
307
280
|
}
|
|
308
|
-
if (!options.withoutSkills) {
|
|
309
|
-
for (const skill of TAKT_SKILLS) {
|
|
310
|
-
const skillSrc = join(extractedDir, ".agents", "skills", skill);
|
|
311
|
-
if (existsSync(skillSrc)) {
|
|
312
|
-
for (const file of collectFiles(skillSrc, join(extractedDir, ".agents", "skills"))) {
|
|
313
|
-
// Skip language-specific SKILL files (only SKILL.md is installed)
|
|
314
|
-
if (file.endsWith("SKILL.ja.md") || file.endsWith("SKILL.en.md"))
|
|
315
|
-
continue;
|
|
316
|
-
console.log(msg.dryRunItem(join(".agents", "skills", file)));
|
|
317
|
-
}
|
|
318
|
-
for (const target of SKILL_SYMLINK_TARGETS) {
|
|
319
|
-
console.log(msg.dryRunItem(`${target}/${skill} -> ../../.agents/skills/${skill}`));
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
console.log(msg.dryRunItem(`${options.refsPath}/builtins/`));
|
|
324
|
-
console.log(msg.dryRunItem(`${options.refsPath}/docs/`));
|
|
325
|
-
}
|
|
326
281
|
console.log("");
|
|
327
282
|
info(msg.dryRunSkipped);
|
|
328
283
|
return;
|
|
329
284
|
}
|
|
330
|
-
// インストール / アップデート
|
|
331
285
|
info(isUpdate ? msg.updating : msg.installing);
|
|
332
286
|
mkdirSync(targetPath, { recursive: true });
|
|
333
287
|
const allFiles = {};
|
|
334
|
-
// pieces(legacy時はsync前にソースのパスを書き換え)
|
|
335
288
|
const piecesSrc = join(extractedTakt, options.lang, PIECE_DIR);
|
|
336
289
|
if (existsSync(piecesSrc)) {
|
|
337
290
|
const piecesDest = join(targetPath, PIECE_DIR);
|
|
@@ -348,7 +301,6 @@ export async function install(options) {
|
|
|
348
301
|
const result = syncDirectory(effectiveSrc, piecesDest, effectiveSrc, piecesDest, isUpdate ? manifest : null, msg, options.cwd);
|
|
349
302
|
Object.assign(allFiles, result.files);
|
|
350
303
|
}
|
|
351
|
-
// facets
|
|
352
304
|
for (const facetType of FACET_TYPES) {
|
|
353
305
|
const srcDir = join(extractedTakt, options.lang, srcFacetPath(facetType));
|
|
354
306
|
if (existsSync(srcDir)) {
|
|
@@ -360,152 +312,6 @@ export async function install(options) {
|
|
|
360
312
|
Object.assign(allFiles, result.files);
|
|
361
313
|
}
|
|
362
314
|
}
|
|
363
|
-
// .gitignore は takt が初回実行時に自動配置するため、インストーラでは生成しない
|
|
364
|
-
// takt スキルのインストール
|
|
365
|
-
const agentSkillsDir = join(options.cwd, ".agents", "skills");
|
|
366
|
-
const extractedSkillsDir = join(extractedDir, ".agents", "skills");
|
|
367
|
-
if (!options.withoutSkills && existsSync(extractedSkillsDir)) {
|
|
368
|
-
info(msg.installingSkills);
|
|
369
|
-
mkdirSync(agentSkillsDir, { recursive: true });
|
|
370
|
-
for (const skill of TAKT_SKILLS) {
|
|
371
|
-
const skillSrc = join(extractedSkillsDir, skill);
|
|
372
|
-
if (!existsSync(skillSrc))
|
|
373
|
-
continue;
|
|
374
|
-
// Prepare a temp copy with language selection applied
|
|
375
|
-
const skillTmp = join(tmpDir, "skill-prep", skill);
|
|
376
|
-
if (existsSync(skillTmp))
|
|
377
|
-
rmSync(skillTmp, { recursive: true });
|
|
378
|
-
cpSync(skillSrc, skillTmp, { recursive: true });
|
|
379
|
-
// Select SKILL.md based on language
|
|
380
|
-
const skillLangMd = join(skillTmp, `SKILL.${options.lang}.md`);
|
|
381
|
-
const skillMdPath = join(skillTmp, "SKILL.md");
|
|
382
|
-
if (existsSync(skillLangMd)) {
|
|
383
|
-
cpSync(skillLangMd, skillMdPath);
|
|
384
|
-
}
|
|
385
|
-
// Remove language-specific SKILL files from temp
|
|
386
|
-
for (const l of ["ja", "en"]) {
|
|
387
|
-
const langFile = join(skillTmp, `SKILL.${l}.md`);
|
|
388
|
-
if (existsSync(langFile)) {
|
|
389
|
-
rmSync(langFile);
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
// SKILL.md 内の references/takt パスを置換
|
|
393
|
-
if (options.refsPath !== DEFAULT_REFS_PATH) {
|
|
394
|
-
if (existsSync(skillMdPath)) {
|
|
395
|
-
const content = readFileSync(skillMdPath, "utf-8");
|
|
396
|
-
const updated = content.replaceAll(DEFAULT_REFS_PATH, options.refsPath);
|
|
397
|
-
writeFileSync(skillMdPath, updated, "utf-8");
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
const skillDest = join(agentSkillsDir, skill);
|
|
401
|
-
if (!isUpdate && existsSync(skillDest)) {
|
|
402
|
-
rmSync(skillDest, { recursive: true });
|
|
403
|
-
}
|
|
404
|
-
const result = syncDirectory(skillTmp, skillDest, skillTmp, skillDest, isUpdate ? manifest : null, msg, options.cwd);
|
|
405
|
-
Object.assign(allFiles, result.files);
|
|
406
|
-
info(msg.skillInstalled(skill));
|
|
407
|
-
}
|
|
408
|
-
// .claude/skills/ と .codex/skills/ にシンボリックリンクを作成
|
|
409
|
-
for (const target of SKILL_SYMLINK_TARGETS) {
|
|
410
|
-
const targetDir = join(options.cwd, target);
|
|
411
|
-
mkdirSync(targetDir, { recursive: true });
|
|
412
|
-
for (const skill of TAKT_SKILLS) {
|
|
413
|
-
if (!existsSync(join(agentSkillsDir, skill)))
|
|
414
|
-
continue;
|
|
415
|
-
const linkPath = join(targetDir, skill);
|
|
416
|
-
if (existsSync(linkPath)) {
|
|
417
|
-
rmSync(linkPath, { recursive: true });
|
|
418
|
-
}
|
|
419
|
-
symlinkSync(`../../.agents/skills/${skill}`, linkPath);
|
|
420
|
-
info(msg.skillSymlinked(skill, target));
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
// takt リファレンスのダウンロード(スキルが参照するbuiltins等)
|
|
425
|
-
if (!options.withoutSkills) {
|
|
426
|
-
const refsDir = join(options.cwd, options.refsPath);
|
|
427
|
-
const needsRefDownload = isUpdate
|
|
428
|
-
? manifest.taktRefHash !== TAKT_REF_HASH
|
|
429
|
-
: !existsSync(join(refsDir, "builtins"));
|
|
430
|
-
if (needsRefDownload) {
|
|
431
|
-
info(msg.downloadingTaktRefs(options.refsPath));
|
|
432
|
-
const taktTmpDir = mkdtempSync(join(tmpdir(), "takt-refs-"));
|
|
433
|
-
try {
|
|
434
|
-
const taktArchive = join(taktTmpDir, "takt.tar.gz");
|
|
435
|
-
const taktTarball = `https://github.com/${TAKT_REPO}/archive/${TAKT_REF_HASH}.tar.gz`;
|
|
436
|
-
await download(taktTarball, taktArchive);
|
|
437
|
-
execSync(`tar -xzf "${taktArchive}" -C "${taktTmpDir}"`, { stdio: "ignore" });
|
|
438
|
-
// takt-{hash}/ ディレクトリを探す
|
|
439
|
-
const taktExtracted = readdirSync(taktTmpDir).find((d) => d.startsWith("takt-") && statSync(join(taktTmpDir, d)).isDirectory());
|
|
440
|
-
if (taktExtracted) {
|
|
441
|
-
const taktRoot = join(taktTmpDir, taktExtracted);
|
|
442
|
-
mkdirSync(refsDir, { recursive: true });
|
|
443
|
-
// builtins/ を syncDirectory でコピー
|
|
444
|
-
const builtinsSrc = join(taktRoot, "builtins");
|
|
445
|
-
if (existsSync(builtinsSrc)) {
|
|
446
|
-
const builtinsDest = join(refsDir, "builtins");
|
|
447
|
-
const result = syncDirectory(builtinsSrc, builtinsDest, builtinsSrc, builtinsDest, isUpdate ? manifest : null, msg, options.cwd);
|
|
448
|
-
Object.assign(allFiles, result.files);
|
|
449
|
-
}
|
|
450
|
-
// docs/faceted-prompting.ja.md をコピー
|
|
451
|
-
const fpSrc = join(taktRoot, "docs", "faceted-prompting.ja.md");
|
|
452
|
-
if (existsSync(fpSrc)) {
|
|
453
|
-
const docsDir = join(refsDir, "docs");
|
|
454
|
-
mkdirSync(docsDir, { recursive: true });
|
|
455
|
-
const fpDest = join(docsDir, "faceted-prompting.ja.md");
|
|
456
|
-
const fpKey = relative(options.cwd, fpDest).split("\\").join("/");
|
|
457
|
-
const fpHash = computeFileHash(fpSrc);
|
|
458
|
-
if (!existsSync(fpDest)) {
|
|
459
|
-
cpSync(fpSrc, fpDest);
|
|
460
|
-
info(msg.fileAdded(fpKey));
|
|
461
|
-
}
|
|
462
|
-
else if (isUpdate) {
|
|
463
|
-
const recordedHash = manifest.files[fpKey];
|
|
464
|
-
if (recordedHash === undefined) {
|
|
465
|
-
warn(msg.fileSkippedCustomized(fpKey));
|
|
466
|
-
}
|
|
467
|
-
else {
|
|
468
|
-
const currentHash = computeFileHash(fpDest);
|
|
469
|
-
if (currentHash === recordedHash) {
|
|
470
|
-
cpSync(fpSrc, fpDest);
|
|
471
|
-
info(msg.fileUpdated(fpKey));
|
|
472
|
-
}
|
|
473
|
-
else {
|
|
474
|
-
warn(msg.fileSkippedCustomized(fpKey));
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
else {
|
|
479
|
-
cpSync(fpSrc, fpDest);
|
|
480
|
-
}
|
|
481
|
-
allFiles[fpKey] = fpHash;
|
|
482
|
-
}
|
|
483
|
-
info(msg.taktRefsInstalled);
|
|
484
|
-
}
|
|
485
|
-
else {
|
|
486
|
-
warn(msg.taktRefsError);
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
catch {
|
|
490
|
-
warn(msg.taktRefsError);
|
|
491
|
-
}
|
|
492
|
-
finally {
|
|
493
|
-
rmSync(taktTmpDir, { recursive: true, force: true });
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
else {
|
|
497
|
-
info(msg.taktRefsSkipped);
|
|
498
|
-
// Preserve existing file hashes from manifest for refs
|
|
499
|
-
if (isUpdate) {
|
|
500
|
-
for (const [key, hash] of Object.entries(manifest.files)) {
|
|
501
|
-
if (key.startsWith(options.refsPath)) {
|
|
502
|
-
allFiles[key] = hash;
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
// アーカイブの package.json から devDependencies を取得
|
|
509
315
|
const sddPkgPath = join(extractedDir, "package.json");
|
|
510
316
|
const sddDevDependencies = {};
|
|
511
317
|
if (existsSync(sddPkgPath)) {
|
|
@@ -515,7 +321,6 @@ export async function install(options) {
|
|
|
515
321
|
sddDevDependencies[key] = value;
|
|
516
322
|
}
|
|
517
323
|
}
|
|
518
|
-
// package.json に npm scripts と devDependencies を追加
|
|
519
324
|
const pkgPath = join(options.cwd, "package.json");
|
|
520
325
|
if (existsSync(pkgPath)) {
|
|
521
326
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
@@ -569,12 +374,10 @@ export async function install(options) {
|
|
|
569
374
|
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf-8");
|
|
570
375
|
info(msg.scriptsCreated);
|
|
571
376
|
}
|
|
572
|
-
// マニフェスト書き込み
|
|
573
377
|
const newManifest = {
|
|
574
378
|
version: version,
|
|
575
379
|
installedAt: new Date().toISOString(),
|
|
576
380
|
lang: options.lang,
|
|
577
|
-
taktRefHash: TAKT_REF_HASH,
|
|
578
381
|
files: allFiles,
|
|
579
382
|
};
|
|
580
383
|
writeFileSync(manifestPath, JSON.stringify(newManifest, null, 2) + "\n", "utf-8");
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-takt-sdd",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.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": "
|
|
10
|
+
"build": "tsc && node scripts/add-shebang.js",
|
|
11
11
|
"prepare": "npm run build"
|
|
12
12
|
},
|
|
13
13
|
"keywords": [
|