agent-conf 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -67,10 +67,6 @@ var LockfileSchema = z.object({
67
67
  // src/core/lockfile.ts
68
68
  var CONFIG_DIR = ".agent-conf";
69
69
  var LOCKFILE_NAME = "lockfile.json";
70
- var CLI_VERSION = "0.1.0";
71
- function getBuildCommit() {
72
- return true ? "495cb19c3410dc3d585d83d93279944ff665eb9e" : "unknown";
73
- }
74
70
  function getLockfilePath(targetDir) {
75
71
  return path.join(targetDir, CONFIG_DIR, LOCKFILE_NAME);
76
72
  }
@@ -103,7 +99,7 @@ async function writeLockfile(targetDir, options) {
103
99
  targets: options.targets ?? ["claude"],
104
100
  marker_prefix: options.markerPrefix
105
101
  },
106
- cli_version: CLI_VERSION
102
+ cli_version: getCliVersion()
107
103
  };
108
104
  await fs.mkdir(path.dirname(lockfilePath), { recursive: true });
109
105
  await fs.writeFile(lockfilePath, `${JSON.stringify(lockfile, null, 2)}
@@ -115,28 +111,30 @@ function hashContent(content) {
115
111
  return `sha256:${hash.slice(0, 12)}`;
116
112
  }
117
113
  function getCliVersion() {
118
- return CLI_VERSION;
114
+ return true ? "2.2.0" : "0.0.0";
119
115
  }
120
116
  async function checkCliVersionMismatch(targetDir) {
121
117
  const lockfile = await readLockfile(targetDir);
122
118
  if (!lockfile) {
123
119
  return null;
124
120
  }
125
- if (lockfile.source.type !== "github") {
126
- return null;
127
- }
128
- const cliCommit = getBuildCommit();
129
- const lockfileCommit = lockfile.source.commit_sha;
130
- if (cliCommit === "unknown") {
121
+ const currentVersion = getCliVersion();
122
+ const lockfileVersion = lockfile.cli_version;
123
+ if (!currentVersion || !lockfileVersion) {
131
124
  return null;
132
125
  }
133
- const cliShort = cliCommit.slice(0, 7);
134
- const lockfileShort = lockfileCommit.slice(0, 7);
135
- if (cliShort !== lockfileShort) {
136
- return {
137
- cliCommit: cliShort,
138
- lockfileCommit: lockfileShort
139
- };
126
+ const current = currentVersion.split(".").map(Number);
127
+ const lockfile_ = lockfileVersion.split(".").map(Number);
128
+ for (let i = 0; i < 3; i++) {
129
+ if ((lockfile_[i] || 0) > (current[i] || 0)) {
130
+ return {
131
+ currentVersion,
132
+ lockfileVersion
133
+ };
134
+ }
135
+ if ((current[i] || 0) > (lockfile_[i] || 0)) {
136
+ return null;
137
+ }
140
138
  }
141
139
  return null;
142
140
  }
@@ -897,6 +895,7 @@ async function deleteOrphanedSkills(targetDir, orphanedSkills, targets, previous
897
895
  }
898
896
 
899
897
  // src/commands/shared.ts
898
+ import * as fs12 from "fs/promises";
900
899
  import * as path12 from "path";
901
900
  import * as prompts3 from "@clack/prompts";
902
901
  import pc5 from "picocolors";
@@ -1661,8 +1660,7 @@ async function resolveVersion(options, status, _commandName, repo) {
1661
1660
  releaseInfo: release
1662
1661
  };
1663
1662
  } catch {
1664
- spinner.fail("Failed to fetch latest release, falling back to master");
1665
- logger.warn("Could not fetch latest release. Using master branch instead.");
1663
+ spinner.info("No releases found, using master branch");
1666
1664
  return {
1667
1665
  ref: "master",
1668
1666
  version: void 0,
@@ -1850,6 +1848,7 @@ async function performSync(options) {
1850
1848
  workflowSpinner.stop();
1851
1849
  }
1852
1850
  const hookResult = await installPreCommitHook(targetDir);
1851
+ const summaryLines = [];
1853
1852
  console.log();
1854
1853
  console.log(pc5.bold("Sync complete:"));
1855
1854
  console.log();
@@ -1857,38 +1856,71 @@ async function performSync(options) {
1857
1856
  if (result.agentsMd.merged) {
1858
1857
  const label = context.commandName === "sync" ? "(updated)" : "(merged)";
1859
1858
  console.log(` ${pc5.green("+")} ${agentsMdPath} ${pc5.dim(label)}`);
1859
+ summaryLines.push(`- \`AGENTS.md\` ${label}`);
1860
1860
  } else {
1861
1861
  console.log(` ${pc5.green("+")} ${agentsMdPath} ${pc5.dim("(created)")}`);
1862
+ summaryLines.push("- `AGENTS.md` (created)");
1862
1863
  }
1863
1864
  for (const targetResult of result.targets) {
1864
1865
  const config = getTargetConfig(targetResult.target);
1865
1866
  if (config.instructionsFile) {
1866
1867
  const instructionsPath = targetResult.instructionsMd.location === "root" ? formatPath(path12.join(targetDir, config.instructionsFile)) : formatPath(path12.join(targetDir, config.dir, config.instructionsFile));
1868
+ const instructionsRelPath = targetResult.instructionsMd.location === "root" ? config.instructionsFile : `${config.dir}/${config.instructionsFile}`;
1867
1869
  if (targetResult.instructionsMd.created) {
1868
1870
  console.log(` ${pc5.green("+")} ${instructionsPath} ${pc5.dim("(created)")}`);
1871
+ summaryLines.push(`- \`${instructionsRelPath}\` (created)`);
1869
1872
  } else if (targetResult.instructionsMd.updated) {
1870
1873
  const hint = targetResult.instructionsMd.contentMerged ? "(content merged into AGENTS.md, reference added)" : "(reference added)";
1871
1874
  console.log(` ${pc5.yellow("~")} ${instructionsPath} ${pc5.dim(hint)}`);
1875
+ summaryLines.push(`- \`${instructionsRelPath}\` ${hint}`);
1872
1876
  } else {
1873
1877
  console.log(` ${pc5.dim("-")} ${instructionsPath} ${pc5.dim("(unchanged)")}`);
1878
+ summaryLines.push(`- \`${instructionsRelPath}\` (unchanged)`);
1874
1879
  }
1875
1880
  }
1876
1881
  const skillsPath = formatPath(path12.join(targetDir, config.dir, "skills"));
1882
+ const skillsRelPath = `${config.dir}/skills/`;
1883
+ const newSkills = result.skills.synced.filter((s) => !previousSkills.includes(s)).sort();
1884
+ const updatedSkills = result.skills.synced.filter((s) => previousSkills.includes(s)).sort();
1885
+ const removedSkills = orphanResult.deleted.sort();
1877
1886
  console.log(
1878
1887
  ` ${pc5.green("+")} ${skillsPath}/ ${pc5.dim(`(${result.skills.synced.length} skills, ${targetResult.skills.copied} files)`)}`
1879
1888
  );
1880
- if (orphanResult.deleted.length > 0) {
1881
- for (const skill of orphanResult.deleted) {
1882
- const orphanPath = formatPath(path12.join(targetDir, config.dir, "skills", skill));
1883
- console.log(
1884
- ` ${pc5.red("-")} ${orphanPath}/ ${pc5.dim("(removed - no longer in source)")}`
1885
- );
1889
+ summaryLines.push(
1890
+ `- \`${skillsRelPath}\` (${result.skills.synced.length} skills, ${targetResult.skills.copied} files)`
1891
+ );
1892
+ const MAX_ITEMS_DEFAULT = 5;
1893
+ const shouldExpand = options.expandChanges === true;
1894
+ const formatSkillList = (skills, icon, colorFn, label, mdLabel) => {
1895
+ if (skills.length === 0) return;
1896
+ const maxDisplay = shouldExpand ? skills.length : MAX_ITEMS_DEFAULT;
1897
+ const displaySkills = skills.slice(0, maxDisplay);
1898
+ const hiddenCount = skills.length - displaySkills.length;
1899
+ for (const skill of displaySkills) {
1900
+ const skillPath = formatPath(path12.join(targetDir, config.dir, "skills", skill));
1901
+ const skillRelPath = `${config.dir}/skills/${skill}/`;
1902
+ console.log(` ${colorFn(icon)} ${skillPath}/ ${pc5.dim(`(${label})`)}`);
1903
+ summaryLines.push(` - \`${skillRelPath}\` (${mdLabel})`);
1886
1904
  }
1905
+ if (hiddenCount > 0) {
1906
+ console.log(` ${pc5.dim(` ... ${hiddenCount} more ${label}`)}`);
1907
+ summaryLines.push(` - ... ${hiddenCount} more ${mdLabel}`);
1908
+ }
1909
+ };
1910
+ formatSkillList(newSkills, "+", pc5.green, "new", "new");
1911
+ formatSkillList(updatedSkills, "~", pc5.yellow, "updated", "updated");
1912
+ for (const skill of removedSkills) {
1913
+ const orphanPath = formatPath(path12.join(targetDir, config.dir, "skills", skill));
1914
+ const orphanRelPath = `${config.dir}/skills/${skill}/`;
1915
+ console.log(` ${pc5.red("-")} ${orphanPath}/ ${pc5.dim("(removed)")}`);
1916
+ summaryLines.push(` - \`${orphanRelPath}\` (removed)`);
1887
1917
  }
1888
1918
  if (orphanResult.skipped.length > 0) {
1889
1919
  for (const skill of orphanResult.skipped) {
1890
1920
  const orphanPath = formatPath(path12.join(targetDir, config.dir, "skills", skill));
1891
- console.log(` ${pc5.yellow("!")} ${orphanPath}/ ${pc5.dim("(orphaned but skipped)")}`);
1921
+ const orphanRelPath = `${config.dir}/skills/${skill}/`;
1922
+ console.log(` ${pc5.yellow("!")} ${orphanPath}/ ${pc5.dim("(orphaned but skipped)")}`);
1923
+ summaryLines.push(` - \`${orphanRelPath}\` (orphaned but skipped)`);
1892
1924
  }
1893
1925
  }
1894
1926
  }
@@ -1896,29 +1928,37 @@ async function performSync(options) {
1896
1928
  for (const filename of workflowResult.created) {
1897
1929
  const workflowPath = formatPath(path12.join(targetDir, ".github/workflows", filename));
1898
1930
  console.log(` ${pc5.green("+")} ${workflowPath} ${pc5.dim("(created)")}`);
1931
+ summaryLines.push(`- \`.github/workflows/${filename}\` (created)`);
1899
1932
  }
1900
1933
  for (const filename of workflowResult.updated) {
1901
1934
  const workflowPath = formatPath(path12.join(targetDir, ".github/workflows", filename));
1902
1935
  console.log(` ${pc5.yellow("~")} ${workflowPath} ${pc5.dim("(updated)")}`);
1936
+ summaryLines.push(`- \`.github/workflows/${filename}\` (updated)`);
1903
1937
  }
1904
1938
  for (const filename of workflowResult.unchanged) {
1905
1939
  const workflowPath = formatPath(path12.join(targetDir, ".github/workflows", filename));
1906
1940
  console.log(` ${pc5.dim("-")} ${workflowPath} ${pc5.dim("(unchanged)")}`);
1941
+ summaryLines.push(`- \`.github/workflows/${filename}\` (unchanged)`);
1907
1942
  }
1908
1943
  }
1909
1944
  const lockfilePath = formatPath(path12.join(targetDir, ".agent-conf", "agent-conf.lock"));
1910
1945
  console.log(` ${pc5.green("+")} ${lockfilePath}`);
1946
+ summaryLines.push("- `.agent-conf/lockfile.json` (updated)");
1911
1947
  const hookPath = formatPath(path12.join(targetDir, ".git/hooks/pre-commit"));
1912
1948
  if (hookResult.installed) {
1913
1949
  if (hookResult.alreadyExisted && !hookResult.wasUpdated) {
1914
1950
  console.log(` ${pc5.dim("-")} ${hookPath} ${pc5.dim("(unchanged)")}`);
1951
+ summaryLines.push("- `.git/hooks/pre-commit` (unchanged)");
1915
1952
  } else if (hookResult.wasUpdated) {
1916
1953
  console.log(` ${pc5.yellow("~")} ${hookPath} ${pc5.dim("(updated)")}`);
1954
+ summaryLines.push("- `.git/hooks/pre-commit` (updated)");
1917
1955
  } else {
1918
1956
  console.log(` ${pc5.green("+")} ${hookPath} ${pc5.dim("(installed)")}`);
1957
+ summaryLines.push("- `.git/hooks/pre-commit` (installed)");
1919
1958
  }
1920
1959
  } else if (hookResult.alreadyExisted) {
1921
1960
  console.log(` ${pc5.yellow("!")} ${hookPath} ${pc5.dim("(skipped - custom hook exists)")}`);
1961
+ summaryLines.push("- `.git/hooks/pre-commit` (skipped - custom hook exists)");
1922
1962
  }
1923
1963
  console.log();
1924
1964
  console.log(pc5.dim(`Source: ${formatSourceString(resolvedSource.source)}`));
@@ -1928,6 +1968,19 @@ async function performSync(options) {
1928
1968
  if (targets.length > 1) {
1929
1969
  console.log(pc5.dim(`Targets: ${targets.join(", ")}`));
1930
1970
  }
1971
+ if (options.summaryFile) {
1972
+ const sourceStr = formatSourceString(resolvedSource.source);
1973
+ const versionStr = resolvedVersion.version ? `v${resolvedVersion.version}` : resolvedVersion.ref;
1974
+ const summary = `## Changes
1975
+
1976
+ ${summaryLines.join("\n")}
1977
+
1978
+ ---
1979
+ **Source:** ${sourceStr}
1980
+ **Version:** ${versionStr}
1981
+ `;
1982
+ await fs12.writeFile(options.summaryFile, summary, "utf-8");
1983
+ }
1931
1984
  prompts3.outro(pc5.green("Done!"));
1932
1985
  } catch (error) {
1933
1986
  syncSpinner.fail("Sync failed");
@@ -1978,7 +2031,7 @@ async function initCommand(options) {
1978
2031
  }
1979
2032
 
1980
2033
  // src/commands/init-canonical-repo.ts
1981
- import * as fs12 from "fs/promises";
2034
+ import * as fs13 from "fs/promises";
1982
2035
  import * as path13 from "path";
1983
2036
  import * as prompts5 from "@clack/prompts";
1984
2037
  import pc7 from "picocolors";
@@ -2161,7 +2214,7 @@ jobs:
2161
2214
  run: npm install -g agent-conf
2162
2215
 
2163
2216
  - name: Run sync
2164
- run: agent-conf sync --yes
2217
+ run: agent-conf sync --yes --summary-file /tmp/sync-summary.md --expand-changes
2165
2218
  env:
2166
2219
  GITHUB_TOKEN: \${{ secrets.token }}
2167
2220
 
@@ -2205,10 +2258,17 @@ jobs:
2205
2258
  env:
2206
2259
  GH_TOKEN: \${{ github.token }}
2207
2260
  run: |
2261
+ # Read sync summary if available
2262
+ if [ -f /tmp/sync-summary.md ]; then
2263
+ SYNC_SUMMARY=$(cat /tmp/sync-summary.md)
2264
+ else
2265
+ SYNC_SUMMARY="## Changes
2266
+ - Synced agent configuration from canonical repository"
2267
+ fi
2268
+
2208
2269
  PR_BODY="This PR was automatically created by the ${prefix} sync workflow.
2209
2270
 
2210
- ## Changes
2211
- - Synced agent configuration from canonical repository
2271
+ $SYNC_SUMMARY
2212
2272
 
2213
2273
  ---
2214
2274
  *This is an automated PR. Review the changes and merge when ready.*"
@@ -2398,27 +2458,27 @@ async function initCanonicalRepoCommand(options) {
2398
2458
  await ensureDir(skillsDir);
2399
2459
  await ensureDir(workflowsDir);
2400
2460
  const configPath = path13.join(resolvedOptions.targetDir, "agent-conf.yaml");
2401
- await fs12.writeFile(configPath, generateConfigYaml(resolvedOptions), "utf-8");
2461
+ await fs13.writeFile(configPath, generateConfigYaml(resolvedOptions), "utf-8");
2402
2462
  const agentsMdPath = path13.join(instructionsDir, "AGENTS.md");
2403
- await fs12.writeFile(agentsMdPath, generateAgentsMd(resolvedOptions), "utf-8");
2463
+ await fs13.writeFile(agentsMdPath, generateAgentsMd(resolvedOptions), "utf-8");
2404
2464
  if (resolvedOptions.includeExamples) {
2405
2465
  const exampleSkillDir = path13.join(skillsDir, "example-skill");
2406
2466
  const referencesDir = path13.join(exampleSkillDir, "references");
2407
2467
  await ensureDir(referencesDir);
2408
2468
  const skillMdPath = path13.join(exampleSkillDir, "SKILL.md");
2409
- await fs12.writeFile(skillMdPath, generateExampleSkillMd(), "utf-8");
2469
+ await fs13.writeFile(skillMdPath, generateExampleSkillMd(), "utf-8");
2410
2470
  const gitkeepPath = path13.join(referencesDir, ".gitkeep");
2411
- await fs12.writeFile(gitkeepPath, "", "utf-8");
2471
+ await fs13.writeFile(gitkeepPath, "", "utf-8");
2412
2472
  }
2413
2473
  const syncWorkflowPath = path13.join(workflowsDir, "sync-reusable.yml");
2414
2474
  const checkWorkflowPath = path13.join(workflowsDir, "check-reusable.yml");
2415
2475
  const repoFullName = resolvedOptions.organization ? `${resolvedOptions.organization}/${resolvedOptions.name}` : resolvedOptions.name;
2416
- await fs12.writeFile(
2476
+ await fs13.writeFile(
2417
2477
  syncWorkflowPath,
2418
2478
  generateSyncWorkflow2(repoFullName, resolvedOptions.markerPrefix),
2419
2479
  "utf-8"
2420
2480
  );
2421
- await fs12.writeFile(
2481
+ await fs13.writeFile(
2422
2482
  checkWorkflowPath,
2423
2483
  generateCheckWorkflow2(repoFullName, resolvedOptions.markerPrefix),
2424
2484
  "utf-8"
@@ -2603,7 +2663,9 @@ async function syncCommand(options) {
2603
2663
  },
2604
2664
  tempDir,
2605
2665
  yes: options.yes,
2606
- sourceRepo: repository
2666
+ sourceRepo: repository,
2667
+ summaryFile: options.summaryFile,
2668
+ expandChanges: options.expandChanges
2607
2669
  });
2608
2670
  }
2609
2671
 
@@ -2690,14 +2752,10 @@ async function warnIfCliOutdated() {
2690
2752
  console.log();
2691
2753
  console.log(
2692
2754
  pc11.yellow(
2693
- `\u26A0 CLI is outdated: built from ${mismatch.cliCommit}, but repo was synced from ${mismatch.lockfileCommit}`
2694
- )
2695
- );
2696
- console.log(
2697
- pc11.yellow(
2698
- " Rebuild the CLI: cd <agent-conf-repo>/cli && pnpm build && pnpm link --global"
2755
+ `\u26A0 CLI is outdated: v${mismatch.currentVersion} installed, but repo was synced with v${mismatch.lockfileVersion}`
2699
2756
  )
2700
2757
  );
2758
+ console.log(pc11.yellow(" Run: agent-conf upgrade-cli"));
2701
2759
  console.log();
2702
2760
  }
2703
2761
  } catch {
@@ -2719,7 +2777,7 @@ function createCli() {
2719
2777
  program.command("sync").description("Sync content from canonical repository (fetches latest by default)").option(
2720
2778
  "-s, --source <repo>",
2721
2779
  "Canonical repository in owner/repo format (e.g., acme/standards)"
2722
- ).option("--local [path]", "Use local canonical repository (auto-discover or specify path)").option("-y, --yes", "Non-interactive mode (merge by default)").option("--override", "Override existing AGENTS.md instead of merging").option("--ref <ref>", "GitHub ref/version to sync from").option("--pinned", "Use lockfile version without fetching latest").option("-t, --target <targets...>", "Target platforms (claude, codex)", ["claude"]).action(
2780
+ ).option("--local [path]", "Use local canonical repository (auto-discover or specify path)").option("-y, --yes", "Non-interactive mode (merge by default)").option("--override", "Override existing AGENTS.md instead of merging").option("--ref <ref>", "GitHub ref/version to sync from").option("--pinned", "Use lockfile version without fetching latest").option("-t, --target <targets...>", "Target platforms (claude, codex)", ["claude"]).option("--summary-file <path>", "Write sync summary to file (markdown, for CI)").option("--expand-changes", "Show all items in output (default: first 5)").action(
2723
2781
  async (options) => {
2724
2782
  await syncCommand(options);
2725
2783
  }