@h-rig/core 0.0.6-alpha.176 → 0.0.6-alpha.177
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/src/baked-secrets.d.ts +3 -6
- package/dist/src/baked-secrets.js +9 -67
- package/dist/src/capability-loaders.js +132 -20
- package/dist/src/declarative-config.js +5 -2
- package/dist/src/harness-paths.d.ts +0 -9
- package/dist/src/harness-paths.js +1 -16
- package/dist/src/hook-materializer.d.ts +9 -60
- package/dist/src/hook-materializer.js +3 -132
- package/dist/src/hook-protocol.js +1 -31
- package/dist/src/hook-runner.d.ts +3 -3
- package/dist/src/hook-runner.js +132 -20
- package/dist/src/hook-runtime.js +1 -31
- package/dist/src/json-files.js +0 -1
- package/dist/src/kernel-entrypoint.js +132 -20
- package/dist/src/layout.d.ts +2 -2
- package/dist/src/layout.js +2 -8
- package/dist/src/load-config.js +132 -20
- package/dist/src/placement.d.ts +16 -8
- package/dist/src/placement.js +18 -961
- package/dist/src/plugin-host-context.d.ts +2 -3
- package/dist/src/plugin-host-context.js +170 -294
- package/dist/src/project-plugins.js +132 -20
- package/dist/src/remote-config.d.ts +38 -96
- package/dist/src/remote-config.js +35 -524
- package/dist/src/root-resolver.js +0 -1
- package/dist/src/run-provisioning.d.ts +17 -38
- package/dist/src/run-provisioning.js +19 -112
- package/dist/src/runtime-events.js +0 -4
- package/dist/src/runtime-overlay.js +0 -2
- package/dist/src/server-paths.d.ts +0 -4
- package/dist/src/server-paths.js +36 -125
- package/package.json +3 -7
- package/dist/src/profile-ops.d.ts +0 -9
- package/dist/src/profile-ops.js +0 -252
|
@@ -20,12 +20,11 @@
|
|
|
20
20
|
* NOTE: registries are instantiated here. The validatorRegistry is consumed
|
|
21
21
|
* by CLI/harness validation and completion verification. Task dispatch and
|
|
22
22
|
* closeout read/update the configured plugin task source directly, with
|
|
23
|
-
* materialized
|
|
23
|
+
* materialized compatibility data kept behind plugin-owned seams.
|
|
24
24
|
*/
|
|
25
|
-
import type { RepoRegistry, RigConfig } from "@rig/contracts";
|
|
25
|
+
import type { AgentRoleRegistry, RepoRegistry, RigConfig } from "@rig/contracts";
|
|
26
26
|
import type { PluginHost } from "./plugin-host";
|
|
27
27
|
import { type TaskFieldRegistry, type TaskSourceRegistry } from "./plugin-host-registries";
|
|
28
|
-
import type { AgentRoleRegistry } from "@rig/contracts";
|
|
29
28
|
import { type ValidatorRegistry } from "./validator-registry";
|
|
30
29
|
/** All registries populated from the declarative RigPlugin contributions. */
|
|
31
30
|
export interface PluginHostContext {
|
|
@@ -225,7 +225,7 @@ function createPluginHost(plugins) {
|
|
|
225
225
|
// packages/core/src/load-config.ts
|
|
226
226
|
import { existsSync as existsSync2, mkdirSync, mkdtempSync, readFileSync as readFileSync2, readdirSync, rmSync, statSync } from "fs";
|
|
227
227
|
import { isBuiltin } from "module";
|
|
228
|
-
import { dirname, isAbsolute, join as join2, relative, resolve } from "path";
|
|
228
|
+
import { basename, dirname, isAbsolute, join as join2, relative, resolve } from "path";
|
|
229
229
|
import { pathToFileURL } from "url";
|
|
230
230
|
import { Schema as Schema3 } from "effect";
|
|
231
231
|
import { RigConfig as RigConfig3 } from "@rig/contracts";
|
|
@@ -292,8 +292,11 @@ function parseDeclarativeFile(path) {
|
|
|
292
292
|
}
|
|
293
293
|
function loadDeclarativeConfig(path) {
|
|
294
294
|
const data = parseDeclarativeFile(path);
|
|
295
|
-
const standardSection = data.standard && typeof data.standard === "object" && !Array.isArray(data.standard) ? data.standard :
|
|
296
|
-
|
|
295
|
+
const standardSection = data.standard && typeof data.standard === "object" && !Array.isArray(data.standard) ? data.standard : null;
|
|
296
|
+
if (standardSection?.enabled !== true && standardSection?.enabled !== false) {
|
|
297
|
+
throw new Error(`Declarative config ${path} must explicitly set [standard] enabled = true or false.`);
|
|
298
|
+
}
|
|
299
|
+
const useStandard = standardSection.enabled === true;
|
|
297
300
|
let plugins = [];
|
|
298
301
|
if (useStandard) {
|
|
299
302
|
const resolver = getStandardPluginsResolver();
|
|
@@ -335,19 +338,27 @@ function packageNameAndSubpath(specifier) {
|
|
|
335
338
|
function exportTargetFromEntry(entry) {
|
|
336
339
|
if (typeof entry === "string")
|
|
337
340
|
return entry;
|
|
338
|
-
if (
|
|
341
|
+
if (Array.isArray(entry)) {
|
|
342
|
+
for (const candidate of entry) {
|
|
343
|
+
const target = exportTargetFromEntry(candidate);
|
|
344
|
+
if (target)
|
|
345
|
+
return target;
|
|
346
|
+
}
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
349
|
+
if (entry && typeof entry === "object") {
|
|
339
350
|
const conditions = entry;
|
|
340
|
-
for (const key of ["bun", "import", "default", "require"]) {
|
|
341
|
-
|
|
342
|
-
|
|
351
|
+
for (const key of ["bun", "node", "import", "default", "require"]) {
|
|
352
|
+
const target = exportTargetFromEntry(conditions[key]);
|
|
353
|
+
if (target)
|
|
354
|
+
return target;
|
|
343
355
|
}
|
|
344
356
|
}
|
|
345
357
|
return null;
|
|
346
358
|
}
|
|
347
359
|
function patternExportTarget(record, subpath) {
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
continue;
|
|
360
|
+
const entries = Object.entries(record).filter(([pattern]) => pattern.includes("*")).sort(([a], [b]) => b.replace("*", "").length - a.replace("*", "").length);
|
|
361
|
+
for (const [pattern, entry] of entries) {
|
|
351
362
|
const [prefix = "", suffix = ""] = pattern.split("*");
|
|
352
363
|
if (!subpath.startsWith(prefix) || !subpath.endsWith(suffix))
|
|
353
364
|
continue;
|
|
@@ -372,6 +383,49 @@ function exportTargetFromPackageJson(pkg, subpath) {
|
|
|
372
383
|
return target;
|
|
373
384
|
return subpath === "." && typeof pkg.module === "string" ? pkg.module : subpath === "." && typeof pkg.main === "string" ? pkg.main : null;
|
|
374
385
|
}
|
|
386
|
+
function patternImportTarget(record, specifier) {
|
|
387
|
+
for (const [pattern, entry] of Object.entries(record)) {
|
|
388
|
+
if (!pattern.includes("*"))
|
|
389
|
+
continue;
|
|
390
|
+
const [prefix = "", suffix = ""] = pattern.split("*");
|
|
391
|
+
if (!specifier.startsWith(prefix) || !specifier.endsWith(suffix))
|
|
392
|
+
continue;
|
|
393
|
+
const replacement = specifier.slice(prefix.length, specifier.length - suffix.length);
|
|
394
|
+
const target = exportTargetFromEntry(entry);
|
|
395
|
+
if (target)
|
|
396
|
+
return target.replace("*", replacement);
|
|
397
|
+
}
|
|
398
|
+
return null;
|
|
399
|
+
}
|
|
400
|
+
function resolvePackagePrivateImport(specifier, importer, projectRoot) {
|
|
401
|
+
if (!specifier.startsWith("#") || !importer || !isAbsolute(importer))
|
|
402
|
+
return null;
|
|
403
|
+
let dir = dirname(importer);
|
|
404
|
+
const stop = resolve(projectRoot);
|
|
405
|
+
while (isWithinDir(dir, stop)) {
|
|
406
|
+
const packageJsonPath = join2(dir, "package.json");
|
|
407
|
+
if (existsSync2(packageJsonPath)) {
|
|
408
|
+
try {
|
|
409
|
+
const pkg = JSON.parse(readFileSync2(packageJsonPath, "utf8"));
|
|
410
|
+
const imports = pkg.imports;
|
|
411
|
+
if (imports && typeof imports === "object" && !Array.isArray(imports)) {
|
|
412
|
+
const record = imports;
|
|
413
|
+
const target = exportTargetFromEntry(record[specifier]) ?? patternImportTarget(record, specifier);
|
|
414
|
+
if (target)
|
|
415
|
+
return resolveModulePath(join2(dir, target));
|
|
416
|
+
}
|
|
417
|
+
} catch {
|
|
418
|
+
return null;
|
|
419
|
+
}
|
|
420
|
+
return null;
|
|
421
|
+
}
|
|
422
|
+
const parent = dirname(dir);
|
|
423
|
+
if (parent === dir)
|
|
424
|
+
return null;
|
|
425
|
+
dir = parent;
|
|
426
|
+
}
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
375
429
|
function resolvePackageDirFromBunStore(packageName, nodeModulesDir) {
|
|
376
430
|
const storeDir = join2(nodeModulesDir, ".bun");
|
|
377
431
|
if (!existsSync2(storeDir))
|
|
@@ -446,8 +500,15 @@ function resolvePackageExportFromDir(packageDir, subpath) {
|
|
|
446
500
|
if (existsSync2(packageJsonPath)) {
|
|
447
501
|
try {
|
|
448
502
|
const pkg = JSON.parse(readFileSync2(packageJsonPath, "utf8"));
|
|
449
|
-
const
|
|
450
|
-
|
|
503
|
+
const targets = [
|
|
504
|
+
exportTargetFromPackageJson(pkg, subpath),
|
|
505
|
+
...subpath === "." ? [typeof pkg.module === "string" ? pkg.module : null, typeof pkg.main === "string" ? pkg.main : null] : []
|
|
506
|
+
];
|
|
507
|
+
const seen = new Set;
|
|
508
|
+
for (const target of targets) {
|
|
509
|
+
if (!target || seen.has(target))
|
|
510
|
+
continue;
|
|
511
|
+
seen.add(target);
|
|
451
512
|
const resolved = resolveModulePath(join2(packageDir, target));
|
|
452
513
|
if (resolved)
|
|
453
514
|
return resolved;
|
|
@@ -535,10 +596,17 @@ async function importConfigViaRuntimeBundleUnserialized(configPath) {
|
|
|
535
596
|
}
|
|
536
597
|
const RUNTIME_ONLY_EXTERNAL_PACKAGES = new Set(["effect", "mupdf", "fastembed", "onnxruntime-node", "markit-ai"]);
|
|
537
598
|
const configDir = dirname(configPath);
|
|
599
|
+
const configProjectRoot = basename(configDir) === ".rig" ? dirname(configDir) : configDir;
|
|
538
600
|
const UNRESOLVED_NAMESPACE = "rig-config-unresolved";
|
|
601
|
+
const ABSOLUTE_EXTERNAL_NAMESPACE = "rig-config-absolute-external";
|
|
539
602
|
const unresolvedLocalPlugin = {
|
|
540
603
|
name: "rig-config-unresolved-local",
|
|
541
604
|
setup(build) {
|
|
605
|
+
build.onLoad({ filter: /[\\/]@oh-my-pi[\\/]pi-coding-agent[\\/]src[\\/]export[\\/]html[\\/](?:template\.css|template\.html|template\.js|tool-views\.generated\.js)$/ }, (args) => ({
|
|
606
|
+
loader: "js",
|
|
607
|
+
contents: `export default ${JSON.stringify(readFileSync2(args.path, "utf8"))};
|
|
608
|
+
`
|
|
609
|
+
}));
|
|
542
610
|
build.onLoad({ filter: /\.(?:html|txt)$/ }, (args) => ({
|
|
543
611
|
loader: "js",
|
|
544
612
|
contents: `export default ${JSON.stringify(readFileSync2(args.path, "utf8"))};
|
|
@@ -548,32 +616,77 @@ async function importConfigViaRuntimeBundleUnserialized(configPath) {
|
|
|
548
616
|
const directFilePath = resolvedFilePath(args.path, configDir);
|
|
549
617
|
if (directFilePath)
|
|
550
618
|
return { path: directFilePath };
|
|
619
|
+
if (args.path.startsWith("#")) {
|
|
620
|
+
const packagePrivatePath = resolvePackagePrivateImport(args.path, args.importer, configProjectRoot);
|
|
621
|
+
if (packagePrivatePath)
|
|
622
|
+
return { path: packagePrivatePath };
|
|
623
|
+
try {
|
|
624
|
+
const parent2 = args.importer && isAbsolute(args.importer) ? dirname(args.importer) : configProjectRoot;
|
|
625
|
+
const resolved = bun.resolveSync?.(args.path, parent2);
|
|
626
|
+
const filePath = resolvedFilePath(resolved, configProjectRoot);
|
|
627
|
+
if (filePath)
|
|
628
|
+
return { path: filePath };
|
|
629
|
+
} catch {}
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
551
632
|
const packageImport = packageNameAndSubpath(args.path);
|
|
552
|
-
if (packageImport &&
|
|
553
|
-
|
|
633
|
+
if (packageImport?.packageName === "uhyphen" && packageImport.subpath === ".") {
|
|
634
|
+
const uhyphenPath = resolveProjectPackageImport("uhyphen", configProjectRoot);
|
|
635
|
+
if (uhyphenPath)
|
|
636
|
+
return { path: uhyphenPath };
|
|
637
|
+
}
|
|
638
|
+
if (packageImport && packageImport.packageName !== "uhyphen") {
|
|
639
|
+
try {
|
|
640
|
+
const parent2 = args.importer && isAbsolute(args.importer) ? dirname(args.importer) : configProjectRoot;
|
|
641
|
+
const resolved = bun.resolveSync?.(args.path, parent2);
|
|
642
|
+
const filePath = resolvedFilePath(resolved, configProjectRoot);
|
|
643
|
+
if (filePath)
|
|
644
|
+
return { path: filePath };
|
|
645
|
+
} catch {}
|
|
554
646
|
}
|
|
555
|
-
const projectPackagePath = resolveProjectPackageImport(args.path,
|
|
647
|
+
const projectPackagePath = packageImport ? resolveProjectPackageImport(args.path, configProjectRoot) : null;
|
|
556
648
|
if (projectPackagePath)
|
|
557
649
|
return { path: projectPackagePath };
|
|
650
|
+
if (packageImport && (packageImport.packageName.startsWith("@rig/") || RUNTIME_ONLY_EXTERNAL_PACKAGES.has(packageImport.packageName))) {
|
|
651
|
+
return { path: args.path, external: true };
|
|
652
|
+
}
|
|
558
653
|
if (/^(?:node|bun):/.test(args.path) || isBuiltin(args.path))
|
|
559
654
|
return;
|
|
560
655
|
if (packageImport)
|
|
561
656
|
return { path: args.path, external: true };
|
|
562
|
-
const
|
|
657
|
+
const importerDir = args.importer && isAbsolute(args.importer) ? dirname(args.importer) : null;
|
|
658
|
+
if (args.path.startsWith(".") && importerDir) {
|
|
659
|
+
const fromImporter = resolveModulePath(resolve(importerDir, args.path));
|
|
660
|
+
if (fromImporter)
|
|
661
|
+
return { path: fromImporter };
|
|
662
|
+
if (/[\\/]node_modules[\\/]/.test(args.importer ?? ""))
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
665
|
+
const parentCandidates = args.path.startsWith(".") ? [importerDir, configDir].filter((value) => Boolean(value)) : [importerDir ?? configDir];
|
|
563
666
|
for (const parent2 of parentCandidates) {
|
|
564
|
-
const filePath = resolvedFilePath(resolve(parent2, args.path),
|
|
667
|
+
const filePath = resolvedFilePath(resolve(parent2, args.path), configProjectRoot);
|
|
565
668
|
if (filePath)
|
|
566
669
|
return { path: filePath };
|
|
567
670
|
}
|
|
568
671
|
const parent = parentCandidates[0] ?? configDir;
|
|
569
672
|
try {
|
|
570
673
|
const resolved = bun.resolveSync?.(args.path, parent) ?? resolve(parent, args.path);
|
|
571
|
-
const filePath = resolvedFilePath(resolved,
|
|
674
|
+
const filePath = resolvedFilePath(resolved, configProjectRoot);
|
|
572
675
|
if (filePath)
|
|
573
676
|
return { path: filePath };
|
|
574
677
|
} catch {}
|
|
575
678
|
return { path: args.path, namespace: UNRESOLVED_NAMESPACE };
|
|
576
679
|
});
|
|
680
|
+
build.onLoad({ filter: /.*/, namespace: ABSOLUTE_EXTERNAL_NAMESPACE }, (args) => {
|
|
681
|
+
const href = pathToFileURL(args.path).href;
|
|
682
|
+
return {
|
|
683
|
+
loader: "js",
|
|
684
|
+
contents: `export * from ${JSON.stringify(href)};
|
|
685
|
+
const mod = await import(${JSON.stringify(href)});
|
|
686
|
+
export default (mod && "default" in mod) ? mod.default : mod;
|
|
687
|
+
`
|
|
688
|
+
};
|
|
689
|
+
});
|
|
577
690
|
build.onLoad({ filter: /.*/, namespace: UNRESOLVED_NAMESPACE }, (args) => ({
|
|
578
691
|
loader: "js",
|
|
579
692
|
contents: `module.exports = {};
|
|
@@ -585,7 +698,6 @@ throw new Error(${JSON.stringify(`Failed to bundle ${configPath}: Could not reso
|
|
|
585
698
|
const result = await bun.build({
|
|
586
699
|
entrypoints: [configPath],
|
|
587
700
|
target: "bun",
|
|
588
|
-
external: ["effect", "mupdf", "fastembed", "onnxruntime-node", "markit-ai"],
|
|
589
701
|
format: "esm",
|
|
590
702
|
throw: false,
|
|
591
703
|
packages: "bundle",
|
|
@@ -596,7 +708,7 @@ throw new Error(${JSON.stringify(`Failed to bundle ${configPath}: Could not reso
|
|
|
596
708
|
`);
|
|
597
709
|
throw new Error(`Failed to bundle ${configPath}: ${detail || "unknown bundler error"}`);
|
|
598
710
|
}
|
|
599
|
-
const bundleParentDir = join2(
|
|
711
|
+
const bundleParentDir = join2(configProjectRoot, ".rig", "tmp");
|
|
600
712
|
mkdirSync(bundleParentDir, { recursive: true });
|
|
601
713
|
const dir = mkdtempSync(join2(bundleParentDir, "rig-config-bundle-"));
|
|
602
714
|
try {
|
|
@@ -790,8 +902,17 @@ function createTaskFieldRegistry(extensions) {
|
|
|
790
902
|
// packages/core/src/plugin-host-context.ts
|
|
791
903
|
import {
|
|
792
904
|
MANAGED_REPO_SERVICE_CAPABILITY,
|
|
905
|
+
REPO_CHANGE_SET,
|
|
906
|
+
REPO_NATIVE_GIT,
|
|
907
|
+
RUNTIME_SECRETS,
|
|
793
908
|
SESSION_ASSET_MATERIALIZER,
|
|
794
|
-
|
|
909
|
+
SESSION_HOOK_MATERIALIZER,
|
|
910
|
+
TASK_ARTIFACTS,
|
|
911
|
+
TASK_STATE_STORE,
|
|
912
|
+
TASK_TRACKER_READINESS_POLICY,
|
|
913
|
+
TASK_TRACKER_RECONCILIATION_POLICY,
|
|
914
|
+
TASK_TRACKER_REPO_LOCATOR,
|
|
915
|
+
TASK_TRACKER_STATE,
|
|
795
916
|
TOOL_MATERIALIZER
|
|
796
917
|
} from "@rig/contracts";
|
|
797
918
|
|
|
@@ -945,277 +1066,19 @@ function setScopeRules(rules) {
|
|
|
945
1066
|
scopeRulesState().rules = rules ?? null;
|
|
946
1067
|
}
|
|
947
1068
|
|
|
948
|
-
// packages/core/src/hook-materializer.ts
|
|
949
|
-
import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync } from "fs";
|
|
950
|
-
import { dirname as dirname2, resolve as resolve4 } from "path";
|
|
951
|
-
|
|
952
|
-
// packages/core/src/hook-runtime.ts
|
|
953
|
-
import { appendFileSync, existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync3, realpathSync, writeSync } from "fs";
|
|
954
|
-
import { resolve as resolve3 } from "path";
|
|
955
|
-
import { RIG_DEFINITION_DIRNAME, RIG_STATE_DIRNAME } from "@rig/contracts";
|
|
956
|
-
function bunRuntime() {
|
|
957
|
-
const runtime = globalThis;
|
|
958
|
-
return runtime.Bun;
|
|
959
|
-
}
|
|
960
|
-
function normalizeBuildConfig(value) {
|
|
961
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
962
|
-
return {};
|
|
963
|
-
}
|
|
964
|
-
return Object.fromEntries(Object.entries(value).filter((entry) => typeof entry[1] === "string"));
|
|
965
|
-
}
|
|
966
|
-
function readBuildConfigForCoreHooks() {
|
|
967
|
-
if (typeof __RIG_BUILD_CONFIG__ !== "undefined") {
|
|
968
|
-
return normalizeBuildConfig(__RIG_BUILD_CONFIG__);
|
|
969
|
-
}
|
|
970
|
-
const raw = process.env.RIG_BUILD_CONFIG_JSON?.trim();
|
|
971
|
-
if (!raw) {
|
|
972
|
-
return {};
|
|
973
|
-
}
|
|
974
|
-
try {
|
|
975
|
-
return normalizeBuildConfig(JSON.parse(raw));
|
|
976
|
-
} catch {
|
|
977
|
-
return {};
|
|
978
|
-
}
|
|
979
|
-
}
|
|
980
|
-
var BUILD_CONFIG = readBuildConfigForCoreHooks();
|
|
981
|
-
var BAKED_PROJECT_ROOT = BUILD_CONFIG.AGENT_PROJECT_ROOT ?? "";
|
|
982
|
-
var BAKED_TASK_ID = BUILD_CONFIG.AGENT_TASK_ID ?? "";
|
|
983
|
-
var BAKED_STATE_DIR = BUILD_CONFIG.AGENT_STATE_DIR ?? "";
|
|
984
|
-
var BAKED_BUN_PATH = BUILD_CONFIG.AGENT_BUN_PATH ?? "";
|
|
985
|
-
var BAKED_TASK_CONFIG = BUILD_CONFIG.AGENT_TASK_CONFIG ?? "";
|
|
986
|
-
var BAKED_POLICY_CONTENT = BUILD_CONFIG.AGENT_POLICY_CONTENT ?? "";
|
|
987
|
-
var BAKED_TASK_SCOPES = BUILD_CONFIG.AGENT_TASK_SCOPES ?? "";
|
|
988
|
-
function normalizeExecutablePath(candidate) {
|
|
989
|
-
if (!candidate) {
|
|
990
|
-
return "";
|
|
991
|
-
}
|
|
992
|
-
const normalized = resolve3(candidate);
|
|
993
|
-
if (!existsSync5(normalized)) {
|
|
994
|
-
return "";
|
|
995
|
-
}
|
|
996
|
-
try {
|
|
997
|
-
return realpathSync(normalized);
|
|
998
|
-
} catch {
|
|
999
|
-
return normalized;
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
|
-
function looksLikeRuntimeGateway(candidate) {
|
|
1003
|
-
const normalized = resolve3(candidate).replace(/\\/g, "/");
|
|
1004
|
-
return normalized.includes("/.rig/bin/") || normalized.endsWith("/rig-shell") || normalized.endsWith("/rig-agent");
|
|
1005
|
-
}
|
|
1006
|
-
function resolveBunBinaryPath() {
|
|
1007
|
-
const explicit = normalizeExecutablePath(process.env.RIG_BUN_PATH?.trim());
|
|
1008
|
-
if (explicit) {
|
|
1009
|
-
return explicit;
|
|
1010
|
-
}
|
|
1011
|
-
const bunWhich = bunRuntime()?.which?.("bun");
|
|
1012
|
-
const pathBun = normalizeExecutablePath(bunWhich?.trim());
|
|
1013
|
-
if (pathBun && !looksLikeRuntimeGateway(pathBun)) {
|
|
1014
|
-
return pathBun;
|
|
1015
|
-
}
|
|
1016
|
-
const home = process.env.HOME?.trim();
|
|
1017
|
-
const fallbackCandidates = [
|
|
1018
|
-
home ? resolve3(home, ".bun/bin/bun") : "",
|
|
1019
|
-
"/opt/homebrew/bin/bun",
|
|
1020
|
-
"/usr/local/bin/bun",
|
|
1021
|
-
"/usr/bin/bun"
|
|
1022
|
-
];
|
|
1023
|
-
for (const candidate of fallbackCandidates) {
|
|
1024
|
-
const normalized = normalizeExecutablePath(candidate);
|
|
1025
|
-
if (normalized) {
|
|
1026
|
-
return normalized;
|
|
1027
|
-
}
|
|
1028
|
-
}
|
|
1029
|
-
const execPath = normalizeExecutablePath(process.execPath?.trim());
|
|
1030
|
-
if (execPath && !looksLikeRuntimeGateway(execPath)) {
|
|
1031
|
-
return execPath;
|
|
1032
|
-
}
|
|
1033
|
-
throw new Error("bun not found in PATH");
|
|
1034
|
-
}
|
|
1035
|
-
function resolveBunCliInvocation() {
|
|
1036
|
-
if (BAKED_BUN_PATH) {
|
|
1037
|
-
return {
|
|
1038
|
-
command: BAKED_BUN_PATH,
|
|
1039
|
-
env: {}
|
|
1040
|
-
};
|
|
1041
|
-
}
|
|
1042
|
-
if (process.env.RIG_BUN_PATH?.trim()) {
|
|
1043
|
-
return {
|
|
1044
|
-
command: process.env.RIG_BUN_PATH.trim(),
|
|
1045
|
-
env: {}
|
|
1046
|
-
};
|
|
1047
|
-
}
|
|
1048
|
-
try {
|
|
1049
|
-
const systemBun = resolveBunBinaryPath();
|
|
1050
|
-
return {
|
|
1051
|
-
command: systemBun,
|
|
1052
|
-
env: {}
|
|
1053
|
-
};
|
|
1054
|
-
} catch {}
|
|
1055
|
-
if (process.execPath?.trim()) {
|
|
1056
|
-
return {
|
|
1057
|
-
command: process.execPath,
|
|
1058
|
-
env: { BUN_BE_BUN: "1" }
|
|
1059
|
-
};
|
|
1060
|
-
}
|
|
1061
|
-
return { command: "bun", env: {} };
|
|
1062
|
-
}
|
|
1063
|
-
|
|
1064
|
-
// packages/core/src/hook-materializer.ts
|
|
1065
|
-
var MARKER_PLUGIN = "_rigPlugin";
|
|
1066
|
-
var MARKER_HOOK_ID = "_rigHookId";
|
|
1067
|
-
function matcherToString(matcher) {
|
|
1068
|
-
if (matcher.kind === "all")
|
|
1069
|
-
return;
|
|
1070
|
-
if (matcher.kind === "tool")
|
|
1071
|
-
return matcher.name;
|
|
1072
|
-
return matcher.pattern;
|
|
1073
|
-
}
|
|
1074
|
-
function isPluginOwned(cmd) {
|
|
1075
|
-
return typeof cmd[MARKER_PLUGIN] === "string";
|
|
1076
|
-
}
|
|
1077
|
-
function shellQuote(value) {
|
|
1078
|
-
return `'${value.replaceAll("'", `'\\''`)}'`;
|
|
1079
|
-
}
|
|
1080
|
-
function resolveHookRunnerPath() {
|
|
1081
|
-
const sibling = resolve4(import.meta.dirname, "hook-runner.ts");
|
|
1082
|
-
if (existsSync6(sibling)) {
|
|
1083
|
-
return sibling;
|
|
1084
|
-
}
|
|
1085
|
-
return "$CLAUDE_PROJECT_DIR/node_modules/@rig/core/src/hook-runner.ts";
|
|
1086
|
-
}
|
|
1087
|
-
function buildTypedHookShimCommand(pluginName, hook, projectRoot) {
|
|
1088
|
-
const runnerPath = resolveHookRunnerPath();
|
|
1089
|
-
const runnerArg = runnerPath.startsWith("$CLAUDE_PROJECT_DIR") ? `"${runnerPath}"` : shellQuote(runnerPath);
|
|
1090
|
-
const bun = resolveBunCliInvocation();
|
|
1091
|
-
const envPrefix = Object.entries(bun.env).map(([key, value]) => `${key}=${shellQuote(value)}`).join(" ");
|
|
1092
|
-
const parts = [
|
|
1093
|
-
envPrefix,
|
|
1094
|
-
shellQuote(bun.command),
|
|
1095
|
-
runnerArg,
|
|
1096
|
-
"--plugin",
|
|
1097
|
-
shellQuote(pluginName),
|
|
1098
|
-
"--hook",
|
|
1099
|
-
shellQuote(hook.id),
|
|
1100
|
-
"--event",
|
|
1101
|
-
shellQuote(hook.event),
|
|
1102
|
-
"--project-root",
|
|
1103
|
-
shellQuote(projectRoot)
|
|
1104
|
-
].filter(Boolean);
|
|
1105
|
-
return parts.join(" ");
|
|
1106
|
-
}
|
|
1107
|
-
function createPiNoopSessionHookAdapter() {
|
|
1108
|
-
return {
|
|
1109
|
-
id: "pi",
|
|
1110
|
-
materialize() {
|
|
1111
|
-
return {
|
|
1112
|
-
adapterId: "pi",
|
|
1113
|
-
status: "skipped",
|
|
1114
|
-
reason: "Pi sessions do not consume Claude Code settings hooks."
|
|
1115
|
-
};
|
|
1116
|
-
}
|
|
1117
|
-
};
|
|
1118
|
-
}
|
|
1119
|
-
function createClaudeCodeSessionHookAdapter() {
|
|
1120
|
-
return {
|
|
1121
|
-
id: "claude-code",
|
|
1122
|
-
materialize(projectRoot, entries) {
|
|
1123
|
-
return writeClaudeCodeHookSettings(projectRoot, entries);
|
|
1124
|
-
}
|
|
1125
|
-
};
|
|
1126
|
-
}
|
|
1127
|
-
function defaultAgentSessionHookAdapters(env = process.env) {
|
|
1128
|
-
if (env.RIG_AGENT_SESSION_HOOK_ADAPTER === "claude-code") {
|
|
1129
|
-
return [createClaudeCodeSessionHookAdapter()];
|
|
1130
|
-
}
|
|
1131
|
-
if (env.RIG_AGENT_SESSION_HOOK_ADAPTER === "pi" || typeof env.PI_CODING_AGENT_SESSION_DIR === "string" && env.PI_CODING_AGENT_SESSION_DIR.trim().length > 0 || env.RIG_RUN_PROCESS === "1") {
|
|
1132
|
-
return [createPiNoopSessionHookAdapter()];
|
|
1133
|
-
}
|
|
1134
|
-
return [createClaudeCodeSessionHookAdapter()];
|
|
1135
|
-
}
|
|
1136
|
-
function materializeSessionHookAdapters(projectRoot, entries, adapters = [createClaudeCodeSessionHookAdapter()]) {
|
|
1137
|
-
return adapters.map((adapter) => adapter.materialize(projectRoot, entries));
|
|
1138
|
-
}
|
|
1139
|
-
function applyClaudeCodeSessionHooksToSettings(existing, entries, projectRoot, options = {}) {
|
|
1140
|
-
const hooks = typeof existing.hooks === "object" && existing.hooks !== null && !Array.isArray(existing.hooks) ? existing.hooks : {};
|
|
1141
|
-
const replacePluginOwned = options.replacePluginOwned ?? true;
|
|
1142
|
-
if (replacePluginOwned) {
|
|
1143
|
-
for (const event of Object.keys(hooks)) {
|
|
1144
|
-
const groups = hooks[event] ?? [];
|
|
1145
|
-
const cleaned = [];
|
|
1146
|
-
for (const group of groups) {
|
|
1147
|
-
const operatorHooks = group.hooks.filter((h) => !isPluginOwned(h));
|
|
1148
|
-
if (operatorHooks.length > 0) {
|
|
1149
|
-
cleaned.push({ ...group, hooks: operatorHooks });
|
|
1150
|
-
}
|
|
1151
|
-
}
|
|
1152
|
-
if (cleaned.length > 0) {
|
|
1153
|
-
hooks[event] = cleaned;
|
|
1154
|
-
} else {
|
|
1155
|
-
delete hooks[event];
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
}
|
|
1159
|
-
const materializedEvents = new Set;
|
|
1160
|
-
for (const { pluginName, hook, typed } of entries) {
|
|
1161
|
-
const command = hook.command ?? (typed ? buildTypedHookShimCommand(pluginName, hook, projectRoot) : undefined);
|
|
1162
|
-
if (!command) {
|
|
1163
|
-
continue;
|
|
1164
|
-
}
|
|
1165
|
-
const event = hook.event;
|
|
1166
|
-
materializedEvents.add(event);
|
|
1167
|
-
const matcherString = matcherToString(hook.matcher);
|
|
1168
|
-
const groups = hooks[event] ??= [];
|
|
1169
|
-
let group = groups.find((g) => g.matcher === matcherString);
|
|
1170
|
-
if (!group) {
|
|
1171
|
-
group = matcherString === undefined ? { hooks: [] } : { matcher: matcherString, hooks: [] };
|
|
1172
|
-
groups.push(group);
|
|
1173
|
-
}
|
|
1174
|
-
const alreadyPresent = group.hooks.some((candidate) => candidate[MARKER_PLUGIN] === pluginName && candidate[MARKER_HOOK_ID] === hook.id);
|
|
1175
|
-
if (alreadyPresent) {
|
|
1176
|
-
continue;
|
|
1177
|
-
}
|
|
1178
|
-
group.hooks.push({
|
|
1179
|
-
type: "command",
|
|
1180
|
-
command,
|
|
1181
|
-
[MARKER_PLUGIN]: pluginName,
|
|
1182
|
-
[MARKER_HOOK_ID]: hook.id
|
|
1183
|
-
});
|
|
1184
|
-
}
|
|
1185
|
-
const next = { ...existing };
|
|
1186
|
-
if (Object.keys(hooks).length > 0) {
|
|
1187
|
-
next.hooks = hooks;
|
|
1188
|
-
} else {
|
|
1189
|
-
delete next.hooks;
|
|
1190
|
-
}
|
|
1191
|
-
return { settings: next, events: [...materializedEvents].sort() };
|
|
1192
|
-
}
|
|
1193
|
-
function writeClaudeCodeHookSettings(projectRoot, entries) {
|
|
1194
|
-
const settingsPath = resolve4(projectRoot, ".claude", "settings.json");
|
|
1195
|
-
const existing = existsSync6(settingsPath) ? safeReadJson(settingsPath) : {};
|
|
1196
|
-
const { settings, events } = applyClaudeCodeSessionHooksToSettings(existing, entries, projectRoot);
|
|
1197
|
-
mkdirSync3(dirname2(settingsPath), { recursive: true });
|
|
1198
|
-
writeFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}
|
|
1199
|
-
`, "utf-8");
|
|
1200
|
-
return {
|
|
1201
|
-
adapterId: "claude-code",
|
|
1202
|
-
status: "materialized",
|
|
1203
|
-
path: settingsPath,
|
|
1204
|
-
events
|
|
1205
|
-
};
|
|
1206
|
-
}
|
|
1207
|
-
function safeReadJson(path) {
|
|
1208
|
-
try {
|
|
1209
|
-
return JSON.parse(readFileSync4(path, "utf-8"));
|
|
1210
|
-
} catch {
|
|
1211
|
-
return {};
|
|
1212
|
-
}
|
|
1213
|
-
}
|
|
1214
|
-
|
|
1215
1069
|
// packages/core/src/plugin-host-context.ts
|
|
1216
1070
|
var ManagedRepoCap = defineCapability(MANAGED_REPO_SERVICE_CAPABILITY);
|
|
1071
|
+
var RepoChangeSetCap = defineCapability(REPO_CHANGE_SET);
|
|
1072
|
+
var RepoNativeGitCap = defineCapability(REPO_NATIVE_GIT);
|
|
1073
|
+
var RuntimeSecretsCap = defineCapability(RUNTIME_SECRETS);
|
|
1217
1074
|
var SessionAssetMaterializerCap = defineCapability(SESSION_ASSET_MATERIALIZER);
|
|
1218
|
-
var
|
|
1075
|
+
var SessionHookMaterializerCap = defineCapability(SESSION_HOOK_MATERIALIZER);
|
|
1076
|
+
var TaskArtifactsCap = defineCapability(TASK_ARTIFACTS);
|
|
1077
|
+
var TaskStateStoreCap = defineCapability(TASK_STATE_STORE);
|
|
1078
|
+
var TaskTrackerReadinessPolicyCap = defineCapability(TASK_TRACKER_READINESS_POLICY);
|
|
1079
|
+
var TaskTrackerReconciliationPolicyCap = defineCapability(TASK_TRACKER_RECONCILIATION_POLICY);
|
|
1080
|
+
var TaskTrackerRepoLocatorCap = defineCapability(TASK_TRACKER_REPO_LOCATOR);
|
|
1081
|
+
var TaskTrackerStateCap = defineCapability(TASK_TRACKER_STATE);
|
|
1219
1082
|
var ToolMaterializerCap = defineCapability(TOOL_MATERIALIZER);
|
|
1220
1083
|
async function buildPluginHostContext(projectRoot) {
|
|
1221
1084
|
let config;
|
|
@@ -1238,10 +1101,20 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
1238
1101
|
validatorRegistry.register(impl);
|
|
1239
1102
|
}
|
|
1240
1103
|
const taskSourceRegistry = buildTaskSourceRegistry(config, pluginHost, { projectRoot });
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1104
|
+
async function installIfResolved(capability) {
|
|
1105
|
+
const impl = await capability.resolve(pluginHost);
|
|
1106
|
+
if (impl)
|
|
1107
|
+
installCapability(capability, impl);
|
|
1108
|
+
}
|
|
1109
|
+
await installIfResolved(RepoChangeSetCap);
|
|
1110
|
+
await installIfResolved(RepoNativeGitCap);
|
|
1111
|
+
await installIfResolved(RuntimeSecretsCap);
|
|
1112
|
+
await installIfResolved(TaskArtifactsCap);
|
|
1113
|
+
await installIfResolved(TaskStateStoreCap);
|
|
1114
|
+
await installIfResolved(TaskTrackerReadinessPolicyCap);
|
|
1115
|
+
await installIfResolved(TaskTrackerReconciliationPolicyCap);
|
|
1116
|
+
await installIfResolved(TaskTrackerRepoLocatorCap);
|
|
1117
|
+
await installIfResolved(TaskTrackerStateCap);
|
|
1245
1118
|
const toolMaterializer = await ToolMaterializerCap.resolve(pluginHost);
|
|
1246
1119
|
if (toolMaterializer) {
|
|
1247
1120
|
installCapability(ToolMaterializerCap, toolMaterializer);
|
|
@@ -1268,7 +1141,10 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
1268
1141
|
typed: Boolean(hook.handler)
|
|
1269
1142
|
})));
|
|
1270
1143
|
if (hookEntries.length > 0) {
|
|
1271
|
-
|
|
1144
|
+
const sessionHookMaterializer = await SessionHookMaterializerCap.resolve(pluginHost);
|
|
1145
|
+
if (sessionHookMaterializer) {
|
|
1146
|
+
await sessionHookMaterializer.materializeSessionHooks(projectRoot, hookEntries);
|
|
1147
|
+
}
|
|
1272
1148
|
}
|
|
1273
1149
|
} catch (err) {
|
|
1274
1150
|
console.warn(`[plugin-host] hook materialization failed: ${err instanceof Error ? err.message : err}`);
|