@sunasteriskrnd/takumi 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +605 -227
  2. package/package.json +2 -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";
@@ -64049,7 +64137,96 @@ async function maybeShowConfigUpdateNotification(claudeDir, global3) {
64049
64137
  init_package_installer();
64050
64138
  init_logger();
64051
64139
 
64140
+ // src/domains/ui/prompts/agent-selection-prompts.ts
64141
+ init_provider_registry();
64142
+
64143
+ // src/services/package-installer/agent-cli-detector.ts
64144
+ init_process_executor();
64145
+ var DETECT_TIMEOUT_MS = 5000;
64146
+ var BINARY_CANDIDATES = {
64147
+ "claude-code": process.platform === "win32" ? ["claude.exe", "claude.cmd", "claude"] : ["claude"],
64148
+ codex: process.platform === "win32" ? ["codex.exe", "codex.cmd", "codex"] : ["codex"]
64149
+ };
64150
+ async function probeBinary(candidates) {
64151
+ for (const bin of candidates) {
64152
+ const needsShell = process.platform === "win32" && /\.(cmd|bat)$/i.test(bin);
64153
+ try {
64154
+ const { stdout: stdout2 } = await execFileAsync5(bin, ["--version"], {
64155
+ timeout: DETECT_TIMEOUT_MS,
64156
+ encoding: "utf8",
64157
+ shell: needsShell
64158
+ });
64159
+ return typeof stdout2 === "string" ? stdout2 : String(stdout2);
64160
+ } catch {}
64161
+ }
64162
+ return null;
64163
+ }
64164
+ function extractVersion(stdout2) {
64165
+ const match2 = stdout2.match(/(\d+\.\d+\.\d+(?:[-+][\w.]+)?)/);
64166
+ return match2 ? match2[1] : undefined;
64167
+ }
64168
+ async function detectAgentInstallations(providers2) {
64169
+ const probes = providers2.filter((p) => (p in BINARY_CANDIDATES)).map(async (provider) => {
64170
+ const candidates = BINARY_CANDIDATES[provider];
64171
+ if (!candidates) {
64172
+ return [provider, { installed: false }];
64173
+ }
64174
+ const stdout2 = await probeBinary(candidates);
64175
+ const detection = stdout2 ? { installed: true, version: extractVersion(stdout2) } : { installed: false };
64176
+ return [provider, detection];
64177
+ });
64178
+ const entries = await Promise.all(probes);
64179
+ const result = {};
64180
+ for (const [provider, detection] of entries) {
64181
+ result[provider] = detection;
64182
+ }
64183
+ return result;
64184
+ }
64185
+
64186
+ // src/domains/ui/prompts/agent-selection-prompts.ts
64187
+ function buildDetectionNote(supported, detections) {
64188
+ const lines = supported.map((provider) => {
64189
+ const detection = detections[provider];
64190
+ const label = providers[provider]?.displayName ?? provider;
64191
+ if (detection?.installed) {
64192
+ const version3 = detection.version ? ` v${detection.version}` : "";
64193
+ return ` ✓ ${label}${version3} detected on PATH`;
64194
+ }
64195
+ return ` ✗ ${label} not detected on PATH`;
64196
+ });
64197
+ lines.push("");
64198
+ lines.push("Init writes config files regardless — detection only informs defaults.");
64199
+ return lines.join(`
64200
+ `);
64201
+ }
64202
+ function computeInitialSelection(supported, detections) {
64203
+ if (detections["claude-code"]?.installed)
64204
+ return ["claude-code"];
64205
+ const firstInstalled = supported.find((p) => detections[p]?.installed);
64206
+ return firstInstalled ? [firstInstalled] : [];
64207
+ }
64208
+ async function promptAgentSelection(supported) {
64209
+ const detections = await detectAgentInstallations(supported);
64210
+ note(buildDetectionNote(supported, detections), "Detected agent CLIs");
64211
+ const options2 = supported.map((provider) => {
64212
+ const detection = detections[provider];
64213
+ const label = providers[provider]?.displayName ?? provider;
64214
+ const hint = detection?.installed ? detection.version ? `installed v${detection.version}` : "installed" : "not detected — config will still be written";
64215
+ return { value: provider, label, hint };
64216
+ });
64217
+ const initialValues = computeInitialSelection(supported, detections);
64218
+ const selected = await ae({
64219
+ message: "Select agent(s) to initialize",
64220
+ options: options2,
64221
+ required: true,
64222
+ initialValues
64223
+ });
64224
+ if (lD(selected))
64225
+ return null;
64226
+ return selected;
64227
+ }
64052
64228
  // src/domains/ui/prompts/kit-prompts.ts
64229
+ init_logger();
64053
64230
  init_types2();
64054
64231
  async function selectKit(defaultKit, accessibleKits) {
64055
64232
  const kits = accessibleKits ?? Object.keys(AVAILABLE_KITS);
@@ -64067,6 +64244,39 @@ async function selectKit(defaultKit, accessibleKits) {
64067
64244
  }
64068
64245
  return kit;
64069
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
+ }
64070
64280
  async function getDirectory(defaultDir = ".") {
64071
64281
  const dir = await te({
64072
64282
  message: "Enter target directory:",
@@ -64730,6 +64940,9 @@ class PromptsManager {
64730
64940
  async selectKit(defaultKit, accessibleKits) {
64731
64941
  return selectKit(defaultKit, accessibleKits);
64732
64942
  }
64943
+ async selectKits(accessibleKits, defaults2) {
64944
+ return selectKits(accessibleKits, defaults2);
64945
+ }
64733
64946
  async selectVersion(versions, defaultVersion) {
64734
64947
  return selectVersion(versions, defaultVersion);
64735
64948
  }
@@ -64805,6 +65018,9 @@ class PromptsManager {
64805
65018
  async promptSkillsInstallation() {
64806
65019
  return promptSkillsInstallation();
64807
65020
  }
65021
+ async promptAgentSelection(supported) {
65022
+ return promptAgentSelection(supported);
65023
+ }
64808
65024
  showPackageInstallationResults(results) {
64809
65025
  const successfulInstalls = [];
64810
65026
  const failedInstalls = [];
@@ -64868,6 +65084,8 @@ class PromptsManager {
64868
65084
 
64869
65085
  // src/commands/init/init-command.ts
64870
65086
  init_logger();
65087
+ init_path_resolver();
65088
+ init_types2();
64871
65089
 
64872
65090
  // src/commands/init/context-factory.ts
64873
65091
  function createInitContext(rawOptions, prompts) {
@@ -69545,8 +69763,28 @@ async function handleDownload(ctx) {
69545
69763
  // src/commands/init/phases/options-resolver.ts
69546
69764
  init_logger();
69547
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
+ }
69548
69785
  async function resolveOptions(ctx) {
69549
69786
  const explicitDir = ctx.rawOptions.dir !== undefined;
69787
+ const explicitAgents = Array.isArray(ctx.rawOptions.agents) && ctx.rawOptions.agents.length > 0;
69550
69788
  const parsed = UpdateCommandOptionsSchema.parse(ctx.rawOptions);
69551
69789
  const validOptions = {
69552
69790
  kit: parsed.kit,
@@ -69589,8 +69827,6 @@ async function resolveOptions(ctx) {
69589
69827
  ` + "For other agents, run init without --sync to perform a fresh install.");
69590
69828
  }
69591
69829
  validOptions.agents = Array.from(new Set(validOptions.agents));
69592
- } else {
69593
- validOptions.agents = ["claude-code"];
69594
69830
  }
69595
69831
  ConfigManager.setGlobalFlag(validOptions.global);
69596
69832
  if (validOptions.global) {
@@ -69635,10 +69871,52 @@ Example: takumi init --use-git --release v2.1.0`);
69635
69871
  Choose one approach.`);
69636
69872
  }
69637
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
+ }
69638
69896
  if (validOptions.yes) {
69639
69897
  logger.info("Running in non-interactive mode (--yes flag)");
69640
69898
  }
69641
69899
  const initialInstallSkills = validOptions.installSkills ? true : undefined;
69900
+ if (!explicitAgents) {
69901
+ if (isNonInteractive2) {
69902
+ validOptions.agents = ["claude-code"];
69903
+ } else {
69904
+ const supported = listSupportedProviders();
69905
+ const selected = await ctx.prompts.promptAgentSelection(supported);
69906
+ if (selected === null) {
69907
+ logger.warning("Agent selection cancelled");
69908
+ return {
69909
+ ...ctx,
69910
+ options: validOptions,
69911
+ explicitDir,
69912
+ isNonInteractive: isNonInteractive2,
69913
+ installSkills: initialInstallSkills,
69914
+ cancelled: true
69915
+ };
69916
+ }
69917
+ validOptions.agents = selected;
69918
+ }
69919
+ }
69642
69920
  return {
69643
69921
  ...ctx,
69644
69922
  options: validOptions,
@@ -70052,48 +70330,58 @@ async function handleSelection(ctx) {
70052
70330
  return { ...ctx, cancelled: true };
70053
70331
  }
70054
70332
  }
70055
- let kitType;
70056
- const kitOption = ctx.options.kit || config.defaults?.kit;
70057
- if (kitOption) {
70333
+ let selectedKits = ctx.options.selectedKits;
70334
+ if (!selectedKits || selectedKits.length === 0) {
70058
70335
  const allKitTypes = Object.keys(AVAILABLE_KITS);
70059
- if (kitOption === "all" || kitOption.includes(",")) {
70060
- const kitsToInstall = accessibleKits ?? allKitTypes;
70061
- if (kitsToInstall.length === 0) {
70062
- logger.error("No kits accessible for installation");
70063
- return { ...ctx, cancelled: true };
70064
- }
70065
- kitType = kitsToInstall[0];
70066
- logger.info(`Using kit: ${AVAILABLE_KITS[kitType].name}`);
70067
- } else {
70068
- 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)) {
70069
70341
  logger.error(`Invalid kit: ${kitOption}`);
70070
70342
  logger.info(`Valid kits: ${allKitTypes.join(", ")}`);
70071
70343
  return { ...ctx, cancelled: true };
70344
+ } else {
70345
+ selectedKits = [kitOption];
70072
70346
  }
70073
- kitType = kitOption;
70074
- if (accessibleKits && !accessibleKits.includes(kitType)) {
70075
- logger.error(`No access to ${AVAILABLE_KITS[kitType].name}`);
70076
- logger.info("Request access from your team lead or check your GitHub invitation");
70077
- 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);
70078
70360
  }
70079
70361
  }
70080
70362
  }
70081
- if (!kitType) {
70082
- if (ctx.isNonInteractive) {
70083
- if (!accessibleKits || accessibleKits.length === 0) {
70084
- throw new Error("Kit must be specified via --kit flag in non-interactive mode (no accessible kits detected)");
70085
- }
70086
- kitType = accessibleKits[0];
70087
- logger.info(`Auto-selected: ${AVAILABLE_KITS[kitType].name}`);
70088
- } else if (accessibleKits?.length === 1) {
70089
- kitType = accessibleKits[0];
70090
- logger.info(`Using ${AVAILABLE_KITS[kitType].name} (only accessible kit)`);
70091
- } else {
70092
- 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 };
70369
+ }
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);
70093
70376
  }
70094
70377
  }
70378
+ const kitType = selectedKits[0];
70095
70379
  const kit = AVAILABLE_KITS[kitType];
70096
- 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
+ }
70097
70385
  let targetDir;
70098
70386
  if (ctx.explicitDir) {
70099
70387
  targetDir = ctx.options.dir;
@@ -70302,12 +70590,30 @@ async function handleSelection(ctx) {
70302
70590
  ...ctx,
70303
70591
  kit,
70304
70592
  kitType,
70593
+ selectedKits,
70305
70594
  resolvedDir,
70306
70595
  release,
70307
70596
  selectedVersion,
70308
70597
  accessibleKits
70309
70598
  };
70310
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
+ }
70311
70617
  function resolveGlobalTargetDir(targetAgents) {
70312
70618
  const primary = targetAgents[0];
70313
70619
  if (primary) {
@@ -70348,7 +70654,7 @@ async function handleSync(ctx) {
70348
70654
  Run 'takumi init' to update.`, "Legacy Installation");
70349
70655
  return { ...ctx, cancelled: true };
70350
70656
  }
70351
- let kitType = ctx.options.kit;
70657
+ let kitType = ctx.options.selectedKits?.[0];
70352
70658
  if (!kitType) {
70353
70659
  const engineerMeta = await readKitManifest(claudeDir, "engineer");
70354
70660
  if (engineerMeta) {
@@ -71181,23 +71487,91 @@ async function executeInit(options2, prompts) {
71181
71487
  ctx = await handleSelection(ctx);
71182
71488
  if (ctx.cancelled)
71183
71489
  return;
71184
- ctx = await handleDownload(ctx);
71185
- 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");
71186
71505
  return;
71187
- if (!isSyncMode) {
71188
- ctx = await handleTransforms(ctx);
71189
- if (ctx.cancelled)
71190
- return;
71191
71506
  }
71192
- if (isSyncMode) {
71193
- ctx = await executeSyncMerge(ctx);
71194
- 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))
71195
71570
  return;
71196
71571
  }
71197
- const results = await dispatchInstallers(ctx, targetAgents);
71572
+ ctx = lastCtx;
71573
+ const results = aggregatedResults;
71198
71574
  ctx.installerResults = results;
71199
- if (results.some((r2) => r2.cancelled))
71200
- return;
71201
71575
  if (targetAgents.length > 1) {
71202
71576
  displayMultiInstallerSummary(results);
71203
71577
  }
@@ -71258,7 +71632,7 @@ async function initCommand(options2) {
71258
71632
  import { existsSync as existsSync47 } from "node:fs";
71259
71633
  import { readFile as readFile45, rm as rm13, unlink as unlink15 } from "node:fs/promises";
71260
71634
  import { homedir as homedir25 } from "node:os";
71261
- 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";
71262
71636
  init_dist2();
71263
71637
  var import_picocolors27 = __toESM(require_picocolors(), 1);
71264
71638
  init_logger();
@@ -71740,7 +72114,7 @@ async function executeDeleteAction(action, options2) {
71740
72114
  async function processMetadataDeletions(skillSourcePath, installGlobally) {
71741
72115
  if (!skillSourcePath)
71742
72116
  return;
71743
- const sourceMetadataPath = join102(resolve26(skillSourcePath, ".."), "metadata.json");
72117
+ const sourceMetadataPath = join103(resolve26(skillSourcePath, ".."), "metadata.json");
71744
72118
  if (!existsSync47(sourceMetadataPath))
71745
72119
  return;
71746
72120
  let sourceMetadata;
@@ -71753,11 +72127,11 @@ async function processMetadataDeletions(skillSourcePath, installGlobally) {
71753
72127
  }
71754
72128
  if (!sourceMetadata.deletions || sourceMetadata.deletions.length === 0)
71755
72129
  return;
71756
- const claudeDir = installGlobally ? join102(homedir25(), ".claude") : join102(process.cwd(), ".claude");
72130
+ const claudeDir = installGlobally ? join103(homedir25(), ".claude") : join103(process.cwd(), ".claude");
71757
72131
  if (!existsSync47(claudeDir))
71758
72132
  return;
71759
72133
  try {
71760
- const result = await handleDeletions(sourceMetadata, claudeDir);
72134
+ const result = await handleDeletions(sourceMetadata, claudeDir, undefined);
71761
72135
  if (result.deletedPaths.length > 0) {
71762
72136
  logger.verbose(`[migrate] Cleaned up ${result.deletedPaths.length} deprecated path(s): ${result.deletedPaths.join(", ")}`);
71763
72137
  }
@@ -71901,8 +72275,8 @@ async function migrateCommand(options2) {
71901
72275
  selectedProviders = Array.from(new Set(selectedProviders));
71902
72276
  let installGlobally = options2.global ?? false;
71903
72277
  if (options2.global === undefined && !options2.yes) {
71904
- const projectTarget = join102(process.cwd(), ".claude");
71905
- const globalTarget = join102(homedir25(), ".claude");
72278
+ const projectTarget = join103(process.cwd(), ".claude");
72279
+ const globalTarget = join103(homedir25(), ".claude");
71906
72280
  const scopeChoice = await ie({
71907
72281
  message: "Installation scope",
71908
72282
  options: [
@@ -71954,7 +72328,7 @@ async function migrateCommand(options2) {
71954
72328
  }
71955
72329
  const providerNames = selectedProviders.map((prov) => import_picocolors27.default.cyan(providers[prov].displayName)).join(", ");
71956
72330
  f2.message(` Providers: ${providerNames}`);
71957
- const targetDir = installGlobally ? join102(homedir25(), ".claude") : join102(process.cwd(), ".claude");
72331
+ const targetDir = installGlobally ? join103(homedir25(), ".claude") : join103(process.cwd(), ".claude");
71958
72332
  f2.message(` Scope: ${installGlobally ? "Global" : "Project"} ${import_picocolors27.default.dim(`-> ${targetDir}`)}`);
71959
72333
  const cmdProviders = getProvidersSupporting("commands");
71960
72334
  const unsupportedCmd = selectedProviders.filter((pv) => !cmdProviders.includes(pv));
@@ -72464,7 +72838,7 @@ async function handleDirectorySetup(ctx) {
72464
72838
  };
72465
72839
  }
72466
72840
  // src/commands/new/phases/project-creation.ts
72467
- import { join as join103 } from "node:path";
72841
+ import { join as join104 } from "node:path";
72468
72842
  init_github_client();
72469
72843
  init_logger();
72470
72844
  init_output_manager();
@@ -72618,7 +72992,7 @@ async function projectCreation(kit, resolvedDir, validOptions, isNonInteractive2
72618
72992
  output.section("Installing");
72619
72993
  logger.verbose("Installation target", { directory: resolvedDir });
72620
72994
  const merger = new FileMerger;
72621
- const claudeDir = join103(resolvedDir, ".claude");
72995
+ const claudeDir = join104(resolvedDir, ".claude");
72622
72996
  merger.setMultiKitContext(claudeDir, kit);
72623
72997
  if (validOptions.exclude && validOptions.exclude.length > 0) {
72624
72998
  merger.addIgnorePatterns(validOptions.exclude);
@@ -72671,10 +73045,10 @@ async function handleProjectCreation(ctx) {
72671
73045
  };
72672
73046
  }
72673
73047
  // src/commands/new/phases/post-setup.ts
72674
- import { join as join105 } from "node:path";
73048
+ import { join as join106 } from "node:path";
72675
73049
 
72676
73050
  // src/domains/installation/setup-wizard.ts
72677
- import { join as join104 } from "node:path";
73051
+ import { join as join105 } from "node:path";
72678
73052
  init_logger();
72679
73053
  init_dist2();
72680
73054
  var import_fs_extra36 = __toESM(require_lib(), 1);
@@ -72754,7 +73128,7 @@ async function parseEnvFile(path9) {
72754
73128
  }
72755
73129
  }
72756
73130
  async function checkGlobalConfig() {
72757
- const globalEnvPath = join104(getClaudeDir(), ".env");
73131
+ const globalEnvPath = join105(getClaudeDir(), ".env");
72758
73132
  if (!await import_fs_extra36.pathExists(globalEnvPath))
72759
73133
  return false;
72760
73134
  const env2 = await parseEnvFile(globalEnvPath);
@@ -72770,7 +73144,7 @@ async function runSetupWizard(options2) {
72770
73144
  let globalEnv = {};
72771
73145
  const hasGlobalConfig = !isGlobal && await checkGlobalConfig();
72772
73146
  if (!isGlobal) {
72773
- const globalEnvPath = join104(getClaudeDir(), ".env");
73147
+ const globalEnvPath = join105(getClaudeDir(), ".env");
72774
73148
  if (await import_fs_extra36.pathExists(globalEnvPath)) {
72775
73149
  globalEnv = await parseEnvFile(globalEnvPath);
72776
73150
  }
@@ -72833,7 +73207,7 @@ async function runSetupWizard(options2) {
72833
73207
  }
72834
73208
  }
72835
73209
  await generateEnvFile(targetDir, values);
72836
- f2.success(`Configuration saved to ${join104(targetDir, ".env")}`);
73210
+ f2.success(`Configuration saved to ${join105(targetDir, ".env")}`);
72837
73211
  return true;
72838
73212
  }
72839
73213
  async function promptForAdditionalGeminiKeys(primaryKey) {
@@ -72936,9 +73310,9 @@ async function postSetup(resolvedDir, validOptions, isNonInteractive2, prompts)
72936
73310
  withSudo: validOptions.withSudo
72937
73311
  });
72938
73312
  }
72939
- const claudeDir = join105(resolvedDir, ".claude");
73313
+ const claudeDir = join106(resolvedDir, ".claude");
72940
73314
  await promptSetupWizardIfNeeded({
72941
- envPath: join105(claudeDir, ".env"),
73315
+ envPath: join106(claudeDir, ".env"),
72942
73316
  claudeDir,
72943
73317
  isGlobal: false,
72944
73318
  isNonInteractive: isNonInteractive2,
@@ -73015,11 +73389,11 @@ Example: tkm new --use-git --release v2.1.0`);
73015
73389
  // src/commands/plan/plan-command.ts
73016
73390
  init_output_manager();
73017
73391
  import { existsSync as existsSync52, statSync as statSync5 } from "node:fs";
73018
- 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";
73019
73393
 
73020
73394
  // src/commands/plan/plan-read-handlers.ts
73021
73395
  import { existsSync as existsSync51, statSync as statSync4 } from "node:fs";
73022
- 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";
73023
73397
 
73024
73398
  // src/domains/plan-parser/index.ts
73025
73399
  import { dirname as dirname31 } from "node:path";
@@ -73400,12 +73774,12 @@ function parsePlanFile(planFilePath, options2) {
73400
73774
  }
73401
73775
  // src/domains/plan-parser/plan-scanner.ts
73402
73776
  import { existsSync as existsSync48, readdirSync as readdirSync5 } from "node:fs";
73403
- import { join as join106 } from "node:path";
73777
+ import { join as join107 } from "node:path";
73404
73778
  function scanPlanDir(dir) {
73405
73779
  if (!existsSync48(dir))
73406
73780
  return [];
73407
73781
  try {
73408
- 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);
73409
73783
  } catch {
73410
73784
  return [];
73411
73785
  }
@@ -73474,7 +73848,7 @@ function validatePlanFile(filePath, strict = false) {
73474
73848
  var import_gray_matter7 = __toESM(require_gray_matter(), 1);
73475
73849
  import { mkdirSync as mkdirSync3, readFileSync as readFileSync14, writeFileSync as writeFileSync5 } from "node:fs";
73476
73850
  import { existsSync as existsSync50 } from "node:fs";
73477
- 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";
73478
73852
  function phaseNameToFilename(id, name) {
73479
73853
  const numMatch = /^(\d+)([a-z]*)$/i.exec(id);
73480
73854
  const num = numMatch ? numMatch[1] : id;
@@ -73582,12 +73956,12 @@ function scaffoldPlan(options2) {
73582
73956
  mkdirSync3(dir, { recursive: true });
73583
73957
  const resolvedPhases = resolvePhaseIds(options2.phases);
73584
73958
  const optionsWithResolved = { ...options2, phases: resolvedPhases };
73585
- const planFile = join107(dir, "plan.md");
73959
+ const planFile = join108(dir, "plan.md");
73586
73960
  writeFileSync5(planFile, generatePlanMd(optionsWithResolved), "utf8");
73587
73961
  const phaseFiles = [];
73588
73962
  for (const phase of resolvedPhases) {
73589
73963
  const filename = phaseNameToFilename(phase.id, phase.name);
73590
- const phaseFile = join107(dir, filename);
73964
+ const phaseFile = join108(dir, filename);
73591
73965
  writeFileSync5(phaseFile, generatePhaseTemplate(phase), "utf8");
73592
73966
  phaseFiles.push(phaseFile);
73593
73967
  }
@@ -73667,7 +74041,7 @@ function phaseNameFilenameFromTableRow(body, phaseId, planDir) {
73667
74041
  continue;
73668
74042
  const linkMatch = /\[([^\]]+)\]\(\.\/([^)]+)\)/.exec(row);
73669
74043
  if (linkMatch)
73670
- return join107(planDir, linkMatch[2]);
74044
+ return join108(planDir, linkMatch[2]);
73671
74045
  }
73672
74046
  return null;
73673
74047
  }
@@ -73748,7 +74122,7 @@ function addPhase(planFile, name, afterId) {
73748
74122
  `);
73749
74123
  }
73750
74124
  writeFileSync5(planFile, import_gray_matter7.default.stringify(updatedBody, frontmatter), "utf8");
73751
- const phaseFilePath = join107(planDir, filename);
74125
+ const phaseFilePath = join108(planDir, filename);
73752
74126
  writeFileSync5(phaseFilePath, generatePhaseTemplate({ id: phaseId, name }), "utf8");
73753
74127
  return { phaseId, phaseFile: phaseFilePath };
73754
74128
  }
@@ -73852,7 +74226,7 @@ async function handleValidate(target, options2) {
73852
74226
  }
73853
74227
  async function handleStatus(target, options2) {
73854
74228
  const t = target ? resolve29(target) : null;
73855
- 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;
73856
74230
  if (plansDir) {
73857
74231
  const planFiles = scanPlanDir(plansDir);
73858
74232
  if (planFiles.length === 0) {
@@ -74087,7 +74461,7 @@ function resolvePlanFile(target) {
74087
74461
  const stat13 = statSync5(t);
74088
74462
  if (stat13.isFile())
74089
74463
  return t;
74090
- const candidate = join109(t, "plan.md");
74464
+ const candidate = join110(t, "plan.md");
74091
74465
  if (existsSync52(candidate))
74092
74466
  return candidate;
74093
74467
  }
@@ -74095,7 +74469,7 @@ function resolvePlanFile(target) {
74095
74469
  let dir = process.cwd();
74096
74470
  const root = parse2(dir).root;
74097
74471
  while (dir !== root) {
74098
- const candidate = join109(dir, "plan.md");
74472
+ const candidate = join110(dir, "plan.md");
74099
74473
  if (existsSync52(candidate))
74100
74474
  return candidate;
74101
74475
  dir = dirname33(dir);
@@ -74367,112 +74741,112 @@ var import_picocolors34 = __toESM(require_picocolors(), 1);
74367
74741
  // src/commands/skills/agents.ts
74368
74742
  import { existsSync as existsSync54 } from "node:fs";
74369
74743
  import { homedir as homedir26 } from "node:os";
74370
- import { join as join110 } from "node:path";
74744
+ import { join as join111 } from "node:path";
74371
74745
  var home6 = homedir26();
74372
74746
  var agents = {
74373
74747
  "claude-code": {
74374
74748
  name: "claude-code",
74375
74749
  displayName: "Claude Code",
74376
74750
  projectPath: ".claude/skills",
74377
- globalPath: join110(home6, ".claude/skills"),
74378
- detect: async () => existsSync54(join110(home6, ".claude"))
74751
+ globalPath: join111(home6, ".claude/skills"),
74752
+ detect: async () => existsSync54(join111(home6, ".claude"))
74379
74753
  },
74380
74754
  cursor: {
74381
74755
  name: "cursor",
74382
74756
  displayName: "Cursor",
74383
74757
  projectPath: ".cursor/skills",
74384
- globalPath: join110(home6, ".cursor/skills"),
74385
- detect: async () => existsSync54(join110(home6, ".cursor"))
74758
+ globalPath: join111(home6, ".cursor/skills"),
74759
+ detect: async () => existsSync54(join111(home6, ".cursor"))
74386
74760
  },
74387
74761
  codex: {
74388
74762
  name: "codex",
74389
74763
  displayName: "Codex",
74390
74764
  projectPath: ".codex/skills",
74391
- globalPath: join110(home6, ".codex/skills"),
74392
- detect: async () => existsSync54(join110(home6, ".codex"))
74765
+ globalPath: join111(home6, ".codex/skills"),
74766
+ detect: async () => existsSync54(join111(home6, ".codex"))
74393
74767
  },
74394
74768
  opencode: {
74395
74769
  name: "opencode",
74396
74770
  displayName: "OpenCode",
74397
74771
  projectPath: ".opencode/skills",
74398
- globalPath: join110(home6, ".config/opencode/skills"),
74399
- detect: async () => existsSync54(join110(home6, ".config/opencode"))
74772
+ globalPath: join111(home6, ".config/opencode/skills"),
74773
+ detect: async () => existsSync54(join111(home6, ".config/opencode"))
74400
74774
  },
74401
74775
  goose: {
74402
74776
  name: "goose",
74403
74777
  displayName: "Goose",
74404
74778
  projectPath: ".goose/skills",
74405
- globalPath: join110(home6, ".config/goose/skills"),
74406
- detect: async () => existsSync54(join110(home6, ".config/goose"))
74779
+ globalPath: join111(home6, ".config/goose/skills"),
74780
+ detect: async () => existsSync54(join111(home6, ".config/goose"))
74407
74781
  },
74408
74782
  "gemini-cli": {
74409
74783
  name: "gemini-cli",
74410
74784
  displayName: "Gemini CLI",
74411
74785
  projectPath: ".agents/skills",
74412
- globalPath: join110(home6, ".agents/skills"),
74413
- detect: async () => existsSync54(join110(home6, ".gemini"))
74786
+ globalPath: join111(home6, ".agents/skills"),
74787
+ detect: async () => existsSync54(join111(home6, ".gemini"))
74414
74788
  },
74415
74789
  antigravity: {
74416
74790
  name: "antigravity",
74417
74791
  displayName: "Antigravity",
74418
74792
  projectPath: ".agent/skills",
74419
- globalPath: join110(home6, ".gemini/antigravity/skills"),
74420
- 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"))
74421
74795
  },
74422
74796
  "github-copilot": {
74423
74797
  name: "github-copilot",
74424
74798
  displayName: "GitHub Copilot",
74425
74799
  projectPath: ".github/skills",
74426
- globalPath: join110(home6, ".copilot/skills"),
74427
- detect: async () => existsSync54(join110(home6, ".copilot"))
74800
+ globalPath: join111(home6, ".copilot/skills"),
74801
+ detect: async () => existsSync54(join111(home6, ".copilot"))
74428
74802
  },
74429
74803
  amp: {
74430
74804
  name: "amp",
74431
74805
  displayName: "Amp",
74432
74806
  projectPath: ".agents/skills",
74433
- globalPath: join110(home6, ".config/agents/skills"),
74434
- detect: async () => existsSync54(join110(home6, ".config/amp"))
74807
+ globalPath: join111(home6, ".config/agents/skills"),
74808
+ detect: async () => existsSync54(join111(home6, ".config/amp"))
74435
74809
  },
74436
74810
  kilo: {
74437
74811
  name: "kilo",
74438
74812
  displayName: "Kilo Code",
74439
74813
  projectPath: ".kilocode/skills",
74440
- globalPath: join110(home6, ".kilocode/skills"),
74441
- detect: async () => existsSync54(join110(home6, ".kilocode"))
74814
+ globalPath: join111(home6, ".kilocode/skills"),
74815
+ detect: async () => existsSync54(join111(home6, ".kilocode"))
74442
74816
  },
74443
74817
  roo: {
74444
74818
  name: "roo",
74445
74819
  displayName: "Roo Code",
74446
74820
  projectPath: ".roo/skills",
74447
- globalPath: join110(home6, ".roo/skills"),
74448
- detect: async () => existsSync54(join110(home6, ".roo"))
74821
+ globalPath: join111(home6, ".roo/skills"),
74822
+ detect: async () => existsSync54(join111(home6, ".roo"))
74449
74823
  },
74450
74824
  windsurf: {
74451
74825
  name: "windsurf",
74452
74826
  displayName: "Windsurf",
74453
74827
  projectPath: ".windsurf/skills",
74454
- globalPath: join110(home6, ".codeium/windsurf/skills"),
74455
- detect: async () => existsSync54(join110(home6, ".codeium/windsurf"))
74828
+ globalPath: join111(home6, ".codeium/windsurf/skills"),
74829
+ detect: async () => existsSync54(join111(home6, ".codeium/windsurf"))
74456
74830
  },
74457
74831
  cline: {
74458
74832
  name: "cline",
74459
74833
  displayName: "Cline",
74460
74834
  projectPath: ".cline/skills",
74461
- globalPath: join110(home6, ".cline/skills"),
74462
- detect: async () => existsSync54(join110(home6, ".cline"))
74835
+ globalPath: join111(home6, ".cline/skills"),
74836
+ detect: async () => existsSync54(join111(home6, ".cline"))
74463
74837
  },
74464
74838
  openhands: {
74465
74839
  name: "openhands",
74466
74840
  displayName: "OpenHands",
74467
74841
  projectPath: ".openhands/skills",
74468
- globalPath: join110(home6, ".openhands/skills"),
74469
- detect: async () => existsSync54(join110(home6, ".openhands"))
74842
+ globalPath: join111(home6, ".openhands/skills"),
74843
+ detect: async () => existsSync54(join111(home6, ".openhands"))
74470
74844
  }
74471
74845
  };
74472
74846
  function getInstallPath(skillName, agent, options2) {
74473
74847
  const config = agents[agent];
74474
74848
  const basePath = options2.global ? config.globalPath : config.projectPath;
74475
- return join110(basePath, skillName);
74849
+ return join111(basePath, skillName);
74476
74850
  }
74477
74851
  function isSkillInstalled(skillName, agent, options2) {
74478
74852
  const installPath = getInstallPath(skillName, agent, options2);
@@ -74483,16 +74857,16 @@ function isSkillInstalled(skillName, agent, options2) {
74483
74857
  import { existsSync as existsSync56 } from "node:fs";
74484
74858
  import { cp as cp4, mkdir as mkdir31, rm as rm14, stat as stat13 } from "node:fs/promises";
74485
74859
  import { homedir as homedir28 } from "node:os";
74486
- 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";
74487
74861
 
74488
74862
  // src/commands/skills/skills-registry.ts
74489
74863
  init_zod();
74490
74864
  import { existsSync as existsSync55 } from "node:fs";
74491
74865
  import { mkdir as mkdir30, readFile as readFile47, writeFile as writeFile35 } from "node:fs/promises";
74492
74866
  import { homedir as homedir27 } from "node:os";
74493
- 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";
74494
74868
  var home7 = homedir27();
74495
- var REGISTRY_PATH2 = join111(home7, ".sunagentkit", "skill-registry.json");
74869
+ var REGISTRY_PATH2 = join112(home7, ".sunagentkit", "skill-registry.json");
74496
74870
  var SkillInstallationSchema = exports_external.object({
74497
74871
  skill: exports_external.string(),
74498
74872
  agent: exports_external.string(),
@@ -74630,7 +75004,7 @@ async function syncRegistry() {
74630
75004
  var LEGACY_SKILL_PATHS = {
74631
75005
  "gemini-cli": {
74632
75006
  project: ".gemini/skills",
74633
- global: join112(homedir28(), ".gemini/skills")
75007
+ global: join113(homedir28(), ".gemini/skills")
74634
75008
  }
74635
75009
  };
74636
75010
  function isSamePath3(path1, path22) {
@@ -74664,7 +75038,7 @@ async function cleanupLegacySkillPath(skillName, agent, global3) {
74664
75038
  if (!legacy)
74665
75039
  return;
74666
75040
  const legacyBase = global3 ? legacy.global : legacy.project;
74667
- const legacyPath = join112(legacyBase, skillName);
75041
+ const legacyPath = join113(legacyBase, skillName);
74668
75042
  if (!existsSync56(legacyPath))
74669
75043
  return;
74670
75044
  await rm14(legacyPath, { recursive: true, force: true });
@@ -74674,7 +75048,7 @@ async function cleanupLegacySkillPath(skillName, agent, global3) {
74674
75048
  if (entry.skill === skillName && entry.agent === agent && entry.global === global3) {
74675
75049
  if (entry.path === legacyPath) {
74676
75050
  const newBase = global3 ? agents[agent].globalPath : agents[agent].projectPath;
74677
- entry.path = join112(newBase, skillName);
75051
+ entry.path = join113(newBase, skillName);
74678
75052
  changed = true;
74679
75053
  }
74680
75054
  }
@@ -74759,7 +75133,7 @@ function getInstallPreview(skill, targetAgents, options2) {
74759
75133
  // src/commands/skills/skills-uninstaller.ts
74760
75134
  import { existsSync as existsSync57 } from "node:fs";
74761
75135
  import { rm as rm15 } from "node:fs/promises";
74762
- import { join as join113 } from "node:path";
75136
+ import { join as join114 } from "node:path";
74763
75137
  async function uninstallSkillFromAgent(skill, agent, global3) {
74764
75138
  const agentConfig = agents[agent];
74765
75139
  const registry = await readRegistry();
@@ -74807,7 +75181,7 @@ async function uninstallSkillFromAgent(skill, agent, global3) {
74807
75181
  async function forceUninstallSkill(skill, agent, global3) {
74808
75182
  const agentConfig = agents[agent];
74809
75183
  const basePath = global3 ? agentConfig.globalPath : agentConfig.projectPath;
74810
- const path9 = join113(basePath, skill);
75184
+ const path9 = join114(basePath, skill);
74811
75185
  if (!existsSync57(path9)) {
74812
75186
  return {
74813
75187
  skill,
@@ -75312,12 +75686,12 @@ init_logger();
75312
75686
  // src/commands/telemetry/shared.ts
75313
75687
  import { existsSync as existsSync58, readFileSync as readFileSync15, readdirSync as readdirSync6 } from "node:fs";
75314
75688
  import { homedir as homedir29 } from "node:os";
75315
- import { join as join114 } from "node:path";
75689
+ import { join as join115 } from "node:path";
75316
75690
  init_token_store();
75317
- var USER_CACHE_PATH = join114(homedir29(), ".claude", "sk-user.json");
75318
- var EVENT_BUFFER_DIR = join114(homedir29(), ".claude", "sk-events");
75319
- var RATE_STATE_PATH = join114(homedir29(), ".claude", "sk-rate-state.json");
75320
- 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");
75321
75695
  var TELEMETRY_HOOK_FIELD = "hooks.telemetry";
75322
75696
  var TOKEN_PLACEHOLDER = "__INJECT_AT_RELEASE__";
75323
75697
  function readUserCache() {
@@ -75404,7 +75778,7 @@ async function handleDisable() {
75404
75778
  // src/commands/telemetry/phases/purge-local-handler.ts
75405
75779
  init_logger();
75406
75780
  import { existsSync as existsSync59, readdirSync as readdirSync7, unlinkSync as unlinkSync5 } from "node:fs";
75407
- import { join as join115 } from "node:path";
75781
+ import { join as join116 } from "node:path";
75408
75782
  function removeIfExists(path9) {
75409
75783
  try {
75410
75784
  if (!existsSync59(path9))
@@ -75424,7 +75798,7 @@ function removeBufferFiles() {
75424
75798
  if (!file.endsWith(".jsonl"))
75425
75799
  continue;
75426
75800
  try {
75427
- unlinkSync5(join115(EVENT_BUFFER_DIR, file));
75801
+ unlinkSync5(join116(EVENT_BUFFER_DIR, file));
75428
75802
  count += 1;
75429
75803
  } catch {}
75430
75804
  }
@@ -75650,13 +76024,13 @@ async function detectInstallations() {
75650
76024
 
75651
76025
  // src/commands/uninstall/removal-handler.ts
75652
76026
  import { readdirSync as readdirSync9, rmSync as rmSync6 } from "node:fs";
75653
- 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";
75654
76028
  init_logger();
75655
76029
  var import_fs_extra38 = __toESM(require_lib(), 1);
75656
76030
 
75657
76031
  // src/commands/uninstall/analysis-handler.ts
75658
76032
  import { readdirSync as readdirSync8, rmSync as rmSync5 } from "node:fs";
75659
- import { dirname as dirname36, join as join116 } from "node:path";
76033
+ import { dirname as dirname36, join as join117 } from "node:path";
75660
76034
  init_logger();
75661
76035
  var import_picocolors35 = __toESM(require_picocolors(), 1);
75662
76036
  function classifyFileByOwnership(ownership, forceOverwrite, deleteReason) {
@@ -75703,7 +76077,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
75703
76077
  if (uninstallManifest.isMultiKit && kit && metadata?.kits?.[kit]) {
75704
76078
  const kitFiles = metadata.kits[kit].files || [];
75705
76079
  for (const trackedFile of kitFiles) {
75706
- const filePath = join116(installation.path, trackedFile.path);
76080
+ const filePath = join117(installation.path, trackedFile.path);
75707
76081
  if (uninstallManifest.filesToPreserve.includes(trackedFile.path)) {
75708
76082
  result.toPreserve.push({ path: trackedFile.path, reason: "shared with other kit" });
75709
76083
  continue;
@@ -75733,7 +76107,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
75733
76107
  return result;
75734
76108
  }
75735
76109
  for (const trackedFile of allTrackedFiles) {
75736
- const filePath = join116(installation.path, trackedFile.path);
76110
+ const filePath = join117(installation.path, trackedFile.path);
75737
76111
  const ownershipResult = await OwnershipChecker.checkOwnership(filePath, metadata, installation.path);
75738
76112
  if (!ownershipResult.exists)
75739
76113
  continue;
@@ -75830,7 +76204,7 @@ async function removeInstallations(installations, options2) {
75830
76204
  let removedCount = 0;
75831
76205
  let cleanedDirs = 0;
75832
76206
  for (const item of analysis.toDelete) {
75833
- const filePath = join117(installation.path, item.path);
76207
+ const filePath = join118(installation.path, item.path);
75834
76208
  if (!await import_fs_extra38.pathExists(filePath))
75835
76209
  continue;
75836
76210
  if (!await isPathSafeToRemove(filePath, installation.path)) {
@@ -76032,7 +76406,7 @@ ${import_picocolors36.default.yellow("User modifications will be permanently del
76032
76406
  // src/commands/update-cli.ts
76033
76407
  init_takumi_config_manager();
76034
76408
  import { exec as exec8, spawn as spawn2 } from "node:child_process";
76035
- import { join as join118 } from "node:path";
76409
+ import { join as join119 } from "node:path";
76036
76410
  import { promisify as promisify14 } from "node:util";
76037
76411
 
76038
76412
  // src/domains/github/npm-registry.ts
@@ -76199,7 +76573,7 @@ var import_fs_extra39 = __toESM(require_lib(), 1);
76199
76573
  // package.json
76200
76574
  var package_default = {
76201
76575
  name: "@sunasteriskrnd/takumi",
76202
- version: "0.5.0",
76576
+ version: "0.6.0",
76203
76577
  description: "CLI tool for bootstrapping and managing Takumi projects",
76204
76578
  type: "module",
76205
76579
  repository: {
@@ -76222,6 +76596,7 @@ var package_default = {
76222
76596
  build: `bun build src/index.ts --outdir dist --target node --external @octokit/rest --external better-sqlite3 --external yauzl-promise --external @node-rs/crc32 && node -e "const fs=require('fs'),f='dist/index.js',c=fs.readFileSync(f,'utf-8');fs.writeFileSync(f,c.replace(/^#!.*\\n\\/\\/ @bun\\n/,''))"`,
76223
76597
  "verify:package": "node scripts/prepublish-check.js",
76224
76598
  test: "bun test",
76599
+ "test:ci": "NON_INTERACTIVE=true CI_SAFE_MODE=true bun test",
76225
76600
  "test:integration": "CK_RUN_CLI_INTEGRATION=1 bun test tests/integration/cli.test.ts",
76226
76601
  "test:watch": "bun test --watch",
76227
76602
  "test:quick": "./scripts/dev-quick-start.sh test",
@@ -76383,7 +76758,7 @@ function selectKitForUpdate(params) {
76383
76758
  };
76384
76759
  }
76385
76760
  async function readMetadataFile(claudeDir) {
76386
- const metadataPath = join118(claudeDir, "metadata.json");
76761
+ const metadataPath = join119(claudeDir, "metadata.json");
76387
76762
  try {
76388
76763
  if (!await import_fs_extra39.pathExists(metadataPath)) {
76389
76764
  return null;
@@ -76884,7 +77259,7 @@ init_logger();
76884
77259
  import { existsSync as existsSync65 } from "node:fs";
76885
77260
  import { rm as rm16 } from "node:fs/promises";
76886
77261
  import { homedir as homedir31 } from "node:os";
76887
- import { join as join125 } from "node:path";
77262
+ import { join as join126 } from "node:path";
76888
77263
  var import_picocolors38 = __toESM(require_picocolors(), 1);
76889
77264
 
76890
77265
  // src/commands/watch/phases/implementation-runner.ts
@@ -77394,7 +77769,7 @@ function spawnAndCollect3(command, args) {
77394
77769
 
77395
77770
  // src/commands/watch/phases/issue-processor.ts
77396
77771
  import { mkdir as mkdir32, writeFile as writeFile37 } from "node:fs/promises";
77397
- import { join as join121 } from "node:path";
77772
+ import { join as join122 } from "node:path";
77398
77773
 
77399
77774
  // src/commands/watch/phases/approval-detector.ts
77400
77775
  init_logger();
@@ -77769,9 +78144,9 @@ async function checkAwaitingApproval(state, setup, options2, watchLog, projectDi
77769
78144
 
77770
78145
  // src/commands/watch/phases/plan-dir-finder.ts
77771
78146
  import { readdir as readdir32, stat as stat14 } from "node:fs/promises";
77772
- import { join as join120 } from "node:path";
78147
+ import { join as join121 } from "node:path";
77773
78148
  async function findRecentPlanDir(cwd2, issueNumber, watchLog) {
77774
- const plansRoot = join120(cwd2, "plans");
78149
+ const plansRoot = join121(cwd2, "plans");
77775
78150
  try {
77776
78151
  const entries = await readdir32(plansRoot);
77777
78152
  const tenMinAgo = Date.now() - 10 * 60 * 1000;
@@ -77780,14 +78155,14 @@ async function findRecentPlanDir(cwd2, issueNumber, watchLog) {
77780
78155
  for (const entry of entries) {
77781
78156
  if (entry === "watch" || entry === "reports" || entry === "visuals")
77782
78157
  continue;
77783
- const dirPath = join120(plansRoot, entry);
78158
+ const dirPath = join121(plansRoot, entry);
77784
78159
  const dirStat = await stat14(dirPath);
77785
78160
  if (!dirStat.isDirectory())
77786
78161
  continue;
77787
78162
  if (dirStat.mtimeMs < tenMinAgo)
77788
78163
  continue;
77789
78164
  try {
77790
- await stat14(join120(dirPath, "plan.md"));
78165
+ await stat14(join121(dirPath, "plan.md"));
77791
78166
  } catch {
77792
78167
  continue;
77793
78168
  }
@@ -78018,13 +78393,13 @@ async function handlePlanGeneration(issue, state, config, setup, options2, watch
78018
78393
  stats.plansCreated++;
78019
78394
  const detectedPlanDir = await findRecentPlanDir(projectDir, issue.number, watchLog);
78020
78395
  if (detectedPlanDir) {
78021
- state.activeIssues[numStr].planPath = join121(detectedPlanDir, "plan.md");
78396
+ state.activeIssues[numStr].planPath = join122(detectedPlanDir, "plan.md");
78022
78397
  watchLog.info(`Plan directory detected: ${detectedPlanDir}`);
78023
78398
  } else {
78024
78399
  try {
78025
- const planDir = join121(projectDir, "plans", "watch");
78400
+ const planDir = join122(projectDir, "plans", "watch");
78026
78401
  await mkdir32(planDir, { recursive: true });
78027
- const planFilePath = join121(planDir, `issue-${issue.number}-plan.md`);
78402
+ const planFilePath = join122(planDir, `issue-${issue.number}-plan.md`);
78028
78403
  await writeFile37(planFilePath, planResult.planText, "utf-8");
78029
78404
  state.activeIssues[numStr].planPath = planFilePath;
78030
78405
  watchLog.info(`Plan saved (fallback) to ${planFilePath}`);
@@ -78329,18 +78704,18 @@ init_logger();
78329
78704
  import { spawnSync as spawnSync5 } from "node:child_process";
78330
78705
  import { existsSync as existsSync62 } from "node:fs";
78331
78706
  import { readdir as readdir33, stat as stat15 } from "node:fs/promises";
78332
- import { join as join122 } from "node:path";
78707
+ import { join as join123 } from "node:path";
78333
78708
  async function scanForRepos(parentDir) {
78334
78709
  const repos = [];
78335
78710
  const entries = await readdir33(parentDir);
78336
78711
  for (const entry of entries) {
78337
78712
  if (entry.startsWith("."))
78338
78713
  continue;
78339
- const fullPath = join122(parentDir, entry);
78714
+ const fullPath = join123(parentDir, entry);
78340
78715
  const entryStat = await stat15(fullPath);
78341
78716
  if (!entryStat.isDirectory())
78342
78717
  continue;
78343
- const gitDir = join122(fullPath, ".git");
78718
+ const gitDir = join123(fullPath, ".git");
78344
78719
  if (!existsSync62(gitDir))
78345
78720
  continue;
78346
78721
  const result = spawnSync5("gh", ["repo", "view", "--json", "owner,name"], {
@@ -78367,7 +78742,7 @@ init_logger();
78367
78742
  import { spawnSync as spawnSync6 } from "node:child_process";
78368
78743
  import { existsSync as existsSync63 } from "node:fs";
78369
78744
  import { homedir as homedir30 } from "node:os";
78370
- import { join as join123 } from "node:path";
78745
+ import { join as join124 } from "node:path";
78371
78746
  async function validateSetup(cwd2) {
78372
78747
  const workDir = cwd2 ?? process.cwd();
78373
78748
  const ghVersion = spawnSync6("gh", ["--version"], { encoding: "utf-8", timeout: 1e4 });
@@ -78398,7 +78773,7 @@ Run this command from a directory with a GitHub remote.`);
78398
78773
  } catch {
78399
78774
  throw new Error(`Failed to parse repository info: ${ghRepo.stdout}`);
78400
78775
  }
78401
- const skillsPath = join123(homedir30(), ".claude", "skills");
78776
+ const skillsPath = join124(homedir30(), ".claude", "skills");
78402
78777
  const skillsAvailable = existsSync63(skillsPath);
78403
78778
  if (!skillsAvailable) {
78404
78779
  logger.warning(`Takumi Engineer skills not found at ${skillsPath}`);
@@ -78417,7 +78792,7 @@ init_path_resolver();
78417
78792
  import { createWriteStream as createWriteStream4, statSync as statSync6 } from "node:fs";
78418
78793
  import { existsSync as existsSync64 } from "node:fs";
78419
78794
  import { mkdir as mkdir34, rename as rename9 } from "node:fs/promises";
78420
- import { join as join124 } from "node:path";
78795
+ import { join as join125 } from "node:path";
78421
78796
 
78422
78797
  class WatchLogger {
78423
78798
  logStream = null;
@@ -78425,7 +78800,7 @@ class WatchLogger {
78425
78800
  logPath = null;
78426
78801
  maxBytes;
78427
78802
  constructor(logDir, maxBytes = 0) {
78428
- this.logDir = logDir ?? join124(PathResolver.getTakumiDir(), "logs");
78803
+ this.logDir = logDir ?? join125(PathResolver.getTakumiDir(), "logs");
78429
78804
  this.maxBytes = maxBytes;
78430
78805
  }
78431
78806
  async init() {
@@ -78434,7 +78809,7 @@ class WatchLogger {
78434
78809
  await mkdir34(this.logDir, { recursive: true });
78435
78810
  }
78436
78811
  const dateStr = formatDate(new Date);
78437
- this.logPath = join124(this.logDir, `watch-${dateStr}.log`);
78812
+ this.logPath = join125(this.logDir, `watch-${dateStr}.log`);
78438
78813
  this.logStream = createWriteStream4(this.logPath, { flags: "a", mode: 384 });
78439
78814
  } catch (error) {
78440
78815
  logger.warning(`Cannot create watch log file: ${error instanceof Error ? error.message : "Unknown"}`);
@@ -78614,7 +78989,7 @@ async function watchCommand(options2) {
78614
78989
  }
78615
78990
  async function discoverRepos(options2, watchLog) {
78616
78991
  const cwd2 = process.cwd();
78617
- const isGitRepo = existsSync65(join125(cwd2, ".git"));
78992
+ const isGitRepo = existsSync65(join126(cwd2, ".git"));
78618
78993
  if (options2.force) {
78619
78994
  await forceRemoveLock(watchLog);
78620
78995
  }
@@ -78684,7 +79059,7 @@ async function resetState(state, projectDir, watchLog) {
78684
79059
  watchLog.info(`Watch state reset (--force) for ${projectDir}`);
78685
79060
  }
78686
79061
  async function forceRemoveLock(watchLog) {
78687
- const lockPath = join125(homedir31(), ".sunagentkit", "locks", `${LOCK_NAME}.lock`);
79062
+ const lockPath = join126(homedir31(), ".sunagentkit", "locks", `${LOCK_NAME}.lock`);
78688
79063
  try {
78689
79064
  await rm16(lockPath, { recursive: true, force: true });
78690
79065
  watchLog.info("Removed existing lock file (--force)");
@@ -78728,13 +79103,13 @@ function sleep2(ms2) {
78728
79103
  // src/cli/command-registry.ts
78729
79104
  init_logger();
78730
79105
  function registerCommands(cli) {
78731
- 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) => {
78732
79107
  if (options2.exclude && !Array.isArray(options2.exclude)) {
78733
79108
  options2.exclude = [options2.exclude];
78734
79109
  }
78735
79110
  await newCommand(options2);
78736
79111
  });
78737
- 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) => {
78738
79113
  if (options2.exclude && !Array.isArray(options2.exclude)) {
78739
79114
  options2.exclude = [options2.exclude];
78740
79115
  }
@@ -78747,6 +79122,9 @@ function registerCommands(cli) {
78747
79122
  if (options2.agent) {
78748
79123
  options2.agents = options2.agent;
78749
79124
  }
79125
+ if (options2.kit && Array.isArray(options2.kit)) {
79126
+ options2.kit = options2.kit.join(",");
79127
+ }
78750
79128
  await initCommand(options2);
78751
79129
  });
78752
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) => {
@@ -78886,7 +79264,7 @@ function registerCommands(cli) {
78886
79264
 
78887
79265
  // src/cli/version-display.ts
78888
79266
  import { existsSync as existsSync77, readFileSync as readFileSync20 } from "node:fs";
78889
- import { join as join137 } from "node:path";
79267
+ import { join as join138 } from "node:path";
78890
79268
  init_help_banner();
78891
79269
  // src/domains/versioning/checking/kit-version-checker.ts
78892
79270
  init_github_client();
@@ -78898,14 +79276,14 @@ init_logger();
78898
79276
  init_path_resolver();
78899
79277
  import { existsSync as existsSync76 } from "node:fs";
78900
79278
  import { mkdir as mkdir35, readFile as readFile52, writeFile as writeFile40 } from "node:fs/promises";
78901
- import { join as join136 } from "node:path";
79279
+ import { join as join137 } from "node:path";
78902
79280
 
78903
79281
  class VersionCacheManager {
78904
79282
  static CACHE_FILENAME = "version-check.json";
78905
79283
  static CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
78906
79284
  static getCacheFile() {
78907
79285
  const cacheDir = PathResolver.getCacheDir(false);
78908
- return join136(cacheDir, VersionCacheManager.CACHE_FILENAME);
79286
+ return join137(cacheDir, VersionCacheManager.CACHE_FILENAME);
78909
79287
  }
78910
79288
  static async load() {
78911
79289
  const cacheFile = VersionCacheManager.getCacheFile();
@@ -79198,8 +79576,8 @@ async function displayVersion() {
79198
79576
  const localSubdir = PROVIDER_LOCAL_SUBDIRS[provider];
79199
79577
  if (!localSubdir)
79200
79578
  continue;
79201
- const localMeta = join137(process.cwd(), localSubdir, "metadata.json");
79202
- if (localMeta === join137(inst.globalRoot(), "metadata.json"))
79579
+ const localMeta = join138(process.cwd(), localSubdir, "metadata.json");
79580
+ if (localMeta === join138(inst.globalRoot(), "metadata.json"))
79203
79581
  continue;
79204
79582
  if (!existsSync77(localMeta))
79205
79583
  continue;
@@ -79224,7 +79602,7 @@ async function displayVersion() {
79224
79602
  }
79225
79603
  const singleInstall = detectedGlobals.length === 1 && detectedGlobals[0]?.provider === "claude-code";
79226
79604
  for (const { provider, path: installPath } of detectedGlobals) {
79227
- const metadataPath = join137(installPath, "metadata.json");
79605
+ const metadataPath = join138(installPath, "metadata.json");
79228
79606
  if (existsSync77(metadataPath)) {
79229
79607
  try {
79230
79608
  const rawMetadata = JSON.parse(readFileSync20(metadataPath, "utf-8"));