create-takt-sdd 0.15.0 → 0.15.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/cli.js +0 -11
- package/dist/i18n.js +8 -16
- package/dist/install.js +50 -210
- package/package.json +2 -2
- package/dist/generated/takt-ref.js +0 -2
package/dist/cli.js
CHANGED
|
@@ -20,7 +20,6 @@ function parseArgs(argv) {
|
|
|
20
20
|
version: false,
|
|
21
21
|
tag: undefined,
|
|
22
22
|
withoutSkills: false,
|
|
23
|
-
refsPath: "references/takt",
|
|
24
23
|
layout: "auto",
|
|
25
24
|
};
|
|
26
25
|
for (let i = 0; i < argv.length; i++) {
|
|
@@ -53,15 +52,6 @@ function parseArgs(argv) {
|
|
|
53
52
|
case "--without-skills":
|
|
54
53
|
args.withoutSkills = true;
|
|
55
54
|
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
55
|
case "--layout": {
|
|
66
56
|
const value = argv[++i];
|
|
67
57
|
if (!value || !isLayout(value)) {
|
|
@@ -104,7 +94,6 @@ async function main() {
|
|
|
104
94
|
dryRun: args.dryRun,
|
|
105
95
|
tag: args.tag,
|
|
106
96
|
withoutSkills: args.withoutSkills,
|
|
107
|
-
refsPath: args.refsPath,
|
|
108
97
|
layout: args.layout,
|
|
109
98
|
cwd: process.cwd(),
|
|
110
99
|
});
|
package/dist/i18n.js
CHANGED
|
@@ -16,13 +16,10 @@ 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:
|
|
19
|
+
installingSkills: (source) => `Installing TAKT skills from ${source}...`,
|
|
20
|
+
skillInstalling: (name, source) => `Installing external skill ${name} from ${source}`,
|
|
20
21
|
skillInstalled: (name) => `Installed skill: ${name}`,
|
|
21
|
-
|
|
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.",
|
|
22
|
+
skillInstallFailed: (name, source) => `Warning: Failed to install ${name} from ${source}. Continuing without it.`,
|
|
26
23
|
layoutDetected: (layout) => `Using ${layout} layout`,
|
|
27
24
|
fileAdded: (path) => `Added: ${path}`,
|
|
28
25
|
fileUpdated: (path) => `Updated: ${path}`,
|
|
@@ -35,9 +32,8 @@ Options:
|
|
|
35
32
|
--lang <en|ja> Message language (default: en)
|
|
36
33
|
--force Overwrite existing .takt/ directory (ignored if manifest exists)
|
|
37
34
|
--dry-run Preview without writing files
|
|
38
|
-
--without-skills Skip installing
|
|
35
|
+
--without-skills Skip installing TAKT skills via external skills add
|
|
39
36
|
--layout <mode> Directory layout: auto, modern, legacy (default: auto)
|
|
40
|
-
--refs-path <path> Path for takt references (default: references/takt)
|
|
41
37
|
-h, --help Show this help
|
|
42
38
|
-v, --version Show version`,
|
|
43
39
|
usageExamples: `
|
|
@@ -79,13 +75,10 @@ const ja = {
|
|
|
79
75
|
scriptsCreated: "npm scripts と devDependencies 付きの package.json を作成しました",
|
|
80
76
|
depsAdded: (keys) => `devDependencies を追加しました: ${keys.join(", ")}`,
|
|
81
77
|
depsUpdated: (keys) => `devDependencies を更新しました: ${keys.join(", ")}`,
|
|
82
|
-
installingSkills:
|
|
78
|
+
installingSkills: (source) => `${source} から TAKT スキルをインストール中...`,
|
|
79
|
+
skillInstalling: (name, source) => `${source} から外部スキルをインストール中: ${name}`,
|
|
83
80
|
skillInstalled: (name) => `スキルをインストールしました: ${name}`,
|
|
84
|
-
|
|
85
|
-
downloadingTaktRefs: (refsPath) => `${refsPath}/ に takt ビルトインをダウンロード中...`,
|
|
86
|
-
taktRefsInstalled: "takt リファレンスをインストールしました(builtins, docs)",
|
|
87
|
-
taktRefsSkipped: "takt リファレンスは既に存在するためスキップしました",
|
|
88
|
-
taktRefsError: "警告: takt リファレンスのダウンロードに失敗しました。スキルがスタイルガイドを参照できない可能性があります。",
|
|
81
|
+
skillInstallFailed: (name, source) => `警告: ${source} から ${name} のインストールに失敗しました。このスキルなしで継続します。`,
|
|
89
82
|
layoutDetected: (layout) => `${layout} レイアウトを使用します`,
|
|
90
83
|
fileAdded: (path) => `追加: ${path}`,
|
|
91
84
|
fileUpdated: (path) => `更新: ${path}`,
|
|
@@ -98,9 +91,8 @@ const ja = {
|
|
|
98
91
|
--lang <en|ja> メッセージ言語 (デフォルト: en)
|
|
99
92
|
--force 既存の .takt/ を上書き(マニフェストがある場合は無視)
|
|
100
93
|
--dry-run プレビューのみ(ファイル書き込みなし)
|
|
101
|
-
--without-skills
|
|
94
|
+
--without-skills external skills add による TAKT スキル導入をスキップ
|
|
102
95
|
--layout <mode> ディレクトリレイアウト: auto, modern, legacy(デフォルト: auto)
|
|
103
|
-
--refs-path <path> takt リファレンスのパス(デフォルト: references/takt)
|
|
104
96
|
-h, --help ヘルプを表示
|
|
105
97
|
-v, --version バージョンを表示`,
|
|
106
98
|
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",
|
|
@@ -28,6 +24,15 @@ const FACET_TYPES = [
|
|
|
28
24
|
"knowledge",
|
|
29
25
|
"output-contracts",
|
|
30
26
|
];
|
|
27
|
+
const EXTERNAL_SKILL_SOURCE = "j5ik2o/ai-tools";
|
|
28
|
+
const EXTERNAL_TAKT_SKILLS = [
|
|
29
|
+
"takt-analyzer",
|
|
30
|
+
"takt-facet-builder",
|
|
31
|
+
"takt-optimizer",
|
|
32
|
+
"takt-piece-builder",
|
|
33
|
+
"takt-skill-updater",
|
|
34
|
+
"takt-task-builder",
|
|
35
|
+
];
|
|
31
36
|
function srcFacetPath(facetType) {
|
|
32
37
|
return `facets/${facetType}`;
|
|
33
38
|
}
|
|
@@ -54,7 +59,7 @@ function detectLayout() {
|
|
|
54
59
|
function rewritePiecePathsForLegacy(piecesDir) {
|
|
55
60
|
if (!existsSync(piecesDir))
|
|
56
61
|
return;
|
|
57
|
-
for (const file of readdirSync(piecesDir).filter(f => f.endsWith(".yaml"))) {
|
|
62
|
+
for (const file of readdirSync(piecesDir).filter((f) => f.endsWith(".yaml"))) {
|
|
58
63
|
const filePath = join(piecesDir, file);
|
|
59
64
|
let content = readFileSync(filePath, "utf-8");
|
|
60
65
|
for (const type of FACET_TYPES) {
|
|
@@ -63,33 +68,22 @@ function rewritePiecePathsForLegacy(piecesDir) {
|
|
|
63
68
|
writeFileSync(filePath, content, "utf-8");
|
|
64
69
|
}
|
|
65
70
|
}
|
|
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
71
|
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
|
|
72
|
+
"cc-sdd:full": "takt --pipeline --skip-git -w cc-sdd-full -t",
|
|
73
|
+
"cc-sdd:requirements": "takt --pipeline --skip-git -w cc-sdd-requirements -t",
|
|
74
|
+
"cc-sdd:validate-gap": "takt --pipeline --skip-git -w cc-sdd-validate-gap -t",
|
|
75
|
+
"cc-sdd:design": "takt --pipeline --skip-git -w cc-sdd-design -t",
|
|
76
|
+
"cc-sdd:validate-design": "takt --pipeline --skip-git -w cc-sdd-validate-design -t",
|
|
77
|
+
"cc-sdd:tasks": "takt --pipeline --skip-git -w cc-sdd-tasks -t",
|
|
78
|
+
"cc-sdd:impl": "takt --pipeline --skip-git -w cc-sdd-impl -t",
|
|
79
|
+
"cc-sdd:validate-impl": "takt --pipeline --skip-git -w cc-sdd-validate-impl -t",
|
|
80
|
+
"cc-sdd:steering": "takt --pipeline --skip-git -w cc-sdd-steering -t",
|
|
81
|
+
"cc-sdd:steering-custom": "takt --pipeline --skip-git -w cc-sdd-steering-custom -t",
|
|
82
|
+
"opsx:full": "takt --pipeline --skip-git -w opsx-full -t",
|
|
83
|
+
"opsx:propose": "takt --pipeline --skip-git -w opsx-propose -t",
|
|
84
|
+
"opsx:apply": "takt --pipeline --skip-git -w opsx-apply -t",
|
|
85
|
+
"opsx:archive": "takt --pipeline --skip-git -w opsx-archive -t",
|
|
86
|
+
"opsx:explore": "takt --skip-git -w opsx-explore",
|
|
93
87
|
};
|
|
94
88
|
function info(msg) {
|
|
95
89
|
console.log(`\x1b[1;34m==>\x1b[0m ${msg}`);
|
|
@@ -144,7 +138,6 @@ function resolveTag(tagOption, installerVersion) {
|
|
|
144
138
|
if (tagOption === "latest") {
|
|
145
139
|
return fetchLatestTag();
|
|
146
140
|
}
|
|
147
|
-
// Accept both "v0.1.0" and "0.1.0"
|
|
148
141
|
return tagOption.startsWith("v") ? tagOption : `v${tagOption}`;
|
|
149
142
|
}
|
|
150
143
|
function download(url, dest) {
|
|
@@ -217,7 +210,6 @@ function syncDirectory(srcDir, destDir, srcBase, destBase, manifest, msg, cwd) {
|
|
|
217
210
|
const srcHash = computeFileHash(srcPath);
|
|
218
211
|
files[manifestKey] = srcHash;
|
|
219
212
|
if (!existsSync(destPath)) {
|
|
220
|
-
// New file — copy
|
|
221
213
|
mkdirSync(dirname(destPath), { recursive: true });
|
|
222
214
|
cpSync(srcPath, destPath);
|
|
223
215
|
info(msg.fileAdded(manifestKey));
|
|
@@ -225,48 +217,61 @@ function syncDirectory(srcDir, destDir, srcBase, destBase, manifest, msg, cwd) {
|
|
|
225
217
|
else if (manifest !== null) {
|
|
226
218
|
const recordedHash = manifest.files[manifestKey];
|
|
227
219
|
if (recordedHash === undefined) {
|
|
228
|
-
// File exists but not in manifest (pre-manifest environment)
|
|
229
220
|
warn(msg.fileSkippedCustomized(manifestKey));
|
|
230
221
|
}
|
|
231
222
|
else {
|
|
232
223
|
const currentHash = computeFileHash(destPath);
|
|
233
224
|
if (currentHash === recordedHash) {
|
|
234
|
-
// User has not modified — safe to overwrite
|
|
235
225
|
cpSync(srcPath, destPath);
|
|
236
226
|
info(msg.fileUpdated(manifestKey));
|
|
237
227
|
}
|
|
238
228
|
else {
|
|
239
|
-
// User has customized — skip
|
|
240
229
|
warn(msg.fileSkippedCustomized(manifestKey));
|
|
241
230
|
}
|
|
242
231
|
}
|
|
243
232
|
}
|
|
244
233
|
else {
|
|
245
|
-
// No manifest, fresh install or force — overwrite
|
|
246
234
|
cpSync(srcPath, destPath);
|
|
247
235
|
}
|
|
248
236
|
}
|
|
249
237
|
return { files };
|
|
250
238
|
}
|
|
239
|
+
function skillInstallCommand(skill) {
|
|
240
|
+
return `npx -y skills add ${EXTERNAL_SKILL_SOURCE} --skill ${skill}`;
|
|
241
|
+
}
|
|
242
|
+
function installExternalSkills(cwd, msg) {
|
|
243
|
+
info(msg.installingSkills(EXTERNAL_SKILL_SOURCE));
|
|
244
|
+
for (const skill of EXTERNAL_TAKT_SKILLS) {
|
|
245
|
+
const command = skillInstallCommand(skill);
|
|
246
|
+
info(msg.skillInstalling(skill, EXTERNAL_SKILL_SOURCE));
|
|
247
|
+
try {
|
|
248
|
+
execSync(command, {
|
|
249
|
+
cwd,
|
|
250
|
+
stdio: "inherit",
|
|
251
|
+
});
|
|
252
|
+
info(msg.skillInstalled(skill));
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
warn(msg.skillInstallFailed(skill, EXTERNAL_SKILL_SOURCE));
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
251
259
|
export async function install(options) {
|
|
252
260
|
const msg = getMessages(options.lang);
|
|
253
261
|
const targetPath = join(options.cwd, TARGET_DIR);
|
|
254
262
|
const manifestPath = join(targetPath, MANIFEST_FILE);
|
|
255
|
-
// tar の存在チェック
|
|
256
263
|
try {
|
|
257
264
|
execSync("which tar", { stdio: "ignore" });
|
|
258
265
|
}
|
|
259
266
|
catch {
|
|
260
267
|
errorExit(msg.tarNotFound);
|
|
261
268
|
}
|
|
262
|
-
// マニフェスト読み込み&モード判定
|
|
263
269
|
const manifest = loadManifest(manifestPath);
|
|
264
270
|
const isUpdate = manifest !== null;
|
|
265
271
|
const piecesExist = existsSync(join(targetPath, "pieces"));
|
|
266
272
|
if (!isUpdate && piecesExist && !options.force) {
|
|
267
273
|
errorExit(msg.existsError("npx create-takt-sdd"));
|
|
268
274
|
}
|
|
269
|
-
// ダウンロード
|
|
270
275
|
info(msg.downloading);
|
|
271
276
|
const tmpDir = mkdtempSync(join(tmpdir(), "takt-sdd-"));
|
|
272
277
|
const archivePath = join(tmpDir, "archive.tar.gz");
|
|
@@ -285,17 +290,14 @@ export async function install(options) {
|
|
|
285
290
|
}
|
|
286
291
|
const resolvedLayout = options.layout === "auto" ? detectLayout() : options.layout;
|
|
287
292
|
info(msg.layoutDetected(resolvedLayout));
|
|
288
|
-
// dry-run: ファイル一覧のみ表示
|
|
289
293
|
if (options.dryRun) {
|
|
290
294
|
info(msg.dryRunHeader);
|
|
291
|
-
// pieces
|
|
292
295
|
const piecesSrcDry = join(extractedTakt, options.lang, PIECE_DIR);
|
|
293
296
|
if (existsSync(piecesSrcDry)) {
|
|
294
297
|
for (const file of collectFiles(piecesSrcDry, piecesSrcDry)) {
|
|
295
298
|
console.log(msg.dryRunItem(join(TARGET_DIR, PIECE_DIR, file)));
|
|
296
299
|
}
|
|
297
300
|
}
|
|
298
|
-
// facets
|
|
299
301
|
for (const facetType of FACET_TYPES) {
|
|
300
302
|
const srcDir = join(extractedTakt, options.lang, srcFacetPath(facetType));
|
|
301
303
|
if (existsSync(srcDir)) {
|
|
@@ -306,32 +308,17 @@ export async function install(options) {
|
|
|
306
308
|
}
|
|
307
309
|
}
|
|
308
310
|
if (!options.withoutSkills) {
|
|
309
|
-
for (const skill of
|
|
310
|
-
|
|
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
|
-
}
|
|
311
|
+
for (const skill of EXTERNAL_TAKT_SKILLS) {
|
|
312
|
+
console.log(msg.dryRunItem(skillInstallCommand(skill)));
|
|
322
313
|
}
|
|
323
|
-
console.log(msg.dryRunItem(`${options.refsPath}/builtins/`));
|
|
324
|
-
console.log(msg.dryRunItem(`${options.refsPath}/docs/`));
|
|
325
314
|
}
|
|
326
315
|
console.log("");
|
|
327
316
|
info(msg.dryRunSkipped);
|
|
328
317
|
return;
|
|
329
318
|
}
|
|
330
|
-
// インストール / アップデート
|
|
331
319
|
info(isUpdate ? msg.updating : msg.installing);
|
|
332
320
|
mkdirSync(targetPath, { recursive: true });
|
|
333
321
|
const allFiles = {};
|
|
334
|
-
// pieces(legacy時はsync前にソースのパスを書き換え)
|
|
335
322
|
const piecesSrc = join(extractedTakt, options.lang, PIECE_DIR);
|
|
336
323
|
if (existsSync(piecesSrc)) {
|
|
337
324
|
const piecesDest = join(targetPath, PIECE_DIR);
|
|
@@ -348,7 +335,6 @@ export async function install(options) {
|
|
|
348
335
|
const result = syncDirectory(effectiveSrc, piecesDest, effectiveSrc, piecesDest, isUpdate ? manifest : null, msg, options.cwd);
|
|
349
336
|
Object.assign(allFiles, result.files);
|
|
350
337
|
}
|
|
351
|
-
// facets
|
|
352
338
|
for (const facetType of FACET_TYPES) {
|
|
353
339
|
const srcDir = join(extractedTakt, options.lang, srcFacetPath(facetType));
|
|
354
340
|
if (existsSync(srcDir)) {
|
|
@@ -360,152 +346,9 @@ export async function install(options) {
|
|
|
360
346
|
Object.assign(allFiles, result.files);
|
|
361
347
|
}
|
|
362
348
|
}
|
|
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
349
|
if (!options.withoutSkills) {
|
|
426
|
-
|
|
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
|
-
}
|
|
350
|
+
installExternalSkills(options.cwd, msg);
|
|
507
351
|
}
|
|
508
|
-
// アーカイブの package.json から devDependencies を取得
|
|
509
352
|
const sddPkgPath = join(extractedDir, "package.json");
|
|
510
353
|
const sddDevDependencies = {};
|
|
511
354
|
if (existsSync(sddPkgPath)) {
|
|
@@ -515,7 +358,6 @@ export async function install(options) {
|
|
|
515
358
|
sddDevDependencies[key] = value;
|
|
516
359
|
}
|
|
517
360
|
}
|
|
518
|
-
// package.json に npm scripts と devDependencies を追加
|
|
519
361
|
const pkgPath = join(options.cwd, "package.json");
|
|
520
362
|
if (existsSync(pkgPath)) {
|
|
521
363
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
@@ -569,12 +411,10 @@ export async function install(options) {
|
|
|
569
411
|
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf-8");
|
|
570
412
|
info(msg.scriptsCreated);
|
|
571
413
|
}
|
|
572
|
-
// マニフェスト書き込み
|
|
573
414
|
const newManifest = {
|
|
574
415
|
version: version,
|
|
575
416
|
installedAt: new Date().toISOString(),
|
|
576
417
|
lang: options.lang,
|
|
577
|
-
taktRefHash: TAKT_REF_HASH,
|
|
578
418
|
files: allFiles,
|
|
579
419
|
};
|
|
580
420
|
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.15.
|
|
3
|
+
"version": "0.15.1",
|
|
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": [
|