@omnidev-ai/cli 0.18.0 → 0.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +417 -151
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2638,7 +2638,10 @@ async function loadSkills(capabilityPath, capabilityId, variables) {
2638
2638
  const skillPath = join6(dir, entry.name, "SKILL.md");
2639
2639
  if (existsSync8(skillPath)) {
2640
2640
  const skill = await parseSkillFile(skillPath, capabilityId, resolvedVariables, `skill file ${skillPath}`);
2641
- skills.push(skill);
2641
+ skills.push({
2642
+ ...skill,
2643
+ sourcePath: join6(dir, entry.name)
2644
+ });
2642
2645
  }
2643
2646
  }
2644
2647
  }
@@ -3524,7 +3527,7 @@ import { existsSync as existsSync13 } from "node:fs";
3524
3527
  import { spawn } from "node:child_process";
3525
3528
  import { cp, mkdir, readdir, readFile as readFile10, rename, rm, stat, writeFile as writeFile3 } from "node:fs/promises";
3526
3529
  import { join as join9 } from "node:path";
3527
- import { createHash } from "node:crypto";
3530
+ import { createHash as createHash2 } from "node:crypto";
3528
3531
  async function spawnCapture(command, args, options) {
3529
3532
  const timeout = options?.timeout ?? 60000;
3530
3533
  return await new Promise((resolve2, reject) => {
@@ -3733,7 +3736,7 @@ function escapeTomlString(value) {
3733
3736
  return value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
3734
3737
  }
3735
3738
  async function computeContentHash(dirPath, excludePatterns = CONTENT_HASH_EXCLUDES) {
3736
- const hash = createHash("sha256");
3739
+ const hash = createHash2("sha256");
3737
3740
  const files = [];
3738
3741
  async function collectFiles(currentPath, relativeTo) {
3739
3742
  const entries = await readdir(currentPath, { withFileTypes: true });
@@ -5168,29 +5171,107 @@ var init_mcp_json = __esm(() => {
5168
5171
  });
5169
5172
 
5170
5173
  // ../core/src/state/manifest.ts
5171
- import { existsSync as existsSync17, mkdirSync as mkdirSync2, rmSync } from "node:fs";
5174
+ import { createHash as createHash3 } from "node:crypto";
5175
+ import { existsSync as existsSync17, mkdirSync as mkdirSync2, readdirSync as readdirSync7, rmSync } from "node:fs";
5176
+ import { dirname, join as join10 } from "node:path";
5172
5177
  import { readFile as readFile14, writeFile as writeFile7 } from "node:fs/promises";
5173
- async function loadManifest() {
5174
- if (!existsSync17(MANIFEST_PATH)) {
5178
+ function createEmptyManifest() {
5179
+ return {
5180
+ version: CURRENT_VERSION,
5181
+ syncedAt: new Date().toISOString(),
5182
+ capabilities: {},
5183
+ providers: {}
5184
+ };
5185
+ }
5186
+ function normalizeManifest(parsed) {
5187
+ if (parsed.version === CURRENT_VERSION && "providers" in parsed) {
5175
5188
  return {
5176
5189
  version: CURRENT_VERSION,
5177
- syncedAt: new Date().toISOString(),
5178
- capabilities: {}
5190
+ syncedAt: parsed.syncedAt,
5191
+ capabilities: parsed.capabilities,
5192
+ providers: parsed.providers ?? {}
5179
5193
  };
5180
5194
  }
5195
+ return {
5196
+ version: CURRENT_VERSION,
5197
+ syncedAt: parsed.syncedAt,
5198
+ capabilities: parsed.capabilities,
5199
+ providers: {}
5200
+ };
5201
+ }
5202
+ function hashContent2(content) {
5203
+ return createHash3("sha256").update(content).digest("hex");
5204
+ }
5205
+ function normalizePath(path) {
5206
+ return path.replace(/\\/g, "/");
5207
+ }
5208
+ function isDirectoryEmpty(path) {
5209
+ return readdirSync7(path).length === 0;
5210
+ }
5211
+ async function cleanupManagedOutput(output) {
5212
+ const outputPath = join10(process.cwd(), output.path);
5213
+ if (!existsSync17(outputPath)) {
5214
+ return { deleted: false };
5215
+ }
5216
+ if (output.cleanupStrategy === "remove-json-key") {
5217
+ if (!output.jsonKey) {
5218
+ return { deleted: false, reason: `missing jsonKey metadata for ${output.path}` };
5219
+ }
5220
+ let parsed;
5221
+ try {
5222
+ parsed = JSON.parse(await readFile14(outputPath, "utf-8"));
5223
+ } catch {
5224
+ return { deleted: false, reason: `could not parse JSON at ${output.path}` };
5225
+ }
5226
+ const currentValue = parsed[output.jsonKey];
5227
+ if (currentValue === undefined) {
5228
+ return { deleted: false };
5229
+ }
5230
+ if (hashContent2(JSON.stringify(currentValue)) !== output.hash) {
5231
+ return { deleted: false, reason: `managed section changed at ${output.path}` };
5232
+ }
5233
+ delete parsed[output.jsonKey];
5234
+ if (Object.keys(parsed).length === 0) {
5235
+ rmSync(outputPath);
5236
+ } else {
5237
+ await writeFile7(outputPath, `${JSON.stringify(parsed, null, 2)}
5238
+ `, "utf-8");
5239
+ }
5240
+ return { deleted: true };
5241
+ }
5242
+ const currentContent = await readFile14(outputPath, "utf-8");
5243
+ if (hashContent2(currentContent) !== output.hash) {
5244
+ return { deleted: false, reason: `managed file changed at ${output.path}` };
5245
+ }
5246
+ rmSync(outputPath);
5247
+ if (output.cleanupStrategy === "delete-file-and-prune-empty-parents" && output.pruneRoot) {
5248
+ const pruneRoot = join10(process.cwd(), output.pruneRoot);
5249
+ let currentDir = dirname(outputPath);
5250
+ while (normalizePath(currentDir).startsWith(normalizePath(pruneRoot)) && normalizePath(currentDir) !== normalizePath(pruneRoot) && existsSync17(currentDir) && isDirectoryEmpty(currentDir)) {
5251
+ rmSync(currentDir, { recursive: true });
5252
+ currentDir = dirname(currentDir);
5253
+ }
5254
+ }
5255
+ return { deleted: true };
5256
+ }
5257
+ async function loadManifest() {
5258
+ if (!existsSync17(MANIFEST_PATH)) {
5259
+ return createEmptyManifest();
5260
+ }
5181
5261
  const content = await readFile14(MANIFEST_PATH, "utf-8");
5182
- return JSON.parse(content);
5262
+ return normalizeManifest(JSON.parse(content));
5183
5263
  }
5184
5264
  async function saveManifest(manifest) {
5185
5265
  mkdirSync2(".omni/state", { recursive: true });
5186
5266
  await writeFile7(MANIFEST_PATH, `${JSON.stringify(manifest, null, 2)}
5187
5267
  `, "utf-8");
5188
5268
  }
5189
- function buildManifestFromCapabilities(capabilities2) {
5269
+ function buildManifestFromCapabilities(capabilities2, providerOutputs = new Map) {
5190
5270
  const manifest = {
5191
5271
  version: CURRENT_VERSION,
5192
5272
  syncedAt: new Date().toISOString(),
5193
- capabilities: {}
5273
+ capabilities: {},
5274
+ providers: {}
5194
5275
  };
5195
5276
  for (const cap of capabilities2) {
5196
5277
  const resources = {
@@ -5202,38 +5283,59 @@ function buildManifestFromCapabilities(capabilities2) {
5202
5283
  };
5203
5284
  manifest.capabilities[cap.id] = resources;
5204
5285
  }
5286
+ for (const [providerId, outputs] of providerOutputs) {
5287
+ manifest.providers[providerId] = {
5288
+ outputs: Object.fromEntries(outputs.map((output) => [output.path, output]))
5289
+ };
5290
+ }
5205
5291
  return manifest;
5206
5292
  }
5207
- async function cleanupStaleResources(previousManifest, currentCapabilityIds) {
5208
- const result = {
5293
+ async function cleanupStaleResources(_previousManifest, _currentCapabilityIds) {
5294
+ return {
5209
5295
  deletedSkills: [],
5210
5296
  deletedRules: [],
5211
5297
  deletedCommands: [],
5212
5298
  deletedSubagents: [],
5213
5299
  deletedMcps: []
5214
5300
  };
5215
- for (const [capId, resources] of Object.entries(previousManifest.capabilities)) {
5216
- if (currentCapabilityIds.has(capId)) {
5217
- continue;
5301
+ }
5302
+ async function cleanupStaleManagedOutputs(previousManifest, nextProviders) {
5303
+ const result = {
5304
+ deletedPaths: [],
5305
+ skippedPaths: []
5306
+ };
5307
+ const claimedPaths = new Set;
5308
+ for (const outputs of nextProviders.values()) {
5309
+ for (const output of outputs) {
5310
+ claimedPaths.add(output.path);
5218
5311
  }
5219
- for (const skillName of resources.skills) {
5220
- const skillDir = `.claude/skills/${skillName}`;
5221
- if (existsSync17(skillDir)) {
5222
- rmSync(skillDir, { recursive: true });
5223
- result.deletedSkills.push(skillName);
5312
+ }
5313
+ for (const [providerId, providerState] of Object.entries(previousManifest.providers)) {
5314
+ const nextPaths = new Set((nextProviders.get(providerId) ?? []).map((output) => output.path));
5315
+ for (const output of Object.values(providerState.outputs)) {
5316
+ if (nextPaths.has(output.path)) {
5317
+ continue;
5224
5318
  }
5225
- }
5226
- for (const ruleName of resources.rules) {
5227
- const rulePath = `.cursor/rules/omnidev-${ruleName}.mdc`;
5228
- if (existsSync17(rulePath)) {
5229
- rmSync(rulePath);
5230
- result.deletedRules.push(ruleName);
5319
+ if (claimedPaths.has(output.path)) {
5320
+ continue;
5321
+ }
5322
+ const cleanup = await cleanupManagedOutput(output);
5323
+ if (cleanup.deleted) {
5324
+ result.deletedPaths.push(output.path);
5325
+ } else if (cleanup.reason) {
5326
+ result.skippedPaths.push({
5327
+ path: output.path,
5328
+ reason: cleanup.reason
5329
+ });
5231
5330
  }
5232
5331
  }
5233
5332
  }
5234
5333
  return result;
5235
5334
  }
5236
- var MANIFEST_PATH = ".omni/state/manifest.json", CURRENT_VERSION = 1;
5335
+ function getProviderManagedOutputs(manifest, providerId) {
5336
+ return Object.values(manifest.providers[providerId]?.outputs ?? {});
5337
+ }
5338
+ var MANIFEST_PATH = ".omni/state/manifest.json", CURRENT_VERSION = 2;
5237
5339
  var init_manifest = () => {};
5238
5340
 
5239
5341
  // ../core/src/state/providers.ts
@@ -5382,7 +5484,7 @@ var init_state = __esm(() => {
5382
5484
  // ../core/src/sync.ts
5383
5485
  import { spawn as spawn2 } from "node:child_process";
5384
5486
  import { existsSync as existsSync20, mkdirSync as mkdirSync5, readFileSync as readFileSync3 } from "node:fs";
5385
- import { join as join10 } from "node:path";
5487
+ import { join as join11 } from "node:path";
5386
5488
  function getDeclaredPackageManager(packageManager) {
5387
5489
  if (typeof packageManager !== "string" || packageManager.trim().length === 0) {
5388
5490
  return;
@@ -5391,8 +5493,8 @@ function getDeclaredPackageManager(packageManager) {
5391
5493
  return atIndex === -1 ? packageManager : packageManager.slice(0, atIndex);
5392
5494
  }
5393
5495
  function resolveCapabilityInstallCommand(capabilityPath, options) {
5394
- const packageJsonPath = join10(capabilityPath, "package.json");
5395
- const packageLockPath = join10(capabilityPath, "package-lock.json");
5496
+ const packageJsonPath = join11(capabilityPath, "package.json");
5497
+ const packageLockPath = join11(capabilityPath, "package-lock.json");
5396
5498
  let packageManager;
5397
5499
  try {
5398
5500
  const pkgJson = JSON.parse(readFileSync3(packageJsonPath, "utf-8"));
@@ -5410,13 +5512,13 @@ function resolveCapabilityInstallCommand(capabilityPath, options) {
5410
5512
  };
5411
5513
  }
5412
5514
  async function installCapabilityDependencies(silent) {
5413
- const { readdirSync: readdirSync7 } = await import("node:fs");
5515
+ const { readdirSync: readdirSync8 } = await import("node:fs");
5414
5516
  const { parse: parse2 } = await Promise.resolve().then(() => (init_dist(), exports_dist));
5415
5517
  const capabilitiesDir = ".omni/capabilities";
5416
5518
  if (!existsSync20(capabilitiesDir)) {
5417
5519
  return;
5418
5520
  }
5419
- const entries = readdirSync7(capabilitiesDir, { withFileTypes: true });
5521
+ const entries = readdirSync8(capabilitiesDir, { withFileTypes: true });
5420
5522
  async function commandExists(cmd) {
5421
5523
  return await new Promise((resolve2) => {
5422
5524
  const proc = spawn2(cmd, ["--version"], { stdio: "ignore" });
@@ -5432,9 +5534,9 @@ async function installCapabilityDependencies(silent) {
5432
5534
  if (!entry.isDirectory()) {
5433
5535
  continue;
5434
5536
  }
5435
- const capabilityPath = join10(capabilitiesDir, entry.name);
5436
- const packageJsonPath = join10(capabilityPath, "package.json");
5437
- const capabilityTomlPath = join10(capabilityPath, "capability.toml");
5537
+ const capabilityPath = join11(capabilitiesDir, entry.name);
5538
+ const packageJsonPath = join11(capabilityPath, "package.json");
5539
+ const capabilityTomlPath = join11(capabilityPath, "capability.toml");
5438
5540
  if (!existsSync20(packageJsonPath)) {
5439
5541
  continue;
5440
5542
  }
@@ -5472,7 +5574,7 @@ ${stderr}`));
5472
5574
  reject(error);
5473
5575
  });
5474
5576
  });
5475
- const hasIndexTs = existsSync20(join10(capabilityPath, "index.ts"));
5577
+ const hasIndexTs = existsSync20(join11(capabilityPath, "index.ts"));
5476
5578
  let hasBuildScript = false;
5477
5579
  try {
5478
5580
  const pkgJson = JSON.parse(readFileSync3(packageJsonPath, "utf-8"));
@@ -5501,7 +5603,7 @@ ${stderr}`));
5501
5603
  });
5502
5604
  });
5503
5605
  } else if (hasIndexTs && !silent) {
5504
- const hasBuiltIndex = existsSync20(join10(capabilityPath, "dist", "index.js"));
5606
+ const hasBuiltIndex = existsSync20(join11(capabilityPath, "dist", "index.js"));
5505
5607
  if (!hasBuiltIndex) {
5506
5608
  console.warn(`Warning: Capability at ${capabilityPath} has index.ts but no build script.
5507
5609
  Add a "build" script to package.json (e.g., "build": "tsc") to compile TypeScript.`);
@@ -5572,8 +5674,8 @@ async function syncAgentConfiguration(options) {
5572
5674
  }
5573
5675
  mkdirSync5(".omni", { recursive: true });
5574
5676
  await syncMcpJson(capabilities2, previousManifest);
5575
- const newManifest = buildManifestFromCapabilities(capabilities2);
5576
- await saveManifest(newManifest);
5677
+ const enabledProviderIds = new Set(adapters.map((adapter) => String(adapter.id)));
5678
+ const successfulProviderOutputs = new Map;
5577
5679
  if (adapters.length > 0) {
5578
5680
  const config2 = await loadConfig();
5579
5681
  const ctx = {
@@ -5582,12 +5684,33 @@ async function syncAgentConfiguration(options) {
5582
5684
  };
5583
5685
  for (const adapter of adapters) {
5584
5686
  try {
5585
- await adapter.sync(bundle, ctx);
5687
+ const adapterResult = await adapter.sync(bundle, ctx);
5688
+ successfulProviderOutputs.set(String(adapter.id), adapterResult.managedOutputs ?? []);
5586
5689
  } catch (error) {
5587
5690
  console.error(`Error running ${adapter.displayName} adapter:`, error);
5588
5691
  }
5589
5692
  }
5590
5693
  }
5694
+ const nextProviderOutputs = new Map;
5695
+ if (adapters.length === 0) {
5696
+ for (const providerId of Object.keys(previousManifest.providers)) {
5697
+ nextProviderOutputs.set(providerId, getProviderManagedOutputs(previousManifest, providerId));
5698
+ }
5699
+ } else {
5700
+ for (const providerId of enabledProviderIds) {
5701
+ if (successfulProviderOutputs.has(providerId)) {
5702
+ nextProviderOutputs.set(providerId, successfulProviderOutputs.get(providerId) ?? []);
5703
+ continue;
5704
+ }
5705
+ nextProviderOutputs.set(providerId, getProviderManagedOutputs(previousManifest, providerId));
5706
+ }
5707
+ }
5708
+ const cleanupResult = await cleanupStaleManagedOutputs(previousManifest, nextProviderOutputs);
5709
+ for (const skipped of cleanupResult.skippedPaths) {
5710
+ console.warn(`Warning: skipped cleanup for ${skipped.path} (${skipped.reason})`);
5711
+ }
5712
+ const newManifest = buildManifestFromCapabilities(capabilities2, nextProviderOutputs);
5713
+ await saveManifest(newManifest);
5591
5714
  const result = {
5592
5715
  capabilities: capabilities2.map((c) => c.id),
5593
5716
  skillCount: bundle.skills.length,
@@ -5648,7 +5771,7 @@ var init_types3 = __esm(() => {
5648
5771
  // ../core/src/security/scanner.ts
5649
5772
  import { existsSync as existsSync21 } from "node:fs";
5650
5773
  import { lstat, readdir as readdir2, readFile as readFile17, readlink, realpath } from "node:fs/promises";
5651
- import { join as join11, relative, resolve as resolve2 } from "node:path";
5774
+ import { join as join12, relative, resolve as resolve2 } from "node:path";
5652
5775
  async function scanFileForUnicode(filePath, relativePath) {
5653
5776
  const findings = [];
5654
5777
  try {
@@ -5835,7 +5958,7 @@ async function scanFileForNetworkRequests(filePath, relativePath) {
5835
5958
  async function checkSymlink(symlinkPath, relativePath, capabilityRoot) {
5836
5959
  try {
5837
5960
  const linkTarget = await readlink(symlinkPath);
5838
- const resolvedTarget = resolve2(join11(symlinkPath, "..", linkTarget));
5961
+ const resolvedTarget = resolve2(join12(symlinkPath, "..", linkTarget));
5839
5962
  const normalizedRoot = await realpath(capabilityRoot);
5840
5963
  if (linkTarget.startsWith("/")) {
5841
5964
  return {
@@ -5882,7 +6005,7 @@ async function scanCapability(capabilityId, capabilityPath, settings = DEFAULT_S
5882
6005
  async function scanDirectory(dirPath) {
5883
6006
  const entries = await readdir2(dirPath, { withFileTypes: true });
5884
6007
  for (const entry of entries) {
5885
- const fullPath = join11(dirPath, entry.name);
6008
+ const fullPath = join12(dirPath, entry.name);
5886
6009
  const relativePath = relative(capabilityPath, fullPath);
5887
6010
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "__pycache__") {
5888
6011
  continue;
@@ -6245,7 +6368,9 @@ var init_security = __esm(() => {
6245
6368
 
6246
6369
  // ../core/src/templates/agents.ts
6247
6370
  function generateAgentsTemplate() {
6248
- return `# Project Instructions
6371
+ return `> IMPORTANT: Do not edit this file directly. Edit \`OMNI.md\` instead. This file is a generated copy of \`OMNI.md\` and is ephemeral. Any persistent change must be made in \`OMNI.md\`.
6372
+
6373
+ # Project Instructions
6249
6374
 
6250
6375
  <!-- Add your project-specific instructions here -->
6251
6376
 
@@ -6372,7 +6497,9 @@ function formatDisplayName(kebabCase) {
6372
6497
 
6373
6498
  // ../core/src/templates/claude.ts
6374
6499
  function generateClaudeTemplate() {
6375
- return `# Project Instructions
6500
+ return `> IMPORTANT: Do not edit this file directly. Edit \`OMNI.md\` instead. This file is a generated copy of \`OMNI.md\` and is ephemeral. Any persistent change must be made in \`OMNI.md\`.
6501
+
6502
+ # Project Instructions
6376
6503
 
6377
6504
  <!-- Add your project-specific instructions here -->
6378
6505
  `;
@@ -6496,6 +6623,7 @@ __export(exports_src, {
6496
6623
  hasAnyHooks: () => hasAnyHooks,
6497
6624
  getVersion: () => getVersion,
6498
6625
  getSourceCapabilityPath: () => getSourceCapabilityPath,
6626
+ getProviderManagedOutputs: () => getProviderManagedOutputs,
6499
6627
  getLockFilePath: () => getLockFilePath,
6500
6628
  getHooksDirectory: () => getHooksDirectory,
6501
6629
  getHooksConfigPath: () => getHooksConfigPath,
@@ -6533,6 +6661,7 @@ __export(exports_src, {
6533
6661
  clearAllSecurityAllows: () => clearAllSecurityAllows,
6534
6662
  clearActiveProfileState: () => clearActiveProfileState,
6535
6663
  cleanupStaleResources: () => cleanupStaleResources,
6664
+ cleanupStaleManagedOutputs: () => cleanupStaleManagedOutputs,
6536
6665
  checkVersionMismatch: () => checkVersionMismatch,
6537
6666
  checkForUpdates: () => checkForUpdates,
6538
6667
  buildSyncBundle: () => buildSyncBundle,
@@ -6576,15 +6705,33 @@ var init_src = __esm(() => {
6576
6705
  import { run } from "@stricli/core";
6577
6706
 
6578
6707
  // src/lib/dynamic-app.ts
6579
- import { existsSync as existsSync31 } from "node:fs";
6708
+ import { existsSync as existsSync32 } from "node:fs";
6580
6709
  import { createRequire as createRequire2 } from "node:module";
6581
- import { join as join28 } from "node:path";
6710
+ import { join as join29 } from "node:path";
6582
6711
  import { buildApplication, buildRouteMap as buildRouteMap7 } from "@stricli/core";
6583
6712
 
6584
6713
  // src/commands/add.ts
6585
6714
  import { existsSync as existsSync24 } from "node:fs";
6586
6715
  import { basename as basename5, resolve as resolve3 } from "node:path";
6587
6716
 
6717
+ // ../adapters/src/writers/generic/managed-outputs.ts
6718
+ import { createHash } from "node:crypto";
6719
+ function hashContent(content) {
6720
+ return createHash("sha256").update(content).digest("hex");
6721
+ }
6722
+ function trimTrailingSlash(path) {
6723
+ return path.endsWith("/") ? path.slice(0, -1) : path;
6724
+ }
6725
+ function createManagedOutput(path, writerId, content, options) {
6726
+ return {
6727
+ path,
6728
+ writerId,
6729
+ hash: hashContent(content),
6730
+ cleanupStrategy: options?.cleanupStrategy ?? "delete-file",
6731
+ ...options?.pruneRoot ? { pruneRoot: trimTrailingSlash(options.pruneRoot) } : {},
6732
+ ...options?.jsonKey ? { jsonKey: options.jsonKey } : {}
6733
+ };
6734
+ }
6588
6735
  // ../adapters/src/writers/generic/executor.ts
6589
6736
  async function executeWriters(writerConfigs, bundle, projectRoot, providerId) {
6590
6737
  const seen = new Set;
@@ -6600,6 +6747,7 @@ async function executeWriters(writerConfigs, bundle, projectRoot, providerId) {
6600
6747
  uniqueConfigs.push(config);
6601
6748
  }
6602
6749
  const allFilesWritten = [];
6750
+ const allManagedOutputs = [];
6603
6751
  for (const config of uniqueConfigs) {
6604
6752
  const result = await config.writer.write(bundle, {
6605
6753
  outputPath: config.outputPath,
@@ -6607,25 +6755,27 @@ async function executeWriters(writerConfigs, bundle, projectRoot, providerId) {
6607
6755
  ...providerId ? { providerId } : {}
6608
6756
  });
6609
6757
  allFilesWritten.push(...result.filesWritten);
6758
+ allManagedOutputs.push(...result.managedOutputs ?? []);
6610
6759
  }
6611
6760
  return {
6612
6761
  filesWritten: allFilesWritten,
6613
- deduplicatedCount
6762
+ deduplicatedCount,
6763
+ managedOutputs: allManagedOutputs
6614
6764
  };
6615
6765
  }
6616
6766
  // ../adapters/src/writers/generic/hooks.ts
6617
6767
  init_src();
6618
6768
  import { existsSync as existsSync22 } from "node:fs";
6619
6769
  import { mkdir as mkdir2, readFile as readFile18, writeFile as writeFile10 } from "node:fs/promises";
6620
- import { dirname, join as join12 } from "node:path";
6770
+ import { dirname as dirname2, join as join13 } from "node:path";
6621
6771
  var HooksWriter = {
6622
6772
  id: "hooks",
6623
6773
  async write(bundle, ctx) {
6624
6774
  if (!bundle.hooks) {
6625
6775
  return { filesWritten: [] };
6626
6776
  }
6627
- const settingsPath = join12(ctx.projectRoot, ctx.outputPath);
6628
- const parentDir = dirname(settingsPath);
6777
+ const settingsPath = join13(ctx.projectRoot, ctx.outputPath);
6778
+ const parentDir = dirname2(settingsPath);
6629
6779
  await mkdir2(parentDir, { recursive: true });
6630
6780
  const claudeHooks = transformHooksConfig(bundle.hooks, "toClaude");
6631
6781
  let existingSettings = {};
@@ -6644,14 +6794,20 @@ var HooksWriter = {
6644
6794
  await writeFile10(settingsPath, `${JSON.stringify(newSettings, null, 2)}
6645
6795
  `, "utf-8");
6646
6796
  return {
6647
- filesWritten: [ctx.outputPath]
6797
+ filesWritten: [ctx.outputPath],
6798
+ managedOutputs: [
6799
+ createManagedOutput(ctx.outputPath, this.id, JSON.stringify(claudeHooks), {
6800
+ cleanupStrategy: "remove-json-key",
6801
+ jsonKey: "hooks"
6802
+ })
6803
+ ]
6648
6804
  };
6649
6805
  }
6650
6806
  };
6651
6807
  // ../adapters/src/writers/generic/instructions-md.ts
6652
6808
  import { existsSync as existsSync23 } from "node:fs";
6653
6809
  import { mkdir as mkdir3, readFile as readFile19, writeFile as writeFile11 } from "node:fs/promises";
6654
- import { dirname as dirname2, join as join13 } from "node:path";
6810
+ import { dirname as dirname3, join as join14 } from "node:path";
6655
6811
 
6656
6812
  // ../adapters/src/writers/generic/omni-md.ts
6657
6813
  init_src();
@@ -6673,20 +6829,32 @@ function renderOmniMdForProvider(content, providerId) {
6673
6829
  }
6674
6830
 
6675
6831
  // ../adapters/src/writers/generic/instructions-md.ts
6832
+ function getGeneratedCopyNotice(outputPath) {
6833
+ if (outputPath !== "AGENTS.md" && outputPath !== "CLAUDE.md") {
6834
+ return "";
6835
+ }
6836
+ return "> IMPORTANT: Do not edit this file directly. Edit `OMNI.md` instead. This file is a generated copy of `OMNI.md` and is ephemeral. Any persistent change must be made in `OMNI.md`.";
6837
+ }
6676
6838
  var InstructionsMdWriter = {
6677
6839
  id: "instructions-md",
6678
6840
  async write(bundle, ctx) {
6679
- const outputFullPath = join13(ctx.projectRoot, ctx.outputPath);
6680
- const parentDir = dirname2(outputFullPath);
6841
+ const outputFullPath = join14(ctx.projectRoot, ctx.outputPath);
6842
+ const parentDir = dirname3(outputFullPath);
6681
6843
  if (parentDir !== ctx.projectRoot) {
6682
6844
  await mkdir3(parentDir, { recursive: true });
6683
6845
  }
6684
- const omniMdPath = join13(ctx.projectRoot, "OMNI.md");
6846
+ const omniMdPath = join14(ctx.projectRoot, "OMNI.md");
6685
6847
  let omniMdContent = "";
6686
6848
  if (existsSync23(omniMdPath)) {
6687
6849
  omniMdContent = renderOmniMdForProvider(await readFile19(omniMdPath, "utf-8"), ctx.providerId);
6688
6850
  }
6689
6851
  let content = omniMdContent;
6852
+ const generatedCopyNotice = getGeneratedCopyNotice(ctx.outputPath);
6853
+ if (generatedCopyNotice) {
6854
+ content = content ? `${generatedCopyNotice}
6855
+
6856
+ ${content}` : generatedCopyNotice;
6857
+ }
6690
6858
  if (bundle.instructionsContent) {
6691
6859
  content += `
6692
6860
 
@@ -6695,23 +6863,30 @@ ${bundle.instructionsContent}
6695
6863
  }
6696
6864
  await writeFile11(outputFullPath, content, "utf-8");
6697
6865
  return {
6698
- filesWritten: [ctx.outputPath]
6866
+ filesWritten: [ctx.outputPath],
6867
+ managedOutputs: [createManagedOutput(ctx.outputPath, this.id, content)]
6699
6868
  };
6700
6869
  }
6701
6870
  };
6702
6871
  // ../adapters/src/writers/generic/skills.ts
6703
- import { mkdir as mkdir4, writeFile as writeFile12 } from "node:fs/promises";
6704
- import { join as join14 } from "node:path";
6872
+ import { cp as cp2, mkdir as mkdir4, readdir as readdir3, rm as rm2, writeFile as writeFile12 } from "node:fs/promises";
6873
+ import { join as join15, relative as relative2 } from "node:path";
6705
6874
  var SkillsWriter = {
6706
6875
  id: "skills",
6707
6876
  async write(bundle, ctx) {
6708
- const skillsDir = join14(ctx.projectRoot, ctx.outputPath);
6877
+ const skillsDir = join15(ctx.projectRoot, ctx.outputPath);
6709
6878
  await mkdir4(skillsDir, { recursive: true });
6710
6879
  const filesWritten = [];
6880
+ const managedOutputs = [];
6711
6881
  for (const skill of bundle.skills) {
6712
- const skillDir = join14(skillsDir, skill.name);
6713
- await mkdir4(skillDir, { recursive: true });
6714
- const skillPath = join14(skillDir, "SKILL.md");
6882
+ const skillDir = join15(skillsDir, skill.name);
6883
+ await rm2(skillDir, { recursive: true, force: true });
6884
+ if (skill.sourcePath) {
6885
+ await cp2(skill.sourcePath, skillDir, { recursive: true });
6886
+ } else {
6887
+ await mkdir4(skillDir, { recursive: true });
6888
+ }
6889
+ const skillPath = join15(skillDir, "SKILL.md");
6715
6890
  const content = `---
6716
6891
  name: ${skill.name}
6717
6892
  description: "${skill.description}"
@@ -6719,16 +6894,43 @@ description: "${skill.description}"
6719
6894
 
6720
6895
  ${skill.instructions}`;
6721
6896
  await writeFile12(skillPath, content, "utf-8");
6722
- filesWritten.push(join14(ctx.outputPath, skill.name, "SKILL.md"));
6897
+ const relativePaths = skill.sourcePath ? await listRelativeFiles(skillDir) : ["SKILL.md"];
6898
+ for (const relativeFile of relativePaths) {
6899
+ filesWritten.push(join15(ctx.outputPath, skill.name, relativeFile));
6900
+ }
6901
+ const relativePath = join15(ctx.outputPath, skill.name, "SKILL.md");
6902
+ managedOutputs.push(createManagedOutput(relativePath, this.id, content, {
6903
+ cleanupStrategy: "delete-file-and-prune-empty-parents",
6904
+ pruneRoot: ctx.outputPath
6905
+ }));
6723
6906
  }
6724
6907
  return {
6725
- filesWritten
6908
+ filesWritten,
6909
+ managedOutputs
6726
6910
  };
6727
6911
  }
6728
6912
  };
6913
+ async function listRelativeFiles(basePath) {
6914
+ const files = [];
6915
+ const entries = await readdir3(basePath, { withFileTypes: true });
6916
+ for (const entry of entries) {
6917
+ const entryPath = join15(basePath, entry.name);
6918
+ if (entry.isDirectory()) {
6919
+ const nestedFiles = await listRelativeFiles(entryPath);
6920
+ for (const nestedFile of nestedFiles) {
6921
+ files.push(relative2(basePath, join15(entryPath, nestedFile)));
6922
+ }
6923
+ continue;
6924
+ }
6925
+ if (entry.isFile()) {
6926
+ files.push(entry.name);
6927
+ }
6928
+ }
6929
+ return files.sort((a, b) => a.localeCompare(b));
6930
+ }
6729
6931
  // ../adapters/src/writers/generic/commands-as-skills.ts
6730
6932
  import { mkdir as mkdir5, writeFile as writeFile13 } from "node:fs/promises";
6731
- import { join as join15 } from "node:path";
6933
+ import { join as join16 } from "node:path";
6732
6934
  function generateSkillFrontmatter(command) {
6733
6935
  const lines = ["---"];
6734
6936
  lines.push(`name: ${command.name}`);
@@ -6743,22 +6945,29 @@ function generateSkillFrontmatter(command) {
6743
6945
  var CommandsAsSkillsWriter = {
6744
6946
  id: "commands-as-skills",
6745
6947
  async write(bundle, ctx) {
6746
- const skillsDir = join15(ctx.projectRoot, ctx.outputPath);
6948
+ const skillsDir = join16(ctx.projectRoot, ctx.outputPath);
6747
6949
  await mkdir5(skillsDir, { recursive: true });
6748
6950
  const filesWritten = [];
6951
+ const managedOutputs = [];
6749
6952
  for (const command of bundle.commands) {
6750
- const commandSkillDir = join15(skillsDir, command.name);
6953
+ const commandSkillDir = join16(skillsDir, command.name);
6751
6954
  await mkdir5(commandSkillDir, { recursive: true });
6752
6955
  const frontmatter = generateSkillFrontmatter(command);
6753
6956
  const content = `${frontmatter}
6754
6957
 
6755
6958
  ${command.prompt}`;
6756
- const skillPath = join15(commandSkillDir, "SKILL.md");
6959
+ const skillPath = join16(commandSkillDir, "SKILL.md");
6757
6960
  await writeFile13(skillPath, content, "utf-8");
6758
- filesWritten.push(join15(ctx.outputPath, command.name, "SKILL.md"));
6961
+ const relativePath = join16(ctx.outputPath, command.name, "SKILL.md");
6962
+ filesWritten.push(relativePath);
6963
+ managedOutputs.push(createManagedOutput(relativePath, this.id, content, {
6964
+ cleanupStrategy: "delete-file-and-prune-empty-parents",
6965
+ pruneRoot: ctx.outputPath
6966
+ }));
6759
6967
  }
6760
6968
  return {
6761
- filesWritten
6969
+ filesWritten,
6970
+ managedOutputs
6762
6971
  };
6763
6972
  }
6764
6973
  };
@@ -6811,7 +7020,7 @@ function createProviderScopedBundle(bundle, providerId) {
6811
7020
 
6812
7021
  // ../adapters/src/writers/claude/agents.ts
6813
7022
  import { mkdir as mkdir6, writeFile as writeFile14 } from "node:fs/promises";
6814
- import { join as join16 } from "node:path";
7023
+ import { join as join17 } from "node:path";
6815
7024
  function generateFrontmatter(agent) {
6816
7025
  const lines = ["---"];
6817
7026
  lines.push(`name: ${agent.name}`);
@@ -6838,20 +7047,24 @@ function generateFrontmatter(agent) {
6838
7047
  var ClaudeAgentsWriter = {
6839
7048
  id: "claude-agents",
6840
7049
  async write(bundle, ctx) {
6841
- const agentsDir = join16(ctx.projectRoot, ctx.outputPath);
7050
+ const agentsDir = join17(ctx.projectRoot, ctx.outputPath);
6842
7051
  await mkdir6(agentsDir, { recursive: true });
6843
7052
  const filesWritten = [];
7053
+ const managedOutputs = [];
6844
7054
  for (const agent of bundle.subagents) {
6845
7055
  const frontmatter = generateFrontmatter(agent);
6846
7056
  const content = `${frontmatter}
6847
7057
 
6848
7058
  ${agent.systemPrompt}`;
6849
- const agentPath = join16(agentsDir, `${agent.name}.md`);
7059
+ const agentPath = join17(agentsDir, `${agent.name}.md`);
6850
7060
  await writeFile14(agentPath, content, "utf-8");
6851
- filesWritten.push(join16(ctx.outputPath, `${agent.name}.md`));
7061
+ const relativePath = join17(ctx.outputPath, `${agent.name}.md`);
7062
+ filesWritten.push(relativePath);
7063
+ managedOutputs.push(createManagedOutput(relativePath, this.id, content));
6852
7064
  }
6853
7065
  return {
6854
- filesWritten
7066
+ filesWritten,
7067
+ managedOutputs
6855
7068
  };
6856
7069
  }
6857
7070
  };
@@ -6878,18 +7091,19 @@ var claudeCodeAdapter = {
6878
7091
  const result = await executeWriters(this.writers, providerBundle, ctx.projectRoot, providerId);
6879
7092
  return {
6880
7093
  filesWritten: result.filesWritten,
6881
- filesDeleted: []
7094
+ filesDeleted: [],
7095
+ managedOutputs: result.managedOutputs
6882
7096
  };
6883
7097
  }
6884
7098
  };
6885
7099
  // ../adapters/src/codex/index.ts
6886
7100
  import { mkdirSync as mkdirSync6 } from "node:fs";
6887
- import { join as join18 } from "node:path";
7101
+ import { join as join19 } from "node:path";
6888
7102
 
6889
7103
  // ../adapters/src/writers/codex/toml.ts
6890
7104
  init_dist();
6891
7105
  import { mkdir as mkdir7, writeFile as writeFile15 } from "node:fs/promises";
6892
- import { dirname as dirname3, join as join17 } from "node:path";
7106
+ import { dirname as dirname4, join as join18 } from "node:path";
6893
7107
  var FILE_HEADER = `# Generated by OmniDev - DO NOT EDIT
6894
7108
  # Run \`omnidev sync\` to regenerate
6895
7109
 
@@ -6940,8 +7154,8 @@ var CodexTomlWriter = {
6940
7154
  if (mcps.size === 0) {
6941
7155
  return { filesWritten: [] };
6942
7156
  }
6943
- const configPath = join17(ctx.projectRoot, ctx.outputPath);
6944
- const parentDir = dirname3(configPath);
7157
+ const configPath = join18(ctx.projectRoot, ctx.outputPath);
7158
+ const parentDir = dirname4(configPath);
6945
7159
  await mkdir7(parentDir, { recursive: true });
6946
7160
  const mcpServers = {};
6947
7161
  for (const [id, mcp] of mcps) {
@@ -6959,7 +7173,8 @@ var CodexTomlWriter = {
6959
7173
  const tomlContent = FILE_HEADER + stringify(codexConfig);
6960
7174
  await writeFile15(configPath, tomlContent, "utf-8");
6961
7175
  return {
6962
- filesWritten: [ctx.outputPath]
7176
+ filesWritten: [ctx.outputPath],
7177
+ managedOutputs: [createManagedOutput(ctx.outputPath, this.id, tomlContent)]
6963
7178
  };
6964
7179
  }
6965
7180
  };
@@ -6974,7 +7189,7 @@ var codexAdapter = {
6974
7189
  { writer: CodexTomlWriter, outputPath: ".codex/config.toml" }
6975
7190
  ],
6976
7191
  async init(ctx) {
6977
- const codexDir = join18(ctx.projectRoot, ".codex");
7192
+ const codexDir = join19(ctx.projectRoot, ".codex");
6978
7193
  mkdirSync6(codexDir, { recursive: true });
6979
7194
  return {
6980
7195
  filesCreated: [".codex/"],
@@ -6987,17 +7202,18 @@ var codexAdapter = {
6987
7202
  const result = await executeWriters(this.writers, providerBundle, ctx.projectRoot, providerId);
6988
7203
  return {
6989
7204
  filesWritten: result.filesWritten,
6990
- filesDeleted: []
7205
+ filesDeleted: [],
7206
+ managedOutputs: result.managedOutputs
6991
7207
  };
6992
7208
  }
6993
7209
  };
6994
7210
  // ../adapters/src/cursor/index.ts
6995
7211
  import { mkdirSync as mkdirSync7 } from "node:fs";
6996
- import { join as join23 } from "node:path";
7212
+ import { join as join24 } from "node:path";
6997
7213
 
6998
7214
  // ../adapters/src/writers/cursor/agents.ts
6999
7215
  import { mkdir as mkdir8, writeFile as writeFile16 } from "node:fs/promises";
7000
- import { join as join19 } from "node:path";
7216
+ import { join as join20 } from "node:path";
7001
7217
  function mapModelToCursor(model) {
7002
7218
  if (!model || model === "inherit")
7003
7219
  return "inherit";
@@ -7029,50 +7245,58 @@ function generateFrontmatter2(agent) {
7029
7245
  var CursorAgentsWriter = {
7030
7246
  id: "cursor-agents",
7031
7247
  async write(bundle, ctx) {
7032
- const agentsDir = join19(ctx.projectRoot, ctx.outputPath);
7248
+ const agentsDir = join20(ctx.projectRoot, ctx.outputPath);
7033
7249
  await mkdir8(agentsDir, { recursive: true });
7034
7250
  const filesWritten = [];
7251
+ const managedOutputs = [];
7035
7252
  for (const agent of bundle.subagents) {
7036
7253
  const frontmatter = generateFrontmatter2(agent);
7037
7254
  const content = `${frontmatter}
7038
7255
 
7039
7256
  ${agent.systemPrompt}`;
7040
- const agentPath = join19(agentsDir, `${agent.name}.md`);
7257
+ const agentPath = join20(agentsDir, `${agent.name}.md`);
7041
7258
  await writeFile16(agentPath, content, "utf-8");
7042
- filesWritten.push(join19(ctx.outputPath, `${agent.name}.md`));
7259
+ const relativePath = join20(ctx.outputPath, `${agent.name}.md`);
7260
+ filesWritten.push(relativePath);
7261
+ managedOutputs.push(createManagedOutput(relativePath, this.id, content));
7043
7262
  }
7044
7263
  return {
7045
- filesWritten
7264
+ filesWritten,
7265
+ managedOutputs
7046
7266
  };
7047
7267
  }
7048
7268
  };
7049
7269
  // ../adapters/src/writers/cursor/commands.ts
7050
7270
  import { mkdir as mkdir9, writeFile as writeFile17 } from "node:fs/promises";
7051
- import { join as join20 } from "node:path";
7271
+ import { join as join21 } from "node:path";
7052
7272
  var CursorCommandsWriter = {
7053
7273
  id: "cursor-commands",
7054
7274
  async write(bundle, ctx) {
7055
- const commandsDir = join20(ctx.projectRoot, ctx.outputPath);
7275
+ const commandsDir = join21(ctx.projectRoot, ctx.outputPath);
7056
7276
  await mkdir9(commandsDir, { recursive: true });
7057
7277
  const filesWritten = [];
7278
+ const managedOutputs = [];
7058
7279
  for (const command of bundle.commands) {
7059
7280
  const content = `# ${command.name}
7060
7281
 
7061
7282
  ${command.description}
7062
7283
 
7063
7284
  ${command.prompt}`;
7064
- const commandPath = join20(commandsDir, `${command.name}.md`);
7285
+ const commandPath = join21(commandsDir, `${command.name}.md`);
7065
7286
  await writeFile17(commandPath, content, "utf-8");
7066
- filesWritten.push(join20(ctx.outputPath, `${command.name}.md`));
7287
+ const relativePath = join21(ctx.outputPath, `${command.name}.md`);
7288
+ filesWritten.push(relativePath);
7289
+ managedOutputs.push(createManagedOutput(relativePath, this.id, content));
7067
7290
  }
7068
7291
  return {
7069
- filesWritten
7292
+ filesWritten,
7293
+ managedOutputs
7070
7294
  };
7071
7295
  }
7072
7296
  };
7073
7297
  // ../adapters/src/writers/cursor/mcp-json.ts
7074
7298
  import { mkdir as mkdir10, writeFile as writeFile18 } from "node:fs/promises";
7075
- import { dirname as dirname4, join as join21 } from "node:path";
7299
+ import { dirname as dirname5, join as join22 } from "node:path";
7076
7300
  function buildCursorMcpConfig(mcp) {
7077
7301
  const transport = mcp.transport ?? "stdio";
7078
7302
  if (transport === "http" || transport === "sse") {
@@ -7117,8 +7341,8 @@ var CursorMcpJsonWriter = {
7117
7341
  if (mcps.size === 0) {
7118
7342
  return { filesWritten: [] };
7119
7343
  }
7120
- const configPath = join21(ctx.projectRoot, ctx.outputPath);
7121
- const parentDir = dirname4(configPath);
7344
+ const configPath = join22(ctx.projectRoot, ctx.outputPath);
7345
+ const parentDir = dirname5(configPath);
7122
7346
  await mkdir10(parentDir, { recursive: true });
7123
7347
  const mcpServers = {};
7124
7348
  for (const [id, mcp] of mcps) {
@@ -7133,29 +7357,35 @@ var CursorMcpJsonWriter = {
7133
7357
  const cursorMcpJson = {
7134
7358
  mcpServers
7135
7359
  };
7136
- await writeFile18(configPath, `${JSON.stringify(cursorMcpJson, null, 2)}
7137
- `, "utf-8");
7360
+ const content = `${JSON.stringify(cursorMcpJson, null, 2)}
7361
+ `;
7362
+ await writeFile18(configPath, content, "utf-8");
7138
7363
  return {
7139
- filesWritten: [ctx.outputPath]
7364
+ filesWritten: [ctx.outputPath],
7365
+ managedOutputs: [createManagedOutput(ctx.outputPath, this.id, content)]
7140
7366
  };
7141
7367
  }
7142
7368
  };
7143
7369
  // ../adapters/src/writers/cursor/rules.ts
7144
7370
  import { mkdir as mkdir11, writeFile as writeFile19 } from "node:fs/promises";
7145
- import { join as join22 } from "node:path";
7371
+ import { join as join23 } from "node:path";
7146
7372
  var CursorRulesWriter = {
7147
7373
  id: "cursor-rules",
7148
7374
  async write(bundle, ctx) {
7149
- const rulesDir = join22(ctx.projectRoot, ctx.outputPath);
7375
+ const rulesDir = join23(ctx.projectRoot, ctx.outputPath);
7150
7376
  await mkdir11(rulesDir, { recursive: true });
7151
7377
  const filesWritten = [];
7378
+ const managedOutputs = [];
7152
7379
  for (const rule of bundle.rules) {
7153
- const rulePath = join22(rulesDir, `omnidev-${rule.name}.mdc`);
7380
+ const rulePath = join23(rulesDir, `omnidev-${rule.name}.mdc`);
7154
7381
  await writeFile19(rulePath, rule.content, "utf-8");
7155
- filesWritten.push(join22(ctx.outputPath, `omnidev-${rule.name}.mdc`));
7382
+ const relativePath = join23(ctx.outputPath, `omnidev-${rule.name}.mdc`);
7383
+ filesWritten.push(relativePath);
7384
+ managedOutputs.push(createManagedOutput(relativePath, this.id, rule.content));
7156
7385
  }
7157
7386
  return {
7158
- filesWritten
7387
+ filesWritten,
7388
+ managedOutputs
7159
7389
  };
7160
7390
  }
7161
7391
  };
@@ -7172,7 +7402,7 @@ var cursorAdapter = {
7172
7402
  { writer: CursorMcpJsonWriter, outputPath: ".cursor/mcp.json" }
7173
7403
  ],
7174
7404
  async init(ctx) {
7175
- const rulesDir = join23(ctx.projectRoot, ".cursor", "rules");
7405
+ const rulesDir = join24(ctx.projectRoot, ".cursor", "rules");
7176
7406
  mkdirSync7(rulesDir, { recursive: true });
7177
7407
  return {
7178
7408
  filesCreated: [".cursor/rules/"],
@@ -7192,17 +7422,18 @@ var cursorAdapter = {
7192
7422
  filesWritten: [
7193
7423
  ...new Set([...instructionsResult.filesWritten, ...cursorResult.filesWritten])
7194
7424
  ],
7195
- filesDeleted: []
7425
+ filesDeleted: [],
7426
+ managedOutputs: [...instructionsResult.managedOutputs, ...cursorResult.managedOutputs]
7196
7427
  };
7197
7428
  }
7198
7429
  };
7199
7430
  // ../adapters/src/opencode/index.ts
7200
7431
  import { mkdirSync as mkdirSync8 } from "node:fs";
7201
- import { join as join26 } from "node:path";
7432
+ import { join as join27 } from "node:path";
7202
7433
 
7203
7434
  // ../adapters/src/writers/opencode/agents.ts
7204
7435
  import { mkdir as mkdir12, writeFile as writeFile20 } from "node:fs/promises";
7205
- import { join as join24 } from "node:path";
7436
+ import { join as join25 } from "node:path";
7206
7437
  function mapModelToOpenCode(model) {
7207
7438
  if (!model || model === "inherit")
7208
7439
  return;
@@ -7280,26 +7511,30 @@ function generateFrontmatter3(agent) {
7280
7511
  var OpenCodeAgentsWriter = {
7281
7512
  id: "opencode-agents",
7282
7513
  async write(bundle, ctx) {
7283
- const agentsDir = join24(ctx.projectRoot, ctx.outputPath);
7514
+ const agentsDir = join25(ctx.projectRoot, ctx.outputPath);
7284
7515
  await mkdir12(agentsDir, { recursive: true });
7285
7516
  const filesWritten = [];
7517
+ const managedOutputs = [];
7286
7518
  for (const agent of bundle.subagents) {
7287
7519
  const frontmatter = generateFrontmatter3(agent);
7288
7520
  const content = `${frontmatter}
7289
7521
 
7290
7522
  ${agent.systemPrompt}`;
7291
- const agentPath = join24(agentsDir, `${agent.name}.md`);
7523
+ const agentPath = join25(agentsDir, `${agent.name}.md`);
7292
7524
  await writeFile20(agentPath, content, "utf-8");
7293
- filesWritten.push(join24(ctx.outputPath, `${agent.name}.md`));
7525
+ const relativePath = join25(ctx.outputPath, `${agent.name}.md`);
7526
+ filesWritten.push(relativePath);
7527
+ managedOutputs.push(createManagedOutput(relativePath, this.id, content));
7294
7528
  }
7295
7529
  return {
7296
- filesWritten
7530
+ filesWritten,
7531
+ managedOutputs
7297
7532
  };
7298
7533
  }
7299
7534
  };
7300
7535
  // ../adapters/src/writers/opencode/commands.ts
7301
7536
  import { mkdir as mkdir13, writeFile as writeFile21 } from "node:fs/promises";
7302
- import { join as join25 } from "node:path";
7537
+ import { join as join26 } from "node:path";
7303
7538
  function generateFrontmatter4(command) {
7304
7539
  const lines = ["---"];
7305
7540
  lines.push(`description: "${command.description.replace(/"/g, "\\\"")}"`);
@@ -7316,20 +7551,24 @@ function generateFrontmatter4(command) {
7316
7551
  var OpenCodeCommandsWriter = {
7317
7552
  id: "opencode-commands",
7318
7553
  async write(bundle, ctx) {
7319
- const commandsDir = join25(ctx.projectRoot, ctx.outputPath);
7554
+ const commandsDir = join26(ctx.projectRoot, ctx.outputPath);
7320
7555
  await mkdir13(commandsDir, { recursive: true });
7321
7556
  const filesWritten = [];
7557
+ const managedOutputs = [];
7322
7558
  for (const command of bundle.commands) {
7323
7559
  const frontmatter = generateFrontmatter4(command);
7324
7560
  const content = `${frontmatter}
7325
7561
 
7326
7562
  ${command.prompt}`;
7327
- const commandPath = join25(commandsDir, `${command.name}.md`);
7563
+ const commandPath = join26(commandsDir, `${command.name}.md`);
7328
7564
  await writeFile21(commandPath, content, "utf-8");
7329
- filesWritten.push(join25(ctx.outputPath, `${command.name}.md`));
7565
+ const relativePath = join26(ctx.outputPath, `${command.name}.md`);
7566
+ filesWritten.push(relativePath);
7567
+ managedOutputs.push(createManagedOutput(relativePath, this.id, content));
7330
7568
  }
7331
7569
  return {
7332
- filesWritten
7570
+ filesWritten,
7571
+ managedOutputs
7333
7572
  };
7334
7573
  }
7335
7574
  };
@@ -7344,7 +7583,7 @@ var opencodeAdapter = {
7344
7583
  { writer: OpenCodeCommandsWriter, outputPath: ".opencode/commands/" }
7345
7584
  ],
7346
7585
  async init(ctx) {
7347
- const opencodeDir = join26(ctx.projectRoot, ".opencode");
7586
+ const opencodeDir = join27(ctx.projectRoot, ".opencode");
7348
7587
  mkdirSync8(opencodeDir, { recursive: true });
7349
7588
  return {
7350
7589
  filesCreated: [".opencode/"],
@@ -7357,7 +7596,8 @@ var opencodeAdapter = {
7357
7596
  const result = await executeWriters(this.writers, providerBundle, ctx.projectRoot, providerId);
7358
7597
  return {
7359
7598
  filesWritten: result.filesWritten,
7360
- filesDeleted: []
7599
+ filesDeleted: [],
7600
+ managedOutputs: result.managedOutputs
7361
7601
  };
7362
7602
  }
7363
7603
  };
@@ -7802,7 +8042,7 @@ var addRoutes = buildRouteMap({
7802
8042
  // src/commands/capability.ts
7803
8043
  import { existsSync as existsSync25, mkdirSync as mkdirSync9 } from "node:fs";
7804
8044
  import { writeFile as writeFile22 } from "node:fs/promises";
7805
- import { join as join27 } from "node:path";
8045
+ import { join as join28 } from "node:path";
7806
8046
  import { input } from "@inquirer/prompts";
7807
8047
  init_src();
7808
8048
  import { buildCommand as buildCommand2, buildRouteMap as buildRouteMap2 } from "@stricli/core";
@@ -8022,21 +8262,21 @@ async function runCapabilityNew(flags, capabilityId) {
8022
8262
  const name = toTitleCase(id);
8023
8263
  mkdirSync9(capabilityDir, { recursive: true });
8024
8264
  const capabilityToml = generateCapabilityToml2({ id, name });
8025
- await writeFile22(join27(capabilityDir, "capability.toml"), capabilityToml, "utf-8");
8026
- const skillDir = join27(capabilityDir, "skills", "getting-started");
8265
+ await writeFile22(join28(capabilityDir, "capability.toml"), capabilityToml, "utf-8");
8266
+ const skillDir = join28(capabilityDir, "skills", "getting-started");
8027
8267
  mkdirSync9(skillDir, { recursive: true });
8028
- await writeFile22(join27(skillDir, "SKILL.md"), generateSkillTemplate("getting-started"), "utf-8");
8029
- const rulesDir = join27(capabilityDir, "rules");
8268
+ await writeFile22(join28(skillDir, "SKILL.md"), generateSkillTemplate("getting-started"), "utf-8");
8269
+ const rulesDir = join28(capabilityDir, "rules");
8030
8270
  mkdirSync9(rulesDir, { recursive: true });
8031
- await writeFile22(join27(rulesDir, "coding-standards.md"), generateRuleTemplate("coding-standards"), "utf-8");
8032
- const hooksDir = join27(capabilityDir, "hooks");
8271
+ await writeFile22(join28(rulesDir, "coding-standards.md"), generateRuleTemplate("coding-standards"), "utf-8");
8272
+ const hooksDir = join28(capabilityDir, "hooks");
8033
8273
  mkdirSync9(hooksDir, { recursive: true });
8034
- await writeFile22(join27(hooksDir, "hooks.toml"), generateHooksTemplate(), "utf-8");
8035
- await writeFile22(join27(hooksDir, "example-hook.sh"), generateHookScript(), "utf-8");
8036
- await writeFile22(join27(capabilityDir, ".gitignore"), generateGitignore(Boolean(flags.programmatic)), "utf-8");
8274
+ await writeFile22(join28(hooksDir, "hooks.toml"), generateHooksTemplate(), "utf-8");
8275
+ await writeFile22(join28(hooksDir, "example-hook.sh"), generateHookScript(), "utf-8");
8276
+ await writeFile22(join28(capabilityDir, ".gitignore"), generateGitignore(Boolean(flags.programmatic)), "utf-8");
8037
8277
  if (flags.programmatic) {
8038
- await writeFile22(join27(capabilityDir, "package.json"), generatePackageJson(id), "utf-8");
8039
- await writeFile22(join27(capabilityDir, "index.ts"), generateIndexTs(id, name), "utf-8");
8278
+ await writeFile22(join28(capabilityDir, "package.json"), generatePackageJson(id), "utf-8");
8279
+ await writeFile22(join28(capabilityDir, "index.ts"), generateIndexTs(id, name), "utf-8");
8040
8280
  }
8041
8281
  console.log(`✓ Created capability: ${name}`);
8042
8282
  console.log(` Location: ${capabilityDir}`);
@@ -8691,6 +8931,8 @@ async function runProfileSet(profileName) {
8691
8931
  }
8692
8932
 
8693
8933
  // src/commands/provider.ts
8934
+ import { existsSync as existsSync29 } from "node:fs";
8935
+ import { readFile as readFile22 } from "node:fs/promises";
8694
8936
  init_src();
8695
8937
  import { buildCommand as buildCommand6, buildRouteMap as buildRouteMap4 } from "@stricli/core";
8696
8938
  async function runProviderList() {
@@ -8724,6 +8966,7 @@ async function runProviderEnable(_flags, providerId) {
8724
8966
  }
8725
8967
  await enableProvider(providerId);
8726
8968
  console.log(`✓ Enabled provider: ${adapter.displayName}`);
8969
+ await maybeRemindAboutProviderGitignore(providerId);
8727
8970
  const enabledAdapters = await getEnabledAdapters();
8728
8971
  await syncAgentConfiguration({ silent: false, adapters: enabledAdapters });
8729
8972
  }
@@ -8804,10 +9047,33 @@ var providerRoutes = buildRouteMap4({
8804
9047
  brief: "Manage AI provider adapters"
8805
9048
  }
8806
9049
  });
9050
+ async function maybeRemindAboutProviderGitignore(providerId) {
9051
+ const missingEntries = await getMissingGitignoreEntries(getProviderGitignoreFiles([providerId]));
9052
+ if (missingEntries.length === 0) {
9053
+ return;
9054
+ }
9055
+ console.log("");
9056
+ console.log("Also update your .gitignore to ignore provider files if you do not want to commit them:");
9057
+ for (const entry of missingEntries) {
9058
+ console.log(` - ${entry}`);
9059
+ }
9060
+ }
9061
+ async function getMissingGitignoreEntries(entries) {
9062
+ if (entries.length === 0) {
9063
+ return [];
9064
+ }
9065
+ let content = "";
9066
+ if (existsSync29(".gitignore")) {
9067
+ content = await readFile22(".gitignore", "utf-8");
9068
+ }
9069
+ const lines = new Set(content.split(`
9070
+ `).map((line) => line.trim()));
9071
+ return [...new Set(entries)].filter((entry) => !lines.has(entry));
9072
+ }
8807
9073
 
8808
9074
  // src/commands/security.ts
8809
9075
  init_src();
8810
- import { existsSync as existsSync29 } from "node:fs";
9076
+ import { existsSync as existsSync30 } from "node:fs";
8811
9077
  import { buildCommand as buildCommand7, buildRouteMap as buildRouteMap5 } from "@stricli/core";
8812
9078
  var VALID_FINDING_TYPES = [
8813
9079
  "unicode_bidi",
@@ -8926,7 +9192,7 @@ function formatFindingsWithHints(summary) {
8926
9192
  }
8927
9193
  async function runSecurityIssues(flags = {}) {
8928
9194
  try {
8929
- if (!existsSync29("omni.toml")) {
9195
+ if (!existsSync30("omni.toml")) {
8930
9196
  console.log("No config file found");
8931
9197
  console.log(" Run: omnidev init");
8932
9198
  process.exit(1);
@@ -9181,7 +9447,7 @@ var securityRoutes = buildRouteMap5({
9181
9447
  });
9182
9448
 
9183
9449
  // src/commands/sync.ts
9184
- import { existsSync as existsSync30 } from "node:fs";
9450
+ import { existsSync as existsSync31 } from "node:fs";
9185
9451
  init_src();
9186
9452
  import { buildCommand as buildCommand8 } from "@stricli/core";
9187
9453
  var PROVIDERS_STATE_PATH = ".omni/state/providers.json";
@@ -9199,7 +9465,7 @@ async function runSync() {
9199
9465
  const config3 = await loadConfig();
9200
9466
  const activeProfile = await getActiveProfile() ?? "default";
9201
9467
  let adapters = await getEnabledAdapters();
9202
- if (!existsSync30(PROVIDERS_STATE_PATH) || adapters.length === 0) {
9468
+ if (!existsSync31(PROVIDERS_STATE_PATH) || adapters.length === 0) {
9203
9469
  console.log("No providers configured yet. Select your provider(s):");
9204
9470
  const providerIds = await promptForProviders();
9205
9471
  await writeEnabledProviders(providerIds);
@@ -9409,9 +9675,9 @@ async function buildDynamicApp() {
9409
9675
  security: securityRoutes
9410
9676
  };
9411
9677
  debug("Core routes registered", Object.keys(routes));
9412
- const configPath = join28(process.cwd(), "omni.toml");
9413
- debug("Checking for config", { configPath, exists: existsSync31(configPath), cwd: process.cwd() });
9414
- if (existsSync31(configPath)) {
9678
+ const configPath = join29(process.cwd(), "omni.toml");
9679
+ debug("Checking for config", { configPath, exists: existsSync32(configPath), cwd: process.cwd() });
9680
+ if (existsSync32(configPath)) {
9415
9681
  try {
9416
9682
  debug("Loading capability commands...");
9417
9683
  const capabilityCommands = await loadCapabilityCommands();
@@ -9486,25 +9752,25 @@ async function loadCapabilityCommands() {
9486
9752
  return commands;
9487
9753
  }
9488
9754
  async function loadCapabilityExport(capability3) {
9489
- const capabilityPath = join28(process.cwd(), capability3.path);
9490
- const builtIndexPath = join28(capabilityPath, "dist", "index.js");
9491
- const jsIndexPath = join28(capabilityPath, "index.js");
9492
- const tsIndexPath = join28(capabilityPath, "index.ts");
9755
+ const capabilityPath = join29(process.cwd(), capability3.path);
9756
+ const builtIndexPath = join29(capabilityPath, "dist", "index.js");
9757
+ const jsIndexPath = join29(capabilityPath, "index.js");
9758
+ const tsIndexPath = join29(capabilityPath, "index.ts");
9493
9759
  debug(`Checking entry points for '${capability3.id}'`, {
9494
9760
  capabilityPath,
9495
9761
  builtIndexPath,
9496
- builtExists: existsSync31(builtIndexPath),
9762
+ builtExists: existsSync32(builtIndexPath),
9497
9763
  jsIndexPath,
9498
- jsExists: existsSync31(jsIndexPath),
9764
+ jsExists: existsSync32(jsIndexPath),
9499
9765
  tsIndexPath,
9500
- tsExists: existsSync31(tsIndexPath)
9766
+ tsExists: existsSync32(tsIndexPath)
9501
9767
  });
9502
9768
  let indexPath = null;
9503
- if (existsSync31(builtIndexPath)) {
9769
+ if (existsSync32(builtIndexPath)) {
9504
9770
  indexPath = builtIndexPath;
9505
- } else if (existsSync31(jsIndexPath)) {
9771
+ } else if (existsSync32(jsIndexPath)) {
9506
9772
  indexPath = jsIndexPath;
9507
- } else if (existsSync31(tsIndexPath)) {
9773
+ } else if (existsSync32(tsIndexPath)) {
9508
9774
  indexPath = tsIndexPath;
9509
9775
  }
9510
9776
  if (!indexPath) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omnidev-ai/cli",
3
- "version": "0.18.0",
3
+ "version": "0.18.1",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "imports": {