rulesync 8.5.0 → 8.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-Q5FDY7NL.js → chunk-ILMHM7BF.js} +479 -271
- package/dist/cli/index.cjs +444 -236
- package/dist/cli/index.js +2 -2
- package/dist/index.cjs +372 -162
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/cli/index.cjs
CHANGED
|
@@ -21288,15 +21288,156 @@ function mapBashActionToDecision(action) {
|
|
|
21288
21288
|
|
|
21289
21289
|
// src/features/permissions/geminicli-permissions.ts
|
|
21290
21290
|
var import_node_path139 = require("path");
|
|
21291
|
+
var smolToml6 = __toESM(require("smol-toml"), 1);
|
|
21291
21292
|
var import_mini72 = require("zod/mini");
|
|
21292
|
-
|
|
21293
|
-
|
|
21294
|
-
|
|
21295
|
-
|
|
21296
|
-
|
|
21297
|
-
|
|
21298
|
-
|
|
21299
|
-
|
|
21293
|
+
|
|
21294
|
+
// src/utils/logger.ts
|
|
21295
|
+
var BaseLogger = class {
|
|
21296
|
+
_verbose = false;
|
|
21297
|
+
_silent = false;
|
|
21298
|
+
constructor({ verbose = false, silent = false } = {}) {
|
|
21299
|
+
this._silent = silent;
|
|
21300
|
+
this._verbose = verbose && !silent;
|
|
21301
|
+
}
|
|
21302
|
+
get verbose() {
|
|
21303
|
+
return this._verbose;
|
|
21304
|
+
}
|
|
21305
|
+
get silent() {
|
|
21306
|
+
return this._silent;
|
|
21307
|
+
}
|
|
21308
|
+
configure({ verbose, silent }) {
|
|
21309
|
+
if (verbose && silent) {
|
|
21310
|
+
this._silent = false;
|
|
21311
|
+
if (!isEnvTest()) {
|
|
21312
|
+
this.onConflictingFlags();
|
|
21313
|
+
}
|
|
21314
|
+
}
|
|
21315
|
+
this._silent = silent;
|
|
21316
|
+
this._verbose = verbose && !silent;
|
|
21317
|
+
}
|
|
21318
|
+
onConflictingFlags() {
|
|
21319
|
+
console.warn("Both --verbose and --silent specified; --silent takes precedence");
|
|
21320
|
+
}
|
|
21321
|
+
};
|
|
21322
|
+
var ConsoleLogger = class extends BaseLogger {
|
|
21323
|
+
isSuppressed() {
|
|
21324
|
+
return isEnvTest() || this._silent;
|
|
21325
|
+
}
|
|
21326
|
+
get jsonMode() {
|
|
21327
|
+
return false;
|
|
21328
|
+
}
|
|
21329
|
+
captureData(_key, _value) {
|
|
21330
|
+
}
|
|
21331
|
+
getJsonData() {
|
|
21332
|
+
return {};
|
|
21333
|
+
}
|
|
21334
|
+
outputJson(_success, _error) {
|
|
21335
|
+
}
|
|
21336
|
+
info(message, ...args) {
|
|
21337
|
+
if (this.isSuppressed()) return;
|
|
21338
|
+
console.log(message, ...args);
|
|
21339
|
+
}
|
|
21340
|
+
success(message, ...args) {
|
|
21341
|
+
if (this.isSuppressed()) return;
|
|
21342
|
+
console.log(message, ...args);
|
|
21343
|
+
}
|
|
21344
|
+
warn(message, ...args) {
|
|
21345
|
+
if (this.isSuppressed()) return;
|
|
21346
|
+
console.warn(message, ...args);
|
|
21347
|
+
}
|
|
21348
|
+
// Errors are always emitted, even in silent mode
|
|
21349
|
+
error(message, _code, ...args) {
|
|
21350
|
+
if (isEnvTest()) return;
|
|
21351
|
+
const errorMessage = message instanceof Error ? message.message : message;
|
|
21352
|
+
console.error(errorMessage, ...args);
|
|
21353
|
+
}
|
|
21354
|
+
debug(message, ...args) {
|
|
21355
|
+
if (!this._verbose || this.isSuppressed()) return;
|
|
21356
|
+
console.log(message, ...args);
|
|
21357
|
+
}
|
|
21358
|
+
};
|
|
21359
|
+
var JsonLogger = class extends BaseLogger {
|
|
21360
|
+
_jsonOutputDone = false;
|
|
21361
|
+
_jsonData = {};
|
|
21362
|
+
_commandName;
|
|
21363
|
+
_version;
|
|
21364
|
+
constructor({
|
|
21365
|
+
command,
|
|
21366
|
+
version,
|
|
21367
|
+
verbose = false,
|
|
21368
|
+
silent = false
|
|
21369
|
+
}) {
|
|
21370
|
+
super({ verbose, silent });
|
|
21371
|
+
this._commandName = command;
|
|
21372
|
+
this._version = version;
|
|
21373
|
+
}
|
|
21374
|
+
// Suppress raw console.warn in JSON mode to avoid non-JSON text on stderr
|
|
21375
|
+
onConflictingFlags() {
|
|
21376
|
+
}
|
|
21377
|
+
get jsonMode() {
|
|
21378
|
+
return true;
|
|
21379
|
+
}
|
|
21380
|
+
captureData(key, value) {
|
|
21381
|
+
this._jsonData[key] = value;
|
|
21382
|
+
}
|
|
21383
|
+
getJsonData() {
|
|
21384
|
+
return { ...this._jsonData };
|
|
21385
|
+
}
|
|
21386
|
+
outputJson(success, error) {
|
|
21387
|
+
if (this._jsonOutputDone) return;
|
|
21388
|
+
this._jsonOutputDone = true;
|
|
21389
|
+
const output = {
|
|
21390
|
+
success,
|
|
21391
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
21392
|
+
command: this._commandName,
|
|
21393
|
+
version: this._version
|
|
21394
|
+
};
|
|
21395
|
+
if (success) {
|
|
21396
|
+
output.data = this._jsonData;
|
|
21397
|
+
} else if (error) {
|
|
21398
|
+
output.error = {
|
|
21399
|
+
code: error.code,
|
|
21400
|
+
message: error.message
|
|
21401
|
+
};
|
|
21402
|
+
if (error.details) {
|
|
21403
|
+
output.error.details = error.details;
|
|
21404
|
+
}
|
|
21405
|
+
if (error.stack) {
|
|
21406
|
+
output.error.stack = error.stack;
|
|
21407
|
+
}
|
|
21408
|
+
}
|
|
21409
|
+
const jsonStr = JSON.stringify(output, null, 2);
|
|
21410
|
+
if (success) {
|
|
21411
|
+
console.log(jsonStr);
|
|
21412
|
+
} else {
|
|
21413
|
+
console.error(jsonStr);
|
|
21414
|
+
}
|
|
21415
|
+
}
|
|
21416
|
+
info(_message, ..._args) {
|
|
21417
|
+
}
|
|
21418
|
+
success(_message, ..._args) {
|
|
21419
|
+
}
|
|
21420
|
+
warn(_message, ..._args) {
|
|
21421
|
+
}
|
|
21422
|
+
error(message, code, ..._args) {
|
|
21423
|
+
if (isEnvTest()) return;
|
|
21424
|
+
const errorMessage = message instanceof Error ? message.message : message;
|
|
21425
|
+
const errorInfo = {
|
|
21426
|
+
code: code || ErrorCodes.UNKNOWN_ERROR,
|
|
21427
|
+
message: errorMessage
|
|
21428
|
+
};
|
|
21429
|
+
if (this._verbose && message instanceof Error && message.stack) {
|
|
21430
|
+
errorInfo.stack = message.stack;
|
|
21431
|
+
}
|
|
21432
|
+
this.outputJson(false, errorInfo);
|
|
21433
|
+
}
|
|
21434
|
+
debug(_message, ..._args) {
|
|
21435
|
+
}
|
|
21436
|
+
};
|
|
21437
|
+
|
|
21438
|
+
// src/features/permissions/geminicli-permissions.ts
|
|
21439
|
+
var GEMINICLI_POLICY_RELATIVE_DIR_PATH = (0, import_node_path139.join)(".gemini", "policies");
|
|
21440
|
+
var GEMINICLI_POLICY_FILE_NAME = "rulesync.toml";
|
|
21300
21441
|
var RULESYNC_TO_GEMINICLI_TOOL_NAME = {
|
|
21301
21442
|
bash: "run_shell_command",
|
|
21302
21443
|
read: "read_file",
|
|
@@ -21304,16 +21445,32 @@ var RULESYNC_TO_GEMINICLI_TOOL_NAME = {
|
|
|
21304
21445
|
write: "write_file",
|
|
21305
21446
|
webfetch: "web_fetch"
|
|
21306
21447
|
};
|
|
21448
|
+
var GEMINICLI_TO_RULESYNC_TOOL_NAME = Object.fromEntries(
|
|
21449
|
+
Object.entries(RULESYNC_TO_GEMINICLI_TOOL_NAME).map(([k, v]) => [v, k])
|
|
21450
|
+
);
|
|
21451
|
+
var PRIORITY_DENY = 1e6;
|
|
21452
|
+
var PRIORITY_ASK = 1e3;
|
|
21453
|
+
var PRIORITY_ALLOW = 1;
|
|
21454
|
+
var SINGLE_STAR_REGEX = '[^/\\"]*';
|
|
21455
|
+
var DOUBLE_STAR_REGEX = '[^\\"]*';
|
|
21456
|
+
var SINGLE_CHAR_REGEX = '[^/\\"]';
|
|
21457
|
+
var LEGACY_SINGLE_STAR_REGEX = '[^\\"]*';
|
|
21458
|
+
var LEGACY_DOUBLE_STAR_REGEX = ".*";
|
|
21459
|
+
var COMMAND_ARGS_ANCHOR = '"command":"';
|
|
21460
|
+
var VALUE_END_ANCHOR = '\\"';
|
|
21461
|
+
var RESERVED_OBJECT_KEYS = /* @__PURE__ */ new Set([
|
|
21462
|
+
"__proto__",
|
|
21463
|
+
"constructor",
|
|
21464
|
+
"prototype"
|
|
21465
|
+
]);
|
|
21466
|
+
var moduleLogger = new ConsoleLogger();
|
|
21307
21467
|
var GeminicliPermissions = class _GeminicliPermissions extends ToolPermissions {
|
|
21308
21468
|
static getSettablePaths(_options = {}) {
|
|
21309
21469
|
return {
|
|
21310
|
-
relativeDirPath:
|
|
21311
|
-
relativeFilePath:
|
|
21470
|
+
relativeDirPath: GEMINICLI_POLICY_RELATIVE_DIR_PATH,
|
|
21471
|
+
relativeFilePath: GEMINICLI_POLICY_FILE_NAME
|
|
21312
21472
|
};
|
|
21313
21473
|
}
|
|
21314
|
-
isDeletable() {
|
|
21315
|
-
return false;
|
|
21316
|
-
}
|
|
21317
21474
|
static async fromFile({
|
|
21318
21475
|
baseDir = process.cwd(),
|
|
21319
21476
|
validate = true,
|
|
@@ -21321,7 +21478,7 @@ var GeminicliPermissions = class _GeminicliPermissions extends ToolPermissions {
|
|
|
21321
21478
|
}) {
|
|
21322
21479
|
const paths = this.getSettablePaths({ global });
|
|
21323
21480
|
const filePath = (0, import_node_path139.join)(baseDir, paths.relativeDirPath, paths.relativeFilePath);
|
|
21324
|
-
const fileContent = await readFileContentOrNull(filePath) ??
|
|
21481
|
+
const fileContent = await readFileContentOrNull(filePath) ?? "";
|
|
21325
21482
|
return new _GeminicliPermissions({
|
|
21326
21483
|
baseDir,
|
|
21327
21484
|
relativeDirPath: paths.relativeDirPath,
|
|
@@ -21330,63 +21487,72 @@ var GeminicliPermissions = class _GeminicliPermissions extends ToolPermissions {
|
|
|
21330
21487
|
validate
|
|
21331
21488
|
});
|
|
21332
21489
|
}
|
|
21333
|
-
static
|
|
21490
|
+
static fromRulesyncPermissions({
|
|
21334
21491
|
baseDir = process.cwd(),
|
|
21335
21492
|
rulesyncPermissions,
|
|
21336
21493
|
validate = true,
|
|
21337
|
-
|
|
21338
|
-
|
|
21494
|
+
global = false,
|
|
21495
|
+
logger: logger5 = moduleLogger
|
|
21339
21496
|
}) {
|
|
21340
21497
|
const paths = this.getSettablePaths({ global });
|
|
21341
|
-
const
|
|
21342
|
-
const existingContent = await readFileContentOrNull(filePath) ?? JSON.stringify({}, null, 2);
|
|
21343
|
-
const settingsResult = GeminiCliSettingsSchema.safeParse(JSON.parse(existingContent));
|
|
21344
|
-
if (!settingsResult.success) {
|
|
21345
|
-
throw new Error(
|
|
21346
|
-
`Failed to parse existing Gemini CLI settings at ${filePath}: ${formatError(settingsResult.error)}`
|
|
21347
|
-
);
|
|
21348
|
-
}
|
|
21349
|
-
const { allowed, exclude } = convertRulesyncToGeminicliTools({
|
|
21350
|
-
config: rulesyncPermissions.getJson(),
|
|
21351
|
-
logger: logger5
|
|
21352
|
-
});
|
|
21353
|
-
const merged = {
|
|
21354
|
-
...settingsResult.data,
|
|
21355
|
-
tools: {
|
|
21356
|
-
...settingsResult.data.tools,
|
|
21357
|
-
...allowed.length > 0 ? { allowed } : {},
|
|
21358
|
-
...exclude.length > 0 ? { exclude } : {}
|
|
21359
|
-
}
|
|
21360
|
-
};
|
|
21498
|
+
const fileContent = buildGeminicliPolicyContent(rulesyncPermissions.getJson(), logger5);
|
|
21361
21499
|
return new _GeminicliPermissions({
|
|
21362
21500
|
baseDir,
|
|
21363
21501
|
relativeDirPath: paths.relativeDirPath,
|
|
21364
21502
|
relativeFilePath: paths.relativeFilePath,
|
|
21365
|
-
fileContent
|
|
21503
|
+
fileContent,
|
|
21366
21504
|
validate
|
|
21367
21505
|
});
|
|
21368
21506
|
}
|
|
21369
21507
|
toRulesyncPermissions() {
|
|
21370
|
-
let settings;
|
|
21371
|
-
try {
|
|
21372
|
-
const parsed = JSON.parse(this.getFileContent());
|
|
21373
|
-
settings = GeminiCliSettingsSchema.parse(parsed);
|
|
21374
|
-
} catch (error) {
|
|
21375
|
-
throw new Error(
|
|
21376
|
-
`Failed to parse Gemini CLI permissions content in ${(0, import_node_path139.join)(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${formatError(error)}`,
|
|
21377
|
-
{ cause: error }
|
|
21378
|
-
);
|
|
21379
|
-
}
|
|
21380
21508
|
const permission = {};
|
|
21381
|
-
|
|
21382
|
-
|
|
21383
|
-
|
|
21384
|
-
|
|
21385
|
-
|
|
21386
|
-
|
|
21387
|
-
|
|
21388
|
-
|
|
21389
|
-
|
|
21509
|
+
const fileContent = this.getFileContent();
|
|
21510
|
+
if (fileContent.trim().length > 0) {
|
|
21511
|
+
let parsed;
|
|
21512
|
+
try {
|
|
21513
|
+
parsed = smolToml6.parse(fileContent);
|
|
21514
|
+
} catch (error) {
|
|
21515
|
+
throw new Error(
|
|
21516
|
+
`Failed to parse Gemini CLI policy TOML in ${(0, import_node_path139.join)(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${formatError(error)}`,
|
|
21517
|
+
{ cause: error }
|
|
21518
|
+
);
|
|
21519
|
+
}
|
|
21520
|
+
const rules = extractRules(parsed, moduleLogger);
|
|
21521
|
+
for (const [index, rule] of rules.entries()) {
|
|
21522
|
+
const mappedCategory = Object.hasOwn(GEMINICLI_TO_RULESYNC_TOOL_NAME, rule.toolName) ? GEMINICLI_TO_RULESYNC_TOOL_NAME[rule.toolName] : void 0;
|
|
21523
|
+
const category = mappedCategory ?? rule.toolName;
|
|
21524
|
+
if (RESERVED_OBJECT_KEYS.has(category)) {
|
|
21525
|
+
moduleLogger.warn(
|
|
21526
|
+
`Skipping rule #${index} in ${this.getRelativeFilePath()}: toolName "${rule.toolName}" maps to a reserved object key ("${category}") and would risk prototype pollution.`
|
|
21527
|
+
);
|
|
21528
|
+
continue;
|
|
21529
|
+
}
|
|
21530
|
+
const action = mapFromGeminicliDecision(rule.decision);
|
|
21531
|
+
if (!action) {
|
|
21532
|
+
moduleLogger.warn(
|
|
21533
|
+
`Skipping rule #${index} (toolName="${rule.toolName}", commandPrefix=${JSON.stringify(rule.commandPrefix)}, argsPattern=${JSON.stringify(rule.argsPattern)}) in ${this.getRelativeFilePath()}: unknown decision ${JSON.stringify(rule.decision)}`
|
|
21534
|
+
);
|
|
21535
|
+
continue;
|
|
21536
|
+
}
|
|
21537
|
+
if (rule.toolName === "run_shell_command" && rule.commandPrefix !== void 0 && rule.argsPattern !== void 0) {
|
|
21538
|
+
moduleLogger.warn(
|
|
21539
|
+
`Rule #${index} in ${this.getRelativeFilePath()} sets both commandPrefix and argsPattern; rulesync will honor argsPattern and ignore commandPrefix=${JSON.stringify(rule.commandPrefix)}.`
|
|
21540
|
+
);
|
|
21541
|
+
}
|
|
21542
|
+
const pattern = extractPattern(rule);
|
|
21543
|
+
if (RESERVED_OBJECT_KEYS.has(pattern)) {
|
|
21544
|
+
moduleLogger.warn(
|
|
21545
|
+
`Skipping rule #${index} in ${this.getRelativeFilePath()}: pattern "${pattern}" is a reserved object key.`
|
|
21546
|
+
);
|
|
21547
|
+
continue;
|
|
21548
|
+
}
|
|
21549
|
+
const existing = Object.hasOwn(permission, category) ? permission[category] : void 0;
|
|
21550
|
+
const target = existing ?? {};
|
|
21551
|
+
if (existing === void 0) {
|
|
21552
|
+
permission[category] = target;
|
|
21553
|
+
}
|
|
21554
|
+
target[pattern] = action;
|
|
21555
|
+
}
|
|
21390
21556
|
}
|
|
21391
21557
|
return this.toRulesyncPermissionsDefault({
|
|
21392
21558
|
fileContent: JSON.stringify({ permission }, null, 2)
|
|
@@ -21404,50 +21570,238 @@ var GeminicliPermissions = class _GeminicliPermissions extends ToolPermissions {
|
|
|
21404
21570
|
baseDir,
|
|
21405
21571
|
relativeDirPath,
|
|
21406
21572
|
relativeFilePath,
|
|
21407
|
-
fileContent:
|
|
21573
|
+
fileContent: "",
|
|
21408
21574
|
validate: false
|
|
21409
21575
|
});
|
|
21410
21576
|
}
|
|
21411
21577
|
};
|
|
21412
|
-
function
|
|
21413
|
-
|
|
21414
|
-
|
|
21415
|
-
|
|
21416
|
-
const allowed = [];
|
|
21417
|
-
const exclude = [];
|
|
21418
|
-
for (const [toolName, rules] of Object.entries(config.permission)) {
|
|
21578
|
+
function buildGeminicliPolicyContent(config, logger5) {
|
|
21579
|
+
const rules = [];
|
|
21580
|
+
let order = 0;
|
|
21581
|
+
for (const [toolName, entries] of Object.entries(config.permission)) {
|
|
21419
21582
|
const mappedToolName = RULESYNC_TO_GEMINICLI_TOOL_NAME[toolName] ?? toolName;
|
|
21420
|
-
|
|
21421
|
-
|
|
21422
|
-
|
|
21423
|
-
|
|
21424
|
-
if (action === "ask") {
|
|
21425
|
-
logger5?.warn(
|
|
21426
|
-
`Gemini CLI does not support explicit "ask" rules in settings. Skipping ${toolName}:${pattern}`
|
|
21583
|
+
for (const [pattern, action] of Object.entries(entries)) {
|
|
21584
|
+
if (pattern === "") {
|
|
21585
|
+
logger5.warn(
|
|
21586
|
+
`Skipping rule "${toolName}: "": empty pattern is not a valid permission target and would silently match every invocation (bash) or nothing (other tools).`
|
|
21427
21587
|
);
|
|
21428
21588
|
continue;
|
|
21429
21589
|
}
|
|
21430
|
-
|
|
21431
|
-
|
|
21432
|
-
|
|
21433
|
-
|
|
21434
|
-
|
|
21590
|
+
if (hasUnsafeAnchorChar(pattern)) {
|
|
21591
|
+
logger5.warn(
|
|
21592
|
+
`Skipping rule "${toolName}: ${pattern}": pattern contains a character (" or \\) that would break JSON-anchor matching in the Gemini CLI Policy Engine.`
|
|
21593
|
+
);
|
|
21594
|
+
continue;
|
|
21595
|
+
}
|
|
21596
|
+
const decision = mapToGeminicliDecision(action);
|
|
21597
|
+
if (mappedToolName === "run_shell_command" && (pattern === "*" || pattern === "**") && decision !== "ask_user") {
|
|
21598
|
+
logger5.warn(
|
|
21599
|
+
`Skipping rule "${toolName}: ${pattern}" with decision ${decision}: bash match-all patterns are only supported with "ask" because they would otherwise affect every shell command.`
|
|
21600
|
+
);
|
|
21601
|
+
continue;
|
|
21602
|
+
}
|
|
21603
|
+
const currentRule = {
|
|
21604
|
+
toolName: mappedToolName,
|
|
21605
|
+
decision,
|
|
21606
|
+
priority: priorityForDecision(decision)
|
|
21607
|
+
};
|
|
21608
|
+
if (mappedToolName === "run_shell_command") {
|
|
21609
|
+
applyShellPattern({ rule: currentRule, pattern, toolName, logger: logger5 });
|
|
21610
|
+
} else if (pattern !== "*") {
|
|
21611
|
+
currentRule.argsPattern = buildNonShellArgsPattern(pattern);
|
|
21435
21612
|
}
|
|
21613
|
+
rules.push({ rule: currentRule, order: order++ });
|
|
21436
21614
|
}
|
|
21437
21615
|
}
|
|
21438
|
-
|
|
21616
|
+
rules.sort((a, b) => {
|
|
21617
|
+
const diff = toNumber(b.rule.priority) - toNumber(a.rule.priority);
|
|
21618
|
+
return diff !== 0 ? diff : a.order - b.order;
|
|
21619
|
+
});
|
|
21620
|
+
return smolToml6.stringify({ rule: rules.map((entry) => entry.rule) });
|
|
21439
21621
|
}
|
|
21440
|
-
function
|
|
21441
|
-
|
|
21442
|
-
|
|
21443
|
-
|
|
21444
|
-
|
|
21445
|
-
|
|
21446
|
-
|
|
21447
|
-
return
|
|
21448
|
-
|
|
21449
|
-
|
|
21450
|
-
|
|
21622
|
+
function buildNonShellArgsPattern(pattern) {
|
|
21623
|
+
return `"${globPatternToRegex(pattern)}${VALUE_END_ANCHOR}`;
|
|
21624
|
+
}
|
|
21625
|
+
function hasUnsafeAnchorChar(pattern) {
|
|
21626
|
+
return pattern.includes('"') || pattern.includes("\\");
|
|
21627
|
+
}
|
|
21628
|
+
function toNumber(value) {
|
|
21629
|
+
return typeof value === "number" ? value : 0;
|
|
21630
|
+
}
|
|
21631
|
+
function applyShellPattern({
|
|
21632
|
+
rule,
|
|
21633
|
+
pattern,
|
|
21634
|
+
toolName,
|
|
21635
|
+
logger: logger5
|
|
21636
|
+
}) {
|
|
21637
|
+
if (pattern === "*") {
|
|
21638
|
+
return;
|
|
21639
|
+
}
|
|
21640
|
+
const trailingWildcardStripped = pattern.endsWith(" *") ? pattern.slice(0, -2) : pattern;
|
|
21641
|
+
if (hasGlobMetacharacter(trailingWildcardStripped)) {
|
|
21642
|
+
rule.argsPattern = `${COMMAND_ARGS_ANCHOR}${globPatternToRegex(pattern)}`;
|
|
21643
|
+
logger5.warn(
|
|
21644
|
+
`Gemini CLI does not support glob metacharacters inside a bash command prefix; emitting argsPattern for rule "${toolName}: ${pattern}".`
|
|
21645
|
+
);
|
|
21646
|
+
return;
|
|
21647
|
+
}
|
|
21648
|
+
rule.commandPrefix = trailingWildcardStripped;
|
|
21649
|
+
}
|
|
21650
|
+
function hasGlobMetacharacter(pattern) {
|
|
21651
|
+
return /[*?[\]]/.test(pattern);
|
|
21652
|
+
}
|
|
21653
|
+
function priorityForDecision(decision) {
|
|
21654
|
+
if (decision === "deny") return PRIORITY_DENY;
|
|
21655
|
+
if (decision === "ask_user") return PRIORITY_ASK;
|
|
21656
|
+
return PRIORITY_ALLOW;
|
|
21657
|
+
}
|
|
21658
|
+
function mapToGeminicliDecision(action) {
|
|
21659
|
+
if (action === "ask") {
|
|
21660
|
+
return "ask_user";
|
|
21661
|
+
}
|
|
21662
|
+
return action;
|
|
21663
|
+
}
|
|
21664
|
+
function mapFromGeminicliDecision(decision) {
|
|
21665
|
+
if (decision === "allow") return "allow";
|
|
21666
|
+
if (decision === "deny") return "deny";
|
|
21667
|
+
if (decision === "ask_user") return "ask";
|
|
21668
|
+
return null;
|
|
21669
|
+
}
|
|
21670
|
+
function globPatternToRegex(pattern) {
|
|
21671
|
+
let regex = "";
|
|
21672
|
+
let i = 0;
|
|
21673
|
+
while (i < pattern.length) {
|
|
21674
|
+
const char = pattern[i];
|
|
21675
|
+
if (char === void 0) {
|
|
21676
|
+
break;
|
|
21677
|
+
}
|
|
21678
|
+
if (char === "*" && pattern[i + 1] === "*") {
|
|
21679
|
+
regex += DOUBLE_STAR_REGEX;
|
|
21680
|
+
i += 2;
|
|
21681
|
+
continue;
|
|
21682
|
+
}
|
|
21683
|
+
if (char === "*") {
|
|
21684
|
+
regex += SINGLE_STAR_REGEX;
|
|
21685
|
+
i += 1;
|
|
21686
|
+
continue;
|
|
21687
|
+
}
|
|
21688
|
+
if (char === "?") {
|
|
21689
|
+
regex += SINGLE_CHAR_REGEX;
|
|
21690
|
+
i += 1;
|
|
21691
|
+
continue;
|
|
21692
|
+
}
|
|
21693
|
+
if (char === "[") {
|
|
21694
|
+
regex += escapeRegexChar(char);
|
|
21695
|
+
i += 1;
|
|
21696
|
+
continue;
|
|
21697
|
+
}
|
|
21698
|
+
if (char === "]") {
|
|
21699
|
+
regex += escapeRegexChar(char);
|
|
21700
|
+
i += 1;
|
|
21701
|
+
continue;
|
|
21702
|
+
}
|
|
21703
|
+
if (isRegexMetacharacter(char)) {
|
|
21704
|
+
regex += `\\${char}`;
|
|
21705
|
+
i += 1;
|
|
21706
|
+
continue;
|
|
21707
|
+
}
|
|
21708
|
+
regex += char;
|
|
21709
|
+
i += 1;
|
|
21710
|
+
}
|
|
21711
|
+
return regex;
|
|
21712
|
+
}
|
|
21713
|
+
function escapeRegexChar(char) {
|
|
21714
|
+
return `\\${char}`;
|
|
21715
|
+
}
|
|
21716
|
+
function isRegexMetacharacter(char) {
|
|
21717
|
+
return /[.+^${}()|\\]/.test(char);
|
|
21718
|
+
}
|
|
21719
|
+
function regexToGlobPattern(regex) {
|
|
21720
|
+
let source = regex;
|
|
21721
|
+
if (source.endsWith(VALUE_END_ANCHOR)) {
|
|
21722
|
+
source = source.slice(0, -VALUE_END_ANCHOR.length);
|
|
21723
|
+
}
|
|
21724
|
+
let glob = "";
|
|
21725
|
+
let i = 0;
|
|
21726
|
+
while (i < source.length) {
|
|
21727
|
+
if (source.startsWith(DOUBLE_STAR_REGEX, i)) {
|
|
21728
|
+
glob += "**";
|
|
21729
|
+
i += DOUBLE_STAR_REGEX.length;
|
|
21730
|
+
continue;
|
|
21731
|
+
}
|
|
21732
|
+
if (source.startsWith(LEGACY_DOUBLE_STAR_REGEX, i)) {
|
|
21733
|
+
glob += "**";
|
|
21734
|
+
i += LEGACY_DOUBLE_STAR_REGEX.length;
|
|
21735
|
+
continue;
|
|
21736
|
+
}
|
|
21737
|
+
if (source.startsWith(SINGLE_STAR_REGEX, i)) {
|
|
21738
|
+
glob += "*";
|
|
21739
|
+
i += SINGLE_STAR_REGEX.length;
|
|
21740
|
+
continue;
|
|
21741
|
+
}
|
|
21742
|
+
if (source.startsWith(LEGACY_SINGLE_STAR_REGEX, i)) {
|
|
21743
|
+
glob += "*";
|
|
21744
|
+
i += LEGACY_SINGLE_STAR_REGEX.length;
|
|
21745
|
+
continue;
|
|
21746
|
+
}
|
|
21747
|
+
if (source.startsWith(SINGLE_CHAR_REGEX, i)) {
|
|
21748
|
+
glob += "?";
|
|
21749
|
+
i += SINGLE_CHAR_REGEX.length;
|
|
21750
|
+
continue;
|
|
21751
|
+
}
|
|
21752
|
+
const char = source[i];
|
|
21753
|
+
if (char === "\\") {
|
|
21754
|
+
const escaped = source[i + 1];
|
|
21755
|
+
if (escaped !== void 0) {
|
|
21756
|
+
glob += escaped;
|
|
21757
|
+
i += 2;
|
|
21758
|
+
continue;
|
|
21759
|
+
}
|
|
21760
|
+
}
|
|
21761
|
+
glob += char ?? "";
|
|
21762
|
+
i += 1;
|
|
21763
|
+
}
|
|
21764
|
+
return glob;
|
|
21765
|
+
}
|
|
21766
|
+
var GeminicliPolicyRuleSchema = import_mini72.z.looseObject({
|
|
21767
|
+
toolName: import_mini72.z.string(),
|
|
21768
|
+
decision: import_mini72.z.optional(import_mini72.z.unknown()),
|
|
21769
|
+
commandPrefix: import_mini72.z.optional(import_mini72.z.string()),
|
|
21770
|
+
argsPattern: import_mini72.z.optional(import_mini72.z.string())
|
|
21771
|
+
});
|
|
21772
|
+
var GeminicliPolicyFileSchema = import_mini72.z.looseObject({
|
|
21773
|
+
rule: import_mini72.z.optional(import_mini72.z.array(import_mini72.z.looseObject({})))
|
|
21774
|
+
});
|
|
21775
|
+
function extractRules(parsed, logger5) {
|
|
21776
|
+
const parsedFile = GeminicliPolicyFileSchema.safeParse(parsed);
|
|
21777
|
+
if (!parsedFile.success || !parsedFile.data.rule) {
|
|
21778
|
+
return [];
|
|
21779
|
+
}
|
|
21780
|
+
const rules = [];
|
|
21781
|
+
for (const [index, entry] of parsedFile.data.rule.entries()) {
|
|
21782
|
+
const result = GeminicliPolicyRuleSchema.safeParse(entry);
|
|
21783
|
+
if (result.success) {
|
|
21784
|
+
rules.push(result.data);
|
|
21785
|
+
continue;
|
|
21786
|
+
}
|
|
21787
|
+
logger5.warn(
|
|
21788
|
+
`Skipping malformed Gemini CLI policy rule at index ${index}: ${formatError(result.error)}`
|
|
21789
|
+
);
|
|
21790
|
+
}
|
|
21791
|
+
return rules;
|
|
21792
|
+
}
|
|
21793
|
+
function extractPattern(rule) {
|
|
21794
|
+
if (rule.toolName === "run_shell_command") {
|
|
21795
|
+
if (rule.argsPattern) {
|
|
21796
|
+
const stripped = rule.argsPattern.startsWith(COMMAND_ARGS_ANCHOR) ? rule.argsPattern.slice(COMMAND_ARGS_ANCHOR.length) : rule.argsPattern;
|
|
21797
|
+
return regexToGlobPattern(stripped);
|
|
21798
|
+
}
|
|
21799
|
+
if (!rule.commandPrefix) return "*";
|
|
21800
|
+
return rule.commandPrefix.endsWith(" *") || rule.commandPrefix.endsWith("*") ? rule.commandPrefix : `${rule.commandPrefix} *`;
|
|
21801
|
+
}
|
|
21802
|
+
if (!rule.argsPattern) return "*";
|
|
21803
|
+
const regex = rule.argsPattern.startsWith('"') ? rule.argsPattern.slice(1) : rule.argsPattern;
|
|
21804
|
+
return regexToGlobPattern(regex);
|
|
21451
21805
|
}
|
|
21452
21806
|
|
|
21453
21807
|
// src/features/permissions/kiro-permissions.ts
|
|
@@ -24361,152 +24715,6 @@ var import_mini85 = require("zod/mini");
|
|
|
24361
24715
|
// src/mcp/commands.ts
|
|
24362
24716
|
var import_node_path148 = require("path");
|
|
24363
24717
|
var import_mini77 = require("zod/mini");
|
|
24364
|
-
|
|
24365
|
-
// src/utils/logger.ts
|
|
24366
|
-
var BaseLogger = class {
|
|
24367
|
-
_verbose = false;
|
|
24368
|
-
_silent = false;
|
|
24369
|
-
constructor({ verbose = false, silent = false } = {}) {
|
|
24370
|
-
this._silent = silent;
|
|
24371
|
-
this._verbose = verbose && !silent;
|
|
24372
|
-
}
|
|
24373
|
-
get verbose() {
|
|
24374
|
-
return this._verbose;
|
|
24375
|
-
}
|
|
24376
|
-
get silent() {
|
|
24377
|
-
return this._silent;
|
|
24378
|
-
}
|
|
24379
|
-
configure({ verbose, silent }) {
|
|
24380
|
-
if (verbose && silent) {
|
|
24381
|
-
this._silent = false;
|
|
24382
|
-
if (!isEnvTest()) {
|
|
24383
|
-
this.onConflictingFlags();
|
|
24384
|
-
}
|
|
24385
|
-
}
|
|
24386
|
-
this._silent = silent;
|
|
24387
|
-
this._verbose = verbose && !silent;
|
|
24388
|
-
}
|
|
24389
|
-
onConflictingFlags() {
|
|
24390
|
-
console.warn("Both --verbose and --silent specified; --silent takes precedence");
|
|
24391
|
-
}
|
|
24392
|
-
};
|
|
24393
|
-
var ConsoleLogger = class extends BaseLogger {
|
|
24394
|
-
isSuppressed() {
|
|
24395
|
-
return isEnvTest() || this._silent;
|
|
24396
|
-
}
|
|
24397
|
-
get jsonMode() {
|
|
24398
|
-
return false;
|
|
24399
|
-
}
|
|
24400
|
-
captureData(_key, _value) {
|
|
24401
|
-
}
|
|
24402
|
-
getJsonData() {
|
|
24403
|
-
return {};
|
|
24404
|
-
}
|
|
24405
|
-
outputJson(_success, _error) {
|
|
24406
|
-
}
|
|
24407
|
-
info(message, ...args) {
|
|
24408
|
-
if (this.isSuppressed()) return;
|
|
24409
|
-
console.log(message, ...args);
|
|
24410
|
-
}
|
|
24411
|
-
success(message, ...args) {
|
|
24412
|
-
if (this.isSuppressed()) return;
|
|
24413
|
-
console.log(message, ...args);
|
|
24414
|
-
}
|
|
24415
|
-
warn(message, ...args) {
|
|
24416
|
-
if (this.isSuppressed()) return;
|
|
24417
|
-
console.warn(message, ...args);
|
|
24418
|
-
}
|
|
24419
|
-
// Errors are always emitted, even in silent mode
|
|
24420
|
-
error(message, _code, ...args) {
|
|
24421
|
-
if (isEnvTest()) return;
|
|
24422
|
-
const errorMessage = message instanceof Error ? message.message : message;
|
|
24423
|
-
console.error(errorMessage, ...args);
|
|
24424
|
-
}
|
|
24425
|
-
debug(message, ...args) {
|
|
24426
|
-
if (!this._verbose || this.isSuppressed()) return;
|
|
24427
|
-
console.log(message, ...args);
|
|
24428
|
-
}
|
|
24429
|
-
};
|
|
24430
|
-
var JsonLogger = class extends BaseLogger {
|
|
24431
|
-
_jsonOutputDone = false;
|
|
24432
|
-
_jsonData = {};
|
|
24433
|
-
_commandName;
|
|
24434
|
-
_version;
|
|
24435
|
-
constructor({
|
|
24436
|
-
command,
|
|
24437
|
-
version,
|
|
24438
|
-
verbose = false,
|
|
24439
|
-
silent = false
|
|
24440
|
-
}) {
|
|
24441
|
-
super({ verbose, silent });
|
|
24442
|
-
this._commandName = command;
|
|
24443
|
-
this._version = version;
|
|
24444
|
-
}
|
|
24445
|
-
// Suppress raw console.warn in JSON mode to avoid non-JSON text on stderr
|
|
24446
|
-
onConflictingFlags() {
|
|
24447
|
-
}
|
|
24448
|
-
get jsonMode() {
|
|
24449
|
-
return true;
|
|
24450
|
-
}
|
|
24451
|
-
captureData(key, value) {
|
|
24452
|
-
this._jsonData[key] = value;
|
|
24453
|
-
}
|
|
24454
|
-
getJsonData() {
|
|
24455
|
-
return { ...this._jsonData };
|
|
24456
|
-
}
|
|
24457
|
-
outputJson(success, error) {
|
|
24458
|
-
if (this._jsonOutputDone) return;
|
|
24459
|
-
this._jsonOutputDone = true;
|
|
24460
|
-
const output = {
|
|
24461
|
-
success,
|
|
24462
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
24463
|
-
command: this._commandName,
|
|
24464
|
-
version: this._version
|
|
24465
|
-
};
|
|
24466
|
-
if (success) {
|
|
24467
|
-
output.data = this._jsonData;
|
|
24468
|
-
} else if (error) {
|
|
24469
|
-
output.error = {
|
|
24470
|
-
code: error.code,
|
|
24471
|
-
message: error.message
|
|
24472
|
-
};
|
|
24473
|
-
if (error.details) {
|
|
24474
|
-
output.error.details = error.details;
|
|
24475
|
-
}
|
|
24476
|
-
if (error.stack) {
|
|
24477
|
-
output.error.stack = error.stack;
|
|
24478
|
-
}
|
|
24479
|
-
}
|
|
24480
|
-
const jsonStr = JSON.stringify(output, null, 2);
|
|
24481
|
-
if (success) {
|
|
24482
|
-
console.log(jsonStr);
|
|
24483
|
-
} else {
|
|
24484
|
-
console.error(jsonStr);
|
|
24485
|
-
}
|
|
24486
|
-
}
|
|
24487
|
-
info(_message, ..._args) {
|
|
24488
|
-
}
|
|
24489
|
-
success(_message, ..._args) {
|
|
24490
|
-
}
|
|
24491
|
-
warn(_message, ..._args) {
|
|
24492
|
-
}
|
|
24493
|
-
error(message, code, ..._args) {
|
|
24494
|
-
if (isEnvTest()) return;
|
|
24495
|
-
const errorMessage = message instanceof Error ? message.message : message;
|
|
24496
|
-
const errorInfo = {
|
|
24497
|
-
code: code || ErrorCodes.UNKNOWN_ERROR,
|
|
24498
|
-
message: errorMessage
|
|
24499
|
-
};
|
|
24500
|
-
if (this._verbose && message instanceof Error && message.stack) {
|
|
24501
|
-
errorInfo.stack = message.stack;
|
|
24502
|
-
}
|
|
24503
|
-
this.outputJson(false, errorInfo);
|
|
24504
|
-
}
|
|
24505
|
-
debug(_message, ..._args) {
|
|
24506
|
-
}
|
|
24507
|
-
};
|
|
24508
|
-
|
|
24509
|
-
// src/mcp/commands.ts
|
|
24510
24718
|
var logger = new ConsoleLogger({ verbose: false, silent: true });
|
|
24511
24719
|
var maxCommandSizeBytes = 1024 * 1024;
|
|
24512
24720
|
var maxCommandsCount = 1e3;
|
|
@@ -26362,7 +26570,7 @@ function wrapCommand({
|
|
|
26362
26570
|
}
|
|
26363
26571
|
|
|
26364
26572
|
// src/cli/index.ts
|
|
26365
|
-
var getVersion = () => "8.
|
|
26573
|
+
var getVersion = () => "8.6.0";
|
|
26366
26574
|
function wrapCommand2(name, errorCode, handler) {
|
|
26367
26575
|
return wrapCommand({ name, errorCode, handler, getVersion });
|
|
26368
26576
|
}
|