rulesync 30.0.0 → 31.0.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.
@@ -913,6 +913,7 @@ const checksProcessorToolTargetTuple = [
913
913
  "cursor",
914
914
  "factorydroid",
915
915
  "gitlabduo",
916
+ "goose",
916
917
  "hermesagent",
917
918
  "kilo",
918
919
  "qwencode",
@@ -14199,12 +14200,12 @@ const AmpCheckFrontmatterSchema = z.looseObject({
14199
14200
  * this format continue to apply.
14200
14201
  * @see https://ampcode.com/docs/review
14201
14202
  */
14202
- var AmpCheck = class AmpCheck extends ToolCheck {
14203
+ var AmpCheck = class extends ToolCheck {
14203
14204
  frontmatter;
14204
14205
  body;
14205
14206
  constructor({ frontmatter, body, fileContent, ...rest }) {
14206
14207
  if (rest.validate !== false) {
14207
- const result = AmpCheckFrontmatterSchema.safeParse(frontmatter);
14208
+ const result = new.target.getFrontmatterSchema().safeParse(frontmatter);
14208
14209
  if (!result.success) throw new Error(`Invalid frontmatter in ${join(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`);
14209
14210
  }
14210
14211
  super({
@@ -14214,6 +14215,26 @@ var AmpCheck = class AmpCheck extends ToolCheck {
14214
14215
  this.frontmatter = frontmatter;
14215
14216
  this.body = body;
14216
14217
  }
14218
+ /**
14219
+ * The tool target this check format belongs to, which is also the name of
14220
+ * its tool-specific frontmatter section. Goose reads the same per-file
14221
+ * format with a few extra keys, so `GooseCheck` reuses this class through
14222
+ * these hooks.
14223
+ */
14224
+ static getCheckToolTarget() {
14225
+ return "amp";
14226
+ }
14227
+ /** The frontmatter schema a check file of this tool is validated against. */
14228
+ static getFrontmatterSchema() {
14229
+ return AmpCheckFrontmatterSchema;
14230
+ }
14231
+ /**
14232
+ * Frontmatter keys only this tool reads. Import moves them into the tool's
14233
+ * own section so they are not passed on to every other checks target.
14234
+ */
14235
+ static getToolOnlyKeys() {
14236
+ return [];
14237
+ }
14217
14238
  static getSettablePaths({ global = false } = {}) {
14218
14239
  return { relativeDirPath: global ? AMP_CHECKS_GLOBAL_DIR : AMP_CHECKS_PROJECT_DIR };
14219
14240
  }
@@ -14225,6 +14246,10 @@ var AmpCheck = class AmpCheck extends ToolCheck {
14225
14246
  }
14226
14247
  toRulesyncCheck() {
14227
14248
  const { name: _name, description, "severity-default": severityDefault, tools, ...restFields } = this.frontmatter;
14249
+ const checkClass = this.constructor;
14250
+ const toolOnlyKeys = new Set(checkClass.getToolOnlyKeys());
14251
+ const sharedFields = Object.fromEntries(Object.entries(restFields).filter(([key]) => !toolOnlyKeys.has(key)));
14252
+ const toolSection = Object.fromEntries(Object.entries(restFields).filter(([key]) => toolOnlyKeys.has(key)));
14228
14253
  return new RulesyncCheck({
14229
14254
  outputRoot: ".",
14230
14255
  frontmatter: {
@@ -14232,7 +14257,8 @@ var AmpCheck = class AmpCheck extends ToolCheck {
14232
14257
  ...description !== void 0 && { description },
14233
14258
  ...severityDefault !== void 0 && { severity: severityDefault },
14234
14259
  ...tools !== void 0 && { tools },
14235
- ...restFields
14260
+ ...sharedFields,
14261
+ ...Object.keys(toolSection).length > 0 && { [checkClass.getCheckToolTarget()]: toolSection }
14236
14262
  },
14237
14263
  body: this.body,
14238
14264
  relativeDirPath: RULESYNC_CHECKS_RELATIVE_DIR_PATH,
@@ -14247,22 +14273,24 @@ var AmpCheck = class AmpCheck extends ToolCheck {
14247
14273
  const { targets: _targets, description, severity, tools, ...restFields } = rulesyncFrontmatter;
14248
14274
  const toolTargetKeys = new Set(ALL_TOOL_TARGETS);
14249
14275
  const passthroughFields = Object.fromEntries(Object.entries(restFields).filter(([key]) => !toolTargetKeys.has(key) && key !== "name"));
14250
- const ampSection = this.filterToolSpecificSection(rulesyncFrontmatter.amp ?? {}, ["name"]);
14276
+ const toolTarget = this.getCheckToolTarget();
14277
+ const rawSection = rulesyncFrontmatter[toolTarget];
14278
+ const toolSection = this.filterToolSpecificSection(rawSection !== null && typeof rawSection === "object" && !Array.isArray(rawSection) ? rawSection : {}, ["name"]);
14251
14279
  const rawAmpFrontmatter = {
14252
14280
  name,
14253
14281
  ...description !== void 0 && { description },
14254
14282
  ...severity !== void 0 && { "severity-default": severity },
14255
14283
  ...tools !== void 0 && { tools },
14256
14284
  ...passthroughFields,
14257
- ...ampSection
14285
+ ...toolSection
14258
14286
  };
14259
- const result = AmpCheckFrontmatterSchema.safeParse(rawAmpFrontmatter);
14260
- if (!result.success) throw new Error(`Invalid amp check frontmatter in ${relativeFilePath}: ${formatError(result.error)}`);
14287
+ const result = this.getFrontmatterSchema().safeParse(rawAmpFrontmatter);
14288
+ if (!result.success) throw new Error(`Invalid ${toolTarget} check frontmatter in ${relativeFilePath}: ${formatError(result.error)}`);
14261
14289
  const ampFrontmatter = result.data;
14262
14290
  const body = rulesyncCheck.getBody();
14263
14291
  const fileContent = stringifyFrontmatter(body, ampFrontmatter);
14264
14292
  const paths = this.getSettablePaths({ global });
14265
- return new AmpCheck({
14293
+ return new this({
14266
14294
  outputRoot,
14267
14295
  frontmatter: ampFrontmatter,
14268
14296
  body,
@@ -14277,7 +14305,7 @@ var AmpCheck = class AmpCheck extends ToolCheck {
14277
14305
  success: true,
14278
14306
  error: null
14279
14307
  };
14280
- const result = AmpCheckFrontmatterSchema.safeParse(this.frontmatter);
14308
+ const result = this.constructor.getFrontmatterSchema().safeParse(this.frontmatter);
14281
14309
  if (result.success) return {
14282
14310
  success: true,
14283
14311
  error: null
@@ -14290,7 +14318,7 @@ var AmpCheck = class AmpCheck extends ToolCheck {
14290
14318
  static isTargetedByRulesyncCheck(rulesyncCheck) {
14291
14319
  return this.isTargetedByRulesyncCheckDefault({
14292
14320
  rulesyncCheck,
14293
- toolTarget: "amp"
14321
+ toolTarget: this.getCheckToolTarget()
14294
14322
  });
14295
14323
  }
14296
14324
  static async fromFile({ outputRoot = process.cwd(), relativeFilePath, validate = true, global = false }) {
@@ -14298,9 +14326,9 @@ var AmpCheck = class AmpCheck extends ToolCheck {
14298
14326
  const filePath = join(outputRoot, paths.relativeDirPath, relativeFilePath);
14299
14327
  const fileContent = await readFileContent(filePath);
14300
14328
  const { frontmatter, body: content } = parseFrontmatter(fileContent, filePath);
14301
- const result = AmpCheckFrontmatterSchema.safeParse(frontmatter);
14329
+ const result = this.getFrontmatterSchema().safeParse(frontmatter);
14302
14330
  if (!result.success) throw new Error(`Invalid frontmatter in ${filePath}: ${formatError(result.error)}`);
14303
- return new AmpCheck({
14331
+ return new this({
14304
14332
  outputRoot,
14305
14333
  relativeDirPath: paths.relativeDirPath,
14306
14334
  relativeFilePath,
@@ -14311,7 +14339,7 @@ var AmpCheck = class AmpCheck extends ToolCheck {
14311
14339
  });
14312
14340
  }
14313
14341
  static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
14314
- return new AmpCheck({
14342
+ return new this({
14315
14343
  outputRoot,
14316
14344
  relativeDirPath,
14317
14345
  relativeFilePath,
@@ -15411,6 +15439,60 @@ var GitlabduoCheck = class GitlabduoCheck extends ToolCheck {
15411
15439
  }
15412
15440
  };
15413
15441
  //#endregion
15442
+ //#region src/constants/goose-paths.ts
15443
+ const GOOSE_DIR = ".goose";
15444
+ const GOOSE_GLOBAL_DIR = join(".config", "goose");
15445
+ const GOOSE_RULE_FILE_NAME = ".goosehints";
15446
+ const GOOSE_MCP_FILE_NAME = "config.yaml";
15447
+ const GOOSE_PERMISSIONS_FILE_NAME = "permission.yaml";
15448
+ const GOOSE_HOOKS_DIR_PATH = join(".agents", "plugins", "rulesync", "hooks");
15449
+ const GOOSE_HOOKS_FILE_NAME = "hooks.json";
15450
+ const GOOSE_PLUGIN_MCP_DIR_PATH = join(".agents", "plugins", "rulesync");
15451
+ const GOOSE_PLUGIN_MCP_FILE_NAME = ".mcp.json";
15452
+ const GOOSE_SKILLS_DIR_PATH = join(GOOSE_DIR, "skills");
15453
+ const GOOSE_GLOBAL_SKILLS_DIR_PATH = join(GOOSE_GLOBAL_DIR, "skills");
15454
+ const GOOSE_RECIPES_DIR_PATH = join(GOOSE_DIR, "recipes");
15455
+ const GOOSE_GLOBAL_RECIPES_DIR_PATH = join(GOOSE_GLOBAL_DIR, "recipes");
15456
+ const GOOSE_AGENTS_DIR_PATH = join(GOOSE_DIR, "agents");
15457
+ const GOOSE_GLOBAL_AGENTS_DIR_PATH = join(GOOSE_GLOBAL_DIR, "agents");
15458
+ const GOOSE_CHECKS_PROJECT_DIR = join(".agents", "checks");
15459
+ const GOOSE_CHECKS_GLOBAL_DIR = join(GOOSE_GLOBAL_DIR, "checks");
15460
+ //#endregion
15461
+ //#region src/features/checks/goose-check.ts
15462
+ const GooseCheckFrontmatterSchema = z.extend(AmpCheckFrontmatterSchema, {
15463
+ model: z.optional(z.string()),
15464
+ "turn-limit": z.optional(z.int().check(z.nonnegative()))
15465
+ });
15466
+ /**
15467
+ * Represents a Goose review check (`goose review`), written to the user-wide
15468
+ * `~/.config/goose/checks/` (global scope only).
15469
+ *
15470
+ * Goose discovers repository checks in `.agents/checks/*.md`, the same
15471
+ * cross-tool directory the `amp` checks target already writes (Goose's
15472
+ * `tools` and `severity-default` fields exist for parity with Amp's), so the
15473
+ * project scope is left to `amp` rather than having two targets own the same
15474
+ * files. Its global discovery reads `~/.config/goose/checks/` first, then
15475
+ * `~/.config/agents/checks/`. The file format is Amp's, so this class reuses
15476
+ * `AmpCheck` and adds Goose's `model` and `turn-limit`, which live in the
15477
+ * `goose:` section of a rulesync check; `name` is derived from the file name.
15478
+ *
15479
+ * @see https://github.com/aaif-goose/goose/blob/main/crates/goose/src/checks/mod.rs
15480
+ */
15481
+ var GooseCheck = class extends AmpCheck {
15482
+ static getCheckToolTarget() {
15483
+ return "goose";
15484
+ }
15485
+ static getFrontmatterSchema() {
15486
+ return GooseCheckFrontmatterSchema;
15487
+ }
15488
+ static getToolOnlyKeys() {
15489
+ return ["model", "turn-limit"];
15490
+ }
15491
+ static getSettablePaths({ global = false } = {}) {
15492
+ return { relativeDirPath: global ? GOOSE_CHECKS_GLOBAL_DIR : GOOSE_CHECKS_PROJECT_DIR };
15493
+ }
15494
+ };
15495
+ //#endregion
15414
15496
  //#region src/constants/hermesagent-paths.ts
15415
15497
  /**
15416
15498
  * Hermes Agent configuration-layout conventions.
@@ -16139,6 +16221,14 @@ const toolCheckFactories = /* @__PURE__ */ new Map([
16139
16221
  committedOutput: true
16140
16222
  }
16141
16223
  }],
16224
+ ["goose", {
16225
+ class: GooseCheck,
16226
+ meta: {
16227
+ supportsGlobal: true,
16228
+ supportsProject: false,
16229
+ filePattern: "*.md"
16230
+ }
16231
+ }],
16142
16232
  ["hermesagent", {
16143
16233
  class: HermesagentCheck,
16144
16234
  meta: {
@@ -16184,7 +16274,9 @@ const defaultGetFactory$6 = (target) => {
16184
16274
  return factory;
16185
16275
  };
16186
16276
  const allToolTargetKeys$5 = [...toolCheckFactories.keys()];
16187
- const checksProcessorToolTargets = allToolTargetKeys$5;
16277
+ const checksProcessorToolTargets = allToolTargetKeys$5.filter((target) => {
16278
+ return toolCheckFactories.get(target)?.meta.supportsProject !== false;
16279
+ });
16188
16280
  const checksProcessorToolTargetsGlobal = allToolTargetKeys$5.filter((target) => {
16189
16281
  return toolCheckFactories.get(target)?.meta.supportsGlobal ?? false;
16190
16282
  });
@@ -16355,23 +16447,6 @@ var ChecksProcessor = class extends FeatureProcessor {
16355
16447
  }
16356
16448
  };
16357
16449
  //#endregion
16358
- //#region src/constants/goose-paths.ts
16359
- const GOOSE_DIR = ".goose";
16360
- const GOOSE_GLOBAL_DIR = join(".config", "goose");
16361
- const GOOSE_RULE_FILE_NAME = ".goosehints";
16362
- const GOOSE_MCP_FILE_NAME = "config.yaml";
16363
- const GOOSE_PERMISSIONS_FILE_NAME = "permission.yaml";
16364
- const GOOSE_HOOKS_DIR_PATH = join(".agents", "plugins", "rulesync", "hooks");
16365
- const GOOSE_HOOKS_FILE_NAME = "hooks.json";
16366
- const GOOSE_PLUGIN_MCP_DIR_PATH = join(".agents", "plugins", "rulesync");
16367
- const GOOSE_PLUGIN_MCP_FILE_NAME = ".mcp.json";
16368
- const GOOSE_SKILLS_DIR_PATH = join(GOOSE_DIR, "skills");
16369
- const GOOSE_GLOBAL_SKILLS_DIR_PATH = join(GOOSE_GLOBAL_DIR, "skills");
16370
- const GOOSE_RECIPES_DIR_PATH = join(GOOSE_DIR, "recipes");
16371
- const GOOSE_GLOBAL_RECIPES_DIR_PATH = join(GOOSE_GLOBAL_DIR, "recipes");
16372
- const GOOSE_AGENTS_DIR_PATH = join(GOOSE_DIR, "agents");
16373
- const GOOSE_GLOBAL_AGENTS_DIR_PATH = join(GOOSE_GLOBAL_DIR, "agents");
16374
- //#endregion
16375
16450
  //#region src/utils/tool-home.ts
16376
16451
  /**
16377
16452
  * Where the rulesync-side source files of a tool with a home override belong.
@@ -18093,27 +18168,71 @@ const CLINE_HOOKS_GLOBAL_DIR_PATH = join("Documents", "Cline", "Hooks");
18093
18168
  const CLINE_HOOKS_MANIFEST_FILE_NAME = "rulesync-hooks.json";
18094
18169
  //#endregion
18095
18170
  //#region src/features/commands/cline-command.ts
18171
+ const CLINE_WORKFLOW_FIELD_TYPES = {
18172
+ name: "string",
18173
+ disabled: "boolean",
18174
+ enabled: "boolean"
18175
+ };
18176
+ function sanitizeClineWorkflowFrontmatter({ cline, relativeFilePath, logger }) {
18177
+ if (!isRecord$1(cline)) return {};
18178
+ return Object.fromEntries(Object.entries(cline).filter(([key, value]) => {
18179
+ const expected = Object.hasOwn(CLINE_WORKFLOW_FIELD_TYPES, key) ? CLINE_WORKFLOW_FIELD_TYPES[key] : void 0;
18180
+ if (expected === void 0 || typeof value === expected) return true;
18181
+ warnWithFallback(logger, `Cline commands: dropping cline.${key} from ${relativeFilePath}: Cline rejects the whole workflow unless it is a ${expected}.`);
18182
+ return false;
18183
+ }));
18184
+ }
18185
+ /**
18186
+ * Cline workflows (commands). A workflow may carry YAML frontmatter that Cline
18187
+ * reads: `name` (the slash-command name) and a `disabled` / `enabled` switch
18188
+ * (`parseWorkflowConfigFromMarkdown` in Cline's
18189
+ * `user-instruction-config-loader.ts`). The `cline:` section of a
18190
+ * `.rulesync/commands/*.md` file is written as that frontmatter, and every key
18191
+ * of an imported workflow's frontmatter is lifted back into `cline:`, so
18192
+ * hand-written workflow frontmatter survives an import → generate round trip.
18193
+ * Cline's own UI toggle is kept in Cline's state, not in the file. A workflow
18194
+ * without a `cline:` section is written as a bare body, as before.
18195
+ *
18196
+ * @see https://github.com/cline/cline/blob/main/sdk/packages/core/src/extensions/config/user-instruction-config-loader.ts
18197
+ */
18096
18198
  var ClineCommand = class ClineCommand extends ToolCommand {
18097
18199
  static getSettablePaths({ global } = {}) {
18098
18200
  if (global) return { relativeDirPath: CLINE_COMMANDS_GLOBAL_DIR_PATH };
18099
18201
  return { relativeDirPath: CLINE_COMMANDS_DIR_PATH };
18100
18202
  }
18203
+ /** The workflow's own frontmatter, or an empty object for a bare body. */
18204
+ getClineFrontmatter() {
18205
+ const { frontmatter } = parseFrontmatter(this.getFileContent(), this.getFilePath());
18206
+ return isRecord$1(frontmatter) ? frontmatter : {};
18207
+ }
18101
18208
  toRulesyncCommand() {
18209
+ const cline = this.getClineFrontmatter();
18210
+ const rulesyncFrontmatter = {
18211
+ targets: ["*"],
18212
+ ...Object.keys(cline).length > 0 && { cline }
18213
+ };
18214
+ const body = this.getBody();
18102
18215
  return new RulesyncCommand({
18103
18216
  outputRoot: process.cwd(),
18104
- frontmatter: { targets: ["*"] },
18105
- body: this.getFileContent(),
18217
+ frontmatter: rulesyncFrontmatter,
18218
+ body,
18106
18219
  relativeDirPath: RulesyncCommand.getSettablePaths().relativeDirPath,
18107
18220
  relativeFilePath: this.relativeFilePath,
18108
- fileContent: this.getFileContent(),
18221
+ fileContent: stringifyFrontmatter(body, rulesyncFrontmatter),
18109
18222
  validate: true
18110
18223
  });
18111
18224
  }
18112
- static fromRulesyncCommand({ outputRoot = process.cwd(), rulesyncCommand, validate = true, global = false }) {
18225
+ static fromRulesyncCommand({ outputRoot = process.cwd(), rulesyncCommand, validate = true, global = false, logger }) {
18113
18226
  const paths = this.getSettablePaths({ global });
18227
+ const cline = sanitizeClineWorkflowFrontmatter({
18228
+ cline: rulesyncCommand.getFrontmatter().cline,
18229
+ relativeFilePath: rulesyncCommand.getRelativeFilePath(),
18230
+ logger
18231
+ });
18232
+ const body = rulesyncCommand.getBody();
18114
18233
  return new ClineCommand({
18115
18234
  outputRoot,
18116
- fileContent: rulesyncCommand.getBody(),
18235
+ fileContent: Object.keys(cline).length > 0 ? stringifyFrontmatter(body, cline) : body,
18117
18236
  relativeDirPath: paths.relativeDirPath,
18118
18237
  relativeFilePath: rulesyncCommand.getRelativeFilePath(),
18119
18238
  validate
@@ -18126,7 +18245,7 @@ var ClineCommand = class ClineCommand extends ToolCommand {
18126
18245
  };
18127
18246
  }
18128
18247
  getBody() {
18129
- return this.getFileContent();
18248
+ return parseFrontmatter(this.getFileContent(), this.getFilePath()).body.trim();
18130
18249
  }
18131
18250
  static isTargetedByRulesyncCommand(rulesyncCommand) {
18132
18251
  return this.isTargetedByRulesyncCommandDefault({
@@ -18137,12 +18256,13 @@ var ClineCommand = class ClineCommand extends ToolCommand {
18137
18256
  static async fromFile({ outputRoot = process.cwd(), relativeFilePath, validate = true, global = false }) {
18138
18257
  const paths = this.getSettablePaths({ global });
18139
18258
  const filePath = join(outputRoot, paths.relativeDirPath, relativeFilePath);
18140
- const { body: content } = parseFrontmatter(await readFileContent(filePath), filePath);
18259
+ const { frontmatter, body } = parseFrontmatter(await readFileContent(filePath), filePath);
18260
+ const cline = isRecord$1(frontmatter) ? frontmatter : {};
18141
18261
  return new ClineCommand({
18142
18262
  outputRoot,
18143
18263
  relativeDirPath: paths.relativeDirPath,
18144
18264
  relativeFilePath,
18145
- fileContent: content.trim(),
18265
+ fileContent: Object.keys(cline).length > 0 ? stringifyFrontmatter(body.trim(), cline) : body.trim(),
18146
18266
  validate
18147
18267
  });
18148
18268
  }
@@ -40522,6 +40642,35 @@ function convertFromCodexFormat(codexMcp) {
40522
40642
  }
40523
40643
  return result;
40524
40644
  }
40645
+ /**
40646
+ * Keys Codex refuses on each transport. Its `McpServerConfig` deserializer
40647
+ * calls `throw_if_set` for these, and the error fails the whole `config.toml`,
40648
+ * not just the one server, so they are dropped with a warning instead of
40649
+ * written. Checked against `codex-rs/config/src/mcp_types.rs` at rust-v0.162.1.
40650
+ */
40651
+ const CODEX_STDIO_REJECTED_KEYS = [
40652
+ "url",
40653
+ "bearer_token_env_var",
40654
+ "bearer_token",
40655
+ "http_headers_helper",
40656
+ "http_headers",
40657
+ "env_http_headers",
40658
+ "oauth",
40659
+ "oauth_resource",
40660
+ "auth"
40661
+ ];
40662
+ const CODEX_HTTP_REJECTED_KEYS = [
40663
+ "args",
40664
+ "env",
40665
+ "env_vars",
40666
+ "cwd",
40667
+ "bearer_token"
40668
+ ];
40669
+ function dropTransportRejectedKeys({ converted, isStdio, serverName }) {
40670
+ const dropped = (isStdio ? CODEX_STDIO_REJECTED_KEYS : CODEX_HTTP_REJECTED_KEYS).filter((key) => converted[key] !== void 0);
40671
+ for (const key of dropped) delete converted[key];
40672
+ if (dropped.length > 0) warnWithFallback(void 0, `[CodexCliMcp] Dropping ${dropped.map((key) => `'${key}'`).join(", ")} from ${isStdio ? "stdio" : "url-based"} MCP server "${serverName}": Codex rejects ${dropped.length === 1 ? "this key" : "these keys"} on a ${isStdio ? "stdio" : "url-based"} server and would fail to load the whole config.toml.`);
40673
+ }
40525
40674
  function convertToCodexFormat(mcpServers) {
40526
40675
  const result = {};
40527
40676
  const originalNames = /* @__PURE__ */ new Map();
@@ -40564,6 +40713,11 @@ function convertToCodexFormat(mcpServers) {
40564
40713
  converted,
40565
40714
  serverName: name
40566
40715
  });
40716
+ dropTransportRejectedKeys({
40717
+ converted,
40718
+ isStdio,
40719
+ serverName: name
40720
+ });
40567
40721
  const previousName = originalNames.get(codexName);
40568
40722
  if (previousName !== void 0) warnWithFallback(void 0, `Codex MCP server name collision: "${previousName}" and "${name}" both normalize to "${codexName}"; "${name}" (processed last) overwrites "${previousName}".`);
40569
40723
  originalNames.set(codexName, name);
@@ -67784,10 +67938,15 @@ var TaktPermissions = class TaktPermissions extends ToolPermissions {
67784
67938
  outputRoot,
67785
67939
  logger
67786
67940
  });
67941
+ const inheritedProvider = global ? void 0 : await readGlobalTaktProvider({
67942
+ projectFilePath: filePath,
67943
+ logger
67944
+ });
67787
67945
  const rulesyncJson = rulesyncPermissions.getJson();
67788
67946
  const provider = resolveActiveProvider({
67789
67947
  config,
67790
- runtime: runtime.active ? runtime.config : void 0
67948
+ runtime: runtime.active ? runtime.config : void 0,
67949
+ inheritedProvider
67791
67950
  });
67792
67951
  const mode = deriveTaktPermissionMode(rulesyncJson);
67793
67952
  const override = isPlainObject$1(rulesyncJson.takt) ? rulesyncJson.takt : void 0;
@@ -67897,10 +68056,12 @@ var TaktPermissions = class TaktPermissions extends ToolPermissions {
67897
68056
  * `provider_profiles` (unless that key is the pre-0.68.0 `claude` fallback),
67898
68057
  * else the `claude-sdk` default (Takt 0.68.0+).
67899
68058
  */
67900
- function resolveActiveProvider({ config, runtime }) {
68059
+ function resolveActiveProvider({ config, runtime, inheritedProvider }) {
67901
68060
  const fromRuntime = runtime === void 0 ? void 0 : resolveRuntimeProvider(runtime);
67902
68061
  if (fromRuntime !== void 0) return fromRuntime;
67903
- if (typeof config[TAKT_PROVIDER_KEY] === "string" && config[TAKT_PROVIDER_KEY].trim() !== "") return config[TAKT_PROVIDER_KEY];
68062
+ const local = readProviderName(config);
68063
+ if (local !== void 0) return local;
68064
+ if (inheritedProvider !== void 0) return inheritedProvider;
67904
68065
  const profiles = config[TAKT_PROVIDER_PROFILES_KEY];
67905
68066
  if (isPlainObject$1(profiles)) {
67906
68067
  const keys = Object.keys(profiles);
@@ -67908,6 +68069,43 @@ function resolveActiveProvider({ config, runtime }) {
67908
68069
  }
67909
68070
  return TAKT_DEFAULT_PROVIDER;
67910
68071
  }
68072
+ /**
68073
+ * The top-level `provider:` of a Takt `config.yaml`, when it names one: either
68074
+ * the plain name or the block form `provider: { type: <name>, ... }` Takt also
68075
+ * accepts (`ConfigProviderReference`).
68076
+ */
68077
+ function readProviderName(config) {
68078
+ const raw = config[TAKT_PROVIDER_KEY];
68079
+ const provider = isPlainObject$1(raw) ? raw.type : raw;
68080
+ return typeof provider === "string" && provider.trim() !== "" ? provider : void 0;
68081
+ }
68082
+ /**
68083
+ * The top-level `provider:` of the global `~/.takt/config.yaml`, read for a
68084
+ * project-scope generate. An unresolvable home directory, a missing or
68085
+ * unparsable file, or one that names no provider all mean "nothing inherited".
68086
+ */
68087
+ async function readGlobalTaktProvider({ projectFilePath, logger }) {
68088
+ let globalPath;
68089
+ try {
68090
+ globalPath = join(getHomeDirectory(), TAKT_DIR, TAKT_CONFIG_FILE_NAME);
68091
+ } catch {
68092
+ return;
68093
+ }
68094
+ if (globalPath === projectFilePath) return;
68095
+ try {
68096
+ const content = await readFileContentOrNull(globalPath);
68097
+ if (content === null) return;
68098
+ return readProviderName(parseSharedConfig({
68099
+ format: "yaml",
68100
+ fileContent: content,
68101
+ filePath: globalPath,
68102
+ invalidRootPolicy: "error"
68103
+ }));
68104
+ } catch (error) {
68105
+ logger?.warn(`Takt permissions: could not read the provider from ${globalPath} (${formatError(error)}); falling back to the project config alone.`);
68106
+ return;
68107
+ }
68108
+ }
67911
68109
  /** A plain object carrying at least one entry (Takt's "assignment" test). */
67912
68110
  function hasEntries(value) {
67913
68111
  return isPlainObject$1(value) && Object.keys(value).length > 0;
@@ -101329,4 +101527,4 @@ async function importChecksCore(params) {
101329
101527
  //#endregion
101330
101528
  export { RulesyncHooks as $, removeFile as $t, groupSpellingsByCaseFoldedIdentity as A, RULESYNC_RELATIVE_DIR_PATH as An, applyFileMode as At, QWENCODE_LOCAL_RULE_FILE_NAME as B, DEPRECATED_FEATURE_REPLACEMENTS as Bn, getFileSize as Bt, COMMANDCODE_SETTINGS_LOCAL_FILE_NAME as C, RULESYNC_IGNORE_RELATIVE_FILE_PATH as Cn, fallbackLogger as Ct, FACTORYDROID_DIR as D, RULESYNC_NPM_SOURCES_LOCK_RELATIVE_FILE_PATH as Dn, withWarnOnceScope as Dt, ChecksProcessor as E, RULESYNC_MCP_SCHEMA_URL as En, resetRunWarningState as Et, CLAUDECODE_LOCAL_RULE_FILE_NAME as F, RULESYNC_USER_CONFIG_DIR_NAME as Fn, createTempDirectory as Ft, RulesyncSubagentFrontmatterSchema as G, quoteForLog as Gn, listDirectoryEntryNames as Gt, AUGMENTCODE_SETTINGS_LOCAL_FILE_NAME as H, truncateText as Hn, isFileNotFoundError as Ht, CLAUDECODE_MEMORIES_DIR_NAME as I, RULESYNC_XDG_CONFIG_HOME_DEFAULT_DIR_NAME as In, directoryExists as It, RulesyncRule as J, stripHiddenCharacters as Jn, pathEscapesRoot as Jt, RulesyncSkill as K, stripControlCharacters as Kn, listFilePathsRecursively as Kt, CLAUDECODE_SETTINGS_LOCAL_FILE_NAME as L, parseCommaSeparatedList as Ln, ensureDir as Lt, CODEXCLI_DIR as M, RULESYNC_SKILLS_RELATIVE_DIR_PATH as Mn, assertTreeContainsNoSymlinks as Mt, CLAUDECODE_AGENT_MEMORY_LOCAL_DIR_NAME as N, RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH as Nn, assertWritablePathInsideRoot as Nt, FACTORYDROID_SETTINGS_LOCAL_FILE_NAME as O, RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH as On, CLIError as Ot, CLAUDECODE_DIR as P, RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH as Pn, checkPathTraversal as Pt, RulesyncIgnore as Q, removeDirectoryStrict as Qt, CLAUDECODE_SKILLS_DIR_PATH as R, ALL_FEATURES as Rn, fileExists as Rt, COMMANDCODE_DIR as S, RULESYNC_HOOKS_RELATIVE_FILE_PATH as Sn, WarningCollectingLogger as St, CODEBUDDY_LOCAL_RULE_FILE_NAME as T, RULESYNC_MCP_RELATIVE_FILE_PATH as Tn, withFallbackLoggerTarget as Tt, getLocalSkillDirNames as U, hasDeceptiveHiddenCharacters as Un, isFileSystemError as Ut, AUGMENTCODE_DIR as V, formatError as Vn, getHomeDirectory as Vt, RulesyncSubagent as W, hasEnclosingMarkOutsideKeycap as Wn, isSymlink as Wt, RulesyncPermissions as X, readFileContentOrNull as Xt, RulesyncRuleFrontmatterSchema as Y, readFileContent as Yt, RulesyncMcp as Z, removeDirectory as Zt, LETTACODE_DIR as _, RULESYNC_COMMANDS_RELATIVE_DIR_PATH as _n, SourceEntrySchema as _t, getProcessorRegistryEntry as a, toPosixPath as an, RulesyncCheck as at, CommandsProcessor as b, RULESYNC_CURATED_RULES_RELATIVE_DIR_PATH as bn, ConsoleLogger as bt, RulesProcessor as c, ALL_TOOL_TARGETS as cn, loadYaml as ct, ELLIPSIS_WIDTH as d, ToolTargetSchema as dn, ConfigResolver as dt, removeFileStrict as en, getRulesyncSourceCandidates as et, displayWidthOf as f, CURATED_RULES_FEATURE_SUBDIR as fn, mergeInputRootConfigs as ft, HooksProcessor as g, RULESYNC_CHECKS_RELATIVE_DIR_PATH as gn, GITIGNORE_DESTINATION_KEY as gt, IgnoreProcessor as h, RULESYNC_AIIGNORE_RELATIVE_FILE_PATH as hn, ConfigFileSchema as ht, inspectInputRoots as i, splitPathSegments as in, RulesyncCommandFrontmatterSchema as it, CODEXCLI_BASH_RULES_FILE_NAME as j, RULESYNC_RULES_RELATIVE_DIR_PATH as jn, assertDirectoryIfExists as jt, caseFoldIdentity as k, RULESYNC_PERMISSIONS_SCHEMA_URL as kn, ErrorCodes as kt, SubagentsProcessor as l, ALL_TOOL_TARGETS_WITH_WILDCARD as ln, SHARED_USER_MANAGED_CONFIG_PATHS as lt, McpProcessor as m, MAX_FILE_SIZE as mn, CONFLICTING_TARGET_PAIRS as mt, formatSourceLoadFailure as n, resolvePath as nn, parseJsonc as nt, convertFromTool as o, writeFileBuffer as on, RulesyncCheckFrontmatterSchema as ot, shortenToWidth as p, FEATURE_SOURCE_TREE_ENTRIES as pn, resolveEffectiveInputRoots as pt, RulesyncSkillFrontmatterSchema as q, stripControlCharactersKeepingLineFeeds as qn, listSubdirectoryNames as qt, generate as r, runWithDirectoryRollback as rn, RulesyncCommand as rt, isPackagingToolTarget as s, writeFileContent as sn, stringifyFrontmatter as st, importFromTool as t, removeTempDirectory as tn, resolveRulesyncSourceWritePath as tt, SkillsProcessor as u, PACKAGING_TOOL_TARGETS as un, SKILL_FILE_NAME as ut, LETTACODE_SETTINGS_LOCAL_FILE_NAME as v, RULESYNC_CONFIG_RELATIVE_FILE_PATH as vn, assertTargetsFeaturesExclusive as vt, CODEBUDDY_DIR as w, RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH as wn, warnOnConflictingFlags as wt, REASONIX_LOCAL_RULE_FILE_NAME as x, RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH as xn, JsonLogger as xt, CRUSH_LOCAL_RULE_FILE_NAME as y, RULESYNC_CONFIG_SCHEMA_URL as yn, findControlCharacter as yt, QWENCODE_DIR as z, ALL_FEATURES_WITH_WILDCARD as zn, findFilesByGlobs as zt };
101331
101529
 
101332
- //# sourceMappingURL=import-DBd2G6Eo.js.map
101530
+ //# sourceMappingURL=import-ORYbMDJK.js.map