priiisk 0.1.2 → 0.1.4

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.
@@ -3545,12 +3545,12 @@ var posixImpl = /* @__PURE__ */ Path.of({
3545
3545
  resolve,
3546
3546
  normalize(path) {
3547
3547
  if (path.length === 0) return ".";
3548
- const isAbsolute = path.charCodeAt(0) === 47;
3548
+ const isAbsolute2 = path.charCodeAt(0) === 47;
3549
3549
  const trailingSeparator = path.charCodeAt(path.length - 1) === 47;
3550
- path = normalizeStringPosix(path, !isAbsolute);
3551
- if (path.length === 0 && !isAbsolute) path = ".";
3550
+ path = normalizeStringPosix(path, !isAbsolute2);
3551
+ if (path.length === 0 && !isAbsolute2) path = ".";
3552
3552
  if (path.length > 0 && trailingSeparator) path += "/";
3553
- if (isAbsolute) return "/" + path;
3553
+ if (isAbsolute2) return "/" + path;
3554
3554
  return path;
3555
3555
  },
3556
3556
  isAbsolute(path) {
@@ -3770,9 +3770,9 @@ var posixImpl = /* @__PURE__ */ Path.of({
3770
3770
  };
3771
3771
  if (path.length === 0) return ret;
3772
3772
  let code = path.charCodeAt(0);
3773
- const isAbsolute = code === 47;
3773
+ const isAbsolute2 = code === 47;
3774
3774
  let start3;
3775
- if (isAbsolute) {
3775
+ if (isAbsolute2) {
3776
3776
  ret.root = "/";
3777
3777
  start3 = 1;
3778
3778
  } else {
@@ -3808,11 +3808,11 @@ var posixImpl = /* @__PURE__ */ Path.of({
3808
3808
  preDotState === 0 || // The (right-most) trimmed path component is exactly '..'
3809
3809
  preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {
3810
3810
  if (end !== -1) {
3811
- if (startPart === 0 && isAbsolute) ret.base = ret.name = path.slice(1, end);
3811
+ if (startPart === 0 && isAbsolute2) ret.base = ret.name = path.slice(1, end);
3812
3812
  else ret.base = ret.name = path.slice(startPart, end);
3813
3813
  }
3814
3814
  } else {
3815
- if (startPart === 0 && isAbsolute) {
3815
+ if (startPart === 0 && isAbsolute2) {
3816
3816
  ret.name = path.slice(1, startDot);
3817
3817
  ret.base = path.slice(1, end);
3818
3818
  } else {
@@ -3822,7 +3822,7 @@ var posixImpl = /* @__PURE__ */ Path.of({
3822
3822
  ret.ext = path.slice(startDot, end);
3823
3823
  }
3824
3824
  if (startPart > 0) ret.dir = path.slice(0, startPart - 1);
3825
- else if (isAbsolute) ret.dir = "/";
3825
+ else if (isAbsolute2) ret.dir = "/";
3826
3826
  return ret;
3827
3827
  },
3828
3828
  sep: "/",
@@ -9008,10 +9008,10 @@ var CloseLatch = /* @__PURE__ */ Reference()("@effect/platform/WorkerRunner/Clos
9008
9008
  var PlatformRunner2 = PlatformRunner;
9009
9009
  var CloseLatch2 = CloseLatch;
9010
9010
 
9011
- // packages/config/src/project/projectPaths.ts
9011
+ // packages/config/src/project/projectScope.ts
9012
9012
  import { createHash } from "node:crypto";
9013
- import { tmpdir } from "node:os";
9014
- import { join as join3, resolve as resolve4 } from "node:path";
9013
+ import { existsSync, realpathSync } from "node:fs";
9014
+ import { basename, dirname, join as join3, parse as parse3, resolve as resolve4 } from "node:path";
9015
9015
 
9016
9016
  // packages/config/src/loaders/storageRoots.ts
9017
9017
  import { homedir } from "node:os";
@@ -9027,78 +9027,22 @@ var resolveConfigRootSync = () => xdgRoot("XDG_CONFIG_HOME", join2(homedir(), ".
9027
9027
  var resolveStateRootSync = () => configuredRoot(PRIIISK_STATE_ROOT_ENV) ?? xdgRoot("XDG_STATE_HOME", join2(homedir(), ".local", "state"));
9028
9028
  var resolveCacheRootSync = () => configuredRoot(PRIIISK_CACHE_ROOT_ENV) ?? xdgRoot("XDG_CACHE_HOME", join2(homedir(), ".cache"));
9029
9029
 
9030
- // packages/config/src/project/projectPaths.ts
9031
- var PRIIISK_RUNTIME_DIR_ENV = "PRIIISK_RUNTIME_DIR";
9032
- var PRIIISK_PI_AGENT_DIR_ENV = "PRIIISK_PI_AGENT_DIR";
9033
- var campRunStorageKey = (runId) => createHash("sha256").update(runId).digest("hex").slice(0, 24);
9034
- var campRunPaths = (paths, runId) => {
9035
- const runDir = join3(paths.runsDir, campRunStorageKey(runId));
9036
- const controllerDir = join3(runDir, "controller");
9037
- return {
9038
- runDir,
9039
- manifestPath: join3(runDir, "camp.json"),
9040
- sessionsDir: join3(runDir, "sessions"),
9041
- controllerDir,
9042
- eventsDir: join3(controllerDir, "events"),
9043
- consumersPath: join3(controllerDir, "consumers.json"),
9044
- receiptsPath: join3(controllerDir, "receipts.json")
9045
- };
9046
- };
9047
- var runtimeOwner = () => {
9048
- const uid = process.getuid?.();
9049
- return uid === void 0 ? "user" : String(uid);
9050
- };
9051
- var resolveRuntimeDirSync = () => {
9052
- const override = process.env[PRIIISK_RUNTIME_DIR_ENV]?.trim();
9053
- if (override !== void 0 && override !== "") return resolve4(override);
9054
- const platformRuntime = process.env.XDG_RUNTIME_DIR?.trim();
9055
- if (platformRuntime !== void 0 && platformRuntime !== "") {
9056
- return join3(resolve4(platformRuntime), "priiisk");
9057
- }
9058
- return join3(tmpdir(), `priiisk-${runtimeOwner()}`);
9059
- };
9060
- var campProjectPaths = (scope3) => {
9061
- const runtimeDir = resolveRuntimeDirSync();
9062
- const controllerDir = join3(scope3.stateDir, "controller");
9063
- return {
9064
- stateDir: scope3.stateDir,
9065
- runsDir: join3(scope3.stateDir, "runs"),
9066
- quarantineDir: join3(scope3.stateDir, "quarantine"),
9067
- sessionsDir: join3(scope3.stateDir, "sessions"),
9068
- controllerDir,
9069
- eventsDir: join3(controllerDir, "events"),
9070
- consumersPath: join3(controllerDir, "consumers.json"),
9071
- receiptsPath: join3(controllerDir, "receipts.json"),
9072
- agentDir: join3(scope3.stateDir, "pi-agent"),
9073
- logsDir: join3(scope3.stateDir, "logs"),
9074
- cacheDir: join3(resolveCacheRootSync(), "projects", scope3.hash),
9075
- runtimeDir,
9076
- socketPath: join3(runtimeDir, `${scope3.hash}.sock`),
9077
- lifecycleLockPath: join3(runtimeDir, `${scope3.hash}.lifecycle.lock`),
9078
- manifestPath: join3(scope3.stateDir, "camp.json"),
9079
- healthPath: join3(scope3.stateDir, "logs", "health.json")
9080
- };
9081
- };
9082
-
9083
9030
  // packages/config/src/project/projectScope.ts
9084
- import { createHash as createHash2 } from "node:crypto";
9085
- import { existsSync, realpathSync } from "node:fs";
9086
- import { basename, dirname, join as join4, parse as parse3, resolve as resolve5 } from "node:path";
9087
9031
  var PRIIISK_PROJECT_CWD_ENV = "PRIIISK_PROJECT_CWD";
9088
9032
  var PROJECTS_DIR_NAME = "projects";
9089
9033
  var PROJECT_HASH_HEX_LENGTH = 12;
9090
- var normalizeProjectCwd = (cwd) => realpathSync.native(resolve5(cwd));
9034
+ var normalizeProjectCwd = (cwd) => realpathSync.native(resolve4(cwd));
9091
9035
  var findProjectRootSync = (cwd) => {
9092
9036
  let current = normalizeProjectCwd(cwd);
9093
9037
  const filesystemRoot = parse3(current).root;
9094
9038
  while (current !== filesystemRoot) {
9095
- if (existsSync(join4(current, ".git"))) return current;
9039
+ if (existsSync(join3(current, ".git"))) return current;
9096
9040
  current = dirname(current);
9097
9041
  }
9098
- return existsSync(join4(filesystemRoot, ".git")) ? filesystemRoot : normalizeProjectCwd(cwd);
9042
+ return existsSync(join3(filesystemRoot, ".git")) ? filesystemRoot : normalizeProjectCwd(cwd);
9099
9043
  };
9100
- var projectHashFromCwd = (cwd) => createHash2("sha256").update(normalizeProjectCwd(cwd)).digest("hex").slice(0, PROJECT_HASH_HEX_LENGTH);
9101
- var projectStateDirFromHash = (hash) => join4(resolveStateRootSync(), PROJECTS_DIR_NAME, hash);
9044
+ var projectHashFromCwd = (cwd) => createHash("sha256").update(normalizeProjectCwd(cwd)).digest("hex").slice(0, PROJECT_HASH_HEX_LENGTH);
9045
+ var projectStateDirFromHash = (hash) => join3(resolveStateRootSync(), PROJECTS_DIR_NAME, hash);
9102
9046
  var projectScopeFromCwd = (cwd) => {
9103
9047
  const normalized = findProjectRootSync(cwd);
9104
9048
  const hash = projectHashFromCwd(normalized);
@@ -9119,6 +9063,62 @@ var resolveProjectScope = Effect_exports.gen(function* () {
9119
9063
  return projectScopeFromCwd(cwd);
9120
9064
  }).pipe(Effect_exports.catchAll(() => Effect_exports.succeed(resolveProjectScopeSync())));
9121
9065
 
9066
+ // packages/config/src/project/projectPaths.ts
9067
+ import { createHash as createHash2 } from "node:crypto";
9068
+ import { tmpdir } from "node:os";
9069
+ import { join as join4, resolve as resolve5 } from "node:path";
9070
+ var PRIIISK_RUNTIME_DIR_ENV = "PRIIISK_RUNTIME_DIR";
9071
+ var PRIIISK_PI_AGENT_DIR_ENV = "PRIIISK_PI_AGENT_DIR";
9072
+ var campRunStorageKey = (runId) => createHash2("sha256").update(runId).digest("hex").slice(0, 24);
9073
+ var campRunPaths = (paths, runId) => {
9074
+ const runDir = join4(paths.runsDir, campRunStorageKey(runId));
9075
+ const controllerDir = join4(runDir, "controller");
9076
+ return {
9077
+ runDir,
9078
+ manifestPath: join4(runDir, "camp.json"),
9079
+ sessionsDir: join4(runDir, "sessions"),
9080
+ controllerDir,
9081
+ eventsDir: join4(controllerDir, "events"),
9082
+ consumersPath: join4(controllerDir, "consumers.json"),
9083
+ receiptsPath: join4(controllerDir, "receipts.json")
9084
+ };
9085
+ };
9086
+ var runtimeOwner = () => {
9087
+ const uid = process.getuid?.();
9088
+ return uid === void 0 ? "user" : String(uid);
9089
+ };
9090
+ var resolveRuntimeDirSync = () => {
9091
+ const override = process.env[PRIIISK_RUNTIME_DIR_ENV]?.trim();
9092
+ if (override !== void 0 && override !== "") return resolve5(override);
9093
+ const platformRuntime = process.env.XDG_RUNTIME_DIR?.trim();
9094
+ if (platformRuntime !== void 0 && platformRuntime !== "") {
9095
+ return join4(resolve5(platformRuntime), "priiisk");
9096
+ }
9097
+ return join4(tmpdir(), `priiisk-${runtimeOwner()}`);
9098
+ };
9099
+ var campProjectPaths = (scope3) => {
9100
+ const runtimeDir = resolveRuntimeDirSync();
9101
+ const controllerDir = join4(scope3.stateDir, "controller");
9102
+ return {
9103
+ stateDir: scope3.stateDir,
9104
+ runsDir: join4(scope3.stateDir, "runs"),
9105
+ quarantineDir: join4(scope3.stateDir, "quarantine"),
9106
+ sessionsDir: join4(scope3.stateDir, "sessions"),
9107
+ controllerDir,
9108
+ eventsDir: join4(controllerDir, "events"),
9109
+ consumersPath: join4(controllerDir, "consumers.json"),
9110
+ receiptsPath: join4(controllerDir, "receipts.json"),
9111
+ agentDir: join4(scope3.stateDir, "pi-agent"),
9112
+ logsDir: join4(scope3.stateDir, "logs"),
9113
+ cacheDir: join4(resolveCacheRootSync(), "projects", scope3.hash),
9114
+ runtimeDir,
9115
+ socketPath: join4(runtimeDir, `${scope3.hash}.sock`),
9116
+ lifecycleLockPath: join4(runtimeDir, `${scope3.hash}.lifecycle.lock`),
9117
+ manifestPath: join4(scope3.stateDir, "camp.json"),
9118
+ healthPath: join4(scope3.stateDir, "logs", "health.json")
9119
+ };
9120
+ };
9121
+
9122
9122
  // packages/config/src/domain/configErrors.ts
9123
9123
  var StateIoError = class extends Data_exports.TaggedError("StateIoError") {
9124
9124
  };
@@ -9194,8 +9194,8 @@ var loadReferencedMcpCredentials = (fs, names) => Effect_exports.gen(function* (
9194
9194
  );
9195
9195
  });
9196
9196
 
9197
- // packages/config/src/loaders/userStoragePreparation.ts
9198
- import { dirname as dirname2 } from "node:path";
9197
+ // packages/config/src/loaders/projectConfigLoader.ts
9198
+ import { join as join6 } from "node:path";
9199
9199
 
9200
9200
  // node_modules/.pnpm/smol-toml@1.7.0/node_modules/smol-toml/dist/date.js
9201
9201
  var DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|[-+]\d{2}:\d{2})?$/i;
@@ -9966,6 +9966,133 @@ var WorkerDefaultsSchema = Schema_exports.Struct({
9966
9966
  directTools: Schema_exports.optional(DirectToolsConfigSchema)
9967
9967
  });
9968
9968
 
9969
+ // packages/config/src/schema/projectConfig.ts
9970
+ var ProjectRolePresetSchema = RolePresetSchema.omit("readTools");
9971
+ var ProjectDefaultsSchema = Schema_exports.partial(WorkerDefaultsSchema.omit("readTools"));
9972
+ var ProjectWorkerConfigSchema = Schema_exports.Struct({
9973
+ schemaVersion: Schema_exports.Literal(1),
9974
+ models: Schema_exports.optional(Schema_exports.Record({ key: Schema_exports.String, value: ModelAliasSchema })),
9975
+ roles: Schema_exports.optional(Schema_exports.Record({ key: Schema_exports.String, value: ProjectRolePresetSchema })),
9976
+ hirePresets: Schema_exports.optional(Schema_exports.Record({ key: Schema_exports.String, value: HirePresetSchema })),
9977
+ skillGroups: Schema_exports.optional(SkillGroupsSchema),
9978
+ defaults: Schema_exports.optional(ProjectDefaultsSchema)
9979
+ });
9980
+ var executableReason = (what) => `${what} \u0437\u0430\u0434\u0430\u0435\u0442 \u0442\u043E, \u0447\u0442\u043E \u043B\u0430\u0433\u0435\u0440\u044C \u0437\u0430\u043F\u0443\u0441\u043A\u0430\u0435\u0442, \u043F\u043E\u044D\u0442\u043E\u043C\u0443 \u043F\u0440\u0438\u043D\u0438\u043C\u0430\u0435\u0442\u0441\u044F \u0442\u043E\u043B\u044C\u043A\u043E \u0438\u0437 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C\u0441\u043A\u043E\u0433\u043E config`;
9981
+ var findProjectConfigForbiddenFields = (parsed) => {
9982
+ if (typeof parsed !== "object" || parsed === null) return [];
9983
+ const found = [];
9984
+ if (Reflect.get(parsed, "mcpServers") !== void 0) {
9985
+ found.push({ field: "mcpServers", reason: executableReason("\u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u0435 MCP-\u0441\u0435\u0440\u0432\u0435\u0440\u0430") });
9986
+ }
9987
+ const defaults = Reflect.get(parsed, "defaults");
9988
+ if (typeof defaults === "object" && defaults !== null && Reflect.get(defaults, "readTools") !== void 0) {
9989
+ found.push({ field: "defaults.readTools", reason: executableReason("\u043A\u0430\u0442\u0430\u043B\u043E\u0433 \u0431\u0438\u043D\u0430\u0440\u0435\u0439") });
9990
+ }
9991
+ const roles = Reflect.get(parsed, "roles");
9992
+ if (typeof roles === "object" && roles !== null) {
9993
+ for (const [role, entry] of Object.entries(roles)) {
9994
+ if (typeof entry === "object" && entry !== null && Reflect.get(entry, "readTools") !== void 0) {
9995
+ found.push({
9996
+ field: `roles.${role}.readTools`,
9997
+ reason: executableReason("\u043A\u0430\u0442\u0430\u043B\u043E\u0433 \u0431\u0438\u043D\u0430\u0440\u0435\u0439 \u0440\u043E\u043B\u0438")
9998
+ });
9999
+ }
10000
+ }
10001
+ }
10002
+ return found;
10003
+ };
10004
+
10005
+ // packages/config/src/loaders/projectConfigLoader.ts
10006
+ var PROJECT_CONFIG_DIRECTORY = ".priiisk";
10007
+ var PROJECT_CONFIG_FILE = "config.toml";
10008
+ var projectConfigPath = (projectCwd) => join6(projectCwd, PROJECT_CONFIG_DIRECTORY, PROJECT_CONFIG_FILE);
10009
+ var decodeProjectConfig = Schema_exports.decodeUnknown(ProjectWorkerConfigSchema, {
10010
+ onExcessProperty: "error"
10011
+ });
10012
+ var loadProjectWorkerConfig = (fs, projectCwd) => Effect_exports.gen(function* () {
10013
+ const path = projectConfigPath(projectCwd);
10014
+ const raw3 = yield* fs.readFileString(path).pipe(
10015
+ Effect_exports.map((content) => content),
10016
+ Effect_exports.catchIf(
10017
+ (error) => error._tag === "SystemError" && error.reason === "NotFound",
10018
+ () => Effect_exports.succeed(void 0)
10019
+ ),
10020
+ Effect_exports.mapError((cause) => new WorkerConfigInvalidError({ path, message: String(cause) }))
10021
+ );
10022
+ if (raw3 === void 0) return void 0;
10023
+ const parsed = yield* Effect_exports.try({
10024
+ try: () => parse4(raw3),
10025
+ catch: (cause) => new WorkerConfigInvalidError({ path, message: `\u043D\u0435\u0432\u0430\u043B\u0438\u0434\u043D\u044B\u0439 TOML: ${String(cause)}` })
10026
+ });
10027
+ const forbidden = findProjectConfigForbiddenFields(parsed);
10028
+ if (forbidden.length > 0) {
10029
+ return yield* Effect_exports.fail(
10030
+ new WorkerConfigInvalidError({
10031
+ path,
10032
+ message: forbidden.map((entry) => `\u043F\u043E\u043B\u0435 ${entry.field} \u043D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E \u0432 project config: ${entry.reason}`).join("; ")
10033
+ })
10034
+ );
10035
+ }
10036
+ return yield* decodeProjectConfig(parsed).pipe(
10037
+ Effect_exports.mapError(
10038
+ (parseError) => new WorkerConfigInvalidError({
10039
+ path,
10040
+ message: `\u043D\u0435 \u043F\u0440\u043E\u0448\u0435\u043B \u0441\u0445\u0435\u043C\u0443: ${String(parseError)}`
10041
+ })
10042
+ )
10043
+ );
10044
+ });
10045
+ var mergeRecords = (user, project, mergeEntry) => {
10046
+ if (project === void 0) return user;
10047
+ const merged = { ...user ?? {} };
10048
+ for (const [key, entry] of Object.entries(project)) {
10049
+ merged[key] = mergeEntry(user?.[key], entry);
10050
+ }
10051
+ return merged;
10052
+ };
10053
+ var mergeWorkerConfigs = (user, project) => {
10054
+ if (project === void 0) return user;
10055
+ const models = { ...user?.models ?? {}, ...project.models ?? {} };
10056
+ const defaults = {
10057
+ ...user?.defaults ?? {},
10058
+ ...project.defaults ?? {},
10059
+ ...user?.defaults?.readTools === void 0 ? {} : { readTools: user.defaults.readTools }
10060
+ };
10061
+ const roles = mergeRecords(user?.roles, project.roles, (userRole, projectRole) => ({
10062
+ ...userRole,
10063
+ ...projectRole,
10064
+ ...userRole?.readTools === void 0 ? {} : { readTools: userRole.readTools }
10065
+ }));
10066
+ const hirePresets = mergeRecords(
10067
+ user?.hirePresets,
10068
+ project.hirePresets,
10069
+ (userPreset, preset) => ({
10070
+ ...userPreset,
10071
+ ...preset
10072
+ })
10073
+ );
10074
+ const skillGroups = mergeRecords(user?.skillGroups, project.skillGroups, (_, groups) => groups);
10075
+ return {
10076
+ schemaVersion: 1,
10077
+ models,
10078
+ defaults,
10079
+ ...roles === void 0 ? {} : { roles },
10080
+ ...hirePresets === void 0 ? {} : { hirePresets },
10081
+ ...skillGroups === void 0 ? {} : { skillGroups },
10082
+ ...user?.mcpServers === void 0 ? {} : { mcpServers: user.mcpServers }
10083
+ };
10084
+ };
10085
+ var describeProjectConfigOverrides = (project) => [
10086
+ ...project.defaults === void 0 ? [] : ["defaults"],
10087
+ ...project.models === void 0 ? [] : Object.keys(project.models).map((n) => `models.${n}`),
10088
+ ...project.roles === void 0 ? [] : Object.keys(project.roles).map((n) => `roles.${n}`),
10089
+ ...project.hirePresets === void 0 ? [] : Object.keys(project.hirePresets).map((n) => `hirePresets.${n}`),
10090
+ ...project.skillGroups === void 0 ? [] : Object.keys(project.skillGroups).map((n) => `skillGroups.${n}`)
10091
+ ];
10092
+
10093
+ // packages/config/src/loaders/userStoragePreparation.ts
10094
+ import { dirname as dirname2 } from "node:path";
10095
+
9969
10096
  // packages/config/src/schema/workerConfig.ts
9970
10097
  var WorkerConfigSchema = Schema_exports.Struct({
9971
10098
  schemaVersion: Schema_exports.Literal(1),
@@ -9979,7 +10106,7 @@ var WorkerConfigSchema = Schema_exports.Struct({
9979
10106
 
9980
10107
  // packages/config/src/loaders/workerConfigLoader.ts
9981
10108
  var decodeWorkerConfig = Schema_exports.decodeUnknown(WorkerConfigSchema, { onExcessProperty: "error" });
9982
- var loadWorkerConfig = (fs) => Effect_exports.gen(function* () {
10109
+ var loadUserWorkerConfig = (fs) => Effect_exports.gen(function* () {
9983
10110
  const configPath = yield* resolveWorkerConfigPath;
9984
10111
  const raw3 = yield* fs.readFileString(configPath).pipe(
9985
10112
  Effect_exports.map((content) => content),
@@ -10010,19 +10137,25 @@ var loadWorkerConfig = (fs) => Effect_exports.gen(function* () {
10010
10137
  )
10011
10138
  );
10012
10139
  });
10140
+ var loadWorkerConfig = (fs, options4 = {}) => Effect_exports.gen(function* () {
10141
+ const user = yield* loadUserWorkerConfig(fs);
10142
+ const projectCwd = options4.projectCwd ?? (yield* resolveProjectScope.pipe(Effect_exports.map((scope3) => scope3.cwd)));
10143
+ const project = yield* loadProjectWorkerConfig(fs, projectCwd);
10144
+ return mergeWorkerConfigs(user, project);
10145
+ });
10013
10146
 
10014
10147
  // packages/config/src/project/roleProfile.ts
10015
10148
  import { tmpdir as tmpdir2 } from "node:os";
10016
10149
 
10017
10150
  // packages/config/src/project/runtimeAssets.ts
10018
10151
  import { existsSync as existsSync2 } from "node:fs";
10019
- import { dirname as dirname3, join as join6, parse as parse5 } from "node:path";
10152
+ import { dirname as dirname3, join as join7, parse as parse5 } from "node:path";
10020
10153
  import { fileURLToPath } from "node:url";
10021
10154
  var findAssetRoot = (moduleUrl, directoryName) => {
10022
10155
  const root = parse5(fileURLToPath(moduleUrl)).root;
10023
10156
  let current = dirname3(fileURLToPath(moduleUrl));
10024
10157
  for (; ; ) {
10025
- const candidate = join6(current, directoryName);
10158
+ const candidate = join7(current, directoryName);
10026
10159
  if (existsSync2(candidate)) return candidate;
10027
10160
  if (current === root) return candidate;
10028
10161
  current = dirname3(current);
@@ -10030,8 +10163,8 @@ var findAssetRoot = (moduleUrl, directoryName) => {
10030
10163
  };
10031
10164
  var assetRoots = /* @__PURE__ */ new Map();
10032
10165
  var resolveRuntimeAssetRoot = (moduleUrl, directoryName) => {
10033
- const cached2 = assetRoots.get(directoryName);
10034
- if (cached2 !== void 0) return cached2;
10166
+ const cached3 = assetRoots.get(directoryName);
10167
+ if (cached3 !== void 0) return cached3;
10035
10168
  const resolved = findAssetRoot(moduleUrl, directoryName);
10036
10169
  assetRoots.set(directoryName, resolved);
10037
10170
  return resolved;
@@ -10418,9 +10551,108 @@ var listWorkerModelCatalogEntries = (config) => {
10418
10551
  })).sort((left, right) => left.alias.localeCompare(right.alias));
10419
10552
  };
10420
10553
 
10554
+ // packages/config/src/sandbox/directToolSandbox.ts
10555
+ import { execFileSync } from "node:child_process";
10556
+ import { accessSync, constants } from "node:fs";
10557
+ import { delimiter, isAbsolute, join as join8 } from "node:path";
10558
+ var DirectToolSandboxKind = {
10559
+ bubblewrap: "bubblewrap",
10560
+ none: "none"
10561
+ };
10562
+ var DirectToolSandboxAbsence = {
10563
+ unsupportedPlatform: "unsupported_platform",
10564
+ binaryMissing: "binary_missing",
10565
+ probeFailed: "probe_failed",
10566
+ disabled: "disabled"
10567
+ };
10568
+ var DIRECT_TOOL_SANDBOX_ENV = "PRIIISK_DIRECT_TOOL_SANDBOX";
10569
+ var resolveExecutablePath = (bin, environment = process.env) => {
10570
+ const executable = (candidate) => {
10571
+ try {
10572
+ accessSync(candidate, constants.X_OK);
10573
+ return true;
10574
+ } catch {
10575
+ return false;
10576
+ }
10577
+ };
10578
+ if (bin.includes("/")) return isAbsolute(bin) && executable(bin) ? bin : void 0;
10579
+ for (const directory of (environment.PATH ?? "").split(delimiter)) {
10580
+ if (directory === "") continue;
10581
+ const candidate = join8(directory, bin);
10582
+ if (executable(candidate)) return candidate;
10583
+ }
10584
+ return void 0;
10585
+ };
10586
+ var sandboxArguments = (cwd, writable) => [
10587
+ "--unshare-all",
10588
+ "--ro-bind",
10589
+ "/",
10590
+ "/",
10591
+ "--dev",
10592
+ "/dev",
10593
+ "--proc",
10594
+ "/proc",
10595
+ "--tmpfs",
10596
+ "/tmp",
10597
+ ...writable ? ["--bind", cwd, cwd] : [],
10598
+ "--chdir",
10599
+ cwd,
10600
+ "--die-with-parent",
10601
+ "--new-session",
10602
+ "--"
10603
+ ];
10604
+ var probeBubblewrap = (command) => {
10605
+ try {
10606
+ execFileSync(command, [...sandboxArguments("/", false), "/bin/true"], {
10607
+ stdio: "ignore",
10608
+ timeout: 5e3
10609
+ });
10610
+ return void 0;
10611
+ } catch (cause) {
10612
+ return cause instanceof Error ? cause.message : String(cause);
10613
+ }
10614
+ };
10615
+ var cached2;
10616
+ var detectDirectToolSandbox = (environment = process.env, platform = process.platform) => {
10617
+ if (environment[DIRECT_TOOL_SANDBOX_ENV] === "0") {
10618
+ return { kind: DirectToolSandboxKind.none, absence: DirectToolSandboxAbsence.disabled };
10619
+ }
10620
+ if (platform !== "linux") {
10621
+ return {
10622
+ kind: DirectToolSandboxKind.none,
10623
+ absence: DirectToolSandboxAbsence.unsupportedPlatform,
10624
+ detail: platform
10625
+ };
10626
+ }
10627
+ const command = resolveExecutablePath("bwrap", environment);
10628
+ if (command === void 0) {
10629
+ return {
10630
+ kind: DirectToolSandboxKind.none,
10631
+ absence: DirectToolSandboxAbsence.binaryMissing,
10632
+ detail: "bwrap"
10633
+ };
10634
+ }
10635
+ const failure = probeBubblewrap(command);
10636
+ return failure === void 0 ? { kind: DirectToolSandboxKind.bubblewrap, command } : {
10637
+ kind: DirectToolSandboxKind.none,
10638
+ absence: DirectToolSandboxAbsence.probeFailed,
10639
+ detail: failure
10640
+ };
10641
+ };
10642
+ var currentDirectToolSandbox = () => {
10643
+ cached2 ??= detectDirectToolSandbox();
10644
+ return cached2;
10645
+ };
10646
+ var directToolSandboxCommand = (sandbox2, executablePath, args, options4) => sandbox2.kind === DirectToolSandboxKind.bubblewrap && sandbox2.command !== void 0 ? {
10647
+ command: sandbox2.command,
10648
+ args: [...sandboxArguments(options4.cwd, true), executablePath, ...args]
10649
+ } : { command: executablePath, args };
10650
+ var isDirectToolSandboxFailure = (stderr3) => stderr3.startsWith("bwrap:");
10651
+ var describeDirectToolSandbox = (sandbox2) => sandbox2.kind === DirectToolSandboxKind.bubblewrap ? "External binaries run in a bubblewrap sandbox: read-only filesystem, writable worker directory, no network" : sandbox2.absence === DirectToolSandboxAbsence.disabled ? `External binaries run without an OS sandbox: disabled by ${DIRECT_TOOL_SANDBOX_ENV}` : sandbox2.absence === DirectToolSandboxAbsence.unsupportedPlatform ? `External binaries run without an OS sandbox: no supported mechanism on ${sandbox2.detail ?? "this platform"}` : sandbox2.absence === DirectToolSandboxAbsence.binaryMissing ? "External binaries run without an OS sandbox: bubblewrap (bwrap) is not installed" : "External binaries run without an OS sandbox: bubblewrap is present but cannot start";
10652
+
10421
10653
  // packages/protocol/src/domain/protocolVersion.ts
10422
10654
  var PRIIISK_PROTOCOL_VERSION = "11";
10423
- var PRIIISK_PROTOCOL_PACKAGE_VERSION = "0.1.2";
10655
+ var PRIIISK_PROTOCOL_PACKAGE_VERSION = "0.1.4";
10424
10656
  var ProtocolVersionSchema = Schema_exports.String.pipe(Schema_exports.minLength(1));
10425
10657
 
10426
10658
  // packages/protocol/src/domain/protocolIdentifiers.ts
@@ -13295,7 +13527,7 @@ var CampProtocol = class extends RpcGroup_exports.make(
13295
13527
  };
13296
13528
 
13297
13529
  // packages/camp-state/src/bootstrap/campHostVersion.ts
13298
- var PRIIISK_HOST_VERSION = "0.1.2";
13530
+ var PRIIISK_HOST_VERSION = "0.1.4";
13299
13531
 
13300
13532
  // packages/surface/src/domain/surfaceModel.ts
13301
13533
  var NonEmptyString7 = Schema_exports.String.pipe(Schema_exports.minLength(1));
@@ -13936,42 +14168,47 @@ var campHealthLiveness = (snapshot, now, staleAfterMs = CAMP_HEALTH_STALE_AFTER_
13936
14168
  import { randomUUID as randomUUID3 } from "node:crypto";
13937
14169
  var CampHealthPersistenceError = class extends Data_exports.TaggedError("CampHealthPersistenceError") {
13938
14170
  };
14171
+ var CampHealthVersionError = class extends Data_exports.TaggedError("CampHealthVersionError") {
14172
+ };
13939
14173
  var decodeHealth = Schema_exports.decodeUnknown(CampHealthSnapshotSchema, {
13940
14174
  onExcessProperty: "error"
13941
14175
  });
14176
+ var readError = (path, message, cause) => new CampHealthPersistenceError({ operation: "read", path, message, cause });
14177
+ var decodeCampHealth = (path, value) => {
14178
+ if (typeof value === "object" && value !== null && "schemaVersion" in value && typeof value.schemaVersion === "number" && Number.isSafeInteger(value.schemaVersion) && value.schemaVersion !== CAMP_HEALTH_SCHEMA_VERSION) {
14179
+ return Effect_exports.fail(
14180
+ new CampHealthVersionError({
14181
+ path,
14182
+ expectedVersion: CAMP_HEALTH_SCHEMA_VERSION,
14183
+ receivedVersion: value.schemaVersion,
14184
+ message: `health snapshot schemaVersion ${String(value.schemaVersion)} was written by another runtime version; this runtime writes ${String(CAMP_HEALTH_SCHEMA_VERSION)}`
14185
+ })
14186
+ );
14187
+ }
14188
+ return decodeHealth(value).pipe(
14189
+ Effect_exports.mapError(
14190
+ (cause) => readError(path, `health snapshot does not match schema: ${String(cause)}`, cause)
14191
+ )
14192
+ );
14193
+ };
13942
14194
  var loadCampHealth = (fs, path) => fs.exists(path).pipe(
14195
+ Effect_exports.mapError(
14196
+ (cause) => readError(path, `health snapshot is unavailable: ${String(cause)}`, cause)
14197
+ ),
13943
14198
  Effect_exports.flatMap(
13944
14199
  (exists) => exists ? fs.readFileString(path).pipe(
14200
+ Effect_exports.mapError(
14201
+ (cause) => readError(path, `health snapshot is unavailable: ${String(cause)}`, cause)
14202
+ ),
13945
14203
  Effect_exports.flatMap(
13946
14204
  (contents) => Effect_exports.try({
13947
14205
  try: () => JSON.parse(contents),
13948
- catch: (cause) => new CampHealthPersistenceError({
13949
- operation: "read",
13950
- path,
13951
- message: `health snapshot contains invalid JSON: ${String(cause)}`,
13952
- cause
13953
- })
13954
- })
13955
- ),
13956
- Effect_exports.flatMap(decodeHealth),
13957
- Effect_exports.mapError(
13958
- (cause) => cause instanceof CampHealthPersistenceError ? cause : new CampHealthPersistenceError({
13959
- operation: "read",
13960
- path,
13961
- message: `health snapshot is unavailable: ${String(cause)}`,
13962
- cause
14206
+ catch: (cause) => readError(path, `health snapshot contains invalid JSON: ${String(cause)}`, cause)
13963
14207
  })
13964
14208
  ),
14209
+ Effect_exports.flatMap((value) => decodeCampHealth(path, value)),
13965
14210
  Effect_exports.map(Option_exports.some)
13966
14211
  ) : Effect_exports.succeed(Option_exports.none())
13967
- ),
13968
- Effect_exports.mapError(
13969
- (cause) => cause instanceof CampHealthPersistenceError ? cause : new CampHealthPersistenceError({
13970
- operation: "read",
13971
- path,
13972
- message: `health snapshot is unavailable: ${String(cause)}`,
13973
- cause
13974
- })
13975
14212
  )
13976
14213
  );
13977
14214
  var saveCampHealth = (fs, path, snapshot) => {
@@ -14091,7 +14328,7 @@ var launchCampPrepared = (surface, request, persistIntent, handshake, persist) =
14091
14328
 
14092
14329
  // packages/camp-state/src/history/campLegacyState.ts
14093
14330
  import { randomUUID as randomUUID4 } from "node:crypto";
14094
- import { join as join7 } from "node:path";
14331
+ import { join as join9 } from "node:path";
14095
14332
  var LEGACY_CAMP_MANIFEST_VERSION = 1;
14096
14333
  var CampLegacyStateErrorCode = {
14097
14334
  invalidManifest: "legacy_manifest_invalid",
@@ -14156,7 +14393,7 @@ var moveStateFile = (fs, source, destination, message) => fs.rename(source, dest
14156
14393
  );
14157
14394
  var quarantineLegacyCampState = (fs, paths) => Effect_exports.gen(function* () {
14158
14395
  const timestamp = yield* Clock_exports.currentTimeMillis;
14159
- const directory = join7(
14396
+ const directory = join9(
14160
14397
  paths.quarantineDir,
14161
14398
  `legacy-v${String(LEGACY_CAMP_MANIFEST_VERSION)}-${String(timestamp)}-${randomUUID4()}`
14162
14399
  );
@@ -14170,8 +14407,8 @@ var quarantineLegacyCampState = (fs, paths) => Effect_exports.gen(function* () {
14170
14407
  )
14171
14408
  )
14172
14409
  );
14173
- const manifestPath = join7(directory, "camp.json");
14174
- const healthPath = join7(directory, "health.json");
14410
+ const manifestPath = join9(directory, "camp.json");
14411
+ const healthPath = join9(directory, "health.json");
14175
14412
  const hasHealth = yield* fs.exists(paths.healthPath).pipe(
14176
14413
  Effect_exports.mapError(
14177
14414
  (cause) => legacyError(
@@ -14224,7 +14461,7 @@ var quarantineLegacyCampState = (fs, paths) => Effect_exports.gen(function* () {
14224
14461
  });
14225
14462
 
14226
14463
  // packages/camp-state/src/history/campRunCatalog.ts
14227
- import { join as join8 } from "node:path";
14464
+ import { join as join10 } from "node:path";
14228
14465
 
14229
14466
  // packages/camp-state/src/history/campRunCatalogModel.ts
14230
14467
  var CampRunCatalogErrorCode = {
@@ -14314,7 +14551,7 @@ var listCampRuns = (fs, project, paths) => Effect_exports.gen(function* () {
14314
14551
  );
14315
14552
  const historical = yield* Effect_exports.forEach(
14316
14553
  entries,
14317
- (entry) => loadCampManifest(fs, join8(paths.runsDir, entry, "camp.json")).pipe(
14554
+ (entry) => loadCampManifest(fs, join10(paths.runsDir, entry, "camp.json")).pipe(
14318
14555
  Effect_exports.mapError(
14319
14556
  (cause) => catalogError(
14320
14557
  "list",
@@ -14326,7 +14563,7 @@ var listCampRuns = (fs, project, paths) => Effect_exports.gen(function* () {
14326
14563
  Effect_exports.flatMap(
14327
14564
  Option_exports.match({
14328
14565
  onNone: () => Effect_exports.succeed(void 0),
14329
- onSome: (manifest) => campRunPaths(paths, manifest.runId).manifestPath !== join8(paths.runsDir, entry, "camp.json") ? Effect_exports.fail(
14566
+ onSome: (manifest) => campRunPaths(paths, manifest.runId).manifestPath !== join10(paths.runsDir, entry, "camp.json") ? Effect_exports.fail(
14330
14567
  catalogError(
14331
14568
  "list",
14332
14569
  CampRunCatalogErrorCode.nonCanonicalRun,
@@ -14638,13 +14875,16 @@ export {
14638
14875
  AgentRoleSchema,
14639
14876
  PiThinkingLevel,
14640
14877
  PiThinkingLevelSchema,
14878
+ projectConfigPath,
14879
+ loadProjectWorkerConfig,
14880
+ describeProjectConfigOverrides,
14881
+ projectScopeFromCwd,
14882
+ resolveProjectScopeSync,
14883
+ resolveProjectScope,
14641
14884
  loadWorkerConfig,
14642
14885
  PRIIISK_PI_AGENT_DIR_ENV,
14643
14886
  campRunPaths,
14644
14887
  campProjectPaths,
14645
- projectScopeFromCwd,
14646
- resolveProjectScopeSync,
14647
- resolveProjectScope,
14648
14888
  resolveRoleProfilePath,
14649
14889
  prepareCampStorage,
14650
14890
  prepareCampRunStorage,
@@ -14665,6 +14905,12 @@ export {
14665
14905
  resolveRolePreset,
14666
14906
  resolveHirePreset,
14667
14907
  listWorkerModelCatalogEntries,
14908
+ DirectToolSandboxKind,
14909
+ resolveExecutablePath,
14910
+ currentDirectToolSandbox,
14911
+ directToolSandboxCommand,
14912
+ isDirectToolSandboxFailure,
14913
+ describeDirectToolSandbox,
14668
14914
  NetSocket,
14669
14915
  fromDuplex,
14670
14916
  layerNet,
@@ -14703,6 +14949,7 @@ export {
14703
14949
  findCampRecoveryHealthComponent,
14704
14950
  CAMP_HEALTH_HEARTBEAT_PERSIST_INTERVAL_MS,
14705
14951
  campHealthLiveness,
14952
+ CampHealthVersionError,
14706
14953
  loadCampHealth,
14707
14954
  saveCampHealth,
14708
14955
  LEGACY_CAMP_MANIFEST_VERSION,