rulesync 14.0.1 → 14.1.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/README.md +1 -1
- package/dist/cli/index.cjs +19 -8
- package/dist/cli/index.js +19 -8
- package/dist/cli/index.js.map +1 -1
- package/dist/{import-CSnC5vl7.js → import-BN4K49Ta.js} +300 -35
- package/dist/import-BN4K49Ta.js.map +1 -0
- package/dist/{import-Dh9PCQKq.cjs → import-CDKxRD_F.cjs} +324 -47
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/import-CSnC5vl7.js.map +0 -1
|
@@ -30,6 +30,7 @@ const ALL_FEATURES_WITH_WILDCARD = [...ALL_FEATURES, "*"];
|
|
|
30
30
|
const FeatureSchema = z.enum(ALL_FEATURES);
|
|
31
31
|
z.array(FeatureSchema);
|
|
32
32
|
const GitignoreDestinationSchema = z.enum(["gitignore", "gitattributes"]);
|
|
33
|
+
const FlattenedCommandNamingSchema = z.enum(["basename", "path"]);
|
|
33
34
|
const FeatureOptionsSchema = z.record(z.string(), z.unknown());
|
|
34
35
|
const FeatureValueSchema = z.union([
|
|
35
36
|
z.boolean(),
|
|
@@ -322,6 +323,7 @@ const hooksProcessorToolTargetTuple = [
|
|
|
322
323
|
"copilot",
|
|
323
324
|
"copilotcli",
|
|
324
325
|
"opencode",
|
|
326
|
+
"pi",
|
|
325
327
|
"factorydroid",
|
|
326
328
|
"goose",
|
|
327
329
|
"hermesagent",
|
|
@@ -695,16 +697,9 @@ var BaseLogger = class {
|
|
|
695
697
|
return this._silent;
|
|
696
698
|
}
|
|
697
699
|
configure({ verbose, silent }) {
|
|
698
|
-
if (verbose && silent) {
|
|
699
|
-
this._silent = false;
|
|
700
|
-
if (!isEnvTest()) this.onConflictingFlags();
|
|
701
|
-
}
|
|
702
700
|
this._silent = silent;
|
|
703
701
|
this._verbose = verbose && !silent;
|
|
704
702
|
}
|
|
705
|
-
onConflictingFlags() {
|
|
706
|
-
console.warn("Both --verbose and --silent specified; --silent takes precedence");
|
|
707
|
-
}
|
|
708
703
|
};
|
|
709
704
|
/**
|
|
710
705
|
* ConsoleLogger - human-readable terminal output
|
|
@@ -761,7 +756,6 @@ var JsonLogger = class extends BaseLogger {
|
|
|
761
756
|
this._commandName = command;
|
|
762
757
|
this._version = version;
|
|
763
758
|
}
|
|
764
|
-
onConflictingFlags() {}
|
|
765
759
|
get jsonMode() {
|
|
766
760
|
return true;
|
|
767
761
|
}
|
|
@@ -809,17 +803,32 @@ var JsonLogger = class extends BaseLogger {
|
|
|
809
803
|
debug(_message, ..._args) {}
|
|
810
804
|
};
|
|
811
805
|
/**
|
|
806
|
+
* Warn once when both `--verbose` and `--silent` were passed on the command
|
|
807
|
+
* line. Called at CLI-flag parsing time only (`wrapCommand`), so re-configuring
|
|
808
|
+
* a logger from config-file values never re-triggers it. Suppressed in JSON
|
|
809
|
+
* mode to keep non-JSON text off stderr, matching the former JsonLogger
|
|
810
|
+
* behavior.
|
|
811
|
+
*/
|
|
812
|
+
function warnOnConflictingFlags({ verbose, silent, jsonMode }) {
|
|
813
|
+
if (!verbose || !silent || jsonMode || isEnvTest()) return;
|
|
814
|
+
console.warn("Both --verbose and --silent specified; --silent takes precedence");
|
|
815
|
+
}
|
|
816
|
+
/**
|
|
817
|
+
* Shared fallback logger for code paths that have no command logger threaded
|
|
818
|
+
* through (module-level translators, `warnWithFallback(undefined, ...)`).
|
|
819
|
+
* `wrapCommand` configures it from CLI flags and `ConfigResolver.resolve`
|
|
820
|
+
* re-configures it from the resolved config, so `silent`/`verbose` settings
|
|
821
|
+
* are honored even on paths where the command logger is not available.
|
|
822
|
+
*/
|
|
823
|
+
const fallbackLogger = new ConsoleLogger();
|
|
824
|
+
/**
|
|
812
825
|
* Emit a warning through `logger.warn` if a logger is supplied, otherwise
|
|
813
|
-
* fall through to `
|
|
814
|
-
* pattern so call sites stay terse and
|
|
815
|
-
*
|
|
826
|
+
* fall through to the shared `fallbackLogger`. Centralizes the "logger may
|
|
827
|
+
* be optional" pattern so call sites stay terse and the fallback honors the
|
|
828
|
+
* configured `silent` mode.
|
|
816
829
|
*/
|
|
817
830
|
function warnWithFallback(logger, message) {
|
|
818
|
-
|
|
819
|
-
logger.warn(message);
|
|
820
|
-
return;
|
|
821
|
-
}
|
|
822
|
-
console.warn(message);
|
|
831
|
+
(logger ?? fallbackLogger).warn(message);
|
|
823
832
|
}
|
|
824
833
|
//#endregion
|
|
825
834
|
//#region src/utils/validation.ts
|
|
@@ -887,6 +896,7 @@ const ConfigParamsSchema = z.object({
|
|
|
887
896
|
simulateCommands: optional(z.boolean()),
|
|
888
897
|
simulateSubagents: optional(z.boolean()),
|
|
889
898
|
simulateSkills: optional(z.boolean()),
|
|
899
|
+
flattenedCommandNaming: optional(FlattenedCommandNamingSchema),
|
|
890
900
|
gitignoreTargetsOnly: optional(z.boolean()),
|
|
891
901
|
gitignoreDestination: optional(GitignoreDestinationSchema),
|
|
892
902
|
dryRun: optional(z.boolean()),
|
|
@@ -964,13 +974,14 @@ var Config = class Config {
|
|
|
964
974
|
simulateCommands;
|
|
965
975
|
simulateSubagents;
|
|
966
976
|
simulateSkills;
|
|
977
|
+
flattenedCommandNaming;
|
|
967
978
|
gitignoreTargetsOnly;
|
|
968
979
|
gitignoreDestination;
|
|
969
980
|
dryRun;
|
|
970
981
|
check;
|
|
971
982
|
inputRoot;
|
|
972
983
|
sources;
|
|
973
|
-
constructor({ outputRoots, targets, features, verbose, delete: isDelete, global, silent, simulateCommands, simulateSubagents, simulateSkills, gitignoreTargetsOnly, gitignoreDestination, dryRun, check, inputRoot, sources, configFileTargets }) {
|
|
984
|
+
constructor({ outputRoots, targets, features, verbose, delete: isDelete, global, silent, simulateCommands, simulateSubagents, simulateSkills, flattenedCommandNaming, gitignoreTargetsOnly, gitignoreDestination, dryRun, check, inputRoot, sources, configFileTargets }) {
|
|
974
985
|
assertTargetsFeaturesExclusive({
|
|
975
986
|
targets,
|
|
976
987
|
features
|
|
@@ -997,6 +1008,7 @@ var Config = class Config {
|
|
|
997
1008
|
this.simulateCommands = simulateCommands ?? false;
|
|
998
1009
|
this.simulateSubagents = simulateSubagents ?? false;
|
|
999
1010
|
this.simulateSkills = simulateSkills ?? false;
|
|
1011
|
+
this.flattenedCommandNaming = flattenedCommandNaming ?? "basename";
|
|
1000
1012
|
this.gitignoreTargetsOnly = gitignoreTargetsOnly ?? true;
|
|
1001
1013
|
this.gitignoreDestination = gitignoreDestination ?? "gitignore";
|
|
1002
1014
|
this.dryRun = dryRun ?? false;
|
|
@@ -1165,6 +1177,9 @@ var Config = class Config {
|
|
|
1165
1177
|
getSimulateCommands() {
|
|
1166
1178
|
return this.simulateCommands;
|
|
1167
1179
|
}
|
|
1180
|
+
getFlattenedCommandNaming() {
|
|
1181
|
+
return this.flattenedCommandNaming;
|
|
1182
|
+
}
|
|
1168
1183
|
getSimulateSubagents() {
|
|
1169
1184
|
return this.simulateSubagents;
|
|
1170
1185
|
}
|
|
@@ -1217,6 +1232,7 @@ const getDefaults = () => ({
|
|
|
1217
1232
|
simulateCommands: false,
|
|
1218
1233
|
simulateSubagents: false,
|
|
1219
1234
|
simulateSkills: false,
|
|
1235
|
+
flattenedCommandNaming: "basename",
|
|
1220
1236
|
gitignoreTargetsOnly: true,
|
|
1221
1237
|
gitignoreDestination: "gitignore",
|
|
1222
1238
|
dryRun: false,
|
|
@@ -1246,6 +1262,7 @@ const mergeConfigs = (baseConfig, localConfig) => {
|
|
|
1246
1262
|
simulateCommands: localConfig.simulateCommands ?? baseConfig.simulateCommands,
|
|
1247
1263
|
simulateSubagents: localConfig.simulateSubagents ?? baseConfig.simulateSubagents,
|
|
1248
1264
|
simulateSkills: localConfig.simulateSkills ?? baseConfig.simulateSkills,
|
|
1265
|
+
flattenedCommandNaming: localConfig.flattenedCommandNaming ?? baseConfig.flattenedCommandNaming,
|
|
1249
1266
|
gitignoreTargetsOnly: localConfig.gitignoreTargetsOnly ?? baseConfig.gitignoreTargetsOnly,
|
|
1250
1267
|
gitignoreDestination: localConfig.gitignoreDestination ?? baseConfig.gitignoreDestination,
|
|
1251
1268
|
dryRun: localConfig.dryRun ?? baseConfig.dryRun,
|
|
@@ -1324,6 +1341,26 @@ var ConfigResolver = class {
|
|
|
1324
1341
|
validatedConfigPath,
|
|
1325
1342
|
localConfigPath
|
|
1326
1343
|
});
|
|
1344
|
+
const resolvedVerbose = pick({
|
|
1345
|
+
cli: verbose,
|
|
1346
|
+
file: configByFile.verbose,
|
|
1347
|
+
fallback: getDefaults().verbose
|
|
1348
|
+
});
|
|
1349
|
+
const resolvedSilent = pick({
|
|
1350
|
+
cli: silent,
|
|
1351
|
+
file: configByFile.silent,
|
|
1352
|
+
fallback: getDefaults().silent
|
|
1353
|
+
});
|
|
1354
|
+
if (logger !== void 0) {
|
|
1355
|
+
logger.configure({
|
|
1356
|
+
verbose: resolvedVerbose,
|
|
1357
|
+
silent: resolvedSilent
|
|
1358
|
+
});
|
|
1359
|
+
fallbackLogger.configure({
|
|
1360
|
+
verbose: resolvedVerbose,
|
|
1361
|
+
silent: resolvedSilent
|
|
1362
|
+
});
|
|
1363
|
+
}
|
|
1327
1364
|
const resolvedInputRoot = inputRoot ?? configByFile.inputRoot;
|
|
1328
1365
|
const resolvedGlobal = resolveGlobal({
|
|
1329
1366
|
logger,
|
|
@@ -1340,11 +1377,7 @@ var ConfigResolver = class {
|
|
|
1340
1377
|
return new Config({
|
|
1341
1378
|
targets: resolvedTargets,
|
|
1342
1379
|
features: resolvedFeatures,
|
|
1343
|
-
verbose:
|
|
1344
|
-
cli: verbose,
|
|
1345
|
-
file: configByFile.verbose,
|
|
1346
|
-
fallback: getDefaults().verbose
|
|
1347
|
-
}),
|
|
1380
|
+
verbose: resolvedVerbose,
|
|
1348
1381
|
delete: pick({
|
|
1349
1382
|
cli: isDelete,
|
|
1350
1383
|
file: configByFile.delete,
|
|
@@ -1359,11 +1392,7 @@ var ConfigResolver = class {
|
|
|
1359
1392
|
global: resolvedGlobal
|
|
1360
1393
|
}),
|
|
1361
1394
|
global: resolvedGlobal,
|
|
1362
|
-
silent:
|
|
1363
|
-
cli: silent,
|
|
1364
|
-
file: configByFile.silent,
|
|
1365
|
-
fallback: getDefaults().silent
|
|
1366
|
-
}),
|
|
1395
|
+
silent: resolvedSilent,
|
|
1367
1396
|
simulateCommands: pick({
|
|
1368
1397
|
cli: simulateCommands,
|
|
1369
1398
|
file: configByFile.simulateCommands,
|
|
@@ -1401,6 +1430,7 @@ var ConfigResolver = class {
|
|
|
1401
1430
|
}),
|
|
1402
1431
|
inputRoot: resolvedInputRoot !== void 0 ? resolve(resolvedInputRoot) : cwd,
|
|
1403
1432
|
sources: configByFile.sources ?? getDefaults().sources,
|
|
1433
|
+
flattenedCommandNaming: configByFile.flattenedCommandNaming ?? getDefaults().flattenedCommandNaming,
|
|
1404
1434
|
configFileTargets: extractConfigFileTargets(configByFile.targets)
|
|
1405
1435
|
});
|
|
1406
1436
|
}
|
|
@@ -5232,12 +5262,15 @@ var OpenCodeCommand = class OpenCodeCommand extends ToolCommand {
|
|
|
5232
5262
|
}
|
|
5233
5263
|
};
|
|
5234
5264
|
const PI_AGENT_DIR = join(".pi", "agent");
|
|
5265
|
+
const PI_AGENT_EXTENSIONS_DIR_PATH = join(PI_AGENT_DIR, "extensions");
|
|
5235
5266
|
const PI_AGENT_PROMPTS_DIR_PATH = join(PI_AGENT_DIR, "prompts");
|
|
5236
5267
|
const PI_AGENT_SKILLS_DIR_PATH = join(PI_AGENT_DIR, "skills");
|
|
5268
|
+
const PI_EXTENSIONS_DIR_PATH = join(".pi", "extensions");
|
|
5237
5269
|
const PI_PROMPTS_DIR_PATH = join(".pi", "prompts");
|
|
5238
5270
|
const PI_SKILLS_DIR_PATH = join(".pi", "skills");
|
|
5239
5271
|
const PI_RULE_FILE_NAME = "AGENTS.md";
|
|
5240
5272
|
const PI_APPEND_SYSTEM_FILE_NAME = "APPEND_SYSTEM.md";
|
|
5273
|
+
const PI_HOOKS_FILE_NAME = "rulesync-hooks.ts";
|
|
5241
5274
|
//#endregion
|
|
5242
5275
|
//#region src/features/commands/pi-command.ts
|
|
5243
5276
|
/**
|
|
@@ -6415,7 +6448,8 @@ var CommandsProcessor = class extends FeatureProcessor {
|
|
|
6415
6448
|
toolTarget;
|
|
6416
6449
|
global;
|
|
6417
6450
|
getFactory;
|
|
6418
|
-
|
|
6451
|
+
flattenedCommandNaming;
|
|
6452
|
+
constructor({ outputRoot = process.cwd(), inputRoot = process.cwd(), toolTarget, global = false, getFactory = defaultGetFactory$5, dryRun = false, flattenedCommandNaming = "basename", logger }) {
|
|
6419
6453
|
super({
|
|
6420
6454
|
outputRoot,
|
|
6421
6455
|
inputRoot,
|
|
@@ -6427,6 +6461,7 @@ var CommandsProcessor = class extends FeatureProcessor {
|
|
|
6427
6461
|
this.toolTarget = result.data;
|
|
6428
6462
|
this.global = global;
|
|
6429
6463
|
this.getFactory = getFactory;
|
|
6464
|
+
this.flattenedCommandNaming = flattenedCommandNaming;
|
|
6430
6465
|
}
|
|
6431
6466
|
async convertRulesyncFilesToToolFiles(rulesyncFiles) {
|
|
6432
6467
|
const rulesyncCommands = rulesyncFiles.filter((file) => file instanceof RulesyncCommand);
|
|
@@ -6463,8 +6498,9 @@ var CommandsProcessor = class extends FeatureProcessor {
|
|
|
6463
6498
|
});
|
|
6464
6499
|
}
|
|
6465
6500
|
flattenRelativeFilePath(rulesyncCommand) {
|
|
6466
|
-
const
|
|
6467
|
-
|
|
6501
|
+
const relativeFilePath = rulesyncCommand.getRelativeFilePath();
|
|
6502
|
+
const flatPath = this.flattenedCommandNaming === "path" ? toPosixPath(relativeFilePath).split("/").join("-") : basename(relativeFilePath);
|
|
6503
|
+
if (flatPath === relativeFilePath) return rulesyncCommand;
|
|
6468
6504
|
return rulesyncCommand.withRelativeFilePath(flatPath);
|
|
6469
6505
|
}
|
|
6470
6506
|
safeRelativePath(basePath, fullPath) {
|
|
@@ -6790,6 +6826,26 @@ const OPENCODE_HOOK_EVENTS = [
|
|
|
6790
6826
|
/** Hook events supported by Kilo. (Currently identical to OpenCode) */
|
|
6791
6827
|
const KILO_HOOK_EVENTS = OPENCODE_HOOK_EVENTS;
|
|
6792
6828
|
/**
|
|
6829
|
+
* Hook events supported by Pi Coding Agent, bridged through a generated
|
|
6830
|
+
* TypeScript extension (Pi has no static hook config file; its extension API
|
|
6831
|
+
* exposes lifecycle events instead).
|
|
6832
|
+
*
|
|
6833
|
+
* Only canonical events with a semantically faithful Pi extension event are
|
|
6834
|
+
* listed; see CANONICAL_TO_PI_EVENT_NAMES for the mapping.
|
|
6835
|
+
*
|
|
6836
|
+
* @see https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/docs/extensions.md
|
|
6837
|
+
*/
|
|
6838
|
+
const PI_HOOK_EVENTS = [
|
|
6839
|
+
"sessionStart",
|
|
6840
|
+
"sessionEnd",
|
|
6841
|
+
"preToolUse",
|
|
6842
|
+
"postToolUse",
|
|
6843
|
+
"preModelInvocation",
|
|
6844
|
+
"beforeSubmitPrompt",
|
|
6845
|
+
"stop",
|
|
6846
|
+
"preCompact"
|
|
6847
|
+
];
|
|
6848
|
+
/**
|
|
6793
6849
|
* Hook events supported by GitHub Copilot (cloud coding agent).
|
|
6794
6850
|
*
|
|
6795
6851
|
* GitHub now documents an eight-event surface for `.github/hooks/*.json`:
|
|
@@ -7189,6 +7245,7 @@ const HooksConfigSchema = z.looseObject({
|
|
|
7189
7245
|
copilotcli: z.optional(z.looseObject({ hooks: z.optional(hooksRecordSchema) })),
|
|
7190
7246
|
opencode: z.optional(z.looseObject({ hooks: z.optional(hooksRecordSchema) })),
|
|
7191
7247
|
kilo: z.optional(z.looseObject({ hooks: z.optional(hooksRecordSchema) })),
|
|
7248
|
+
pi: z.optional(z.looseObject({ hooks: z.optional(hooksRecordSchema) })),
|
|
7192
7249
|
factorydroid: z.optional(z.looseObject({ hooks: z.optional(hooksRecordSchema) })),
|
|
7193
7250
|
codexcli: z.optional(z.looseObject({ hooks: z.optional(hooksRecordSchema) })),
|
|
7194
7251
|
goose: z.optional(z.looseObject({ hooks: z.optional(hooksRecordSchema) })),
|
|
@@ -7369,6 +7426,31 @@ const CANONICAL_TO_OPENCODE_EVENT_NAMES = {
|
|
|
7369
7426
|
*/
|
|
7370
7427
|
const CANONICAL_TO_KILO_EVENT_NAMES = CANONICAL_TO_OPENCODE_EVENT_NAMES;
|
|
7371
7428
|
/**
|
|
7429
|
+
* Map canonical camelCase event names to Pi Coding Agent extension event
|
|
7430
|
+
* names (snake_case).
|
|
7431
|
+
*
|
|
7432
|
+
* Mapping notes: `sessionEnd` → `session_shutdown` (fires on session
|
|
7433
|
+
* teardown), `beforeSubmitPrompt` → `input` (user input interception),
|
|
7434
|
+
* `preModelInvocation` → `context` (fires before each LLM call), and
|
|
7435
|
+
* `stop` → `agent_end` (agent finished responding; unlike Claude Code's
|
|
7436
|
+
* Stop, this also fires before Pi auto-retries or auto-compacts —
|
|
7437
|
+
* `agent_settled` would skip queued follow-ups instead, a pure trade-off).
|
|
7438
|
+
* Pi events without a faithful canonical counterpart (e.g. `turn_start`,
|
|
7439
|
+
* `agent_settled`) are intentionally unmapped.
|
|
7440
|
+
*
|
|
7441
|
+
* @see https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/docs/extensions.md
|
|
7442
|
+
*/
|
|
7443
|
+
const CANONICAL_TO_PI_EVENT_NAMES = {
|
|
7444
|
+
sessionStart: "session_start",
|
|
7445
|
+
sessionEnd: "session_shutdown",
|
|
7446
|
+
preToolUse: "tool_call",
|
|
7447
|
+
postToolUse: "tool_result",
|
|
7448
|
+
preModelInvocation: "context",
|
|
7449
|
+
beforeSubmitPrompt: "input",
|
|
7450
|
+
stop: "agent_end",
|
|
7451
|
+
preCompact: "session_before_compact"
|
|
7452
|
+
};
|
|
7453
|
+
/**
|
|
7372
7454
|
* Map canonical camelCase event names to Copilot camelCase.
|
|
7373
7455
|
*/
|
|
7374
7456
|
const CANONICAL_TO_COPILOT_EVENT_NAMES = {
|
|
@@ -10799,6 +10881,176 @@ var OpencodeHooks = class OpencodeHooks extends ToolHooks {
|
|
|
10799
10881
|
}
|
|
10800
10882
|
};
|
|
10801
10883
|
//#endregion
|
|
10884
|
+
//#region src/features/hooks/pi-extension-generator.ts
|
|
10885
|
+
/**
|
|
10886
|
+
* Pi extension events fired per tool invocation; handlers for these receive
|
|
10887
|
+
* `event.toolName` and honor the canonical hook `matcher` as a regex on it.
|
|
10888
|
+
*/
|
|
10889
|
+
const PI_TOOL_EVENTS = /* @__PURE__ */ new Set(["tool_call", "tool_result"]);
|
|
10890
|
+
/**
|
|
10891
|
+
* Validate a hook matcher as a regular expression and return it as a JS
|
|
10892
|
+
* string-literal (JSON.stringify quoting) safe to embed in generated code.
|
|
10893
|
+
*/
|
|
10894
|
+
function matcherToEmbeddedLiteral(matcher) {
|
|
10895
|
+
let sanitized = matcher;
|
|
10896
|
+
for (const char of CONTROL_CHARS) sanitized = sanitized.replaceAll(char, "");
|
|
10897
|
+
if (sanitized === "*") sanitized = ".*";
|
|
10898
|
+
try {
|
|
10899
|
+
new RegExp(sanitized);
|
|
10900
|
+
} catch {
|
|
10901
|
+
throw new Error(`Invalid regex pattern in hook matcher: ${sanitized}`);
|
|
10902
|
+
}
|
|
10903
|
+
return JSON.stringify(sanitized);
|
|
10904
|
+
}
|
|
10905
|
+
function collectPiHandlers({ effectiveHooks, eventMap }) {
|
|
10906
|
+
const handlerGroups = {};
|
|
10907
|
+
for (const [canonicalEvent, definitions] of Object.entries(effectiveHooks)) {
|
|
10908
|
+
const piEvent = eventMap[canonicalEvent];
|
|
10909
|
+
if (!piEvent) continue;
|
|
10910
|
+
const handlers = [];
|
|
10911
|
+
for (const def of definitions) {
|
|
10912
|
+
if ((def.type ?? "command") !== "command") continue;
|
|
10913
|
+
if (!def.command) continue;
|
|
10914
|
+
handlers.push({
|
|
10915
|
+
command: def.command,
|
|
10916
|
+
matcher: def.matcher ? def.matcher : void 0
|
|
10917
|
+
});
|
|
10918
|
+
}
|
|
10919
|
+
if (handlers.length > 0) {
|
|
10920
|
+
const existing = handlerGroups[piEvent];
|
|
10921
|
+
if (existing) existing.push(...handlers);
|
|
10922
|
+
else handlerGroups[piEvent] = handlers;
|
|
10923
|
+
}
|
|
10924
|
+
}
|
|
10925
|
+
return handlerGroups;
|
|
10926
|
+
}
|
|
10927
|
+
function buildSubscriptionLines(handlerGroups) {
|
|
10928
|
+
const lines = [];
|
|
10929
|
+
for (const [piEvent, handlers] of Object.entries(handlerGroups)) {
|
|
10930
|
+
const usesToolName = PI_TOOL_EVENTS.has(piEvent) && handlers.some((h) => h.matcher);
|
|
10931
|
+
lines.push(` pi.on(${JSON.stringify(piEvent)}, async (${usesToolName ? "event" : ""}) => {`);
|
|
10932
|
+
for (const handler of handlers) {
|
|
10933
|
+
const embeddedCommand = JSON.stringify(handler.command);
|
|
10934
|
+
if (usesToolName && handler.matcher) {
|
|
10935
|
+
lines.push(` if (new RegExp(${matcherToEmbeddedLiteral(handler.matcher)}).test(event.toolName)) {`);
|
|
10936
|
+
lines.push(` await run(${embeddedCommand});`);
|
|
10937
|
+
lines.push(" }");
|
|
10938
|
+
} else lines.push(` await run(${embeddedCommand});`);
|
|
10939
|
+
}
|
|
10940
|
+
lines.push(" });");
|
|
10941
|
+
}
|
|
10942
|
+
return lines;
|
|
10943
|
+
}
|
|
10944
|
+
/**
|
|
10945
|
+
* Generate the rulesync-owned Pi extension (a TypeScript module with a
|
|
10946
|
+
* default-export factory receiving Pi's ExtensionAPI) that subscribes to the
|
|
10947
|
+
* mapped lifecycle events and executes the configured hook commands via the
|
|
10948
|
+
* platform shell. The generated extension observes events only: it never
|
|
10949
|
+
* blocks or mutates Pi events.
|
|
10950
|
+
*
|
|
10951
|
+
* @see https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/docs/extensions.md
|
|
10952
|
+
*/
|
|
10953
|
+
function generatePiExtensionCode({ config, supportedEvents, eventMap }) {
|
|
10954
|
+
const supported = new Set(supportedEvents);
|
|
10955
|
+
const configHooks = {
|
|
10956
|
+
...config.hooks,
|
|
10957
|
+
...config.pi?.hooks
|
|
10958
|
+
};
|
|
10959
|
+
const effectiveHooks = {};
|
|
10960
|
+
for (const [event, defs] of Object.entries(configHooks)) if (supported.has(event)) effectiveHooks[event] = defs;
|
|
10961
|
+
const subscriptionLines = buildSubscriptionLines(collectPiHandlers({
|
|
10962
|
+
effectiveHooks,
|
|
10963
|
+
eventMap
|
|
10964
|
+
}));
|
|
10965
|
+
const lines = ["// Generated by rulesync. Do not edit manually."];
|
|
10966
|
+
if (subscriptionLines.length === 0) {
|
|
10967
|
+
lines.push("export default function () {}");
|
|
10968
|
+
lines.push("");
|
|
10969
|
+
return lines.join("\n");
|
|
10970
|
+
}
|
|
10971
|
+
lines.push("import { exec } from \"node:child_process\";");
|
|
10972
|
+
lines.push("import { promisify } from \"node:util\";");
|
|
10973
|
+
lines.push("");
|
|
10974
|
+
lines.push("import type { ExtensionAPI } from \"@earendil-works/pi-coding-agent\";");
|
|
10975
|
+
lines.push("");
|
|
10976
|
+
lines.push("const run = promisify(exec);");
|
|
10977
|
+
lines.push("");
|
|
10978
|
+
lines.push("export default function (pi: ExtensionAPI) {");
|
|
10979
|
+
lines.push(...subscriptionLines);
|
|
10980
|
+
lines.push("}");
|
|
10981
|
+
lines.push("");
|
|
10982
|
+
return lines.join("\n");
|
|
10983
|
+
}
|
|
10984
|
+
//#endregion
|
|
10985
|
+
//#region src/features/hooks/pi-hooks.ts
|
|
10986
|
+
/**
|
|
10987
|
+
* Pi Coding Agent has no static hooks config file; its extension API exposes
|
|
10988
|
+
* lifecycle events instead. rulesync bridges canonical hooks by generating a
|
|
10989
|
+
* rulesync-owned TypeScript extension in Pi's extension discovery paths:
|
|
10990
|
+
* `.pi/extensions/rulesync-hooks.ts` (project) and
|
|
10991
|
+
* `~/.pi/agent/extensions/rulesync-hooks.ts` (global).
|
|
10992
|
+
*
|
|
10993
|
+
* @see https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/docs/extensions.md
|
|
10994
|
+
*/
|
|
10995
|
+
var PiHooks = class PiHooks extends ToolHooks {
|
|
10996
|
+
constructor(params) {
|
|
10997
|
+
super({
|
|
10998
|
+
...params,
|
|
10999
|
+
fileContent: params.fileContent ?? ""
|
|
11000
|
+
});
|
|
11001
|
+
}
|
|
11002
|
+
static getSettablePaths(options) {
|
|
11003
|
+
return {
|
|
11004
|
+
relativeDirPath: options?.global ? PI_AGENT_EXTENSIONS_DIR_PATH : PI_EXTENSIONS_DIR_PATH,
|
|
11005
|
+
relativeFilePath: PI_HOOKS_FILE_NAME
|
|
11006
|
+
};
|
|
11007
|
+
}
|
|
11008
|
+
static async fromFile({ outputRoot = process.cwd(), validate = true, global = false }) {
|
|
11009
|
+
const paths = PiHooks.getSettablePaths({ global });
|
|
11010
|
+
const fileContent = await readFileContent(join(outputRoot, paths.relativeDirPath, paths.relativeFilePath));
|
|
11011
|
+
return new PiHooks({
|
|
11012
|
+
outputRoot,
|
|
11013
|
+
relativeDirPath: paths.relativeDirPath,
|
|
11014
|
+
relativeFilePath: paths.relativeFilePath,
|
|
11015
|
+
fileContent,
|
|
11016
|
+
validate
|
|
11017
|
+
});
|
|
11018
|
+
}
|
|
11019
|
+
static fromRulesyncHooks({ outputRoot = process.cwd(), rulesyncHooks, validate = true, global = false }) {
|
|
11020
|
+
const fileContent = generatePiExtensionCode({
|
|
11021
|
+
config: rulesyncHooks.getJson(),
|
|
11022
|
+
supportedEvents: PI_HOOK_EVENTS,
|
|
11023
|
+
eventMap: CANONICAL_TO_PI_EVENT_NAMES
|
|
11024
|
+
});
|
|
11025
|
+
const paths = PiHooks.getSettablePaths({ global });
|
|
11026
|
+
return new PiHooks({
|
|
11027
|
+
outputRoot,
|
|
11028
|
+
relativeDirPath: paths.relativeDirPath,
|
|
11029
|
+
relativeFilePath: paths.relativeFilePath,
|
|
11030
|
+
fileContent,
|
|
11031
|
+
validate
|
|
11032
|
+
});
|
|
11033
|
+
}
|
|
11034
|
+
toRulesyncHooks() {
|
|
11035
|
+
throw new Error("Not implemented because Pi hooks are generated as a TypeScript extension file.");
|
|
11036
|
+
}
|
|
11037
|
+
validate() {
|
|
11038
|
+
return {
|
|
11039
|
+
success: true,
|
|
11040
|
+
error: null
|
|
11041
|
+
};
|
|
11042
|
+
}
|
|
11043
|
+
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
|
|
11044
|
+
return new PiHooks({
|
|
11045
|
+
outputRoot,
|
|
11046
|
+
relativeDirPath,
|
|
11047
|
+
relativeFilePath,
|
|
11048
|
+
fileContent: "",
|
|
11049
|
+
validate: false
|
|
11050
|
+
});
|
|
11051
|
+
}
|
|
11052
|
+
};
|
|
11053
|
+
//#endregion
|
|
10802
11054
|
//#region src/features/hooks/qwencode-hooks.ts
|
|
10803
11055
|
/**
|
|
10804
11056
|
* Build a single Qwen Code hook object from a canonical hook definition.
|
|
@@ -11568,6 +11820,17 @@ const toolHooksFactories = /* @__PURE__ */ new Map([
|
|
|
11568
11820
|
supportedHookTypes: ["command"],
|
|
11569
11821
|
supportsMatcher: true
|
|
11570
11822
|
}],
|
|
11823
|
+
["pi", {
|
|
11824
|
+
class: PiHooks,
|
|
11825
|
+
meta: {
|
|
11826
|
+
supportsProject: true,
|
|
11827
|
+
supportsGlobal: true,
|
|
11828
|
+
supportsImport: false
|
|
11829
|
+
},
|
|
11830
|
+
supportedEvents: PI_HOOK_EVENTS,
|
|
11831
|
+
supportedHookTypes: ["command"],
|
|
11832
|
+
supportsMatcher: true
|
|
11833
|
+
}],
|
|
11571
11834
|
["factorydroid", {
|
|
11572
11835
|
class: FactorydroidHooks,
|
|
11573
11836
|
meta: {
|
|
@@ -19321,7 +19584,7 @@ function convertAntigravityIdeToRulesyncPermissions(params) {
|
|
|
19321
19584
|
}
|
|
19322
19585
|
//#endregion
|
|
19323
19586
|
//#region src/features/permissions/augmentcode-permissions.ts
|
|
19324
|
-
const moduleLogger$1 =
|
|
19587
|
+
const moduleLogger$1 = fallbackLogger;
|
|
19325
19588
|
z.enum([
|
|
19326
19589
|
"allow",
|
|
19327
19590
|
"deny",
|
|
@@ -23126,7 +23389,7 @@ const QwenSettingsPermissionsSchema = z.looseObject({
|
|
|
23126
23389
|
deny: z.optional(z.array(z.string()))
|
|
23127
23390
|
});
|
|
23128
23391
|
const QwenSettingsSchema = z.looseObject({ permissions: z.optional(QwenSettingsPermissionsSchema) });
|
|
23129
|
-
const moduleLogger =
|
|
23392
|
+
const moduleLogger = fallbackLogger;
|
|
23130
23393
|
/**
|
|
23131
23394
|
* Mapping from rulesync canonical tool category names (lowercase) to Qwen Code tool names (PascalCase).
|
|
23132
23395
|
* Unknown names pass through as-is (e.g., mcp__server__tool).
|
|
@@ -40533,7 +40796,8 @@ function buildCommandsStrategy(ctx) {
|
|
|
40533
40796
|
toolTarget,
|
|
40534
40797
|
global,
|
|
40535
40798
|
dryRun,
|
|
40536
|
-
logger
|
|
40799
|
+
logger,
|
|
40800
|
+
flattenedCommandNaming: config.getFlattenedCommandNaming()
|
|
40537
40801
|
}),
|
|
40538
40802
|
loadSource: (p) => p.loadToolFiles(),
|
|
40539
40803
|
toRulesync: (p, files) => p.convertToolFilesToRulesyncFiles(files),
|
|
@@ -41373,6 +41637,7 @@ async function generateCommandsCore(params) {
|
|
|
41373
41637
|
toolTarget,
|
|
41374
41638
|
global: config.getGlobal(),
|
|
41375
41639
|
dryRun: config.isPreviewMode(),
|
|
41640
|
+
flattenedCommandNaming: config.getFlattenedCommandNaming(),
|
|
41376
41641
|
logger
|
|
41377
41642
|
});
|
|
41378
41643
|
const result = await processFeatureWithRulesyncFiles({
|
|
@@ -41896,6 +42161,6 @@ async function importChecksCore(params) {
|
|
|
41896
42161
|
return writtenCount;
|
|
41897
42162
|
}
|
|
41898
42163
|
//#endregion
|
|
41899
|
-
export {
|
|
42164
|
+
export { getFileSize as $, CLAUDECODE_SETTINGS_LOCAL_FILE_NAME as A, RULESYNC_OVERVIEW_FILE_NAME as At, findControlCharacter as B, formatError as Bt, CommandsProcessor as C, RULESYNC_IGNORE_RELATIVE_FILE_PATH as Ct, CLAUDECODE_DIR as D, RULESYNC_MCP_RELATIVE_FILE_PATH as Dt, CODEXCLI_DIR as E, RULESYNC_MCP_JSONC_FILE_NAME as Et, RulesyncCheck as F, RULESYNC_RELATIVE_DIR_PATH as Ft, CLIError as G, JsonLogger as H, ALL_FEATURES_WITH_WILDCARD as Ht, RulesyncCheckFrontmatterSchema as I, RULESYNC_RULES_RELATIVE_DIR_PATH as It, createTempDirectory as J, ErrorCodes as K, stringifyFrontmatter as L, RULESYNC_SKILLS_RELATIVE_DIR_PATH as Lt, RulesyncCommand as M, RULESYNC_PERMISSIONS_JSONC_FILE_NAME as Mt, RulesyncCommandFrontmatterSchema as N, RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH as Nt, CLAUDECODE_LOCAL_RULE_FILE_NAME as O, RULESYNC_MCP_SCHEMA_URL as Ot, ChecksProcessor as P, RULESYNC_PERMISSIONS_SCHEMA_URL as Pt, findFilesByGlobs as Q, loadYaml as R, RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH as Rt, RulesyncHooks as S, RULESYNC_HOOKS_RELATIVE_FILE_PATH as St, CODEXCLI_BASH_RULES_FILE_NAME as T, RULESYNC_MCP_FILE_NAME as Tt, fallbackLogger as U, ConsoleLogger as V, ALL_FEATURES as Vt, warnOnConflictingFlags as W, ensureDir as X, directoryExists as Y, fileExists as Z, McpProcessor as _, RULESYNC_CONFIG_RELATIVE_FILE_PATH as _t, convertFromTool as a, removeFile as at, RulesyncIgnore as b, RULESYNC_HOOKS_FILE_NAME as bt, RulesyncRuleFrontmatterSchema as c, writeFileContent as ct, RulesyncSubagentFrontmatterSchema as d, ToolTargetSchema as dt, getHomeDirectory as et, SkillsProcessor as f, MAX_FILE_SIZE as ft, RulesyncPermissions as g, RULESYNC_COMMANDS_RELATIVE_DIR_PATH as gt, RulesyncSkillFrontmatterSchema as h, RULESYNC_CHECKS_RELATIVE_DIR_PATH as ht, getProcessorRegistryEntry as i, removeDirectory as it, CLAUDECODE_SKILLS_DIR_PATH as j, RULESYNC_PERMISSIONS_FILE_NAME as jt, CLAUDECODE_MEMORIES_DIR_NAME as k, RULESYNC_NPM_SOURCES_LOCK_RELATIVE_FILE_PATH as kt, SubagentsProcessor as l, ALL_TOOL_TARGETS as lt, RulesyncSkill as m, RULESYNC_AIIGNORE_RELATIVE_FILE_PATH as mt, checkRulesyncDirExists as n, listDirectoryFiles as nt, RulesProcessor as o, removeTempDirectory as ot, getLocalSkillDirNames as p, RULESYNC_AIIGNORE_FILE_NAME as pt, checkPathTraversal as q, generate as r, readFileContent as rt, RulesyncRule as s, toPosixPath as st, importFromTool as t, isSymlink as tt, RulesyncSubagent as u, ALL_TOOL_TARGETS_WITH_WILDCARD as ut, RulesyncMcp as v, RULESYNC_CONFIG_SCHEMA_URL as vt, SKILL_FILE_NAME$1 as w, RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH as wt, HooksProcessor as x, RULESYNC_HOOKS_JSONC_FILE_NAME as xt, IgnoreProcessor as y, RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH as yt, ConfigResolver as z, RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH as zt };
|
|
41900
42165
|
|
|
41901
|
-
//# sourceMappingURL=import-
|
|
42166
|
+
//# sourceMappingURL=import-BN4K49Ta.js.map
|