@sunasteriskrnd/takumi 1.0.0-dev.8 → 1.0.0-dev.9

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.
Files changed (2) hide show
  1. package/dist/index.js +492 -225
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -11225,12 +11225,12 @@ function isSafeRelativeLayoutPath(value) {
11225
11225
  return segments.every((segment) => segment.length > 0 && segment !== "." && segment !== "..");
11226
11226
  }
11227
11227
  function isValidKitType(value) {
11228
- return value === "engineer";
11228
+ return value === "engineer" || value === "extras";
11229
11229
  }
11230
- var KitType, KitConfigSchema, KitLayoutSchema, TakumiPackageMetadataSchema, DEFAULT_KIT_LAYOUT, AVAILABLE_KITS, NEVER_COPY_PATTERNS, USER_CONFIG_PATTERNS, PROTECTED_PATTERNS;
11230
+ var KitType, KitConfigSchema, KitLayoutSchema, TakumiPackageMetadataSchema, DEFAULT_KIT_LAYOUT, AVAILABLE_KITS, BASE_KIT = "engineer", NEVER_COPY_PATTERNS, USER_CONFIG_PATTERNS, PROTECTED_PATTERNS;
11231
11231
  var init_kit = __esm(() => {
11232
11232
  init_zod();
11233
- KitType = exports_external.enum(["engineer"]);
11233
+ KitType = exports_external.enum(["engineer", "extras"]);
11234
11234
  KitConfigSchema = exports_external.object({
11235
11235
  id: KitType,
11236
11236
  name: exports_external.string(),
@@ -11256,6 +11256,13 @@ var init_kit = __esm(() => {
11256
11256
  repo: "takumi",
11257
11257
  owner: "sun-asterisk-internal",
11258
11258
  description: "Engineering toolkit for building with Claude"
11259
+ },
11260
+ extras: {
11261
+ id: "extras",
11262
+ name: "Takumi Extras",
11263
+ repo: "takumi-extras",
11264
+ owner: "sun-asterisk-internal",
11265
+ description: "Extras agent kit"
11259
11266
  }
11260
11267
  };
11261
11268
  NEVER_COPY_PATTERNS = [
@@ -11444,13 +11451,14 @@ var init_metadata = __esm(() => {
11444
11451
  KitMetadataSchema = exports_external.object({
11445
11452
  version: exports_external.string(),
11446
11453
  installedAt: exports_external.string(),
11454
+ installState: exports_external.enum(["pending", "complete"]).optional(),
11447
11455
  files: exports_external.array(TrackedFileSchema).optional(),
11448
11456
  lastUpdateCheck: exports_external.string().optional(),
11449
11457
  dismissedVersion: exports_external.string().optional(),
11450
11458
  installedSettings: InstalledSettingsSchema.optional()
11451
11459
  });
11452
11460
  MultiKitMetadataSchema = exports_external.object({
11453
- kits: exports_external.record(KitType, KitMetadataSchema).optional(),
11461
+ kits: exports_external.record(exports_external.string(), KitMetadataSchema).optional(),
11454
11462
  scope: exports_external.enum(["local", "global"]).optional(),
11455
11463
  name: exports_external.string().optional(),
11456
11464
  version: exports_external.string().optional(),
@@ -12116,6 +12124,7 @@ __export(exports_types, {
12116
12124
  DEFAULT_FOLDERS: () => DEFAULT_FOLDERS,
12117
12125
  ConfigSchema: () => ConfigSchema,
12118
12126
  CodingLevelSchema: () => CodingLevelSchema,
12127
+ BASE_KIT: () => BASE_KIT,
12119
12128
  AuthenticationError: () => AuthenticationError,
12120
12129
  ApiStatusOptionsSchema: () => ApiStatusOptionsSchema,
12121
12130
  ApiSetupOptionsSchema: () => ApiSetupOptionsSchema,
@@ -34554,9 +34563,9 @@ __export(exports_worktree_manager, {
34554
34563
  });
34555
34564
  import { existsSync as existsSync60 } from "node:fs";
34556
34565
  import { readFile as readFile49, writeFile as writeFile36 } from "node:fs/promises";
34557
- import { join as join119 } from "node:path";
34566
+ import { join as join120 } from "node:path";
34558
34567
  async function createWorktree(projectDir, issueNumber, baseBranch) {
34559
- const worktreePath = join119(projectDir, WORKTREE_DIR, `issue-${issueNumber}`);
34568
+ const worktreePath = join120(projectDir, WORKTREE_DIR, `issue-${issueNumber}`);
34560
34569
  const branchName = `sk-watch/issue-${issueNumber}`;
34561
34570
  await spawnAndCollect("git", ["fetch", "origin", baseBranch], projectDir).catch(() => {
34562
34571
  logger.warning(`[worktree] Could not fetch origin/${baseBranch}, using local`);
@@ -34574,7 +34583,7 @@ async function createWorktree(projectDir, issueNumber, baseBranch) {
34574
34583
  return worktreePath;
34575
34584
  }
34576
34585
  async function removeWorktree(projectDir, issueNumber) {
34577
- const worktreePath = join119(projectDir, WORKTREE_DIR, `issue-${issueNumber}`);
34586
+ const worktreePath = join120(projectDir, WORKTREE_DIR, `issue-${issueNumber}`);
34578
34587
  const branchName = `sk-watch/issue-${issueNumber}`;
34579
34588
  try {
34580
34589
  await spawnAndCollect("git", ["worktree", "remove", worktreePath, "--force"], projectDir);
@@ -34588,7 +34597,7 @@ async function listActiveWorktrees(projectDir) {
34588
34597
  try {
34589
34598
  const output2 = await spawnAndCollect("git", ["worktree", "list", "--porcelain"], projectDir);
34590
34599
  const issueNumbers = [];
34591
- const worktreePrefix = join119(projectDir, WORKTREE_DIR, "issue-").replace(/\\/g, "/");
34600
+ const worktreePrefix = join120(projectDir, WORKTREE_DIR, "issue-").replace(/\\/g, "/");
34592
34601
  for (const line of output2.split(`
34593
34602
  `)) {
34594
34603
  if (line.startsWith("worktree ")) {
@@ -34616,7 +34625,7 @@ async function cleanupAllWorktrees(projectDir) {
34616
34625
  await spawnAndCollect("git", ["worktree", "prune"], projectDir).catch(() => {});
34617
34626
  }
34618
34627
  async function ensureGitignore(projectDir) {
34619
- const gitignorePath = join119(projectDir, ".gitignore");
34628
+ const gitignorePath = join120(projectDir, ".gitignore");
34620
34629
  try {
34621
34630
  const content = existsSync60(gitignorePath) ? await readFile49(gitignorePath, "utf-8") : "";
34622
34631
  if (!content.includes(".worktrees")) {
@@ -34723,7 +34732,7 @@ import { createHash as createHash8 } from "node:crypto";
34723
34732
  import { existsSync as existsSync66, mkdirSync as mkdirSync4, readFileSync as readFileSync16, readdirSync as readdirSync10, statSync as statSync7 } from "node:fs";
34724
34733
  import { rename as rename10, writeFile as writeFile38 } from "node:fs/promises";
34725
34734
  import { homedir as homedir32 } from "node:os";
34726
- import { basename as basename17, join as join126 } from "node:path";
34735
+ import { basename as basename17, join as join127 } from "node:path";
34727
34736
  function getCachedContext(repoPath) {
34728
34737
  const cachePath = getCacheFilePath(repoPath);
34729
34738
  if (!existsSync66(cachePath))
@@ -34766,25 +34775,25 @@ function computeSourceHash(repoPath) {
34766
34775
  }
34767
34776
  function getDocSourcePaths(repoPath) {
34768
34777
  const paths = [];
34769
- const docsDir = join126(repoPath, "docs");
34778
+ const docsDir = join127(repoPath, "docs");
34770
34779
  if (existsSync66(docsDir)) {
34771
34780
  try {
34772
34781
  const files = readdirSync10(docsDir);
34773
34782
  for (const f4 of files) {
34774
34783
  if (f4.endsWith(".md"))
34775
- paths.push(join126(docsDir, f4));
34784
+ paths.push(join127(docsDir, f4));
34776
34785
  }
34777
34786
  } catch {}
34778
34787
  }
34779
- const readme = join126(repoPath, "README.md");
34788
+ const readme = join127(repoPath, "README.md");
34780
34789
  if (existsSync66(readme))
34781
34790
  paths.push(readme);
34782
- const stylesDir = join126(repoPath, "assets", "writing-styles");
34791
+ const stylesDir = join127(repoPath, "assets", "writing-styles");
34783
34792
  if (existsSync66(stylesDir)) {
34784
34793
  try {
34785
34794
  const files = readdirSync10(stylesDir);
34786
34795
  for (const f4 of files) {
34787
- paths.push(join126(stylesDir, f4));
34796
+ paths.push(join127(stylesDir, f4));
34788
34797
  }
34789
34798
  } catch {}
34790
34799
  }
@@ -34793,11 +34802,11 @@ function getDocSourcePaths(repoPath) {
34793
34802
  function getCacheFilePath(repoPath) {
34794
34803
  const repoName = basename17(repoPath).replace(/[^a-zA-Z0-9_-]/g, "_");
34795
34804
  const pathHash = createHash8("sha256").update(repoPath).digest("hex").slice(0, 8);
34796
- return join126(CACHE_DIR, `${repoName}-${pathHash}-context-cache.json`);
34805
+ return join127(CACHE_DIR, `${repoName}-${pathHash}-context-cache.json`);
34797
34806
  }
34798
34807
  var CACHE_DIR, CACHE_TTL_MS3;
34799
34808
  var init_context_cache_manager = __esm(() => {
34800
- CACHE_DIR = join126(homedir32(), ".sunagentkit", "cache");
34809
+ CACHE_DIR = join127(homedir32(), ".sunagentkit", "cache");
34801
34810
  CACHE_TTL_MS3 = 24 * 60 * 60 * 1000;
34802
34811
  });
34803
34812
 
@@ -34978,7 +34987,7 @@ function extractContentFromResponse(response) {
34978
34987
  // src/commands/content/phases/docs-summarizer.ts
34979
34988
  import { execSync as execSync5 } from "node:child_process";
34980
34989
  import { existsSync as existsSync67, readFileSync as readFileSync17, readdirSync as readdirSync11 } from "node:fs";
34981
- import { join as join127 } from "node:path";
34990
+ import { join as join128 } from "node:path";
34982
34991
  async function summarizeProjectDocs(repoPath, contentLogger) {
34983
34992
  const rawContent = collectRawDocs(repoPath);
34984
34993
  if (rawContent.total.length < 200) {
@@ -35032,12 +35041,12 @@ function collectRawDocs(repoPath) {
35032
35041
  return capped;
35033
35042
  };
35034
35043
  const docsContent = [];
35035
- const docsDir = join127(repoPath, "docs");
35044
+ const docsDir = join128(repoPath, "docs");
35036
35045
  if (existsSync67(docsDir)) {
35037
35046
  try {
35038
35047
  const files = readdirSync11(docsDir).filter((f4) => f4.endsWith(".md")).sort();
35039
35048
  for (const f4 of files) {
35040
- const content = readCapped(join127(docsDir, f4), 5000);
35049
+ const content = readCapped(join128(docsDir, f4), 5000);
35041
35050
  if (content) {
35042
35051
  docsContent.push(`### ${f4}
35043
35052
  ${content}`);
@@ -35051,21 +35060,21 @@ ${content}`);
35051
35060
  let brand = "";
35052
35061
  const brandCandidates = ["docs/brand-guidelines.md", "docs/design-guidelines.md"];
35053
35062
  for (const p2 of brandCandidates) {
35054
- brand = readCapped(join127(repoPath, p2), 3000);
35063
+ brand = readCapped(join128(repoPath, p2), 3000);
35055
35064
  if (brand)
35056
35065
  break;
35057
35066
  }
35058
35067
  let styles3 = "";
35059
- const stylesDir = join127(repoPath, "assets", "writing-styles");
35068
+ const stylesDir = join128(repoPath, "assets", "writing-styles");
35060
35069
  if (existsSync67(stylesDir)) {
35061
35070
  try {
35062
35071
  const files = readdirSync11(stylesDir).slice(0, 3);
35063
- styles3 = files.map((f4) => readCapped(join127(stylesDir, f4), 1000)).filter(Boolean).join(`
35072
+ styles3 = files.map((f4) => readCapped(join128(stylesDir, f4), 1000)).filter(Boolean).join(`
35064
35073
 
35065
35074
  `);
35066
35075
  } catch {}
35067
35076
  }
35068
- const readme = readCapped(join127(repoPath, "README.md"), 3000);
35077
+ const readme = readCapped(join128(repoPath, "README.md"), 3000);
35069
35078
  const total = [docs, brand, styles3, readme].join(`
35070
35079
  `);
35071
35080
  return { docs, brand, styles: styles3, readme, total };
@@ -35252,9 +35261,9 @@ IMPORTANT: Generate the image and output the path as JSON: {"imagePath": "/path/
35252
35261
  import { execSync as execSync6 } from "node:child_process";
35253
35262
  import { existsSync as existsSync68, mkdirSync as mkdirSync5, readdirSync as readdirSync12 } from "node:fs";
35254
35263
  import { homedir as homedir33 } from "node:os";
35255
- import { join as join128 } from "node:path";
35264
+ import { join as join129 } from "node:path";
35256
35265
  async function generatePhoto(_content, context, config, platform10, contentId, contentLogger) {
35257
- const mediaDir = join128(config.contentDir.replace(/^~/, homedir33()), "media", String(contentId));
35266
+ const mediaDir = join129(config.contentDir.replace(/^~/, homedir33()), "media", String(contentId));
35258
35267
  if (!existsSync68(mediaDir)) {
35259
35268
  mkdirSync5(mediaDir, { recursive: true });
35260
35269
  }
@@ -35279,7 +35288,7 @@ async function generatePhoto(_content, context, config, platform10, contentId, c
35279
35288
  const imageFile = files.find((f4) => /\.(png|jpg|jpeg|webp)$/i.test(f4));
35280
35289
  if (imageFile) {
35281
35290
  const ext2 = imageFile.split(".").pop() ?? "png";
35282
- return { path: join128(mediaDir, imageFile), ...dimensions, format: ext2 };
35291
+ return { path: join129(mediaDir, imageFile), ...dimensions, format: ext2 };
35283
35292
  }
35284
35293
  contentLogger.warn(`Photo generation produced no image for content ${contentId}`);
35285
35294
  return null;
@@ -35369,7 +35378,7 @@ var init_content_creator = __esm(() => {
35369
35378
  // src/commands/content/phases/content-logger.ts
35370
35379
  import { createWriteStream as createWriteStream5, existsSync as existsSync69, mkdirSync as mkdirSync6, statSync as statSync8 } from "node:fs";
35371
35380
  import { homedir as homedir34 } from "node:os";
35372
- import { join as join129 } from "node:path";
35381
+ import { join as join130 } from "node:path";
35373
35382
 
35374
35383
  class ContentLogger {
35375
35384
  stream = null;
@@ -35377,7 +35386,7 @@ class ContentLogger {
35377
35386
  logDir;
35378
35387
  maxBytes;
35379
35388
  constructor(maxBytes = 0) {
35380
- this.logDir = join129(homedir34(), ".sunagentkit", "logs");
35389
+ this.logDir = join130(homedir34(), ".sunagentkit", "logs");
35381
35390
  this.maxBytes = maxBytes;
35382
35391
  }
35383
35392
  init() {
@@ -35409,7 +35418,7 @@ class ContentLogger {
35409
35418
  }
35410
35419
  }
35411
35420
  getLogPath() {
35412
- return join129(this.logDir, `content-${this.getDateStr()}.log`);
35421
+ return join130(this.logDir, `content-${this.getDateStr()}.log`);
35413
35422
  }
35414
35423
  write(level, message) {
35415
35424
  this.rotateIfNeeded();
@@ -35426,18 +35435,18 @@ class ContentLogger {
35426
35435
  if (dateStr !== this.currentDate) {
35427
35436
  this.close();
35428
35437
  this.currentDate = dateStr;
35429
- const logPath = join129(this.logDir, `content-${dateStr}.log`);
35438
+ const logPath = join130(this.logDir, `content-${dateStr}.log`);
35430
35439
  this.stream = createWriteStream5(logPath, { flags: "a", mode: 384 });
35431
35440
  return;
35432
35441
  }
35433
35442
  if (this.maxBytes > 0 && this.stream) {
35434
- const logPath = join129(this.logDir, `content-${this.currentDate}.log`);
35443
+ const logPath = join130(this.logDir, `content-${this.currentDate}.log`);
35435
35444
  try {
35436
35445
  const stat16 = statSync8(logPath);
35437
35446
  if (stat16.size >= this.maxBytes) {
35438
35447
  this.close();
35439
35448
  const suffix = Date.now();
35440
- const rotatedPath = join129(this.logDir, `content-${this.currentDate}-${suffix}.log`);
35449
+ const rotatedPath = join130(this.logDir, `content-${this.currentDate}-${suffix}.log`);
35441
35450
  import("node:fs/promises").then(({ rename: rename11 }) => rename11(logPath, rotatedPath).catch(() => {}));
35442
35451
  this.stream = createWriteStream5(logPath, { flags: "w", mode: 384 });
35443
35452
  }
@@ -35663,7 +35672,7 @@ function isNoiseCommit(title, author) {
35663
35672
  // src/commands/content/phases/change-detector.ts
35664
35673
  import { execSync as execSync8 } from "node:child_process";
35665
35674
  import { existsSync as existsSync71, readFileSync as readFileSync18, readdirSync as readdirSync13, statSync as statSync9 } from "node:fs";
35666
- import { join as join130 } from "node:path";
35675
+ import { join as join131 } from "node:path";
35667
35676
  function detectCommits(repo, since) {
35668
35677
  try {
35669
35678
  const fetchUrl = sshToHttps(repo.remoteUrl);
@@ -35761,7 +35770,7 @@ function detectTags(repo, since) {
35761
35770
  }
35762
35771
  }
35763
35772
  function detectCompletedPlans(repo, since) {
35764
- const plansDir = join130(repo.path, "plans");
35773
+ const plansDir = join131(repo.path, "plans");
35765
35774
  if (!existsSync71(plansDir))
35766
35775
  return [];
35767
35776
  const sinceMs = new Date(since).getTime();
@@ -35771,7 +35780,7 @@ function detectCompletedPlans(repo, since) {
35771
35780
  for (const entry of entries) {
35772
35781
  if (!entry.isDirectory())
35773
35782
  continue;
35774
- const planFile = join130(plansDir, entry.name, "plan.md");
35783
+ const planFile = join131(plansDir, entry.name, "plan.md");
35775
35784
  if (!existsSync71(planFile))
35776
35785
  continue;
35777
35786
  try {
@@ -35849,7 +35858,7 @@ function classifyCommit(event) {
35849
35858
  // src/commands/content/phases/repo-discoverer.ts
35850
35859
  import { execSync as execSync9 } from "node:child_process";
35851
35860
  import { readdirSync as readdirSync14 } from "node:fs";
35852
- import { join as join131 } from "node:path";
35861
+ import { join as join132 } from "node:path";
35853
35862
  function discoverRepos2(cwd2) {
35854
35863
  const repos = [];
35855
35864
  if (isGitRepoRoot(cwd2)) {
@@ -35862,7 +35871,7 @@ function discoverRepos2(cwd2) {
35862
35871
  for (const entry of entries) {
35863
35872
  if (!entry.isDirectory() || entry.name.startsWith("."))
35864
35873
  continue;
35865
- const dirPath = join131(cwd2, entry.name);
35874
+ const dirPath = join132(cwd2, entry.name);
35866
35875
  if (isGitRepoRoot(dirPath)) {
35867
35876
  const info = getRepoInfo(dirPath);
35868
35877
  if (info)
@@ -36529,9 +36538,9 @@ var init_types3 = __esm(() => {
36529
36538
 
36530
36539
  // src/commands/content/phases/state-manager.ts
36531
36540
  import { readFile as readFile51, rename as rename11, writeFile as writeFile39 } from "node:fs/promises";
36532
- import { join as join132 } from "node:path";
36541
+ import { join as join133 } from "node:path";
36533
36542
  async function loadContentConfig(projectDir) {
36534
- const configPath = join132(projectDir, TAKUMI_CONFIG_FILE2);
36543
+ const configPath = join133(projectDir, TAKUMI_CONFIG_FILE2);
36535
36544
  try {
36536
36545
  const raw = await readFile51(configPath, "utf-8");
36537
36546
  const json = JSON.parse(raw);
@@ -36541,13 +36550,13 @@ async function loadContentConfig(projectDir) {
36541
36550
  }
36542
36551
  }
36543
36552
  async function saveContentConfig(projectDir, config) {
36544
- const configPath = join132(projectDir, TAKUMI_CONFIG_FILE2);
36553
+ const configPath = join133(projectDir, TAKUMI_CONFIG_FILE2);
36545
36554
  const json = await readJsonSafe(configPath);
36546
36555
  json.content = { ...json.content, ...config };
36547
36556
  await atomicWrite3(configPath, json);
36548
36557
  }
36549
36558
  async function loadContentState(projectDir) {
36550
- const configPath = join132(projectDir, TAKUMI_CONFIG_FILE2);
36559
+ const configPath = join133(projectDir, TAKUMI_CONFIG_FILE2);
36551
36560
  try {
36552
36561
  const raw = await readFile51(configPath, "utf-8");
36553
36562
  const json = JSON.parse(raw);
@@ -36558,7 +36567,7 @@ async function loadContentState(projectDir) {
36558
36567
  }
36559
36568
  }
36560
36569
  async function saveContentState(projectDir, state) {
36561
- const configPath = join132(projectDir, TAKUMI_CONFIG_FILE2);
36570
+ const configPath = join133(projectDir, TAKUMI_CONFIG_FILE2);
36562
36571
  const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);
36563
36572
  for (const key of Object.keys(state.dailyPostCounts)) {
36564
36573
  const dateStr = key.slice(-10);
@@ -36840,7 +36849,7 @@ var init_platform_setup_x = __esm(() => {
36840
36849
 
36841
36850
  // src/commands/content/phases/setup-wizard.ts
36842
36851
  import { existsSync as existsSync72 } from "node:fs";
36843
- import { join as join133 } from "node:path";
36852
+ import { join as join134 } from "node:path";
36844
36853
  async function runSetupWizard2(cwd2, contentLogger) {
36845
36854
  console.log();
36846
36855
  oe(import_picocolors40.default.bgCyan(import_picocolors40.default.white(" SK Content — Multi-Channel Content Engine ")));
@@ -36908,8 +36917,8 @@ async function showRepoSummary(cwd2) {
36908
36917
  function detectBrandAssets(cwd2, contentLogger) {
36909
36918
  const repos = discoverRepos2(cwd2);
36910
36919
  for (const repo of repos) {
36911
- const hasGuidelines = existsSync72(join133(repo.path, "docs", "brand-guidelines.md"));
36912
- const hasStyles = existsSync72(join133(repo.path, "assets", "writing-styles"));
36920
+ const hasGuidelines = existsSync72(join134(repo.path, "docs", "brand-guidelines.md"));
36921
+ const hasStyles = existsSync72(join134(repo.path, "assets", "writing-styles"));
36913
36922
  if (!hasGuidelines) {
36914
36923
  f2.warning(`${repo.name}: No docs/brand-guidelines.md — content will use generic tone.`);
36915
36924
  contentLogger.warn(`${repo.name}: missing docs/brand-guidelines.md`);
@@ -37051,9 +37060,9 @@ __export(exports_content_subcommands, {
37051
37060
  });
37052
37061
  import { existsSync as existsSync74, readFileSync as readFileSync19, unlinkSync as unlinkSync6 } from "node:fs";
37053
37062
  import { homedir as homedir36 } from "node:os";
37054
- import { join as join134 } from "node:path";
37063
+ import { join as join135 } from "node:path";
37055
37064
  function isDaemonRunning() {
37056
- const lockFile = join134(LOCK_DIR, `${LOCK_NAME2}.lock`);
37065
+ const lockFile = join135(LOCK_DIR, `${LOCK_NAME2}.lock`);
37057
37066
  if (!existsSync74(lockFile))
37058
37067
  return { running: false, pid: null };
37059
37068
  try {
@@ -37085,7 +37094,7 @@ async function startContent(options2) {
37085
37094
  await contentCommand(options2);
37086
37095
  }
37087
37096
  async function stopContent() {
37088
- const lockFile = join134(LOCK_DIR, `${LOCK_NAME2}.lock`);
37097
+ const lockFile = join135(LOCK_DIR, `${LOCK_NAME2}.lock`);
37089
37098
  if (!existsSync74(lockFile)) {
37090
37099
  logger.info("Content daemon is not running.");
37091
37100
  return;
@@ -37124,9 +37133,9 @@ async function statusContent() {
37124
37133
  } catch {}
37125
37134
  }
37126
37135
  async function logsContent(options2) {
37127
- const logDir = join134(homedir36(), ".sunagentkit", "logs");
37136
+ const logDir = join135(homedir36(), ".sunagentkit", "logs");
37128
37137
  const dateStr = new Date().toISOString().slice(0, 10).replace(/-/g, "");
37129
- const logPath = join134(logDir, `content-${dateStr}.log`);
37138
+ const logPath = join135(logDir, `content-${dateStr}.log`);
37130
37139
  if (!existsSync74(logPath)) {
37131
37140
  logger.info("No content logs found for today.");
37132
37141
  return;
@@ -37158,13 +37167,13 @@ var init_content_subcommands = __esm(() => {
37158
37167
  init_setup_wizard();
37159
37168
  init_state_manager();
37160
37169
  init_content_review_commands();
37161
- LOCK_DIR = join134(homedir36(), ".sunagentkit", "locks");
37170
+ LOCK_DIR = join135(homedir36(), ".sunagentkit", "locks");
37162
37171
  });
37163
37172
 
37164
37173
  // src/commands/content/content-command.ts
37165
37174
  import { existsSync as existsSync75, mkdirSync as mkdirSync8, unlinkSync as unlinkSync7, writeFileSync as writeFileSync6 } from "node:fs";
37166
37175
  import { homedir as homedir37 } from "node:os";
37167
- import { join as join135 } from "node:path";
37176
+ import { join as join136 } from "node:path";
37168
37177
  async function contentCommand(options2) {
37169
37178
  const cwd2 = process.cwd();
37170
37179
  const contentLogger = new ContentLogger;
@@ -37342,8 +37351,8 @@ var init_content_command = __esm(() => {
37342
37351
  init_publisher();
37343
37352
  init_review_manager();
37344
37353
  init_state_manager();
37345
- LOCK_DIR2 = join135(homedir37(), ".sunagentkit", "locks");
37346
- LOCK_FILE = join135(LOCK_DIR2, "sk-content.lock");
37354
+ LOCK_DIR2 = join136(homedir37(), ".sunagentkit", "locks");
37355
+ LOCK_FILE = join136(LOCK_DIR2, "sk-content.lock");
37347
37356
  });
37348
37357
 
37349
37358
  // src/commands/content/index.ts
@@ -49278,28 +49287,32 @@ var import_fs_extra6 = __toESM(require_lib(), 1);
49278
49287
  var import_picomatch = __toESM(require_picomatch2(), 1);
49279
49288
  function findFileInMetadata(metadata, path3) {
49280
49289
  if (!metadata)
49281
- return null;
49290
+ return { tracked: null, ownerKit: null };
49282
49291
  if (metadata.kits) {
49283
- for (const kitMeta of Object.values(metadata.kits)) {
49284
- if (kitMeta?.files) {
49285
- const found = kitMeta.files.find((f3) => f3.path === path3);
49286
- if (found)
49287
- return found;
49288
- }
49292
+ for (const [kitName, kitMeta] of Object.entries(metadata.kits)) {
49293
+ if (!kitMeta?.files)
49294
+ continue;
49295
+ const found = kitMeta.files.find((f3) => f3.path === path3);
49296
+ if (found)
49297
+ return { tracked: found, ownerKit: kitName };
49289
49298
  }
49290
49299
  }
49291
49300
  if (metadata.files) {
49292
49301
  const found = metadata.files.find((f3) => f3.path === path3);
49293
49302
  if (found)
49294
- return found;
49303
+ return { tracked: found, ownerKit: null };
49295
49304
  }
49296
- return null;
49305
+ return { tracked: null, ownerKit: null };
49297
49306
  }
49298
- function shouldDeletePath(path3, metadata) {
49299
- const tracked = findFileInMetadata(metadata, path3);
49307
+ function shouldDeletePath(path3, metadata, installingKit) {
49308
+ const { tracked, ownerKit } = findFileInMetadata(metadata, path3);
49300
49309
  if (!tracked)
49301
49310
  return true;
49302
- return tracked.ownership !== "user";
49311
+ if (tracked.ownership === "user")
49312
+ return false;
49313
+ if (installingKit && ownerKit && ownerKit !== installingKit)
49314
+ return false;
49315
+ return true;
49303
49316
  }
49304
49317
  function collectFilesRecursively(dir, baseDir) {
49305
49318
  const results = [];
@@ -49422,7 +49435,7 @@ async function updateMetadataAfterDeletion(claudeDir, deletedPaths) {
49422
49435
  logger.debug("Failed to write updated metadata.json");
49423
49436
  }
49424
49437
  }
49425
- async function handleDeletions(sourceMetadata, claudeDir) {
49438
+ async function handleDeletions(sourceMetadata, claudeDir, installingKit) {
49426
49439
  const deletionPatterns = sourceMetadata.deletions || [];
49427
49440
  if (deletionPatterns.length === 0) {
49428
49441
  return { deletedPaths: [], preservedPaths: [], errors: [] };
@@ -49439,9 +49452,9 @@ async function handleDeletions(sourceMetadata, claudeDir) {
49439
49452
  result.errors.push(path3);
49440
49453
  continue;
49441
49454
  }
49442
- if (!shouldDeletePath(path3, userMetadata)) {
49455
+ if (!shouldDeletePath(path3, userMetadata, installingKit)) {
49443
49456
  result.preservedPaths.push(path3);
49444
- logger.verbose(`Preserved user file: ${path3}`);
49457
+ logger.verbose(`Preserved file (cross-kit or user-owned): ${path3}`);
49445
49458
  continue;
49446
49459
  }
49447
49460
  if (existsSync13(fullPath)) {
@@ -52510,14 +52523,17 @@ async function writeManifest(providerRoot, kitName, version3, scope, kitType, tr
52510
52523
  logger.debug(`Could not read existing metadata: ${error}`);
52511
52524
  }
52512
52525
  }
52526
+ const existingKits = existingMetadata.kits || {};
52527
+ const otherKitsExist = Object.keys(existingKits).some((k2) => k2 !== kit);
52513
52528
  const installedAt = new Date().toISOString();
52529
+ const existingKitMeta = existingKits[kit];
52514
52530
  const kitMetadata = {
52531
+ ...existingKitMeta ?? {},
52515
52532
  version: version3,
52516
52533
  installedAt,
52534
+ installState: "complete",
52517
52535
  files: trackedFiles.length > 0 ? trackedFiles : undefined
52518
52536
  };
52519
- const existingKits = existingMetadata.kits || {};
52520
- const otherKitsExist = Object.keys(existingKits).some((k2) => k2 !== kit);
52521
52537
  const metadata = {
52522
52538
  kits: {
52523
52539
  ...existingKits,
@@ -52548,6 +52564,69 @@ async function writeManifest(providerRoot, kitName, version3, scope, kitType, tr
52548
52564
  }
52549
52565
  }
52550
52566
  }
52567
+ async function writeKitPending(providerRoot, kit, version3, scope) {
52568
+ const metadataPath = join28(providerRoot, "metadata.json");
52569
+ await import_fs_extra10.ensureFile(metadataPath);
52570
+ let release = null;
52571
+ try {
52572
+ release = await import_proper_lockfile4.lock(metadataPath, {
52573
+ retries: { retries: 5, minTimeout: 100, maxTimeout: 1000 },
52574
+ stale: 60000
52575
+ });
52576
+ logger.debug(`Acquired lock on ${metadataPath} for pending-state write`);
52577
+ const migrationResult = await migrateToMultiKit(providerRoot);
52578
+ if (!migrationResult.success) {
52579
+ logger.warning(`Metadata migration warning: ${migrationResult.error}`);
52580
+ }
52581
+ let existingMetadata = { kits: {} };
52582
+ if (await import_fs_extra10.pathExists(metadataPath)) {
52583
+ try {
52584
+ const content = await import_fs_extra10.readFile(metadataPath, "utf-8");
52585
+ const parsed = JSON.parse(content);
52586
+ if (parsed && typeof parsed === "object" && Object.keys(parsed).length > 0) {
52587
+ existingMetadata = parsed;
52588
+ }
52589
+ } catch (error) {
52590
+ logger.debug(`Could not read existing metadata: ${error}`);
52591
+ }
52592
+ }
52593
+ const existingKits = existingMetadata.kits || {};
52594
+ const pendingMetadata = {
52595
+ version: version3,
52596
+ installedAt: new Date().toISOString(),
52597
+ installState: "pending",
52598
+ files: []
52599
+ };
52600
+ const metadata = {
52601
+ ...existingMetadata,
52602
+ kits: {
52603
+ ...existingKits,
52604
+ [kit]: pendingMetadata
52605
+ },
52606
+ scope
52607
+ };
52608
+ const validated = MetadataSchema.parse(metadata);
52609
+ await import_fs_extra10.writeFile(metadataPath, JSON.stringify(validated, null, 2), "utf-8");
52610
+ logger.debug(`Wrote pending-state entry for kit "${kit}"`);
52611
+ } finally {
52612
+ if (release) {
52613
+ await release();
52614
+ logger.debug(`Released lock on ${metadataPath}`);
52615
+ }
52616
+ }
52617
+ }
52618
+ async function findPendingKits(providerRoot) {
52619
+ const metadata = await readManifest(providerRoot);
52620
+ if (!metadata?.kits)
52621
+ return [];
52622
+ const pending = [];
52623
+ for (const [kitName, kitMeta] of Object.entries(metadata.kits)) {
52624
+ if (kitMeta?.installState === "pending") {
52625
+ pending.push(kitName);
52626
+ }
52627
+ }
52628
+ return pending;
52629
+ }
52551
52630
  async function removeKitFromManifest(providerRoot, kit) {
52552
52631
  const metadataPath = join28(providerRoot, "metadata.json");
52553
52632
  if (!await import_fs_extra10.pathExists(metadataPath))
@@ -52749,6 +52828,12 @@ class ManifestWriter {
52749
52828
  async writeManifest(providerRoot, kitName, version3, scope, kitType) {
52750
52829
  return writeManifest(providerRoot, kitName, version3, scope, kitType, this.getTrackedFiles(), this.getUserConfigFiles());
52751
52830
  }
52831
+ static async writeKitPending(providerRoot, kit, version3, scope) {
52832
+ return writeKitPending(providerRoot, kit, version3, scope);
52833
+ }
52834
+ static async findPendingKits(providerRoot) {
52835
+ return findPendingKits(providerRoot);
52836
+ }
52752
52837
  static async readManifest(providerRoot) {
52753
52838
  return readManifest(providerRoot);
52754
52839
  }
@@ -53716,7 +53801,7 @@ async function handleMerge(ctx) {
53716
53801
  }
53717
53802
  try {
53718
53803
  if (sourceMetadata?.deletions && sourceMetadata.deletions.length > 0) {
53719
- const deletionResult = await handleDeletions(sourceMetadata, ctx.claudeDir);
53804
+ const deletionResult = await handleDeletions(sourceMetadata, ctx.claudeDir, ctx.kitType);
53720
53805
  if (deletionResult.deletedPaths.length > 0) {
53721
53806
  logger.info(`Removed ${deletionResult.deletedPaths.length} deprecated file(s)`);
53722
53807
  for (const path4 of deletionResult.deletedPaths) {
@@ -63269,6 +63354,9 @@ async function doctorCommand(options2 = {}) {
63269
63354
  }
63270
63355
  }
63271
63356
 
63357
+ // src/commands/init/init-command.ts
63358
+ import { join as join102 } from "node:path";
63359
+
63272
63360
  // src/domains/sync/config-version-checker.ts
63273
63361
  init_auth_client();
63274
63362
  import { mkdir as mkdir22, readFile as readFile38, unlink as unlink12, writeFile as writeFile29 } from "node:fs/promises";
@@ -64138,6 +64226,7 @@ async function promptAgentSelection(supported) {
64138
64226
  return selected;
64139
64227
  }
64140
64228
  // src/domains/ui/prompts/kit-prompts.ts
64229
+ init_logger();
64141
64230
  init_types2();
64142
64231
  async function selectKit(defaultKit, accessibleKits) {
64143
64232
  const kits = accessibleKits ?? Object.keys(AVAILABLE_KITS);
@@ -64155,6 +64244,39 @@ async function selectKit(defaultKit, accessibleKits) {
64155
64244
  }
64156
64245
  return kit;
64157
64246
  }
64247
+ async function selectKits(accessibleKits, defaults2) {
64248
+ const kits = accessibleKits ?? Object.keys(AVAILABLE_KITS);
64249
+ const options2 = kits.map((key) => {
64250
+ const isBase = key === BASE_KIT;
64251
+ const cfg = AVAILABLE_KITS[key];
64252
+ return {
64253
+ value: key,
64254
+ label: isBase ? `${cfg.name} (base, required)` : cfg.name,
64255
+ hint: cfg.description
64256
+ };
64257
+ });
64258
+ const initialValues = defaults2 && defaults2.length > 0 ? Array.from(new Set([BASE_KIT, ...defaults2])).filter((k2) => kits.includes(k2)) : kits;
64259
+ const selected = await ae({
64260
+ message: "Select kit(s) to install:",
64261
+ options: options2,
64262
+ initialValues,
64263
+ required: true
64264
+ });
64265
+ if (lD(selected)) {
64266
+ throw new Error("Kit selection cancelled");
64267
+ }
64268
+ const result = selected;
64269
+ if (!result.includes(BASE_KIT) && kits.includes(BASE_KIT)) {
64270
+ logger.info(`"${AVAILABLE_KITS[BASE_KIT].name}" is the base kit and was added back automatically.`);
64271
+ result.unshift(BASE_KIT);
64272
+ }
64273
+ const idx = result.indexOf(BASE_KIT);
64274
+ if (idx > 0) {
64275
+ result.splice(idx, 1);
64276
+ result.unshift(BASE_KIT);
64277
+ }
64278
+ return result;
64279
+ }
64158
64280
  async function getDirectory(defaultDir = ".") {
64159
64281
  const dir = await te({
64160
64282
  message: "Enter target directory:",
@@ -64818,6 +64940,9 @@ class PromptsManager {
64818
64940
  async selectKit(defaultKit, accessibleKits) {
64819
64941
  return selectKit(defaultKit, accessibleKits);
64820
64942
  }
64943
+ async selectKits(accessibleKits, defaults2) {
64944
+ return selectKits(accessibleKits, defaults2);
64945
+ }
64821
64946
  async selectVersion(versions, defaultVersion) {
64822
64947
  return selectVersion(versions, defaultVersion);
64823
64948
  }
@@ -64959,6 +65084,8 @@ class PromptsManager {
64959
65084
 
64960
65085
  // src/commands/init/init-command.ts
64961
65086
  init_logger();
65087
+ init_path_resolver();
65088
+ init_types2();
64962
65089
 
64963
65090
  // src/commands/init/context-factory.ts
64964
65091
  function createInitContext(rawOptions, prompts) {
@@ -69636,6 +69763,25 @@ async function handleDownload(ctx) {
69636
69763
  // src/commands/init/phases/options-resolver.ts
69637
69764
  init_logger();
69638
69765
  init_types2();
69766
+ function parseKitFlag(raw) {
69767
+ const tokens = raw.split(",").map((s3) => s3.trim()).filter((s3) => s3.length > 0);
69768
+ if (tokens.length === 0)
69769
+ return null;
69770
+ if (tokens.length === 1 && tokens[0] === "all") {
69771
+ return Object.keys(AVAILABLE_KITS);
69772
+ }
69773
+ const seen = new Set;
69774
+ const out = [];
69775
+ for (const tok of tokens) {
69776
+ if (!isValidKitType(tok))
69777
+ return null;
69778
+ if (!seen.has(tok)) {
69779
+ seen.add(tok);
69780
+ out.push(tok);
69781
+ }
69782
+ }
69783
+ return out;
69784
+ }
69639
69785
  async function resolveOptions(ctx) {
69640
69786
  const explicitDir = ctx.rawOptions.dir !== undefined;
69641
69787
  const explicitAgents = Array.isArray(ctx.rawOptions.agents) && ctx.rawOptions.agents.length > 0;
@@ -69725,6 +69871,28 @@ Example: takumi init --use-git --release v2.1.0`);
69725
69871
  Choose one approach.`);
69726
69872
  }
69727
69873
  const isNonInteractive2 = validOptions.yes || !process.stdin.isTTY || process.env.CI === "true" || process.env.NON_INTERACTIVE === "true";
69874
+ if (validOptions.kit) {
69875
+ const parsed2 = parseKitFlag(validOptions.kit);
69876
+ if (!parsed2 || parsed2.length === 0) {
69877
+ throw new Error(`Invalid --kit value: "${validOptions.kit}".
69878
+ Valid kits: ${Object.keys(AVAILABLE_KITS).join(", ")}`);
69879
+ }
69880
+ if (!parsed2.includes(BASE_KIT)) {
69881
+ if (isNonInteractive2) {
69882
+ throw new Error(`The "${BASE_KIT}" kit is required when installing additional kits.
69883
+ Re-run with explicit base kit, e.g. --kit ${BASE_KIT} --kit ${parsed2.join(" --kit ")}`);
69884
+ }
69885
+ logger.info(`"${BASE_KIT}" is the required base kit — adding it automatically.`);
69886
+ parsed2.unshift(BASE_KIT);
69887
+ } else {
69888
+ const idx = parsed2.indexOf(BASE_KIT);
69889
+ if (idx > 0) {
69890
+ parsed2.splice(idx, 1);
69891
+ parsed2.unshift(BASE_KIT);
69892
+ }
69893
+ }
69894
+ validOptions.selectedKits = parsed2;
69895
+ }
69728
69896
  if (validOptions.yes) {
69729
69897
  logger.info("Running in non-interactive mode (--yes flag)");
69730
69898
  }
@@ -70162,48 +70330,58 @@ async function handleSelection(ctx) {
70162
70330
  return { ...ctx, cancelled: true };
70163
70331
  }
70164
70332
  }
70165
- let kitType;
70166
- const kitOption = ctx.options.kit || config.defaults?.kit;
70167
- if (kitOption) {
70333
+ let selectedKits = ctx.options.selectedKits;
70334
+ if (!selectedKits || selectedKits.length === 0) {
70168
70335
  const allKitTypes = Object.keys(AVAILABLE_KITS);
70169
- if (kitOption === "all" || kitOption.includes(",")) {
70170
- const kitsToInstall = accessibleKits ?? allKitTypes;
70171
- if (kitsToInstall.length === 0) {
70172
- logger.error("No kits accessible for installation");
70173
- return { ...ctx, cancelled: true };
70174
- }
70175
- kitType = kitsToInstall[0];
70176
- logger.info(`Using kit: ${AVAILABLE_KITS[kitType].name}`);
70177
- } else {
70178
- if (!isValidKitType(kitOption)) {
70336
+ const kitOption = ctx.options.kit || config.defaults?.kit;
70337
+ if (kitOption) {
70338
+ if (kitOption === "all") {
70339
+ selectedKits = accessibleKits ?? allKitTypes;
70340
+ } else if (!isValidKitType(kitOption)) {
70179
70341
  logger.error(`Invalid kit: ${kitOption}`);
70180
70342
  logger.info(`Valid kits: ${allKitTypes.join(", ")}`);
70181
70343
  return { ...ctx, cancelled: true };
70344
+ } else {
70345
+ selectedKits = [kitOption];
70182
70346
  }
70183
- kitType = kitOption;
70184
- if (accessibleKits && !accessibleKits.includes(kitType)) {
70185
- logger.error(`No access to ${AVAILABLE_KITS[kitType].name}`);
70186
- logger.info("Request access from your team lead or check your GitHub invitation");
70187
- return { ...ctx, cancelled: true };
70347
+ }
70348
+ if (!selectedKits || selectedKits.length === 0) {
70349
+ if (ctx.isNonInteractive) {
70350
+ if (!accessibleKits || accessibleKits.length === 0) {
70351
+ throw new Error("Kit must be specified via --kit flag in non-interactive mode (no accessible kits detected)");
70352
+ }
70353
+ selectedKits = [accessibleKits[0]];
70354
+ logger.info(`Auto-selected: ${AVAILABLE_KITS[selectedKits[0]].name}`);
70355
+ } else if (accessibleKits?.length === 1) {
70356
+ selectedKits = [accessibleKits[0]];
70357
+ logger.info(`Using ${AVAILABLE_KITS[selectedKits[0]].name} (only accessible kit)`);
70358
+ } else {
70359
+ selectedKits = await ctx.prompts.selectKits(accessibleKits);
70188
70360
  }
70189
70361
  }
70190
70362
  }
70191
- if (!kitType) {
70192
- if (ctx.isNonInteractive) {
70193
- if (!accessibleKits || accessibleKits.length === 0) {
70194
- throw new Error("Kit must be specified via --kit flag in non-interactive mode (no accessible kits detected)");
70195
- }
70196
- kitType = accessibleKits[0];
70197
- logger.info(`Auto-selected: ${AVAILABLE_KITS[kitType].name}`);
70198
- } else if (accessibleKits?.length === 1) {
70199
- kitType = accessibleKits[0];
70200
- logger.info(`Using ${AVAILABLE_KITS[kitType].name} (only accessible kit)`);
70201
- } else {
70202
- kitType = await ctx.prompts.selectKit(undefined, accessibleKits);
70363
+ if (accessibleKits) {
70364
+ const inaccessible = selectedKits.filter((k3) => !accessibleKits.includes(k3));
70365
+ if (inaccessible.length > 0) {
70366
+ logger.error(`No access to: ${inaccessible.map((k3) => AVAILABLE_KITS[k3].name).join(", ")}`);
70367
+ logger.info("Request access from your team lead or check your GitHub invitation");
70368
+ return { ...ctx, cancelled: true };
70203
70369
  }
70204
70370
  }
70371
+ if (selectedKits.includes(BASE_KIT)) {
70372
+ const idx = selectedKits.indexOf(BASE_KIT);
70373
+ if (idx > 0) {
70374
+ selectedKits.splice(idx, 1);
70375
+ selectedKits.unshift(BASE_KIT);
70376
+ }
70377
+ }
70378
+ const kitType = selectedKits[0];
70205
70379
  const kit = AVAILABLE_KITS[kitType];
70206
- logger.info(`Selected kit: ${kit.name}`);
70380
+ if (selectedKits.length > 1) {
70381
+ logger.info(`Selected kits: ${selectedKits.map((k3) => AVAILABLE_KITS[k3].name).join(", ")} (installed in order)`);
70382
+ } else {
70383
+ logger.info(`Selected kit: ${kit.name}`);
70384
+ }
70207
70385
  let targetDir;
70208
70386
  if (ctx.explicitDir) {
70209
70387
  targetDir = ctx.options.dir;
@@ -70412,12 +70590,30 @@ async function handleSelection(ctx) {
70412
70590
  ...ctx,
70413
70591
  kit,
70414
70592
  kitType,
70593
+ selectedKits,
70415
70594
  resolvedDir,
70416
70595
  release,
70417
70596
  selectedVersion,
70418
70597
  accessibleKits
70419
70598
  };
70420
70599
  }
70600
+ async function resolveReleaseForKit(ctx, kitType) {
70601
+ const isOfflineMode = !!(ctx.options.kitPath || ctx.options.archive);
70602
+ if (isOfflineMode)
70603
+ return;
70604
+ const kit = AVAILABLE_KITS[kitType];
70605
+ if (ctx.options.useGit) {
70606
+ throw new Error(`--use-git is not supported for multi-kit installs (secondary kit: ${kitType}). Run kits individually.`);
70607
+ }
70608
+ if (ctx.options.useGh) {
70609
+ const github = new GitHubClient;
70610
+ const release = await github.getLatestRelease(kit, ctx.options.beta);
70611
+ return release;
70612
+ }
70613
+ const worker = new WorkerSource(getServerUrl(), kitType);
70614
+ const entry = await worker.fetchLatest(ctx.options.beta);
70615
+ return releaseEntryToGitHubRelease(entry, kit);
70616
+ }
70421
70617
  function resolveGlobalTargetDir(targetAgents) {
70422
70618
  const primary = targetAgents[0];
70423
70619
  if (primary) {
@@ -70458,7 +70654,7 @@ async function handleSync(ctx) {
70458
70654
  Run 'takumi init' to update.`, "Legacy Installation");
70459
70655
  return { ...ctx, cancelled: true };
70460
70656
  }
70461
- let kitType = ctx.options.kit;
70657
+ let kitType = ctx.options.selectedKits?.[0];
70462
70658
  if (!kitType) {
70463
70659
  const engineerMeta = await readKitManifest(claudeDir, "engineer");
70464
70660
  if (engineerMeta) {
@@ -71291,23 +71487,91 @@ async function executeInit(options2, prompts) {
71291
71487
  ctx = await handleSelection(ctx);
71292
71488
  if (ctx.cancelled)
71293
71489
  return;
71294
- ctx = await handleDownload(ctx);
71295
- if (ctx.cancelled)
71490
+ if (ctx.resolvedDir && !isSyncMode) {
71491
+ try {
71492
+ const prefix = PathResolver.getPathPrefix(ctx.options.global);
71493
+ const claudeDir = prefix ? join102(ctx.resolvedDir, prefix) : ctx.resolvedDir;
71494
+ const pending = await ManifestWriter.findPendingKits(claudeDir);
71495
+ if (pending.length > 0) {
71496
+ logger.warning(`Previous install was interrupted for kit(s): ${pending.join(", ")}. Re-running install will overwrite the pending entry.`);
71497
+ }
71498
+ } catch (error) {
71499
+ logger.debug(`Pending-kit check skipped: ${error}`);
71500
+ }
71501
+ }
71502
+ const selectedKits = ctx.selectedKits && ctx.selectedKits.length > 0 ? ctx.selectedKits : ctx.kitType ? [ctx.kitType] : [];
71503
+ if (selectedKits.length === 0) {
71504
+ logger.error("No kits resolved for installation");
71296
71505
  return;
71297
- if (!isSyncMode) {
71298
- ctx = await handleTransforms(ctx);
71299
- if (ctx.cancelled)
71300
- return;
71301
71506
  }
71302
- if (isSyncMode) {
71303
- ctx = await executeSyncMerge(ctx);
71304
- if (ctx.cancelled)
71507
+ const aggregatedResults = [];
71508
+ let lastCtx = ctx;
71509
+ for (let i = 0;i < selectedKits.length; i++) {
71510
+ const currentKit = selectedKits[i];
71511
+ if (i > 0) {
71512
+ logger.info(`Installing kit ${i + 1}/${selectedKits.length}: ${AVAILABLE_KITS[currentKit].name}`);
71513
+ if (lastCtx.options.release) {
71514
+ logger.info(`Secondary kit "${currentKit}" uses latest channel — --release applies only to the primary kit.`);
71515
+ }
71516
+ let nextRelease;
71517
+ try {
71518
+ nextRelease = await resolveReleaseForKit(lastCtx, currentKit);
71519
+ } catch (error) {
71520
+ const message = error instanceof Error ? error.message : String(error);
71521
+ logger.error(`Failed to resolve release for ${currentKit}: ${message}`);
71522
+ aggregatedResults.push({
71523
+ provider: targetAgents[0] ?? "claude-code",
71524
+ success: false,
71525
+ cancelled: false,
71526
+ installedFiles: [],
71527
+ error: `Release fetch failed for kit "${currentKit}": ${message}`
71528
+ });
71529
+ continue;
71530
+ }
71531
+ lastCtx = {
71532
+ ...lastCtx,
71533
+ kit: AVAILABLE_KITS[currentKit],
71534
+ kitType: currentKit,
71535
+ release: nextRelease,
71536
+ selectedVersion: nextRelease?.tag_name,
71537
+ tempDir: undefined,
71538
+ extractDir: undefined,
71539
+ archivePath: undefined
71540
+ };
71541
+ } else if (selectedKits.length > 1) {
71542
+ logger.info(`Installing kit ${i + 1}/${selectedKits.length}: ${AVAILABLE_KITS[currentKit].name}`);
71543
+ }
71544
+ if (lastCtx.resolvedDir && lastCtx.release && !isSyncMode) {
71545
+ try {
71546
+ const prefix = PathResolver.getPathPrefix(lastCtx.options.global);
71547
+ const claudeDir = prefix ? join102(lastCtx.resolvedDir, prefix) : lastCtx.resolvedDir;
71548
+ const scope = lastCtx.options.global ? "global" : "local";
71549
+ await ManifestWriter.writeKitPending(claudeDir, currentKit, lastCtx.release.tag_name, scope);
71550
+ } catch (error) {
71551
+ logger.debug(`writeKitPending skipped: ${error}`);
71552
+ }
71553
+ }
71554
+ lastCtx = await handleDownload(lastCtx);
71555
+ if (lastCtx.cancelled)
71556
+ return;
71557
+ if (!isSyncMode) {
71558
+ lastCtx = await handleTransforms(lastCtx);
71559
+ if (lastCtx.cancelled)
71560
+ return;
71561
+ }
71562
+ if (isSyncMode) {
71563
+ lastCtx = await executeSyncMerge(lastCtx);
71564
+ if (lastCtx.cancelled)
71565
+ return;
71566
+ }
71567
+ const kitResults = await dispatchInstallers(lastCtx, targetAgents);
71568
+ aggregatedResults.push(...kitResults);
71569
+ if (kitResults.some((r2) => r2.cancelled))
71305
71570
  return;
71306
71571
  }
71307
- const results = await dispatchInstallers(ctx, targetAgents);
71572
+ ctx = lastCtx;
71573
+ const results = aggregatedResults;
71308
71574
  ctx.installerResults = results;
71309
- if (results.some((r2) => r2.cancelled))
71310
- return;
71311
71575
  if (targetAgents.length > 1) {
71312
71576
  displayMultiInstallerSummary(results);
71313
71577
  }
@@ -71368,7 +71632,7 @@ async function initCommand(options2) {
71368
71632
  import { existsSync as existsSync47 } from "node:fs";
71369
71633
  import { readFile as readFile45, rm as rm13, unlink as unlink15 } from "node:fs/promises";
71370
71634
  import { homedir as homedir25 } from "node:os";
71371
- import { basename as basename12, join as join102, resolve as resolve26 } from "node:path";
71635
+ import { basename as basename12, join as join103, resolve as resolve26 } from "node:path";
71372
71636
  init_dist2();
71373
71637
  var import_picocolors27 = __toESM(require_picocolors(), 1);
71374
71638
  init_logger();
@@ -71850,7 +72114,7 @@ async function executeDeleteAction(action, options2) {
71850
72114
  async function processMetadataDeletions(skillSourcePath, installGlobally) {
71851
72115
  if (!skillSourcePath)
71852
72116
  return;
71853
- const sourceMetadataPath = join102(resolve26(skillSourcePath, ".."), "metadata.json");
72117
+ const sourceMetadataPath = join103(resolve26(skillSourcePath, ".."), "metadata.json");
71854
72118
  if (!existsSync47(sourceMetadataPath))
71855
72119
  return;
71856
72120
  let sourceMetadata;
@@ -71863,11 +72127,11 @@ async function processMetadataDeletions(skillSourcePath, installGlobally) {
71863
72127
  }
71864
72128
  if (!sourceMetadata.deletions || sourceMetadata.deletions.length === 0)
71865
72129
  return;
71866
- const claudeDir = installGlobally ? join102(homedir25(), ".claude") : join102(process.cwd(), ".claude");
72130
+ const claudeDir = installGlobally ? join103(homedir25(), ".claude") : join103(process.cwd(), ".claude");
71867
72131
  if (!existsSync47(claudeDir))
71868
72132
  return;
71869
72133
  try {
71870
- const result = await handleDeletions(sourceMetadata, claudeDir);
72134
+ const result = await handleDeletions(sourceMetadata, claudeDir, undefined);
71871
72135
  if (result.deletedPaths.length > 0) {
71872
72136
  logger.verbose(`[migrate] Cleaned up ${result.deletedPaths.length} deprecated path(s): ${result.deletedPaths.join(", ")}`);
71873
72137
  }
@@ -72011,8 +72275,8 @@ async function migrateCommand(options2) {
72011
72275
  selectedProviders = Array.from(new Set(selectedProviders));
72012
72276
  let installGlobally = options2.global ?? false;
72013
72277
  if (options2.global === undefined && !options2.yes) {
72014
- const projectTarget = join102(process.cwd(), ".claude");
72015
- const globalTarget = join102(homedir25(), ".claude");
72278
+ const projectTarget = join103(process.cwd(), ".claude");
72279
+ const globalTarget = join103(homedir25(), ".claude");
72016
72280
  const scopeChoice = await ie({
72017
72281
  message: "Installation scope",
72018
72282
  options: [
@@ -72064,7 +72328,7 @@ async function migrateCommand(options2) {
72064
72328
  }
72065
72329
  const providerNames = selectedProviders.map((prov) => import_picocolors27.default.cyan(providers[prov].displayName)).join(", ");
72066
72330
  f2.message(` Providers: ${providerNames}`);
72067
- const targetDir = installGlobally ? join102(homedir25(), ".claude") : join102(process.cwd(), ".claude");
72331
+ const targetDir = installGlobally ? join103(homedir25(), ".claude") : join103(process.cwd(), ".claude");
72068
72332
  f2.message(` Scope: ${installGlobally ? "Global" : "Project"} ${import_picocolors27.default.dim(`-> ${targetDir}`)}`);
72069
72333
  const cmdProviders = getProvidersSupporting("commands");
72070
72334
  const unsupportedCmd = selectedProviders.filter((pv) => !cmdProviders.includes(pv));
@@ -72574,7 +72838,7 @@ async function handleDirectorySetup(ctx) {
72574
72838
  };
72575
72839
  }
72576
72840
  // src/commands/new/phases/project-creation.ts
72577
- import { join as join103 } from "node:path";
72841
+ import { join as join104 } from "node:path";
72578
72842
  init_github_client();
72579
72843
  init_logger();
72580
72844
  init_output_manager();
@@ -72728,7 +72992,7 @@ async function projectCreation(kit, resolvedDir, validOptions, isNonInteractive2
72728
72992
  output.section("Installing");
72729
72993
  logger.verbose("Installation target", { directory: resolvedDir });
72730
72994
  const merger = new FileMerger;
72731
- const claudeDir = join103(resolvedDir, ".claude");
72995
+ const claudeDir = join104(resolvedDir, ".claude");
72732
72996
  merger.setMultiKitContext(claudeDir, kit);
72733
72997
  if (validOptions.exclude && validOptions.exclude.length > 0) {
72734
72998
  merger.addIgnorePatterns(validOptions.exclude);
@@ -72781,10 +73045,10 @@ async function handleProjectCreation(ctx) {
72781
73045
  };
72782
73046
  }
72783
73047
  // src/commands/new/phases/post-setup.ts
72784
- import { join as join105 } from "node:path";
73048
+ import { join as join106 } from "node:path";
72785
73049
 
72786
73050
  // src/domains/installation/setup-wizard.ts
72787
- import { join as join104 } from "node:path";
73051
+ import { join as join105 } from "node:path";
72788
73052
  init_logger();
72789
73053
  init_dist2();
72790
73054
  var import_fs_extra36 = __toESM(require_lib(), 1);
@@ -72864,7 +73128,7 @@ async function parseEnvFile(path9) {
72864
73128
  }
72865
73129
  }
72866
73130
  async function checkGlobalConfig() {
72867
- const globalEnvPath = join104(getClaudeDir(), ".env");
73131
+ const globalEnvPath = join105(getClaudeDir(), ".env");
72868
73132
  if (!await import_fs_extra36.pathExists(globalEnvPath))
72869
73133
  return false;
72870
73134
  const env2 = await parseEnvFile(globalEnvPath);
@@ -72880,7 +73144,7 @@ async function runSetupWizard(options2) {
72880
73144
  let globalEnv = {};
72881
73145
  const hasGlobalConfig = !isGlobal && await checkGlobalConfig();
72882
73146
  if (!isGlobal) {
72883
- const globalEnvPath = join104(getClaudeDir(), ".env");
73147
+ const globalEnvPath = join105(getClaudeDir(), ".env");
72884
73148
  if (await import_fs_extra36.pathExists(globalEnvPath)) {
72885
73149
  globalEnv = await parseEnvFile(globalEnvPath);
72886
73150
  }
@@ -72943,7 +73207,7 @@ async function runSetupWizard(options2) {
72943
73207
  }
72944
73208
  }
72945
73209
  await generateEnvFile(targetDir, values);
72946
- f2.success(`Configuration saved to ${join104(targetDir, ".env")}`);
73210
+ f2.success(`Configuration saved to ${join105(targetDir, ".env")}`);
72947
73211
  return true;
72948
73212
  }
72949
73213
  async function promptForAdditionalGeminiKeys(primaryKey) {
@@ -73046,9 +73310,9 @@ async function postSetup(resolvedDir, validOptions, isNonInteractive2, prompts)
73046
73310
  withSudo: validOptions.withSudo
73047
73311
  });
73048
73312
  }
73049
- const claudeDir = join105(resolvedDir, ".claude");
73313
+ const claudeDir = join106(resolvedDir, ".claude");
73050
73314
  await promptSetupWizardIfNeeded({
73051
- envPath: join105(claudeDir, ".env"),
73315
+ envPath: join106(claudeDir, ".env"),
73052
73316
  claudeDir,
73053
73317
  isGlobal: false,
73054
73318
  isNonInteractive: isNonInteractive2,
@@ -73125,11 +73389,11 @@ Example: tkm new --use-git --release v2.1.0`);
73125
73389
  // src/commands/plan/plan-command.ts
73126
73390
  init_output_manager();
73127
73391
  import { existsSync as existsSync52, statSync as statSync5 } from "node:fs";
73128
- import { dirname as dirname33, join as join109, parse as parse2, resolve as resolve31 } from "node:path";
73392
+ import { dirname as dirname33, join as join110, parse as parse2, resolve as resolve31 } from "node:path";
73129
73393
 
73130
73394
  // src/commands/plan/plan-read-handlers.ts
73131
73395
  import { existsSync as existsSync51, statSync as statSync4 } from "node:fs";
73132
- import { basename as basename15, dirname as dirname32, join as join108, relative as relative20, resolve as resolve29 } from "node:path";
73396
+ import { basename as basename15, dirname as dirname32, join as join109, relative as relative20, resolve as resolve29 } from "node:path";
73133
73397
 
73134
73398
  // src/domains/plan-parser/index.ts
73135
73399
  import { dirname as dirname31 } from "node:path";
@@ -73510,12 +73774,12 @@ function parsePlanFile(planFilePath, options2) {
73510
73774
  }
73511
73775
  // src/domains/plan-parser/plan-scanner.ts
73512
73776
  import { existsSync as existsSync48, readdirSync as readdirSync5 } from "node:fs";
73513
- import { join as join106 } from "node:path";
73777
+ import { join as join107 } from "node:path";
73514
73778
  function scanPlanDir(dir) {
73515
73779
  if (!existsSync48(dir))
73516
73780
  return [];
73517
73781
  try {
73518
- return readdirSync5(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join106(dir, entry.name, "plan.md")).filter(existsSync48);
73782
+ return readdirSync5(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join107(dir, entry.name, "plan.md")).filter(existsSync48);
73519
73783
  } catch {
73520
73784
  return [];
73521
73785
  }
@@ -73584,7 +73848,7 @@ function validatePlanFile(filePath, strict = false) {
73584
73848
  var import_gray_matter7 = __toESM(require_gray_matter(), 1);
73585
73849
  import { mkdirSync as mkdirSync3, readFileSync as readFileSync14, writeFileSync as writeFileSync5 } from "node:fs";
73586
73850
  import { existsSync as existsSync50 } from "node:fs";
73587
- import { basename as basename14, dirname as dirname30, join as join107 } from "node:path";
73851
+ import { basename as basename14, dirname as dirname30, join as join108 } from "node:path";
73588
73852
  function phaseNameToFilename(id, name) {
73589
73853
  const numMatch = /^(\d+)([a-z]*)$/i.exec(id);
73590
73854
  const num = numMatch ? numMatch[1] : id;
@@ -73692,12 +73956,12 @@ function scaffoldPlan(options2) {
73692
73956
  mkdirSync3(dir, { recursive: true });
73693
73957
  const resolvedPhases = resolvePhaseIds(options2.phases);
73694
73958
  const optionsWithResolved = { ...options2, phases: resolvedPhases };
73695
- const planFile = join107(dir, "plan.md");
73959
+ const planFile = join108(dir, "plan.md");
73696
73960
  writeFileSync5(planFile, generatePlanMd(optionsWithResolved), "utf8");
73697
73961
  const phaseFiles = [];
73698
73962
  for (const phase of resolvedPhases) {
73699
73963
  const filename = phaseNameToFilename(phase.id, phase.name);
73700
- const phaseFile = join107(dir, filename);
73964
+ const phaseFile = join108(dir, filename);
73701
73965
  writeFileSync5(phaseFile, generatePhaseTemplate(phase), "utf8");
73702
73966
  phaseFiles.push(phaseFile);
73703
73967
  }
@@ -73777,7 +74041,7 @@ function phaseNameFilenameFromTableRow(body, phaseId, planDir) {
73777
74041
  continue;
73778
74042
  const linkMatch = /\[([^\]]+)\]\(\.\/([^)]+)\)/.exec(row);
73779
74043
  if (linkMatch)
73780
- return join107(planDir, linkMatch[2]);
74044
+ return join108(planDir, linkMatch[2]);
73781
74045
  }
73782
74046
  return null;
73783
74047
  }
@@ -73858,7 +74122,7 @@ function addPhase(planFile, name, afterId) {
73858
74122
  `);
73859
74123
  }
73860
74124
  writeFileSync5(planFile, import_gray_matter7.default.stringify(updatedBody, frontmatter), "utf8");
73861
- const phaseFilePath = join107(planDir, filename);
74125
+ const phaseFilePath = join108(planDir, filename);
73862
74126
  writeFileSync5(phaseFilePath, generatePhaseTemplate({ id: phaseId, name }), "utf8");
73863
74127
  return { phaseId, phaseFile: phaseFilePath };
73864
74128
  }
@@ -73962,7 +74226,7 @@ async function handleValidate(target, options2) {
73962
74226
  }
73963
74227
  async function handleStatus(target, options2) {
73964
74228
  const t = target ? resolve29(target) : null;
73965
- const plansDir = t && existsSync51(t) && statSync4(t).isDirectory() && !existsSync51(join108(t, "plan.md")) ? t : null;
74229
+ const plansDir = t && existsSync51(t) && statSync4(t).isDirectory() && !existsSync51(join109(t, "plan.md")) ? t : null;
73966
74230
  if (plansDir) {
73967
74231
  const planFiles = scanPlanDir(plansDir);
73968
74232
  if (planFiles.length === 0) {
@@ -74197,7 +74461,7 @@ function resolvePlanFile(target) {
74197
74461
  const stat13 = statSync5(t);
74198
74462
  if (stat13.isFile())
74199
74463
  return t;
74200
- const candidate = join109(t, "plan.md");
74464
+ const candidate = join110(t, "plan.md");
74201
74465
  if (existsSync52(candidate))
74202
74466
  return candidate;
74203
74467
  }
@@ -74205,7 +74469,7 @@ function resolvePlanFile(target) {
74205
74469
  let dir = process.cwd();
74206
74470
  const root = parse2(dir).root;
74207
74471
  while (dir !== root) {
74208
- const candidate = join109(dir, "plan.md");
74472
+ const candidate = join110(dir, "plan.md");
74209
74473
  if (existsSync52(candidate))
74210
74474
  return candidate;
74211
74475
  dir = dirname33(dir);
@@ -74477,112 +74741,112 @@ var import_picocolors34 = __toESM(require_picocolors(), 1);
74477
74741
  // src/commands/skills/agents.ts
74478
74742
  import { existsSync as existsSync54 } from "node:fs";
74479
74743
  import { homedir as homedir26 } from "node:os";
74480
- import { join as join110 } from "node:path";
74744
+ import { join as join111 } from "node:path";
74481
74745
  var home6 = homedir26();
74482
74746
  var agents = {
74483
74747
  "claude-code": {
74484
74748
  name: "claude-code",
74485
74749
  displayName: "Claude Code",
74486
74750
  projectPath: ".claude/skills",
74487
- globalPath: join110(home6, ".claude/skills"),
74488
- detect: async () => existsSync54(join110(home6, ".claude"))
74751
+ globalPath: join111(home6, ".claude/skills"),
74752
+ detect: async () => existsSync54(join111(home6, ".claude"))
74489
74753
  },
74490
74754
  cursor: {
74491
74755
  name: "cursor",
74492
74756
  displayName: "Cursor",
74493
74757
  projectPath: ".cursor/skills",
74494
- globalPath: join110(home6, ".cursor/skills"),
74495
- detect: async () => existsSync54(join110(home6, ".cursor"))
74758
+ globalPath: join111(home6, ".cursor/skills"),
74759
+ detect: async () => existsSync54(join111(home6, ".cursor"))
74496
74760
  },
74497
74761
  codex: {
74498
74762
  name: "codex",
74499
74763
  displayName: "Codex",
74500
74764
  projectPath: ".codex/skills",
74501
- globalPath: join110(home6, ".codex/skills"),
74502
- detect: async () => existsSync54(join110(home6, ".codex"))
74765
+ globalPath: join111(home6, ".codex/skills"),
74766
+ detect: async () => existsSync54(join111(home6, ".codex"))
74503
74767
  },
74504
74768
  opencode: {
74505
74769
  name: "opencode",
74506
74770
  displayName: "OpenCode",
74507
74771
  projectPath: ".opencode/skills",
74508
- globalPath: join110(home6, ".config/opencode/skills"),
74509
- detect: async () => existsSync54(join110(home6, ".config/opencode"))
74772
+ globalPath: join111(home6, ".config/opencode/skills"),
74773
+ detect: async () => existsSync54(join111(home6, ".config/opencode"))
74510
74774
  },
74511
74775
  goose: {
74512
74776
  name: "goose",
74513
74777
  displayName: "Goose",
74514
74778
  projectPath: ".goose/skills",
74515
- globalPath: join110(home6, ".config/goose/skills"),
74516
- detect: async () => existsSync54(join110(home6, ".config/goose"))
74779
+ globalPath: join111(home6, ".config/goose/skills"),
74780
+ detect: async () => existsSync54(join111(home6, ".config/goose"))
74517
74781
  },
74518
74782
  "gemini-cli": {
74519
74783
  name: "gemini-cli",
74520
74784
  displayName: "Gemini CLI",
74521
74785
  projectPath: ".agents/skills",
74522
- globalPath: join110(home6, ".agents/skills"),
74523
- detect: async () => existsSync54(join110(home6, ".gemini"))
74786
+ globalPath: join111(home6, ".agents/skills"),
74787
+ detect: async () => existsSync54(join111(home6, ".gemini"))
74524
74788
  },
74525
74789
  antigravity: {
74526
74790
  name: "antigravity",
74527
74791
  displayName: "Antigravity",
74528
74792
  projectPath: ".agent/skills",
74529
- globalPath: join110(home6, ".gemini/antigravity/skills"),
74530
- detect: async () => existsSync54(join110(process.cwd(), ".agent")) || existsSync54(join110(home6, ".gemini/antigravity"))
74793
+ globalPath: join111(home6, ".gemini/antigravity/skills"),
74794
+ detect: async () => existsSync54(join111(process.cwd(), ".agent")) || existsSync54(join111(home6, ".gemini/antigravity"))
74531
74795
  },
74532
74796
  "github-copilot": {
74533
74797
  name: "github-copilot",
74534
74798
  displayName: "GitHub Copilot",
74535
74799
  projectPath: ".github/skills",
74536
- globalPath: join110(home6, ".copilot/skills"),
74537
- detect: async () => existsSync54(join110(home6, ".copilot"))
74800
+ globalPath: join111(home6, ".copilot/skills"),
74801
+ detect: async () => existsSync54(join111(home6, ".copilot"))
74538
74802
  },
74539
74803
  amp: {
74540
74804
  name: "amp",
74541
74805
  displayName: "Amp",
74542
74806
  projectPath: ".agents/skills",
74543
- globalPath: join110(home6, ".config/agents/skills"),
74544
- detect: async () => existsSync54(join110(home6, ".config/amp"))
74807
+ globalPath: join111(home6, ".config/agents/skills"),
74808
+ detect: async () => existsSync54(join111(home6, ".config/amp"))
74545
74809
  },
74546
74810
  kilo: {
74547
74811
  name: "kilo",
74548
74812
  displayName: "Kilo Code",
74549
74813
  projectPath: ".kilocode/skills",
74550
- globalPath: join110(home6, ".kilocode/skills"),
74551
- detect: async () => existsSync54(join110(home6, ".kilocode"))
74814
+ globalPath: join111(home6, ".kilocode/skills"),
74815
+ detect: async () => existsSync54(join111(home6, ".kilocode"))
74552
74816
  },
74553
74817
  roo: {
74554
74818
  name: "roo",
74555
74819
  displayName: "Roo Code",
74556
74820
  projectPath: ".roo/skills",
74557
- globalPath: join110(home6, ".roo/skills"),
74558
- detect: async () => existsSync54(join110(home6, ".roo"))
74821
+ globalPath: join111(home6, ".roo/skills"),
74822
+ detect: async () => existsSync54(join111(home6, ".roo"))
74559
74823
  },
74560
74824
  windsurf: {
74561
74825
  name: "windsurf",
74562
74826
  displayName: "Windsurf",
74563
74827
  projectPath: ".windsurf/skills",
74564
- globalPath: join110(home6, ".codeium/windsurf/skills"),
74565
- detect: async () => existsSync54(join110(home6, ".codeium/windsurf"))
74828
+ globalPath: join111(home6, ".codeium/windsurf/skills"),
74829
+ detect: async () => existsSync54(join111(home6, ".codeium/windsurf"))
74566
74830
  },
74567
74831
  cline: {
74568
74832
  name: "cline",
74569
74833
  displayName: "Cline",
74570
74834
  projectPath: ".cline/skills",
74571
- globalPath: join110(home6, ".cline/skills"),
74572
- detect: async () => existsSync54(join110(home6, ".cline"))
74835
+ globalPath: join111(home6, ".cline/skills"),
74836
+ detect: async () => existsSync54(join111(home6, ".cline"))
74573
74837
  },
74574
74838
  openhands: {
74575
74839
  name: "openhands",
74576
74840
  displayName: "OpenHands",
74577
74841
  projectPath: ".openhands/skills",
74578
- globalPath: join110(home6, ".openhands/skills"),
74579
- detect: async () => existsSync54(join110(home6, ".openhands"))
74842
+ globalPath: join111(home6, ".openhands/skills"),
74843
+ detect: async () => existsSync54(join111(home6, ".openhands"))
74580
74844
  }
74581
74845
  };
74582
74846
  function getInstallPath(skillName, agent, options2) {
74583
74847
  const config = agents[agent];
74584
74848
  const basePath = options2.global ? config.globalPath : config.projectPath;
74585
- return join110(basePath, skillName);
74849
+ return join111(basePath, skillName);
74586
74850
  }
74587
74851
  function isSkillInstalled(skillName, agent, options2) {
74588
74852
  const installPath = getInstallPath(skillName, agent, options2);
@@ -74593,16 +74857,16 @@ function isSkillInstalled(skillName, agent, options2) {
74593
74857
  import { existsSync as existsSync56 } from "node:fs";
74594
74858
  import { cp as cp4, mkdir as mkdir31, rm as rm14, stat as stat13 } from "node:fs/promises";
74595
74859
  import { homedir as homedir28 } from "node:os";
74596
- import { dirname as dirname35, join as join112, resolve as resolve33 } from "node:path";
74860
+ import { dirname as dirname35, join as join113, resolve as resolve33 } from "node:path";
74597
74861
 
74598
74862
  // src/commands/skills/skills-registry.ts
74599
74863
  init_zod();
74600
74864
  import { existsSync as existsSync55 } from "node:fs";
74601
74865
  import { mkdir as mkdir30, readFile as readFile47, writeFile as writeFile35 } from "node:fs/promises";
74602
74866
  import { homedir as homedir27 } from "node:os";
74603
- import { dirname as dirname34, join as join111, sep as sep9 } from "node:path";
74867
+ import { dirname as dirname34, join as join112, sep as sep9 } from "node:path";
74604
74868
  var home7 = homedir27();
74605
- var REGISTRY_PATH2 = join111(home7, ".sunagentkit", "skill-registry.json");
74869
+ var REGISTRY_PATH2 = join112(home7, ".sunagentkit", "skill-registry.json");
74606
74870
  var SkillInstallationSchema = exports_external.object({
74607
74871
  skill: exports_external.string(),
74608
74872
  agent: exports_external.string(),
@@ -74740,7 +75004,7 @@ async function syncRegistry() {
74740
75004
  var LEGACY_SKILL_PATHS = {
74741
75005
  "gemini-cli": {
74742
75006
  project: ".gemini/skills",
74743
- global: join112(homedir28(), ".gemini/skills")
75007
+ global: join113(homedir28(), ".gemini/skills")
74744
75008
  }
74745
75009
  };
74746
75010
  function isSamePath3(path1, path22) {
@@ -74774,7 +75038,7 @@ async function cleanupLegacySkillPath(skillName, agent, global3) {
74774
75038
  if (!legacy)
74775
75039
  return;
74776
75040
  const legacyBase = global3 ? legacy.global : legacy.project;
74777
- const legacyPath = join112(legacyBase, skillName);
75041
+ const legacyPath = join113(legacyBase, skillName);
74778
75042
  if (!existsSync56(legacyPath))
74779
75043
  return;
74780
75044
  await rm14(legacyPath, { recursive: true, force: true });
@@ -74784,7 +75048,7 @@ async function cleanupLegacySkillPath(skillName, agent, global3) {
74784
75048
  if (entry.skill === skillName && entry.agent === agent && entry.global === global3) {
74785
75049
  if (entry.path === legacyPath) {
74786
75050
  const newBase = global3 ? agents[agent].globalPath : agents[agent].projectPath;
74787
- entry.path = join112(newBase, skillName);
75051
+ entry.path = join113(newBase, skillName);
74788
75052
  changed = true;
74789
75053
  }
74790
75054
  }
@@ -74869,7 +75133,7 @@ function getInstallPreview(skill, targetAgents, options2) {
74869
75133
  // src/commands/skills/skills-uninstaller.ts
74870
75134
  import { existsSync as existsSync57 } from "node:fs";
74871
75135
  import { rm as rm15 } from "node:fs/promises";
74872
- import { join as join113 } from "node:path";
75136
+ import { join as join114 } from "node:path";
74873
75137
  async function uninstallSkillFromAgent(skill, agent, global3) {
74874
75138
  const agentConfig = agents[agent];
74875
75139
  const registry = await readRegistry();
@@ -74917,7 +75181,7 @@ async function uninstallSkillFromAgent(skill, agent, global3) {
74917
75181
  async function forceUninstallSkill(skill, agent, global3) {
74918
75182
  const agentConfig = agents[agent];
74919
75183
  const basePath = global3 ? agentConfig.globalPath : agentConfig.projectPath;
74920
- const path9 = join113(basePath, skill);
75184
+ const path9 = join114(basePath, skill);
74921
75185
  if (!existsSync57(path9)) {
74922
75186
  return {
74923
75187
  skill,
@@ -75422,12 +75686,12 @@ init_logger();
75422
75686
  // src/commands/telemetry/shared.ts
75423
75687
  import { existsSync as existsSync58, readFileSync as readFileSync15, readdirSync as readdirSync6 } from "node:fs";
75424
75688
  import { homedir as homedir29 } from "node:os";
75425
- import { join as join114 } from "node:path";
75689
+ import { join as join115 } from "node:path";
75426
75690
  init_token_store();
75427
- var USER_CACHE_PATH = join114(homedir29(), ".claude", "sk-user.json");
75428
- var EVENT_BUFFER_DIR = join114(homedir29(), ".claude", "sk-events");
75429
- var RATE_STATE_PATH = join114(homedir29(), ".claude", "sk-rate-state.json");
75430
- var METADATA_PATH = join114(homedir29(), ".claude", "metadata.json");
75691
+ var USER_CACHE_PATH = join115(homedir29(), ".claude", "sk-user.json");
75692
+ var EVENT_BUFFER_DIR = join115(homedir29(), ".claude", "sk-events");
75693
+ var RATE_STATE_PATH = join115(homedir29(), ".claude", "sk-rate-state.json");
75694
+ var METADATA_PATH = join115(homedir29(), ".claude", "metadata.json");
75431
75695
  var TELEMETRY_HOOK_FIELD = "hooks.telemetry";
75432
75696
  var TOKEN_PLACEHOLDER = "__INJECT_AT_RELEASE__";
75433
75697
  function readUserCache() {
@@ -75514,7 +75778,7 @@ async function handleDisable() {
75514
75778
  // src/commands/telemetry/phases/purge-local-handler.ts
75515
75779
  init_logger();
75516
75780
  import { existsSync as existsSync59, readdirSync as readdirSync7, unlinkSync as unlinkSync5 } from "node:fs";
75517
- import { join as join115 } from "node:path";
75781
+ import { join as join116 } from "node:path";
75518
75782
  function removeIfExists(path9) {
75519
75783
  try {
75520
75784
  if (!existsSync59(path9))
@@ -75534,7 +75798,7 @@ function removeBufferFiles() {
75534
75798
  if (!file.endsWith(".jsonl"))
75535
75799
  continue;
75536
75800
  try {
75537
- unlinkSync5(join115(EVENT_BUFFER_DIR, file));
75801
+ unlinkSync5(join116(EVENT_BUFFER_DIR, file));
75538
75802
  count += 1;
75539
75803
  } catch {}
75540
75804
  }
@@ -75760,13 +76024,13 @@ async function detectInstallations() {
75760
76024
 
75761
76025
  // src/commands/uninstall/removal-handler.ts
75762
76026
  import { readdirSync as readdirSync9, rmSync as rmSync6 } from "node:fs";
75763
- import { join as join117, resolve as resolve34, sep as sep10 } from "node:path";
76027
+ import { join as join118, resolve as resolve34, sep as sep10 } from "node:path";
75764
76028
  init_logger();
75765
76029
  var import_fs_extra38 = __toESM(require_lib(), 1);
75766
76030
 
75767
76031
  // src/commands/uninstall/analysis-handler.ts
75768
76032
  import { readdirSync as readdirSync8, rmSync as rmSync5 } from "node:fs";
75769
- import { dirname as dirname36, join as join116 } from "node:path";
76033
+ import { dirname as dirname36, join as join117 } from "node:path";
75770
76034
  init_logger();
75771
76035
  var import_picocolors35 = __toESM(require_picocolors(), 1);
75772
76036
  function classifyFileByOwnership(ownership, forceOverwrite, deleteReason) {
@@ -75813,7 +76077,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
75813
76077
  if (uninstallManifest.isMultiKit && kit && metadata?.kits?.[kit]) {
75814
76078
  const kitFiles = metadata.kits[kit].files || [];
75815
76079
  for (const trackedFile of kitFiles) {
75816
- const filePath = join116(installation.path, trackedFile.path);
76080
+ const filePath = join117(installation.path, trackedFile.path);
75817
76081
  if (uninstallManifest.filesToPreserve.includes(trackedFile.path)) {
75818
76082
  result.toPreserve.push({ path: trackedFile.path, reason: "shared with other kit" });
75819
76083
  continue;
@@ -75843,7 +76107,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
75843
76107
  return result;
75844
76108
  }
75845
76109
  for (const trackedFile of allTrackedFiles) {
75846
- const filePath = join116(installation.path, trackedFile.path);
76110
+ const filePath = join117(installation.path, trackedFile.path);
75847
76111
  const ownershipResult = await OwnershipChecker.checkOwnership(filePath, metadata, installation.path);
75848
76112
  if (!ownershipResult.exists)
75849
76113
  continue;
@@ -75940,7 +76204,7 @@ async function removeInstallations(installations, options2) {
75940
76204
  let removedCount = 0;
75941
76205
  let cleanedDirs = 0;
75942
76206
  for (const item of analysis.toDelete) {
75943
- const filePath = join117(installation.path, item.path);
76207
+ const filePath = join118(installation.path, item.path);
75944
76208
  if (!await import_fs_extra38.pathExists(filePath))
75945
76209
  continue;
75946
76210
  if (!await isPathSafeToRemove(filePath, installation.path)) {
@@ -76142,7 +76406,7 @@ ${import_picocolors36.default.yellow("User modifications will be permanently del
76142
76406
  // src/commands/update-cli.ts
76143
76407
  init_takumi_config_manager();
76144
76408
  import { exec as exec8, spawn as spawn2 } from "node:child_process";
76145
- import { join as join118 } from "node:path";
76409
+ import { join as join119 } from "node:path";
76146
76410
  import { promisify as promisify14 } from "node:util";
76147
76411
 
76148
76412
  // src/domains/github/npm-registry.ts
@@ -76309,7 +76573,7 @@ var import_fs_extra39 = __toESM(require_lib(), 1);
76309
76573
  // package.json
76310
76574
  var package_default = {
76311
76575
  name: "@sunasteriskrnd/takumi",
76312
- version: "1.0.0-dev.8",
76576
+ version: "1.0.0-dev.9",
76313
76577
  description: "CLI tool for bootstrapping and managing Takumi projects",
76314
76578
  type: "module",
76315
76579
  repository: {
@@ -76494,7 +76758,7 @@ function selectKitForUpdate(params) {
76494
76758
  };
76495
76759
  }
76496
76760
  async function readMetadataFile(claudeDir) {
76497
- const metadataPath = join118(claudeDir, "metadata.json");
76761
+ const metadataPath = join119(claudeDir, "metadata.json");
76498
76762
  try {
76499
76763
  if (!await import_fs_extra39.pathExists(metadataPath)) {
76500
76764
  return null;
@@ -76995,7 +77259,7 @@ init_logger();
76995
77259
  import { existsSync as existsSync65 } from "node:fs";
76996
77260
  import { rm as rm16 } from "node:fs/promises";
76997
77261
  import { homedir as homedir31 } from "node:os";
76998
- import { join as join125 } from "node:path";
77262
+ import { join as join126 } from "node:path";
76999
77263
  var import_picocolors38 = __toESM(require_picocolors(), 1);
77000
77264
 
77001
77265
  // src/commands/watch/phases/implementation-runner.ts
@@ -77505,7 +77769,7 @@ function spawnAndCollect3(command, args) {
77505
77769
 
77506
77770
  // src/commands/watch/phases/issue-processor.ts
77507
77771
  import { mkdir as mkdir32, writeFile as writeFile37 } from "node:fs/promises";
77508
- import { join as join121 } from "node:path";
77772
+ import { join as join122 } from "node:path";
77509
77773
 
77510
77774
  // src/commands/watch/phases/approval-detector.ts
77511
77775
  init_logger();
@@ -77880,9 +78144,9 @@ async function checkAwaitingApproval(state, setup, options2, watchLog, projectDi
77880
78144
 
77881
78145
  // src/commands/watch/phases/plan-dir-finder.ts
77882
78146
  import { readdir as readdir32, stat as stat14 } from "node:fs/promises";
77883
- import { join as join120 } from "node:path";
78147
+ import { join as join121 } from "node:path";
77884
78148
  async function findRecentPlanDir(cwd2, issueNumber, watchLog) {
77885
- const plansRoot = join120(cwd2, "plans");
78149
+ const plansRoot = join121(cwd2, "plans");
77886
78150
  try {
77887
78151
  const entries = await readdir32(plansRoot);
77888
78152
  const tenMinAgo = Date.now() - 10 * 60 * 1000;
@@ -77891,14 +78155,14 @@ async function findRecentPlanDir(cwd2, issueNumber, watchLog) {
77891
78155
  for (const entry of entries) {
77892
78156
  if (entry === "watch" || entry === "reports" || entry === "visuals")
77893
78157
  continue;
77894
- const dirPath = join120(plansRoot, entry);
78158
+ const dirPath = join121(plansRoot, entry);
77895
78159
  const dirStat = await stat14(dirPath);
77896
78160
  if (!dirStat.isDirectory())
77897
78161
  continue;
77898
78162
  if (dirStat.mtimeMs < tenMinAgo)
77899
78163
  continue;
77900
78164
  try {
77901
- await stat14(join120(dirPath, "plan.md"));
78165
+ await stat14(join121(dirPath, "plan.md"));
77902
78166
  } catch {
77903
78167
  continue;
77904
78168
  }
@@ -78129,13 +78393,13 @@ async function handlePlanGeneration(issue, state, config, setup, options2, watch
78129
78393
  stats.plansCreated++;
78130
78394
  const detectedPlanDir = await findRecentPlanDir(projectDir, issue.number, watchLog);
78131
78395
  if (detectedPlanDir) {
78132
- state.activeIssues[numStr].planPath = join121(detectedPlanDir, "plan.md");
78396
+ state.activeIssues[numStr].planPath = join122(detectedPlanDir, "plan.md");
78133
78397
  watchLog.info(`Plan directory detected: ${detectedPlanDir}`);
78134
78398
  } else {
78135
78399
  try {
78136
- const planDir = join121(projectDir, "plans", "watch");
78400
+ const planDir = join122(projectDir, "plans", "watch");
78137
78401
  await mkdir32(planDir, { recursive: true });
78138
- const planFilePath = join121(planDir, `issue-${issue.number}-plan.md`);
78402
+ const planFilePath = join122(planDir, `issue-${issue.number}-plan.md`);
78139
78403
  await writeFile37(planFilePath, planResult.planText, "utf-8");
78140
78404
  state.activeIssues[numStr].planPath = planFilePath;
78141
78405
  watchLog.info(`Plan saved (fallback) to ${planFilePath}`);
@@ -78440,18 +78704,18 @@ init_logger();
78440
78704
  import { spawnSync as spawnSync5 } from "node:child_process";
78441
78705
  import { existsSync as existsSync62 } from "node:fs";
78442
78706
  import { readdir as readdir33, stat as stat15 } from "node:fs/promises";
78443
- import { join as join122 } from "node:path";
78707
+ import { join as join123 } from "node:path";
78444
78708
  async function scanForRepos(parentDir) {
78445
78709
  const repos = [];
78446
78710
  const entries = await readdir33(parentDir);
78447
78711
  for (const entry of entries) {
78448
78712
  if (entry.startsWith("."))
78449
78713
  continue;
78450
- const fullPath = join122(parentDir, entry);
78714
+ const fullPath = join123(parentDir, entry);
78451
78715
  const entryStat = await stat15(fullPath);
78452
78716
  if (!entryStat.isDirectory())
78453
78717
  continue;
78454
- const gitDir = join122(fullPath, ".git");
78718
+ const gitDir = join123(fullPath, ".git");
78455
78719
  if (!existsSync62(gitDir))
78456
78720
  continue;
78457
78721
  const result = spawnSync5("gh", ["repo", "view", "--json", "owner,name"], {
@@ -78478,7 +78742,7 @@ init_logger();
78478
78742
  import { spawnSync as spawnSync6 } from "node:child_process";
78479
78743
  import { existsSync as existsSync63 } from "node:fs";
78480
78744
  import { homedir as homedir30 } from "node:os";
78481
- import { join as join123 } from "node:path";
78745
+ import { join as join124 } from "node:path";
78482
78746
  async function validateSetup(cwd2) {
78483
78747
  const workDir = cwd2 ?? process.cwd();
78484
78748
  const ghVersion = spawnSync6("gh", ["--version"], { encoding: "utf-8", timeout: 1e4 });
@@ -78509,7 +78773,7 @@ Run this command from a directory with a GitHub remote.`);
78509
78773
  } catch {
78510
78774
  throw new Error(`Failed to parse repository info: ${ghRepo.stdout}`);
78511
78775
  }
78512
- const skillsPath = join123(homedir30(), ".claude", "skills");
78776
+ const skillsPath = join124(homedir30(), ".claude", "skills");
78513
78777
  const skillsAvailable = existsSync63(skillsPath);
78514
78778
  if (!skillsAvailable) {
78515
78779
  logger.warning(`Takumi Engineer skills not found at ${skillsPath}`);
@@ -78528,7 +78792,7 @@ init_path_resolver();
78528
78792
  import { createWriteStream as createWriteStream4, statSync as statSync6 } from "node:fs";
78529
78793
  import { existsSync as existsSync64 } from "node:fs";
78530
78794
  import { mkdir as mkdir34, rename as rename9 } from "node:fs/promises";
78531
- import { join as join124 } from "node:path";
78795
+ import { join as join125 } from "node:path";
78532
78796
 
78533
78797
  class WatchLogger {
78534
78798
  logStream = null;
@@ -78536,7 +78800,7 @@ class WatchLogger {
78536
78800
  logPath = null;
78537
78801
  maxBytes;
78538
78802
  constructor(logDir, maxBytes = 0) {
78539
- this.logDir = logDir ?? join124(PathResolver.getTakumiDir(), "logs");
78803
+ this.logDir = logDir ?? join125(PathResolver.getTakumiDir(), "logs");
78540
78804
  this.maxBytes = maxBytes;
78541
78805
  }
78542
78806
  async init() {
@@ -78545,7 +78809,7 @@ class WatchLogger {
78545
78809
  await mkdir34(this.logDir, { recursive: true });
78546
78810
  }
78547
78811
  const dateStr = formatDate(new Date);
78548
- this.logPath = join124(this.logDir, `watch-${dateStr}.log`);
78812
+ this.logPath = join125(this.logDir, `watch-${dateStr}.log`);
78549
78813
  this.logStream = createWriteStream4(this.logPath, { flags: "a", mode: 384 });
78550
78814
  } catch (error) {
78551
78815
  logger.warning(`Cannot create watch log file: ${error instanceof Error ? error.message : "Unknown"}`);
@@ -78725,7 +78989,7 @@ async function watchCommand(options2) {
78725
78989
  }
78726
78990
  async function discoverRepos(options2, watchLog) {
78727
78991
  const cwd2 = process.cwd();
78728
- const isGitRepo = existsSync65(join125(cwd2, ".git"));
78992
+ const isGitRepo = existsSync65(join126(cwd2, ".git"));
78729
78993
  if (options2.force) {
78730
78994
  await forceRemoveLock(watchLog);
78731
78995
  }
@@ -78795,7 +79059,7 @@ async function resetState(state, projectDir, watchLog) {
78795
79059
  watchLog.info(`Watch state reset (--force) for ${projectDir}`);
78796
79060
  }
78797
79061
  async function forceRemoveLock(watchLog) {
78798
- const lockPath = join125(homedir31(), ".sunagentkit", "locks", `${LOCK_NAME}.lock`);
79062
+ const lockPath = join126(homedir31(), ".sunagentkit", "locks", `${LOCK_NAME}.lock`);
78799
79063
  try {
78800
79064
  await rm16(lockPath, { recursive: true, force: true });
78801
79065
  watchLog.info("Removed existing lock file (--force)");
@@ -78839,13 +79103,13 @@ function sleep2(ms2) {
78839
79103
  // src/cli/command-registry.ts
78840
79104
  init_logger();
78841
79105
  function registerCommands(cli) {
78842
- cli.command("new", "Bootstrap a new Takumi project (with interactive version selection)").option("--dir <dir>", "Target directory (default: .)").option("--kit <kit>", "Kit to use (engineer)").option("-r, --release <version>", "Skip version selection, use specific version (e.g., latest, v1.0.0)").option("--force", "Overwrite existing files without confirmation").option("--exclude <pattern>", "Exclude files matching glob pattern (can be used multiple times)").option("--opencode", "Install OpenCode CLI package (non-interactive mode)").option("--gemini", "Install Google Gemini CLI package (non-interactive mode)").option("--install-skills", "Install skills dependencies (non-interactive mode)").option("--with-sudo", "Include system packages requiring sudo (Linux: ffmpeg, imagemagick)").option("--prefix", "Add /sk: prefix to all slash commands by moving them to commands/sk/ subdirectory").option("--beta", "Show beta versions in selection prompt").option("--refresh", "Bypass release cache to fetch latest versions from GitHub").option("--docs-dir <name>", "Custom docs folder name (default: docs)").option("--plans-dir <name>", "Custom plans folder name (default: plans)").option("-y, --yes", "Non-interactive mode with sensible defaults (skip all prompts)").option("--use-git", "Use git clone instead of GitHub API (uses SSH/HTTPS credentials)").option("--archive <path>", "Use local archive file instead of downloading (zip/tar.gz)").option("--kit-path <path>", "Use local kit directory instead of downloading").option("--local", "Use local monorepo as kit source (auto-detects from CLI location)").option("--use-gh", "Force GitHub release source (bypass Worker R2 proxy; default uses Worker)").action(async (options2) => {
79106
+ cli.command("new", "Bootstrap a new Takumi project (with interactive version selection)").option("--dir <dir>", "Target directory (default: .)").option("--kit <kit>", "Kit(s) to install (engineer, extras). Repeat the flag to install multiple kits, e.g. --kit engineer --kit extras.").option("-r, --release <version>", "Skip version selection, use specific version (e.g., latest, v1.0.0)").option("--force", "Overwrite existing files without confirmation").option("--exclude <pattern>", "Exclude files matching glob pattern (can be used multiple times)").option("--opencode", "Install OpenCode CLI package (non-interactive mode)").option("--gemini", "Install Google Gemini CLI package (non-interactive mode)").option("--install-skills", "Install skills dependencies (non-interactive mode)").option("--with-sudo", "Include system packages requiring sudo (Linux: ffmpeg, imagemagick)").option("--prefix", "Add /sk: prefix to all slash commands by moving them to commands/sk/ subdirectory").option("--beta", "Show beta versions in selection prompt").option("--refresh", "Bypass release cache to fetch latest versions from GitHub").option("--docs-dir <name>", "Custom docs folder name (default: docs)").option("--plans-dir <name>", "Custom plans folder name (default: plans)").option("-y, --yes", "Non-interactive mode with sensible defaults (skip all prompts)").option("--use-git", "Use git clone instead of GitHub API (uses SSH/HTTPS credentials)").option("--archive <path>", "Use local archive file instead of downloading (zip/tar.gz)").option("--kit-path <path>", "Use local kit directory instead of downloading").option("--local", "Use local monorepo as kit source (auto-detects from CLI location)").option("--use-gh", "Force GitHub release source (bypass Worker R2 proxy; default uses Worker)").action(async (options2) => {
78843
79107
  if (options2.exclude && !Array.isArray(options2.exclude)) {
78844
79108
  options2.exclude = [options2.exclude];
78845
79109
  }
78846
79110
  await newCommand(options2);
78847
79111
  });
78848
- cli.command("init", "Initialize or update Takumi project (with interactive version selection)").option("--dir <dir>", "Target directory (default: .)").option("--kit <kit>", "Kit to use (engineer)").option("-r, --release <version>", "Skip version selection, use specific version (e.g., latest, v1.0.0)").option("--exclude <pattern>", "Exclude files matching glob pattern (can be used multiple times)").option("--only <pattern>", "Include only files matching glob pattern (can be used multiple times)").option("-g, --global", "Use platform-specific user configuration directory").option("--fresh", "Full reset: remove SK files, replace settings.json and CLAUDE.md, reinstall from scratch").option("--force", "Force reinstall even if already at latest version (use with --yes; re-onboards missing files without full reset)").option("--install-skills", "Install skills dependencies (non-interactive mode)").option("--with-sudo", "Include system packages requiring sudo (Linux: ffmpeg, imagemagick)").option("--prefix", "Add /sk: prefix to all slash commands by moving them to commands/sk/ subdirectory").option("--beta", "Show beta versions in selection prompt").option("--refresh", "Bypass release cache to fetch latest versions from GitHub").option("--dry-run", "Preview changes without applying them (requires --prefix)").option("--force-overwrite", "Override ownership protections and delete user-modified files (requires --prefix)").option("--force-overwrite-settings", "Fully replace settings.json instead of selective merge (destroys user customizations)").option("--skip-setup", "Skip interactive configuration wizard").option("--docs-dir <name>", "Custom docs folder name (default: docs)").option("--plans-dir <name>", "Custom plans folder name (default: plans)").option("-y, --yes", "Non-interactive mode with sensible defaults (skip all prompts)").option("--sync", "Sync config files from upstream with interactive hunk-by-hunk merge").option("--use-git", "Use git clone instead of GitHub API (uses SSH/HTTPS credentials)").option("--archive <path>", "Use local archive file instead of downloading (zip/tar.gz)").option("--kit-path <path>", "Use local kit directory instead of downloading").option("--local", "Use local monorepo as kit source (auto-detects from CLI location)").option("--use-gh", "Force GitHub release source (bypass Worker R2 proxy; default uses Worker)").option("-a, --agent <agents...>", "Target agents (claude-code, codex). Default: claude-code").action(async (options2) => {
79112
+ cli.command("init", "Initialize or update Takumi project (with interactive version selection)").option("--dir <dir>", "Target directory (default: .)").option("--kit <kit>", "Kit(s) to install (engineer, extras). Repeat the flag to install multiple kits, e.g. --kit engineer --kit extras.").option("-r, --release <version>", "Skip version selection, use specific version (e.g., latest, v1.0.0)").option("--exclude <pattern>", "Exclude files matching glob pattern (can be used multiple times)").option("--only <pattern>", "Include only files matching glob pattern (can be used multiple times)").option("-g, --global", "Use platform-specific user configuration directory").option("--fresh", "Full reset: remove SK files, replace settings.json and CLAUDE.md, reinstall from scratch").option("--force", "Force reinstall even if already at latest version (use with --yes; re-onboards missing files without full reset)").option("--install-skills", "Install skills dependencies (non-interactive mode)").option("--with-sudo", "Include system packages requiring sudo (Linux: ffmpeg, imagemagick)").option("--prefix", "Add /sk: prefix to all slash commands by moving them to commands/sk/ subdirectory").option("--beta", "Show beta versions in selection prompt").option("--refresh", "Bypass release cache to fetch latest versions from GitHub").option("--dry-run", "Preview changes without applying them (requires --prefix)").option("--force-overwrite", "Override ownership protections and delete user-modified files (requires --prefix)").option("--force-overwrite-settings", "Fully replace settings.json instead of selective merge (destroys user customizations)").option("--skip-setup", "Skip interactive configuration wizard").option("--docs-dir <name>", "Custom docs folder name (default: docs)").option("--plans-dir <name>", "Custom plans folder name (default: plans)").option("-y, --yes", "Non-interactive mode with sensible defaults (skip all prompts)").option("--sync", "Sync config files from upstream with interactive hunk-by-hunk merge").option("--use-git", "Use git clone instead of GitHub API (uses SSH/HTTPS credentials)").option("--archive <path>", "Use local archive file instead of downloading (zip/tar.gz)").option("--kit-path <path>", "Use local kit directory instead of downloading").option("--local", "Use local monorepo as kit source (auto-detects from CLI location)").option("--use-gh", "Force GitHub release source (bypass Worker R2 proxy; default uses Worker)").option("-a, --agent <agents...>", "Target agents (claude-code, codex). Default: claude-code").action(async (options2) => {
78849
79113
  if (options2.exclude && !Array.isArray(options2.exclude)) {
78850
79114
  options2.exclude = [options2.exclude];
78851
79115
  }
@@ -78858,6 +79122,9 @@ function registerCommands(cli) {
78858
79122
  if (options2.agent) {
78859
79123
  options2.agents = options2.agent;
78860
79124
  }
79125
+ if (options2.kit && Array.isArray(options2.kit)) {
79126
+ options2.kit = options2.kit.join(",");
79127
+ }
78861
79128
  await initCommand(options2);
78862
79129
  });
78863
79130
  cli.command("update", "Update Takumi CLI to the latest version").option("-r, --release <version>", "Update to a specific version").option("--check", "Check for updates without installing").option("-y, --yes", "Non-interactive mode with sensible defaults (skip all prompts)").option("-d, --dev", "Update to the latest dev version").option("--beta", "Alias for --dev (deprecated)").option("--registry <url>", "Custom npm registry URL").option("--kit <kit>", "[DEPRECATED] Use 'takumi init --kit <kit>' instead").option("-g, --global", "[DEPRECATED] Use 'takumi init --global' instead").action(async (options2) => {
@@ -78997,7 +79264,7 @@ function registerCommands(cli) {
78997
79264
 
78998
79265
  // src/cli/version-display.ts
78999
79266
  import { existsSync as existsSync77, readFileSync as readFileSync20 } from "node:fs";
79000
- import { join as join137 } from "node:path";
79267
+ import { join as join138 } from "node:path";
79001
79268
  init_help_banner();
79002
79269
  // src/domains/versioning/checking/kit-version-checker.ts
79003
79270
  init_github_client();
@@ -79009,14 +79276,14 @@ init_logger();
79009
79276
  init_path_resolver();
79010
79277
  import { existsSync as existsSync76 } from "node:fs";
79011
79278
  import { mkdir as mkdir35, readFile as readFile52, writeFile as writeFile40 } from "node:fs/promises";
79012
- import { join as join136 } from "node:path";
79279
+ import { join as join137 } from "node:path";
79013
79280
 
79014
79281
  class VersionCacheManager {
79015
79282
  static CACHE_FILENAME = "version-check.json";
79016
79283
  static CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
79017
79284
  static getCacheFile() {
79018
79285
  const cacheDir = PathResolver.getCacheDir(false);
79019
- return join136(cacheDir, VersionCacheManager.CACHE_FILENAME);
79286
+ return join137(cacheDir, VersionCacheManager.CACHE_FILENAME);
79020
79287
  }
79021
79288
  static async load() {
79022
79289
  const cacheFile = VersionCacheManager.getCacheFile();
@@ -79309,8 +79576,8 @@ async function displayVersion() {
79309
79576
  const localSubdir = PROVIDER_LOCAL_SUBDIRS[provider];
79310
79577
  if (!localSubdir)
79311
79578
  continue;
79312
- const localMeta = join137(process.cwd(), localSubdir, "metadata.json");
79313
- if (localMeta === join137(inst.globalRoot(), "metadata.json"))
79579
+ const localMeta = join138(process.cwd(), localSubdir, "metadata.json");
79580
+ if (localMeta === join138(inst.globalRoot(), "metadata.json"))
79314
79581
  continue;
79315
79582
  if (!existsSync77(localMeta))
79316
79583
  continue;
@@ -79335,7 +79602,7 @@ async function displayVersion() {
79335
79602
  }
79336
79603
  const singleInstall = detectedGlobals.length === 1 && detectedGlobals[0]?.provider === "claude-code";
79337
79604
  for (const { provider, path: installPath } of detectedGlobals) {
79338
- const metadataPath = join137(installPath, "metadata.json");
79605
+ const metadataPath = join138(installPath, "metadata.json");
79339
79606
  if (existsSync77(metadataPath)) {
79340
79607
  try {
79341
79608
  const rawMetadata = JSON.parse(readFileSync20(metadataPath, "utf-8"));