@tolkbot/cli 0.8.0 → 0.9.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 +233 -75
  2. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -105,7 +105,7 @@ var require_path = __commonJS({
105
105
  Object.defineProperty(exports, "__esModule", { value: true });
106
106
  exports.convertPosixPathToPattern = exports.convertWindowsPathToPattern = exports.convertPathToPattern = exports.escapePosixPath = exports.escapeWindowsPath = exports.escape = exports.removeLeadingDotSegment = exports.makeAbsolute = exports.unixify = void 0;
107
107
  var os3 = __require("os");
108
- var path11 = __require("path");
108
+ var path12 = __require("path");
109
109
  var IS_WINDOWS_PLATFORM = os3.platform() === "win32";
110
110
  var LEADING_DOT_SEGMENT_CHARACTERS_COUNT = 2;
111
111
  var POSIX_UNESCAPED_GLOB_SYMBOLS_RE = /(\\?)([()*?[\]{|}]|^!|[!+@](?=\()|\\(?![!()*+?@[\]{|}]))/g;
@@ -117,7 +117,7 @@ var require_path = __commonJS({
117
117
  }
118
118
  exports.unixify = unixify;
119
119
  function makeAbsolute(cwd, filepath) {
120
- return path11.resolve(cwd, filepath);
120
+ return path12.resolve(cwd, filepath);
121
121
  }
122
122
  exports.makeAbsolute = makeAbsolute;
123
123
  function removeLeadingDotSegment(entry) {
@@ -1416,7 +1416,7 @@ var require_braces = __commonJS({
1416
1416
  var require_constants2 = __commonJS({
1417
1417
  "../../node_modules/.pnpm/picomatch@2.3.2/node_modules/picomatch/lib/constants.js"(exports, module) {
1418
1418
  "use strict";
1419
- var path11 = __require("path");
1419
+ var path12 = __require("path");
1420
1420
  var WIN_SLASH = "\\\\/";
1421
1421
  var WIN_NO_SLASH = `[^${WIN_SLASH}]`;
1422
1422
  var DEFAULT_MAX_EXTGLOB_RECURSION = 0;
@@ -1590,7 +1590,7 @@ var require_constants2 = __commonJS({
1590
1590
  /* | */
1591
1591
  CHAR_ZERO_WIDTH_NOBREAK_SPACE: 65279,
1592
1592
  /* \uFEFF */
1593
- SEP: path11.sep,
1593
+ SEP: path12.sep,
1594
1594
  /**
1595
1595
  * Create EXTGLOB_CHARS
1596
1596
  */
@@ -1617,7 +1617,7 @@ var require_constants2 = __commonJS({
1617
1617
  var require_utils2 = __commonJS({
1618
1618
  "../../node_modules/.pnpm/picomatch@2.3.2/node_modules/picomatch/lib/utils.js"(exports) {
1619
1619
  "use strict";
1620
- var path11 = __require("path");
1620
+ var path12 = __require("path");
1621
1621
  var win32 = process.platform === "win32";
1622
1622
  var {
1623
1623
  REGEX_BACKSLASH,
@@ -1646,7 +1646,7 @@ var require_utils2 = __commonJS({
1646
1646
  if (options && typeof options.windows === "boolean") {
1647
1647
  return options.windows;
1648
1648
  }
1649
- return win32 === true || path11.sep === "\\";
1649
+ return win32 === true || path12.sep === "\\";
1650
1650
  };
1651
1651
  exports.escapeLast = (input2, char, lastIdx) => {
1652
1652
  const idx = input2.lastIndexOf(char, lastIdx);
@@ -3010,7 +3010,7 @@ var require_parse2 = __commonJS({
3010
3010
  var require_picomatch = __commonJS({
3011
3011
  "../../node_modules/.pnpm/picomatch@2.3.2/node_modules/picomatch/lib/picomatch.js"(exports, module) {
3012
3012
  "use strict";
3013
- var path11 = __require("path");
3013
+ var path12 = __require("path");
3014
3014
  var scan = require_scan();
3015
3015
  var parse4 = require_parse2();
3016
3016
  var utils = require_utils2();
@@ -3095,7 +3095,7 @@ var require_picomatch = __commonJS({
3095
3095
  };
3096
3096
  picomatch.matchBase = (input2, glob, options, posix = utils.isWindows(options)) => {
3097
3097
  const regex = glob instanceof RegExp ? glob : picomatch.makeRe(glob, options);
3098
- return regex.test(path11.basename(input2));
3098
+ return regex.test(path12.basename(input2));
3099
3099
  };
3100
3100
  picomatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str);
3101
3101
  picomatch.parse = (pattern, options) => {
@@ -3322,7 +3322,7 @@ var require_pattern = __commonJS({
3322
3322
  "use strict";
3323
3323
  Object.defineProperty(exports, "__esModule", { value: true });
3324
3324
  exports.isAbsolute = exports.partitionAbsoluteAndRelative = exports.removeDuplicateSlashes = exports.matchAny = exports.convertPatternsToRe = exports.makeRe = exports.getPatternParts = exports.expandBraceExpansion = exports.expandPatternsWithBraceExpansion = exports.isAffectDepthOfReadingPattern = exports.endsWithSlashGlobStar = exports.hasGlobStar = exports.getBaseDirectory = exports.isPatternRelatedToParentDirectory = exports.getPatternsOutsideCurrentDirectory = exports.getPatternsInsideCurrentDirectory = exports.getPositivePatterns = exports.getNegativePatterns = exports.isPositivePattern = exports.isNegativePattern = exports.convertToNegativePattern = exports.convertToPositivePattern = exports.isDynamicPattern = exports.isStaticPattern = void 0;
3325
- var path11 = __require("path");
3325
+ var path12 = __require("path");
3326
3326
  var globParent = require_glob_parent();
3327
3327
  var micromatch = require_micromatch();
3328
3328
  var GLOBSTAR = "**";
@@ -3417,7 +3417,7 @@ var require_pattern = __commonJS({
3417
3417
  }
3418
3418
  exports.endsWithSlashGlobStar = endsWithSlashGlobStar;
3419
3419
  function isAffectDepthOfReadingPattern(pattern) {
3420
- const basename = path11.basename(pattern);
3420
+ const basename = path12.basename(pattern);
3421
3421
  return endsWithSlashGlobStar(pattern) || isStaticPattern(basename);
3422
3422
  }
3423
3423
  exports.isAffectDepthOfReadingPattern = isAffectDepthOfReadingPattern;
@@ -3475,7 +3475,7 @@ var require_pattern = __commonJS({
3475
3475
  }
3476
3476
  exports.partitionAbsoluteAndRelative = partitionAbsoluteAndRelative;
3477
3477
  function isAbsolute(pattern) {
3478
- return path11.isAbsolute(pattern);
3478
+ return path12.isAbsolute(pattern);
3479
3479
  }
3480
3480
  exports.isAbsolute = isAbsolute;
3481
3481
  }
@@ -3652,8 +3652,8 @@ var require_utils3 = __commonJS({
3652
3652
  exports.errno = errno;
3653
3653
  var fs10 = require_fs();
3654
3654
  exports.fs = fs10;
3655
- var path11 = require_path();
3656
- exports.path = path11;
3655
+ var path12 = require_path();
3656
+ exports.path = path12;
3657
3657
  var pattern = require_pattern();
3658
3658
  exports.pattern = pattern;
3659
3659
  var stream = require_stream();
@@ -3765,8 +3765,8 @@ var require_async = __commonJS({
3765
3765
  "use strict";
3766
3766
  Object.defineProperty(exports, "__esModule", { value: true });
3767
3767
  exports.read = void 0;
3768
- function read(path11, settings, callback) {
3769
- settings.fs.lstat(path11, (lstatError, lstat) => {
3768
+ function read(path12, settings, callback) {
3769
+ settings.fs.lstat(path12, (lstatError, lstat) => {
3770
3770
  if (lstatError !== null) {
3771
3771
  callFailureCallback(callback, lstatError);
3772
3772
  return;
@@ -3775,7 +3775,7 @@ var require_async = __commonJS({
3775
3775
  callSuccessCallback(callback, lstat);
3776
3776
  return;
3777
3777
  }
3778
- settings.fs.stat(path11, (statError, stat) => {
3778
+ settings.fs.stat(path12, (statError, stat) => {
3779
3779
  if (statError !== null) {
3780
3780
  if (settings.throwErrorOnBrokenSymbolicLink) {
3781
3781
  callFailureCallback(callback, statError);
@@ -3807,13 +3807,13 @@ var require_sync = __commonJS({
3807
3807
  "use strict";
3808
3808
  Object.defineProperty(exports, "__esModule", { value: true });
3809
3809
  exports.read = void 0;
3810
- function read(path11, settings) {
3811
- const lstat = settings.fs.lstatSync(path11);
3810
+ function read(path12, settings) {
3811
+ const lstat = settings.fs.lstatSync(path12);
3812
3812
  if (!lstat.isSymbolicLink() || !settings.followSymbolicLink) {
3813
3813
  return lstat;
3814
3814
  }
3815
3815
  try {
3816
- const stat = settings.fs.statSync(path11);
3816
+ const stat = settings.fs.statSync(path12);
3817
3817
  if (settings.markSymbolicLink) {
3818
3818
  stat.isSymbolicLink = () => true;
3819
3819
  }
@@ -3884,17 +3884,17 @@ var require_out = __commonJS({
3884
3884
  var sync = require_sync();
3885
3885
  var settings_1 = require_settings();
3886
3886
  exports.Settings = settings_1.default;
3887
- function stat(path11, optionsOrSettingsOrCallback, callback) {
3887
+ function stat(path12, optionsOrSettingsOrCallback, callback) {
3888
3888
  if (typeof optionsOrSettingsOrCallback === "function") {
3889
- async.read(path11, getSettings(), optionsOrSettingsOrCallback);
3889
+ async.read(path12, getSettings(), optionsOrSettingsOrCallback);
3890
3890
  return;
3891
3891
  }
3892
- async.read(path11, getSettings(optionsOrSettingsOrCallback), callback);
3892
+ async.read(path12, getSettings(optionsOrSettingsOrCallback), callback);
3893
3893
  }
3894
3894
  exports.stat = stat;
3895
- function statSync2(path11, optionsOrSettings) {
3895
+ function statSync2(path12, optionsOrSettings) {
3896
3896
  const settings = getSettings(optionsOrSettings);
3897
- return sync.read(path11, settings);
3897
+ return sync.read(path12, settings);
3898
3898
  }
3899
3899
  exports.statSync = statSync2;
3900
3900
  function getSettings(settingsOrOptions = {}) {
@@ -4112,16 +4112,16 @@ var require_async2 = __commonJS({
4112
4112
  return;
4113
4113
  }
4114
4114
  const tasks = names.map((name) => {
4115
- const path11 = common.joinPathSegments(directory, name, settings.pathSegmentSeparator);
4115
+ const path12 = common.joinPathSegments(directory, name, settings.pathSegmentSeparator);
4116
4116
  return (done) => {
4117
- fsStat.stat(path11, settings.fsStatSettings, (error62, stats) => {
4117
+ fsStat.stat(path12, settings.fsStatSettings, (error62, stats) => {
4118
4118
  if (error62 !== null) {
4119
4119
  done(error62);
4120
4120
  return;
4121
4121
  }
4122
4122
  const entry = {
4123
4123
  name,
4124
- path: path11,
4124
+ path: path12,
4125
4125
  dirent: utils.fs.createDirentFromStats(name, stats)
4126
4126
  };
4127
4127
  if (settings.stats) {
@@ -4239,7 +4239,7 @@ var require_settings2 = __commonJS({
4239
4239
  "../../node_modules/.pnpm/@nodelib+fs.scandir@2.1.5/node_modules/@nodelib/fs.scandir/out/settings.js"(exports) {
4240
4240
  "use strict";
4241
4241
  Object.defineProperty(exports, "__esModule", { value: true });
4242
- var path11 = __require("path");
4242
+ var path12 = __require("path");
4243
4243
  var fsStat = require_out();
4244
4244
  var fs10 = require_fs4();
4245
4245
  var Settings = class {
@@ -4247,7 +4247,7 @@ var require_settings2 = __commonJS({
4247
4247
  this._options = _options;
4248
4248
  this.followSymbolicLinks = this._getValue(this._options.followSymbolicLinks, false);
4249
4249
  this.fs = fs10.createFileSystemAdapter(this._options.fs);
4250
- this.pathSegmentSeparator = this._getValue(this._options.pathSegmentSeparator, path11.sep);
4250
+ this.pathSegmentSeparator = this._getValue(this._options.pathSegmentSeparator, path12.sep);
4251
4251
  this.stats = this._getValue(this._options.stats, false);
4252
4252
  this.throwErrorOnBrokenSymbolicLink = this._getValue(this._options.throwErrorOnBrokenSymbolicLink, true);
4253
4253
  this.fsStatSettings = new fsStat.Settings({
@@ -4274,17 +4274,17 @@ var require_out2 = __commonJS({
4274
4274
  var sync = require_sync2();
4275
4275
  var settings_1 = require_settings2();
4276
4276
  exports.Settings = settings_1.default;
4277
- function scandir(path11, optionsOrSettingsOrCallback, callback) {
4277
+ function scandir(path12, optionsOrSettingsOrCallback, callback) {
4278
4278
  if (typeof optionsOrSettingsOrCallback === "function") {
4279
- async.read(path11, getSettings(), optionsOrSettingsOrCallback);
4279
+ async.read(path12, getSettings(), optionsOrSettingsOrCallback);
4280
4280
  return;
4281
4281
  }
4282
- async.read(path11, getSettings(optionsOrSettingsOrCallback), callback);
4282
+ async.read(path12, getSettings(optionsOrSettingsOrCallback), callback);
4283
4283
  }
4284
4284
  exports.scandir = scandir;
4285
- function scandirSync(path11, optionsOrSettings) {
4285
+ function scandirSync(path12, optionsOrSettings) {
4286
4286
  const settings = getSettings(optionsOrSettings);
4287
- return sync.read(path11, settings);
4287
+ return sync.read(path12, settings);
4288
4288
  }
4289
4289
  exports.scandirSync = scandirSync;
4290
4290
  function getSettings(settingsOrOptions = {}) {
@@ -4932,7 +4932,7 @@ var require_settings3 = __commonJS({
4932
4932
  "../../node_modules/.pnpm/@nodelib+fs.walk@1.2.8/node_modules/@nodelib/fs.walk/out/settings.js"(exports) {
4933
4933
  "use strict";
4934
4934
  Object.defineProperty(exports, "__esModule", { value: true });
4935
- var path11 = __require("path");
4935
+ var path12 = __require("path");
4936
4936
  var fsScandir = require_out2();
4937
4937
  var Settings = class {
4938
4938
  constructor(_options = {}) {
@@ -4942,7 +4942,7 @@ var require_settings3 = __commonJS({
4942
4942
  this.deepFilter = this._getValue(this._options.deepFilter, null);
4943
4943
  this.entryFilter = this._getValue(this._options.entryFilter, null);
4944
4944
  this.errorFilter = this._getValue(this._options.errorFilter, null);
4945
- this.pathSegmentSeparator = this._getValue(this._options.pathSegmentSeparator, path11.sep);
4945
+ this.pathSegmentSeparator = this._getValue(this._options.pathSegmentSeparator, path12.sep);
4946
4946
  this.fsScandirSettings = new fsScandir.Settings({
4947
4947
  followSymbolicLinks: this._options.followSymbolicLinks,
4948
4948
  fs: this._options.fs,
@@ -5004,7 +5004,7 @@ var require_reader2 = __commonJS({
5004
5004
  "../../node_modules/.pnpm/fast-glob@3.3.3/node_modules/fast-glob/out/readers/reader.js"(exports) {
5005
5005
  "use strict";
5006
5006
  Object.defineProperty(exports, "__esModule", { value: true });
5007
- var path11 = __require("path");
5007
+ var path12 = __require("path");
5008
5008
  var fsStat = require_out();
5009
5009
  var utils = require_utils3();
5010
5010
  var Reader = class {
@@ -5017,7 +5017,7 @@ var require_reader2 = __commonJS({
5017
5017
  });
5018
5018
  }
5019
5019
  _getFullEntryPath(filepath) {
5020
- return path11.resolve(this._settings.cwd, filepath);
5020
+ return path12.resolve(this._settings.cwd, filepath);
5021
5021
  }
5022
5022
  _makeEntry(stats, pattern) {
5023
5023
  const entry = {
@@ -5433,7 +5433,7 @@ var require_provider = __commonJS({
5433
5433
  "../../node_modules/.pnpm/fast-glob@3.3.3/node_modules/fast-glob/out/providers/provider.js"(exports) {
5434
5434
  "use strict";
5435
5435
  Object.defineProperty(exports, "__esModule", { value: true });
5436
- var path11 = __require("path");
5436
+ var path12 = __require("path");
5437
5437
  var deep_1 = require_deep();
5438
5438
  var entry_1 = require_entry();
5439
5439
  var error_1 = require_error();
@@ -5447,7 +5447,7 @@ var require_provider = __commonJS({
5447
5447
  this.entryTransformer = new entry_2.default(this._settings);
5448
5448
  }
5449
5449
  _getRootDirectory(task) {
5450
- return path11.resolve(this._settings.cwd, task.base);
5450
+ return path12.resolve(this._settings.cwd, task.base);
5451
5451
  }
5452
5452
  _getReaderOptions(task) {
5453
5453
  const basePath = task.base === "." ? "" : task.base;
@@ -5787,7 +5787,7 @@ var require_out4 = __commonJS({
5787
5787
  import { Command as Command10, CommanderError, Option as Option2 } from "commander";
5788
5788
 
5789
5789
  // package.json
5790
- var version = "0.8.0";
5790
+ var version = "0.9.0";
5791
5791
 
5792
5792
  // src/commands/auth/index.ts
5793
5793
  import { Command } from "commander";
@@ -29199,8 +29199,8 @@ glossaryCommand.command("remove").description("Remove a glossary term").argument
29199
29199
  });
29200
29200
 
29201
29201
  // src/commands/init/index.tsx
29202
- import { existsSync as existsSync4 } from "fs";
29203
- import path9 from "path";
29202
+ import { existsSync as existsSync5 } from "fs";
29203
+ import path10 from "path";
29204
29204
  import { Box as Box10, render as render10, Text as Text10 } from "ink";
29205
29205
 
29206
29206
  // src/lib/telemetry.ts
@@ -29415,9 +29415,9 @@ function runtimeProperties(cliVersion) {
29415
29415
  };
29416
29416
  }
29417
29417
  var activeCommand = null;
29418
- function beginCommand(path11, cliVersion) {
29418
+ function beginCommand(path12, cliVersion) {
29419
29419
  activeCommand = {
29420
- path: path11,
29420
+ path: path12,
29421
29421
  startedAt: Date.now(),
29422
29422
  cliVersion,
29423
29423
  reported: false
@@ -29436,11 +29436,59 @@ function completeCommand(exitCode) {
29436
29436
  });
29437
29437
  }
29438
29438
 
29439
- // src/commands/init/core.ts
29440
- import { execSync as execSync2 } from "child_process";
29441
- import { existsSync as existsSync3 } from "fs";
29439
+ // src/commands/init/agents-file.ts
29440
+ import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
29442
29441
  import path8 from "path";
29443
29442
 
29443
+ // ../shared/src/agents/index.ts
29444
+ var AGENT_DOCS_URL = "https://docs.tolkbot.ai/docs/for-agents";
29445
+ var AGENT_BLOCK = `## Translations
29446
+
29447
+ TolkBot translates this project. Run its commands in the directory that holds \`tolkbot.json\`.
29448
+
29449
+ - Add new strings to the base locale file only. Never write the other locale files by hand.
29450
+ - After changing strings, run \`npx tolkbot status\` and \`npx tolkbot translate --all\`, then \`npx tolkbot validate\` before committing.
29451
+ - To correct a translation, run \`npx tolkbot set <key> --locale <locale> --value "<text>" --learn "<why>"\`. TolkBot keeps the value and learns from the note.
29452
+ - Leave every key alone that \`npx tolkbot status --keys\` lists as held by a person.
29453
+ - More: ${AGENT_DOCS_URL}`;
29454
+ var AGENT_BLOCK_START = "<!-- tolkbot:start -->";
29455
+ var AGENT_BLOCK_END = "<!-- tolkbot:end -->";
29456
+ var MARKED_AGENT_BLOCK = `${AGENT_BLOCK_START}
29457
+ ${AGENT_BLOCK}
29458
+ ${AGENT_BLOCK_END}`;
29459
+ function withAgentBlock(existing) {
29460
+ if (existing === null) {
29461
+ return {
29462
+ ok: true,
29463
+ change: "created",
29464
+ content: `${MARKED_AGENT_BLOCK}
29465
+ `
29466
+ };
29467
+ }
29468
+ const start = existing.indexOf(AGENT_BLOCK_START);
29469
+ const end = existing.indexOf(AGENT_BLOCK_END);
29470
+ if (start === -1 && end === -1) {
29471
+ const trimmed = existing.replace(/\s+$/, "");
29472
+ const content2 = trimmed === "" ? `${MARKED_AGENT_BLOCK}
29473
+ ` : `${trimmed}
29474
+
29475
+ ${MARKED_AGENT_BLOCK}
29476
+ `;
29477
+ return { ok: true, change: "added", content: content2 };
29478
+ }
29479
+ if (start === -1 || end === -1 || end < start) {
29480
+ return { ok: false, reason: "unmatched_marker" };
29481
+ }
29482
+ const before = existing.slice(0, start);
29483
+ const after = existing.slice(end + AGENT_BLOCK_END.length);
29484
+ const content = `${before}${MARKED_AGENT_BLOCK}${after}`;
29485
+ return {
29486
+ ok: true,
29487
+ change: content === existing ? "unchanged" : "updated",
29488
+ content
29489
+ };
29490
+ }
29491
+
29444
29492
  // src/lib/repository-root.ts
29445
29493
  import { execFileSync } from "child_process";
29446
29494
  import fs7 from "fs";
@@ -29481,7 +29529,52 @@ function realpath(p) {
29481
29529
  }
29482
29530
  }
29483
29531
 
29532
+ // src/commands/init/agents-file.ts
29533
+ var AGENT_FILE_NAMES = ["AGENTS.md", "CLAUDE.md"];
29534
+ function defaultAgentsFile(cwd) {
29535
+ const start = path8.resolve(cwd);
29536
+ const root = gitToplevel(start) ?? start;
29537
+ for (let dir = start; ; dir = path8.dirname(dir)) {
29538
+ for (const name of AGENT_FILE_NAMES) {
29539
+ const candidate = path8.join(dir, name);
29540
+ if (existsSync3(candidate)) return candidate;
29541
+ }
29542
+ if (dir === root || path8.dirname(dir) === dir) break;
29543
+ }
29544
+ return path8.join(root, "AGENTS.md");
29545
+ }
29546
+ function resolveAgentsFile(cwd, requested) {
29547
+ return requested === true ? defaultAgentsFile(cwd) : path8.resolve(cwd, requested);
29548
+ }
29549
+ function writeAgentsFile(file2) {
29550
+ const existing = existsSync3(file2) ? readFileSync3(file2, "utf8") : null;
29551
+ const edit = withAgentBlock(existing);
29552
+ if (!edit.ok) {
29553
+ throw new CliError(
29554
+ `${file2} has a TolkBot block that is missing its start or end marker.`,
29555
+ "Remove the half of the block that is left, or the marker, and run 'tolkbot init --agents-file' again."
29556
+ );
29557
+ }
29558
+ if (edit.change !== "unchanged") writeFileSync2(file2, edit.content);
29559
+ return { path: file2, change: edit.change };
29560
+ }
29561
+ function describeAgentsFile(result, shown) {
29562
+ switch (result.change) {
29563
+ case "created":
29564
+ return `Wrote the agent instructions to ${shown}`;
29565
+ case "added":
29566
+ return `Added the agent instructions to ${shown}`;
29567
+ case "updated":
29568
+ return `Updated the agent instructions in ${shown}`;
29569
+ case "unchanged":
29570
+ return `${shown} already has the agent instructions`;
29571
+ }
29572
+ }
29573
+
29484
29574
  // src/commands/init/core.ts
29575
+ import { execSync as execSync2 } from "child_process";
29576
+ import { existsSync as existsSync4 } from "fs";
29577
+ import path9 from "path";
29485
29578
  var DETECTION_TIMEOUT_MS = 3 * 6e4;
29486
29579
  var DETECTION_POLL_MS = 1e3;
29487
29580
  function getRecommendedFramework(projectType) {
@@ -29588,7 +29681,7 @@ function ambiguousProjectError(candidates) {
29588
29681
  function configInDirectory(dir) {
29589
29682
  try {
29590
29683
  const found = readConfig(dir);
29591
- if (!found || path8.dirname(found.path) !== path8.resolve(dir)) {
29684
+ if (!found || path9.dirname(found.path) !== path9.resolve(dir)) {
29592
29685
  return void 0;
29593
29686
  }
29594
29687
  return {
@@ -29601,7 +29694,7 @@ function configInDirectory(dir) {
29601
29694
  }
29602
29695
  }
29603
29696
  function newProjectName(repository, subpath) {
29604
- return subpath === "" ? repository : path8.posix.basename(subpath);
29697
+ return subpath === "" ? repository : path9.posix.basename(subpath);
29605
29698
  }
29606
29699
  async function linkRepository(cwd, plan, opts = {}) {
29607
29700
  const { owner, name } = resolveRepoIdentity(cwd);
@@ -29682,14 +29775,14 @@ async function linkRepository(cwd, plan, opts = {}) {
29682
29775
  () => convexClient.query(api.projects.getProjectForCli, { projectId })
29683
29776
  );
29684
29777
  requireSourcePattern(project, `${owner}/${name}`);
29685
- const projectDir = path8.join(
29778
+ const projectDir = path9.join(
29686
29779
  root,
29687
29780
  ...project.subpath.split("/").filter(Boolean)
29688
29781
  );
29689
- const configDir = opts.existingConfig?.projectId === projectId ? path8.dirname(opts.existingConfig.path) : (
29782
+ const configDir = opts.existingConfig?.projectId === projectId ? path9.dirname(opts.existingConfig.path) : (
29690
29783
  // A checkout without the project's directory (a sparse one)
29691
29784
  // keeps the config where init ran.
29692
- existsSync3(projectDir) ? projectDir : cwd
29785
+ existsSync4(projectDir) ? projectDir : cwd
29693
29786
  );
29694
29787
  return {
29695
29788
  projectId,
@@ -29719,8 +29812,8 @@ function writeProjectConfig(result, framework, opts) {
29719
29812
  );
29720
29813
  }
29721
29814
  function displayPath(cwd, file2) {
29722
- const relative = path8.relative(cwd, file2);
29723
- return relative.startsWith("..") || path8.isAbsolute(relative) ? file2 : relative;
29815
+ const relative = path9.relative(cwd, file2);
29816
+ return relative.startsWith("..") || path9.isAbsolute(relative) ? file2 : relative;
29724
29817
  }
29725
29818
  function isDetecting(project) {
29726
29819
  return project.initializationStatus === "pending" || project.initializationStatus === "initializing";
@@ -29793,6 +29886,7 @@ function friendlyProjectType(t) {
29793
29886
  function InitWizard({
29794
29887
  force,
29795
29888
  project,
29889
+ agentsFile,
29796
29890
  onComplete,
29797
29891
  onFailure
29798
29892
  }) {
@@ -29807,6 +29901,27 @@ function InitWizard({
29807
29901
  });
29808
29902
  const [error62, setError] = React.useState(null);
29809
29903
  const [pendingChoice, setPendingChoice] = React.useState(null);
29904
+ const agentsTarget = React.useMemo(
29905
+ () => resolveAgentsFile(cwd, agentsFile ?? true),
29906
+ [cwd, agentsFile]
29907
+ );
29908
+ function addAgentInstructions() {
29909
+ try {
29910
+ const result = writeAgentsFile(agentsTarget);
29911
+ setSetupData((prev) => ({
29912
+ ...prev,
29913
+ agentsLine: describeAgentsFile(
29914
+ result,
29915
+ displayPath(cwd, result.path)
29916
+ )
29917
+ }));
29918
+ } catch (err) {
29919
+ setSetupData((prev) => ({
29920
+ ...prev,
29921
+ agentsLine: err instanceof Error ? err.message : String(err)
29922
+ }));
29923
+ }
29924
+ }
29810
29925
  React.useEffect(() => {
29811
29926
  if (step === "detecting") {
29812
29927
  setTimeout(() => {
@@ -29862,7 +29977,12 @@ function InitWizard({
29862
29977
  createdProject: result.createdProject,
29863
29978
  organizationId: result.organizationId
29864
29979
  });
29865
- setStep("done");
29980
+ if (agentsFile) {
29981
+ addAgentInstructions();
29982
+ setStep("done");
29983
+ } else {
29984
+ setStep("agentsOffer");
29985
+ }
29866
29986
  } catch (err) {
29867
29987
  setError(err instanceof Error ? err.message : String(err));
29868
29988
  setStep("done");
@@ -30097,6 +30217,30 @@ function InitWizard({
30097
30217
  ] })
30098
30218
  ] }) });
30099
30219
  }
30220
+ if (step === "agentsOffer") {
30221
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
30222
+ /* @__PURE__ */ jsxs9(Text9, { children: [
30223
+ "Add TolkBot's instructions for coding agents to",
30224
+ " ",
30225
+ displayPath(cwd, agentsTarget),
30226
+ "?"
30227
+ ] }),
30228
+ /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "They tell an agent to run tolkbot translate and validate instead of writing locale files by hand." }),
30229
+ /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx9(
30230
+ Select,
30231
+ {
30232
+ options: [
30233
+ { label: "Yes", value: "yes" },
30234
+ { label: "No", value: "no" }
30235
+ ],
30236
+ onChange: (value) => {
30237
+ if (value === "yes") addAgentInstructions();
30238
+ setStep("done");
30239
+ }
30240
+ }
30241
+ ) })
30242
+ ] });
30243
+ }
30100
30244
  if (step === "done") {
30101
30245
  if (error62) {
30102
30246
  return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
@@ -30125,10 +30269,13 @@ function InitWizard({
30125
30269
  "Files: ",
30126
30270
  setupData.link?.sourcePattern
30127
30271
  ] }) }),
30128
- setupData.configPath && /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsxs9(Text9, { children: [
30129
- "Wrote ",
30130
- displayPath(cwd, setupData.configPath)
30131
- ] }) }),
30272
+ setupData.configPath && /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexDirection: "column", children: [
30273
+ /* @__PURE__ */ jsxs9(Text9, { children: [
30274
+ "Wrote ",
30275
+ displayPath(cwd, setupData.configPath)
30276
+ ] }),
30277
+ setupData.agentsLine && /* @__PURE__ */ jsx9(Text9, { children: setupData.agentsLine })
30278
+ ] }),
30132
30279
  setupData.shouldInstall && /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexDirection: "column", children: [
30133
30280
  /* @__PURE__ */ jsx9(Text9, { children: "Next steps:" }),
30134
30281
  /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "1. Import i18n in your app - see docs" }),
@@ -30195,7 +30342,8 @@ function resolvePlan(cwd, opts) {
30195
30342
  function SummaryUI({
30196
30343
  plan,
30197
30344
  result,
30198
- configPath
30345
+ configPath,
30346
+ agentsLine
30199
30347
  }) {
30200
30348
  return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
30201
30349
  /* @__PURE__ */ jsxs10(Box10, { children: [
@@ -30233,10 +30381,13 @@ function SummaryUI({
30233
30381
  result.createdProject ? " (created)" : " (existing)"
30234
30382
  ] })
30235
30383
  ] }),
30236
- /* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsxs10(Text10, { children: [
30237
- "Wrote ",
30238
- configPath
30239
- ] }) })
30384
+ /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexDirection: "column", children: [
30385
+ /* @__PURE__ */ jsxs10(Text10, { children: [
30386
+ "Wrote ",
30387
+ configPath
30388
+ ] }),
30389
+ agentsLine && /* @__PURE__ */ jsx10(Text10, { children: agentsLine })
30390
+ ] })
30240
30391
  ] });
30241
30392
  }
30242
30393
  async function runHeadless(cwd, opts) {
@@ -30260,6 +30411,7 @@ async function runHeadless(cwd, opts) {
30260
30411
  const configPath = writeProjectConfig(result, plan.framework, {
30261
30412
  force: opts.force
30262
30413
  });
30414
+ const agents = opts.agentsFile ? writeAgentsFile(resolveAgentsFile(cwd, opts.agentsFile)) : null;
30263
30415
  track("cli_init_completed", {
30264
30416
  framework: plan.framework,
30265
30417
  framework_detected: detectedFramework,
@@ -30283,7 +30435,8 @@ async function runHeadless(cwd, opts) {
30283
30435
  baseLocale: result.baseLanguage,
30284
30436
  targets: result.targetLanguages,
30285
30437
  createdProject: result.createdProject,
30286
- installed: plan.install
30438
+ installed: plan.install,
30439
+ agentsFile: agents
30287
30440
  },
30288
30441
  0
30289
30442
  );
@@ -30295,7 +30448,8 @@ async function runHeadless(cwd, opts) {
30295
30448
  {
30296
30449
  plan,
30297
30450
  result,
30298
- configPath: displayPath(cwd, configPath)
30451
+ configPath: displayPath(cwd, configPath),
30452
+ agentsLine: agents ? describeAgentsFile(agents, displayPath(cwd, agents.path)) : null
30299
30453
  }
30300
30454
  )
30301
30455
  ).unmount();
@@ -30318,8 +30472,8 @@ async function requireLogin() {
30318
30472
  }
30319
30473
  function refuseExistingConfig(cwd, force) {
30320
30474
  if (force) return;
30321
- const existing = path9.join(cwd, "tolkbot.json");
30322
- if (existsSync4(existing)) {
30475
+ const existing = path10.join(cwd, "tolkbot.json");
30476
+ if (existsSync5(existing)) {
30323
30477
  throw new CliError(
30324
30478
  `${existing} already exists.`,
30325
30479
  "Run 'tolkbot init --force' to link again and refresh it."
@@ -30344,6 +30498,7 @@ async function runInteractive(opts) {
30344
30498
  {
30345
30499
  force: opts.force,
30346
30500
  project: opts.project,
30501
+ agentsFile: opts.agentsFile,
30347
30502
  onComplete: (summary) => {
30348
30503
  setTelemetryOrganization(summary.organizationId);
30349
30504
  track("cli_init_completed", {
@@ -30440,7 +30595,7 @@ function describeLeftOut(plan) {
30440
30595
 
30441
30596
  // src/commands/translate/apply-core.ts
30442
30597
  import fs8 from "fs/promises";
30443
- import path10 from "path";
30598
+ import path11 from "path";
30444
30599
 
30445
30600
  // ../../node_modules/.pnpm/@noble+hashes@2.4.0/node_modules/@noble/hashes/_u64.js
30446
30601
  var fromNumH = (n) => n / 2 ** 32 | 0;
@@ -31009,7 +31164,7 @@ async function applyTasks(input2) {
31009
31164
  }
31010
31165
  const baseKeys = new Set(getKeys(source.data));
31011
31166
  const target = targetFileFor(sourceFile, dstLocale, files, scope);
31012
- const targetPath = path10.join(root, ...target.relativePath.split("/"));
31167
+ const targetPath = path11.join(root, ...target.relativePath.split("/"));
31013
31168
  const existing = target.existing ? await readTranslationFile(target.existing.absolutePath, format) : void 0;
31014
31169
  if (existing?.error !== void 0) {
31015
31170
  for (const task of tasks) refuse(task, "target_unreadable");
@@ -31064,7 +31219,7 @@ async function applyTasks(input2) {
31064
31219
  async function writeTranslationFile(input2) {
31065
31220
  const { targetPath, data } = input2;
31066
31221
  const model = input2.existingContent ?? input2.sourceContent;
31067
- await fs8.mkdir(path10.dirname(targetPath), { recursive: true });
31222
+ await fs8.mkdir(path11.dirname(targetPath), { recursive: true });
31068
31223
  if (input2.format === "json") {
31069
31224
  await fs8.writeFile(
31070
31225
  targetPath,
@@ -31861,10 +32016,10 @@ function serverMessage(message) {
31861
32016
  }
31862
32017
  function argumentError(message) {
31863
32018
  if (!message.includes("ArgumentValidationError")) return null;
31864
- const path11 = /Path: \.?(\S+)/.exec(message)?.[1];
32019
+ const path12 = /Path: \.?(\S+)/.exec(message)?.[1];
31865
32020
  const value = /Value: (.+)/.exec(message)?.[1];
31866
32021
  return new UsageError(
31867
- path11 && value ? `TolkBot refused ${value} as ${path11}.` : "TolkBot refused the arguments.",
32022
+ path12 && value ? `TolkBot refused ${value} as ${path12}.` : "TolkBot refused the arguments.",
31868
32023
  "Check the id or value passed; list ids with the command's list subcommand."
31869
32024
  );
31870
32025
  }
@@ -35168,7 +35323,7 @@ function buildProgram() {
35168
35323
  });
35169
35324
  program.command("init").description("Initialize TolkBot in the current repo").option("--force", "Overwrite existing config").option(
35170
35325
  "-y, --yes",
35171
- "Skip all prompts, accepting detected settings. Required outside a terminal."
35326
+ "Skip all prompts, accepting detected settings (the default without a terminal)"
35172
35327
  ).option("--json", "Output the result as JSON (implies --yes)").option("--base <locale>", "Base locale (default: detected, else en)").option(
35173
35328
  "--targets <locales>",
35174
35329
  "Comma-separated target locales (default: detected)"
@@ -35181,6 +35336,9 @@ function buildProgram() {
35181
35336
  ).option(
35182
35337
  "--project <slug>",
35183
35338
  "Link this project. Default: the project whose directory you are in, else a new project here."
35339
+ ).option(
35340
+ "--agents-file [path]",
35341
+ "Add TolkBot's instructions for coding agents to this file, by default the nearest AGENTS.md or CLAUDE.md. At a terminal init asks; otherwise it writes them only with this option"
35184
35342
  ).action((opts) => runInit(opts));
35185
35343
  program.command("validate").description("Validate translation files and configuration").option("--json", "Output the report as JSON").option(
35186
35344
  "--strict",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tolkbot/cli",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Command-line interface for TolkBot: AI translation for the i18n files in a GitHub repository.",
5
5
  "license": "UNLICENSED",
6
6
  "homepage": "https://tolkbot.ai",
@@ -66,6 +66,7 @@
66
66
  "typecheck": "tsc --noEmit --emitDeclarationOnly false",
67
67
  "test": "pnpm format && pnpm run lint && pnpm run typecheck && pnpm run test:unit",
68
68
  "test:unit": "vitest run --silent",
69
+ "docs:reference": "UPDATE_CLI_REFERENCE=1 vitest run cli-reference",
69
70
  "check:release": "node ../../scripts/check-cli-release.mjs",
70
71
  "with-env": "dotenv -e ../../.env --",
71
72
  "start": "pnpm with-env node dist/index.js"