priiisk 0.1.7 → 0.1.9

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.
@@ -86,8 +86,8 @@ import {
86
86
  selectCampRun,
87
87
  styleCampUiTone,
88
88
  uniqueCampUiNames
89
- } from "./chunk-YOW4MMBD.js";
90
- import "./chunk-3V5SHVCX.js";
89
+ } from "./chunk-NIJ2J45R.js";
90
+ import "./chunk-F7LGUL2J.js";
91
91
  export {
92
92
  CAMP_UI_BASH_PREVIEW_LINES,
93
93
  CAMP_UI_DEFAULT_TOOL_PREVIEW_LINES,
@@ -41892,6 +41892,15 @@ var CampWorkerInterrupted = class extends Data_exports.TaggedError("CampWorkerIn
41892
41892
  };
41893
41893
  var CampWorkerTerminated = class extends Data_exports.TaggedError("CampWorkerTerminated") {
41894
41894
  };
41895
+ var campTurnFailureReason = (outcome) => {
41896
+ if (outcome.stopReason !== CampTurnStopReason.error && outcome.failureCode === void 0) {
41897
+ return void 0;
41898
+ }
41899
+ return {
41900
+ code: outcome.failureCode === void 0 ? CampFailureCode.unknown : CampFailureCode.providerError,
41901
+ message: outcome.errorMessage ?? "turn ended with an error"
41902
+ };
41903
+ };
41895
41904
 
41896
41905
  // packages/kernel/src/domain/campTopology.ts
41897
41906
  var CampChildClosePolicy = { cascade: "cascade", detach: "detach" };
@@ -43154,25 +43163,9 @@ var rollbackOrFail = (rollback, workerId) => Effect_exports.exit(rollback).pipe(
43154
43163
  )
43155
43164
  )
43156
43165
  );
43157
- var requestOnCurrentBase = (request2, current2) => {
43158
- if (request2.role !== void 0 || request2.preset !== void 0) return request2;
43159
- const overrides = {
43160
- ...request2.overrides,
43161
- ...request2.overrides?.model === void 0 && current2.model !== void 0 ? { model: current2.model } : {},
43162
- ...request2.overrides?.thinkingLevel === void 0 && current2.thinkingLevel !== void 0 ? { thinkingLevel: current2.thinkingLevel } : {}
43163
- };
43164
- return {
43165
- ...request2,
43166
- ...current2.role === void 0 ? {} : { role: current2.role },
43167
- ...current2.preset === void 0 ? {} : { preset: current2.preset },
43168
- overrides
43169
- };
43170
- };
43171
- var updateWorkerEquipment = (runtime6, command, identity6, request2) => Effect_exports.gen(function* () {
43166
+ var updateWorkerEquipment = (runtime6, command, identity6, change) => Effect_exports.gen(function* () {
43172
43167
  const [initial, sessionRef] = yield* requireKernelSession(runtime6, identity6);
43173
- const equipment = yield* runtime6.equipmentResolver.resolve(
43174
- requestOnCurrentBase(request2, initial.equipment)
43175
- );
43168
+ const equipment = yield* runtime6.equipmentResolver.reresolve(initial.equipment, change);
43176
43169
  const resource = yield* getWorkerResource(runtime6, initial.id);
43177
43170
  if (resource === void 0) {
43178
43171
  return yield* Effect_exports.fail(
@@ -43396,9 +43389,11 @@ var handleSessionEvent = (runtime6, id3, event) => Effect_exports.gen(function*
43396
43389
  );
43397
43390
  return { kind: "retrying", worker: worker2, payload: event.payload };
43398
43391
  }
43392
+ const turnError = event.kind === CampSessionEventKind.turnCompleted ? campTurnFailureReason(event.payload.outcome) : void 0;
43399
43393
  const worker = yield* runtime6.registry.updateTimestamps(id3, {
43400
43394
  updatedAt,
43401
- lastActivityAt: updatedAt
43395
+ lastActivityAt: updatedAt,
43396
+ ...event.kind === CampSessionEventKind.turnCompleted ? { turnError: turnError ?? null } : {}
43402
43397
  });
43403
43398
  if (event.kind === CampSessionEventKind.activity) {
43404
43399
  return { kind: "activity", worker, payload: event.payload };
@@ -43910,13 +43905,15 @@ var makeRegistryLifecycleOperations = (stateRef) => ({
43910
43905
  if (isTerminalCampState(record4.state) || record4.state === CampWorkerState.interrupted) {
43911
43906
  return mutationFailure(registryInvalid("registry.updateTimestamps", { id: id3 }), state);
43912
43907
  }
43908
+ const carried = input.turnError === null ? Object.fromEntries(Object.entries(record4).filter(([key]) => key !== "error")) : record4;
43913
43909
  const next4 = {
43914
- ...record4,
43910
+ ...carried,
43915
43911
  updatedAt: input.updatedAt,
43916
43912
  version: record4.version + 1,
43917
43913
  ...input.admittedAt === void 0 ? {} : { admittedAt: input.admittedAt },
43918
43914
  ...input.startedAt === void 0 ? {} : { startedAt: input.startedAt },
43919
- ...input.lastActivityAt === void 0 ? {} : { lastActivityAt: input.lastActivityAt }
43915
+ ...input.lastActivityAt === void 0 ? {} : { lastActivityAt: input.lastActivityAt },
43916
+ ...input.turnError === void 0 || input.turnError === null ? {} : { error: input.turnError }
43920
43917
  };
43921
43918
  return mutationSuccess(next4, {
43922
43919
  ...state,
@@ -20,10 +20,11 @@ import {
20
20
  layerNet,
21
21
  makeCampSurfaceName,
22
22
  resolveProjectScopeSync
23
- } from "./chunk-JND6HOSJ.js";
23
+ } from "./chunk-LH753BUY.js";
24
24
  import {
25
25
  Clock_exports,
26
26
  Config_exports,
27
+ Console_exports,
27
28
  Context_exports,
28
29
  Data_exports,
29
30
  Deferred_exports,
@@ -37,7 +38,7 @@ import {
37
38
  Schedule_exports,
38
39
  Schema_exports,
39
40
  Stream_exports
40
- } from "./chunk-3V5SHVCX.js";
41
+ } from "./chunk-F7LGUL2J.js";
41
42
 
42
43
  // packages/cli/src/doctor/doctorModel.ts
43
44
  var DOCTOR_REPORT_SCHEMA_VERSION = 1;
@@ -111,9 +112,12 @@ var CliSurfaceSelectionError = class extends Data_exports.TaggedError("CliSurfac
111
112
  import { randomUUID } from "node:crypto";
112
113
 
113
114
  // packages/cli/src/domain/cliVersion.ts
114
- var PRIIISK_CLI_VERSION = "0.1.7";
115
+ var PRIIISK_CLI_VERSION = "0.1.9";
115
116
 
116
117
  // packages/cli/src/client/campRpcConnection.ts
118
+ var reportRetry = (options, diagnostic) => options.onRetry === void 0 ? Console_exports.error(
119
+ `[retry] ${diagnostic.operation}: \u043F\u043E\u043F\u044B\u0442\u043A\u0430 ${String(diagnostic.attempt)}, \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0430\u044F \u0432 ${String(diagnostic.nextRetryAt)} \u2014 ${diagnostic.message}`
120
+ ).pipe(Effect_exports.ignore) : options.onRetry(diagnostic);
117
121
  var PRIIISK_CONTROLLER_ID_ENV = "PRIIISK_CONTROLLER_ID";
118
122
  var PRIIISK_CONSUMER_ID_ENV = "PRIIISK_CONSUMER_ID";
119
123
  var protocolRetrySchedule = Schedule_exports.exponential("50 millis").pipe(
@@ -151,12 +155,12 @@ var makeCampProtocolLayer = (socketPath, options) => Effect_exports.gen(function
151
155
  Effect_exports.flatMap(
152
156
  ({ attempt, cause }) => Clock_exports.currentTimeMillis.pipe(
153
157
  Effect_exports.flatMap(
154
- (now) => options.onRetry?.({
158
+ (now) => reportRetry(options, {
155
159
  operation: options.operation,
156
160
  attempt,
157
161
  nextRetryAt: now + 50 * 2 ** (attempt - 1),
158
162
  message: cause instanceof Error ? cause.message : String(cause)
159
- }) ?? Effect_exports.void
163
+ })
160
164
  )
161
165
  )
162
166
  )
@@ -28,7 +28,7 @@ import {
28
28
  makePlatform,
29
29
  makeRunMain,
30
30
  stdin
31
- } from "./chunk-JND6HOSJ.js";
31
+ } from "./chunk-LH753BUY.js";
32
32
  import {
33
33
  BaseProto,
34
34
  __export,
@@ -112,7 +112,7 @@ import {
112
112
  write,
113
113
  zip,
114
114
  zipRight
115
- } from "./chunk-3V5SHVCX.js";
115
+ } from "./chunk-F7LGUL2J.js";
116
116
 
117
117
  // node_modules/.pnpm/@effect+platform-node@0.107.0_@effect+cluster@0.59.0_@effect+platform@0.96.2_effect@3.2_9535e05eb804fa0fb275ce283b448483/node_modules/@effect/platform-node/dist/esm/NodeContext.js
118
118
  var NodeContext_exports = {};
@@ -366,7 +366,7 @@ import {
366
366
  write,
367
367
  zipRight,
368
368
  zipRight2
369
- } from "./chunk-3V5SHVCX.js";
369
+ } from "./chunk-F7LGUL2J.js";
370
370
 
371
371
  // node_modules/.pnpm/detect-libc@2.1.2/node_modules/detect-libc/lib/process.js
372
372
  var require_process = __commonJS({
@@ -10447,15 +10447,7 @@ var resolveNamedServers = (config, names) => {
10447
10447
  };
10448
10448
  };
10449
10449
  var resolveMcpServers = (config, role, mcpOverride) => resolveNamedServers(config, resolveServerNames(config, role, mcpOverride));
10450
- var resolveCampMcpUnion = (config) => resolveNamedServers(
10451
- config,
10452
- Object.values(AgentRole).flatMap((role) => resolveServerNames(config, role, void 0))
10453
- );
10454
- var resolveCampMcpOutsideUnion = (config, mcpOverride) => {
10455
- if (mcpOverride === void 0) return [];
10456
- const allowed = new Set(Object.keys(resolveCampMcpUnion(config).servers));
10457
- return dedupe3(mcpOverride).filter((name) => !allowed.has(name));
10458
- };
10450
+ var resolveCampMcpCatalog = (config) => resolveNamedServers(config, Object.keys(config?.mcpServers ?? {}));
10459
10451
  var applyCampMcpRuntimeDefaults = (servers) => {
10460
10452
  const codegraph = servers.codegraph;
10461
10453
  if (codegraph === void 0 || codegraph.lifecycle !== void 0) return servers;
@@ -10487,6 +10479,7 @@ var resolveNamedThinkingForAlias = (config, alias, namedLevel) => {
10487
10479
  var resolveDefaultPreset = (config) => ({
10488
10480
  modelAlias: config.defaults.model,
10489
10481
  modelId: resolveModelAlias(config, config.defaults.model),
10482
+ abstractThinking: config.defaults.thinking,
10490
10483
  thinking: resolveThinkingForAlias(config, config.defaults.model, config.defaults.thinking)
10491
10484
  });
10492
10485
  var resolveModelAliasForRole = (config, role) => config.roles?.[role]?.model ?? config.defaults.model;
@@ -10499,6 +10492,7 @@ var resolveRolePreset = (config, role) => {
10499
10492
  description: config.roles?.[role]?.description,
10500
10493
  modelAlias,
10501
10494
  modelId: resolveModelAlias(config, modelAlias),
10495
+ abstractThinking,
10502
10496
  thinking: resolveThinkingForAlias(config, modelAlias, abstractThinking),
10503
10497
  readOnly: config.roles?.[role]?.readOnly,
10504
10498
  directTools: config.roles?.[role]?.directTools
@@ -10523,6 +10517,7 @@ var resolveHirePreset = (config, presetName) => {
10523
10517
  role: entry.role,
10524
10518
  modelAlias,
10525
10519
  modelId,
10520
+ abstractThinking,
10526
10521
  thinking,
10527
10522
  readOnly: entry.readOnly ?? (entry.role !== void 0 ? config.roles?.[entry.role]?.readOnly : void 0),
10528
10523
  directTools: entry.directTools ?? (entry.role !== void 0 ? config.roles?.[entry.role]?.directTools : void 0)
@@ -10677,8 +10672,8 @@ var parseDirectToolSandboxStatus = (status) => {
10677
10672
  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";
10678
10673
 
10679
10674
  // packages/protocol/src/domain/protocolVersion.ts
10680
- var PRIIISK_PROTOCOL_VERSION = "11";
10681
- var PRIIISK_PROTOCOL_PACKAGE_VERSION = "0.1.7";
10675
+ var PRIIISK_PROTOCOL_VERSION = "12";
10676
+ var PRIIISK_PROTOCOL_PACKAGE_VERSION = "0.1.9";
10682
10677
  var ProtocolVersionSchema = Schema_exports.String.pipe(Schema_exports.minLength(1));
10683
10678
 
10684
10679
  // packages/protocol/src/domain/protocolIdentifiers.ts
@@ -10939,6 +10934,21 @@ var EquipmentRequestSchema = Schema_exports.Struct({
10939
10934
  })
10940
10935
  )
10941
10936
  });
10937
+ var EquipmentChangeSchema = Schema_exports.Struct({
10938
+ builtinTools: Schema_exports.optional(StringList),
10939
+ customToolNames: Schema_exports.optional(StringList),
10940
+ directTools: Schema_exports.optional(Schema_exports.Union(Schema_exports.Boolean, StringList)),
10941
+ skillNames: Schema_exports.optional(StringList),
10942
+ skillPaths: Schema_exports.optional(StringList),
10943
+ mcp: Schema_exports.optional(
10944
+ Schema_exports.Struct({
10945
+ serverNames: StringList,
10946
+ toolNamesByServer: Schema_exports.optional(
10947
+ Schema_exports.Record({ key: NonEmptyString5, value: Schema_exports.Array(NonEmptyString5) })
10948
+ )
10949
+ })
10950
+ )
10951
+ });
10942
10952
 
10943
10953
  // packages/protocol/src/domain/eventDtos.ts
10944
10954
  var CampEventKindSchema = Schema_exports.Literal(
@@ -13418,12 +13428,16 @@ var CampProtocol = class extends RpcGroup_exports.make(
13418
13428
  success: WorkerSummarySchema,
13419
13429
  error: CampOperationErrorSchema
13420
13430
  }),
13421
- /** Re-equips a live worker; the answer carries the committed equipment revision. */
13431
+ /**
13432
+ * Changes the grant of a live worker; the answer carries the committed
13433
+ * equipment revision. The identity it was hired with is not part of the
13434
+ * payload: changing that means hiring another worker.
13435
+ */
13422
13436
  Rpc_exports.make("Equip", {
13423
13437
  payload: {
13424
13438
  ...CommandContextSchema.fields,
13425
13439
  worker: WorkerSelectorSchema,
13426
- equipment: EquipmentRequestSchema
13440
+ equipment: EquipmentChangeSchema
13427
13441
  },
13428
13442
  success: WorkerSummarySchema,
13429
13443
  error: CampOperationErrorSchema
@@ -13553,7 +13567,7 @@ var CampProtocol = class extends RpcGroup_exports.make(
13553
13567
  };
13554
13568
 
13555
13569
  // packages/camp-state/src/bootstrap/campHostVersion.ts
13556
- var PRIIISK_HOST_VERSION = "0.1.7";
13570
+ var PRIIISK_HOST_VERSION = "0.1.9";
13557
13571
 
13558
13572
  // packages/surface/src/domain/surfaceModel.ts
13559
13573
  var NonEmptyString7 = Schema_exports.String.pipe(Schema_exports.minLength(1));
@@ -14497,12 +14511,27 @@ var CampRunCatalogErrorCode = {
14497
14511
  notFound: "run_not_found",
14498
14512
  notResumable: "run_not_resumable",
14499
14513
  persistenceFailed: "persistence_failed",
14514
+ /**
14515
+ * Checkpoint написан другой версией схемы. Общий `persistence_failed` описывал
14516
+ * бы это как поломку хранилища, тогда как лечение другое и уже названо в
14517
+ * контракте recovery: свежий запуск либо обновление рантайма
14518
+ * (priiisk-nss.6.23).
14519
+ */
14520
+ checkpointUnsupported: "checkpoint_unsupported",
14500
14521
  scopeMismatch: "scope_mismatch"
14501
14522
  };
14502
14523
  var CampRunCatalogError = class extends Data_exports.TaggedError("CampRunCatalogError") {
14503
14524
  };
14504
14525
  var isCampRunResumable = (manifest) => manifest.workers.some((worker) => worker.session.lifecycle !== "pending");
14505
14526
 
14527
+ // packages/camp-state/src/history/campRunCatalogFailures.ts
14528
+ var manifestReadFailure = (operation, message, cause) => new CampRunCatalogError({
14529
+ operation,
14530
+ code: cause instanceof CampManifestVersionError ? CampRunCatalogErrorCode.checkpointUnsupported : CampRunCatalogErrorCode.persistenceFailed,
14531
+ message,
14532
+ ...cause === void 0 ? {} : { cause }
14533
+ });
14534
+
14506
14535
  // packages/camp-state/src/history/campRunCatalog.ts
14507
14536
  var catalogError = (operation, code, message, cause) => new CampRunCatalogError({
14508
14537
  operation,
@@ -14527,12 +14556,7 @@ var summary = (manifest, active) => ({
14527
14556
  });
14528
14557
  var loadRequired = (fs, path, operation) => loadCampManifest(fs, path).pipe(
14529
14558
  Effect_exports.mapError(
14530
- (cause) => catalogError(
14531
- operation,
14532
- CampRunCatalogErrorCode.persistenceFailed,
14533
- `\u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u0442\u044C camp run: ${path}`,
14534
- cause
14535
- )
14559
+ (cause) => manifestReadFailure(operation, `\u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u0442\u044C camp run: ${path}`, cause)
14536
14560
  ),
14537
14561
  Effect_exports.flatMap(
14538
14562
  Option_exports.match({
@@ -14556,12 +14580,7 @@ var pathExists = (fs, path, operation) => fs.exists(path).pipe(
14556
14580
  var listCampRuns = (fs, project, paths) => Effect_exports.gen(function* () {
14557
14581
  const active = yield* loadCampManifest(fs, paths.manifestPath).pipe(
14558
14582
  Effect_exports.mapError(
14559
- (cause) => catalogError(
14560
- "list",
14561
- CampRunCatalogErrorCode.persistenceFailed,
14562
- "\u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u0442\u044C active camp run",
14563
- cause
14564
- )
14583
+ (cause) => manifestReadFailure("list", "\u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u0442\u044C active camp run", cause)
14565
14584
  )
14566
14585
  );
14567
14586
  if (Option_exports.isSome(active)) yield* validateScope("list", project, active.value);
@@ -14921,11 +14940,11 @@ export {
14921
14940
  directToolBin,
14922
14941
  resolveDirectTools,
14923
14942
  resolveMcpServers,
14924
- resolveCampMcpUnion,
14925
- resolveCampMcpOutsideUnion,
14943
+ resolveCampMcpCatalog,
14926
14944
  applyCampMcpRuntimeDefaults,
14927
14945
  resolveMcpSecretEnv,
14928
14946
  resolveModelAlias,
14947
+ resolveThinkingForAlias,
14929
14948
  resolveNamedThinkingForAlias,
14930
14949
  resolveDefaultPreset,
14931
14950
  resolveRolePreset,
@@ -12,7 +12,7 @@ import {
12
12
  Match_exports,
13
13
  Stream_exports,
14
14
  SubscriptionRef_exports
15
- } from "./chunk-3V5SHVCX.js";
15
+ } from "./chunk-F7LGUL2J.js";
16
16
 
17
17
  // packages/host-ui/src/backend/campUiBackend.ts
18
18
  var CampUiBackendError = class extends Data_exports.TaggedError("CampUiBackendError") {
@@ -3,7 +3,7 @@ const require = __priiiskCreateRequire(import.meta.url);
3
3
  import {
4
4
  FileSystem_exports,
5
5
  PRIIISK_PI_AGENT_DIR_ENV
6
- } from "./chunk-JND6HOSJ.js";
6
+ } from "./chunk-LH753BUY.js";
7
7
  import {
8
8
  CampDeliveryPort,
9
9
  CampFailureCode,
@@ -30,7 +30,7 @@ import {
30
30
  __require,
31
31
  __toESM,
32
32
  campScopeClosedReason
33
- } from "./chunk-3V5SHVCX.js";
33
+ } from "./chunk-F7LGUL2J.js";
34
34
 
35
35
  // node_modules/.pnpm/undici@7.28.0/node_modules/undici/lib/core/symbols.js
36
36
  var require_symbols = __commonJS({
@@ -26557,14 +26557,30 @@ var makePiSessionRuntime = (options) => Effect_exports.gen(function* () {
26557
26557
  /*
26558
26558
  * Aborting ends the turn, not the session: the terminal signal stays
26559
26559
  * untouched, so the worker survives its interruption and the next
26560
- * message starts a new turn. Committing the cycle first keeps the late
26561
- * agent_end/agent_settled of the abandoned turn from settling it.
26560
+ * message starts a new turn. The cycle is committed first, because the
26561
+ * late agent_end/agent_settled of the abandoned turn must not settle it.
26562
+ *
26563
+ * An adapter that refuses the abort leaves the turn running, so the
26564
+ * commit is rolled back: otherwise the worker would keep working while
26565
+ * its own settled events were ignored as belonging to a finished cycle
26566
+ * (priiisk-nss.6.27).
26562
26567
  */
26563
26568
  abort: (sessionRef) => requireLive(sessionRef, PiSessionOperation.abort).pipe(
26564
26569
  Effect_exports.flatMap(
26565
- (live) => commitCurrentCycle(live).pipe(
26566
- Effect_exports.zipRight(
26567
- run(live, PiSessionOperation.abort, () => live.runtime.session.abort())
26570
+ (live) => Ref_exports.get(live.lifecycle).pipe(
26571
+ Effect_exports.flatMap(
26572
+ (before) => commitCurrentCycle(live).pipe(
26573
+ Effect_exports.zipRight(
26574
+ run(live, PiSessionOperation.abort, () => live.runtime.session.abort())
26575
+ ),
26576
+ Effect_exports.tapError(
26577
+ () => Ref_exports.update(live.lifecycle, (state) => ({
26578
+ cycle: state.cycle,
26579
+ providerAttempts: state.providerAttempts,
26580
+ ...before.committedCycle === void 0 ? {} : { committedCycle: before.committedCycle }
26581
+ }))
26582
+ )
26583
+ )
26568
26584
  )
26569
26585
  )
26570
26586
  )
@@ -8,13 +8,13 @@ import {
8
8
  makeDoctorReport,
9
9
  resolveCampSurface,
10
10
  withCampRpc
11
- } from "./chunk-ZUREJQA6.js";
11
+ } from "./chunk-GEBZQLE7.js";
12
12
  import {
13
13
  PI_RUNTIME_VERSION,
14
14
  PiModelCatalogIssueCode,
15
15
  inspectPiModelCatalog,
16
16
  makePiOperatorResources
17
- } from "./chunk-WEYE43UO.js";
17
+ } from "./chunk-QEUSNJ3D.js";
18
18
  import {
19
19
  CampHealthComponentStatus,
20
20
  CampHealthOverallStatus,
@@ -48,13 +48,13 @@ import {
48
48
  resolveCredentialsPath,
49
49
  resolveProjectScope,
50
50
  resolveWorkerConfigPath
51
- } from "./chunk-JND6HOSJ.js";
51
+ } from "./chunk-LH753BUY.js";
52
52
  import {
53
53
  Clock_exports,
54
54
  Effect_exports,
55
55
  Option_exports,
56
56
  Ref_exports
57
- } from "./chunk-3V5SHVCX.js";
57
+ } from "./chunk-F7LGUL2J.js";
58
58
 
59
59
  // packages/cli/src/doctor/environmentDoctor.ts
60
60
  import { dirname } from "node:path";
@@ -4,14 +4,14 @@ const require = __priiiskCreateRequire(import.meta.url);
4
4
  import {
5
5
  NodeContext_exports,
6
6
  NodeRuntime_exports
7
- } from "./chunk-7U7PROSV.js";
7
+ } from "./chunk-IORSBZKU.js";
8
8
  import {
9
9
  CampUiBackendError,
10
10
  CampUiHealthStatus,
11
11
  CampUiPlacement,
12
12
  CampUiRuntimeStatus,
13
13
  mountPiCampUi
14
- } from "./chunk-YOW4MMBD.js";
14
+ } from "./chunk-NIJ2J45R.js";
15
15
  import {
16
16
  PiTransport,
17
17
  makePiOperatorResources,
@@ -19,7 +19,7 @@ import {
19
19
  makePiTransportLayer,
20
20
  requirePiModelCatalog,
21
21
  require_undici
22
- } from "./chunk-WEYE43UO.js";
22
+ } from "./chunk-QEUSNJ3D.js";
23
23
  import {
24
24
  AgentRole,
25
25
  AgentRoleSchema,
@@ -67,6 +67,7 @@ import {
67
67
  campRecoveryDiagnosticFromCause,
68
68
  campRunPaths,
69
69
  currentDirectToolSandbox,
70
+ directToolBin,
70
71
  directToolName,
71
72
  directToolSandboxCommand,
72
73
  findCampRecoveryHealthComponent,
@@ -81,8 +82,7 @@ import {
81
82
  prepareCampRunStorage,
82
83
  prepareCampStorage,
83
84
  projectScopeFromCwd,
84
- resolveCampMcpOutsideUnion,
85
- resolveCampMcpUnion,
85
+ resolveCampMcpCatalog,
86
86
  resolveDefaultPreset,
87
87
  resolveDirectTools,
88
88
  resolveExecutablePath,
@@ -96,11 +96,12 @@ import {
96
96
  resolveRolePreset,
97
97
  resolveRoleProfilePath,
98
98
  resolveSkillGroups,
99
+ resolveThinkingForAlias,
99
100
  resolveWorkerSkillsRoot,
100
101
  runningCampManifest,
101
102
  saveCampHealth,
102
103
  saveCampManifest
103
- } from "./chunk-JND6HOSJ.js";
104
+ } from "./chunk-LH753BUY.js";
104
105
  import {
105
106
  CampAskRouter,
106
107
  CampCancellationCode,
@@ -193,7 +194,7 @@ import {
193
194
  withFiberRuntime,
194
195
  workerAliasIdentity,
195
196
  workerIdIdentity
196
- } from "./chunk-3V5SHVCX.js";
197
+ } from "./chunk-F7LGUL2J.js";
197
198
 
198
199
  // node_modules/.pnpm/ws@8.21.1/node_modules/ws/lib/constants.js
199
200
  var require_constants = __commonJS({
@@ -11463,6 +11464,19 @@ var equipmentRequestFromDto = (request) => ({
11463
11464
  }
11464
11465
  }
11465
11466
  });
11467
+ var equipmentChangeFromDto = (change) => ({
11468
+ ...change.builtinTools === void 0 ? {} : { builtinTools: change.builtinTools },
11469
+ ...change.customToolNames === void 0 ? {} : { customToolNames: change.customToolNames },
11470
+ ...change.directTools === void 0 ? {} : { directTools: change.directTools },
11471
+ ...change.skillNames === void 0 ? {} : { skillNames: change.skillNames },
11472
+ ...change.skillPaths === void 0 ? {} : { skillPaths: change.skillPaths },
11473
+ ...change.mcp === void 0 ? {} : {
11474
+ mcp: {
11475
+ serverNames: change.mcp.serverNames,
11476
+ ...change.mcp.toolNamesByServer === void 0 ? {} : { toolNamesByServer: change.mcp.toolNamesByServer }
11477
+ }
11478
+ }
11479
+ });
11466
11480
  var transcriptContentDto = (content) => {
11467
11481
  if (content.kind === "text") return { kind: "text", text: content.text };
11468
11482
  if (content.kind === "thinking") {
@@ -12788,23 +12802,38 @@ var stableJson = (value) => {
12788
12802
  const entries = Object.entries(value).filter(([, entry]) => entry !== void 0).sort(([left], [right]) => left.localeCompare(right));
12789
12803
  return `{${entries.map(([key, entry]) => `${JSON.stringify(key)}:${stableJson(entry)}`).join(",")}}`;
12790
12804
  };
12805
+ var durableFailureSummary = (cause) => {
12806
+ const code = cause?.code;
12807
+ if (typeof code === "string" && code !== "") return code;
12808
+ const name = cause instanceof Error ? cause.name : void 0;
12809
+ return name === void 0 || name === "" ? "unknown" : name;
12810
+ };
12791
12811
  var receiptPersistenceFailure = (operation, cause) => new CampCommandFailure({
12792
12812
  operation,
12793
12813
  code: CampReceiptFailureCode.persistenceFailed,
12794
- message: `command receipt could not be made durable: ${String(cause)}`,
12795
- retryable: true
12814
+ message: `command receipt could not be made durable (${durableFailureSummary(cause)})`,
12815
+ retryable: true,
12816
+ recoveryAction: "manual_recovery"
12796
12817
  });
12797
12818
  var loadCampReceipts = (fs, path, runId) => fs.exists(path).pipe(
12798
12819
  Effect_exports.flatMap((exists) => exists ? fs.readFileString(path) : Effect_exports.succeed(void 0)),
12799
12820
  Effect_exports.flatMap(
12800
- (contents) => contents === void 0 ? Effect_exports.succeed([]) : Effect_exports.try(() => JSON.parse(contents)).pipe(
12821
+ (contents) => contents === void 0 ? Effect_exports.succeed({ receipts: [] }) : Effect_exports.try(() => JSON.parse(contents)).pipe(
12801
12822
  Effect_exports.flatMap(decodeState),
12802
12823
  Effect_exports.map(
12803
- (state) => state.schemaVersion === CAMP_RECEIPT_SCHEMA_VERSION && state.runId === runId ? state.receipts : []
12824
+ (state) => state.schemaVersion === CAMP_RECEIPT_SCHEMA_VERSION && state.runId === runId ? { receipts: state.receipts } : {
12825
+ receipts: [],
12826
+ unreadable: state.runId === runId ? "unsupported_schema_version" : "foreign_run"
12827
+ }
12828
+ ),
12829
+ Effect_exports.catchAll(
12830
+ () => Effect_exports.succeed({ receipts: [], unreadable: "corrupt" })
12804
12831
  )
12805
12832
  )
12806
12833
  ),
12807
- Effect_exports.catchAll(() => Effect_exports.succeed([]))
12834
+ Effect_exports.catchAll(
12835
+ () => Effect_exports.succeed({ receipts: [], unreadable: "unreadable" })
12836
+ )
12808
12837
  );
12809
12838
  var saveCampReceipts = (fs, path, runId, receipts) => {
12810
12839
  const temporaryPath = `${path}.${randomUUID2()}.tmp`;
@@ -12888,9 +12917,15 @@ var makeCampCommandReceiptStoreLayer = (options) => Layer_exports.scoped(
12888
12917
  const retentionMillis = (options.retentionSeconds ?? CAMP_RECEIPT_DEFAULT_RETENTION_SECONDS) * 1e3;
12889
12918
  const restoredAt = yield* Clock_exports.currentTimeMillis;
12890
12919
  const restored = yield* loadCampReceipts(fs, options.statePath, journal.runId);
12891
- const state = yield* Ref_exports.make(campReceiptStateFromRecords(restored, restoredAt));
12920
+ const state = yield* Ref_exports.make(campReceiptStateFromRecords(restored.receipts, restoredAt));
12892
12921
  const inFlight = yield* Ref_exports.make(/* @__PURE__ */ new Map());
12893
- const lastFailure = yield* Ref_exports.make(void 0);
12922
+ const lastFailure = yield* Ref_exports.make(
12923
+ restored.unreadable === void 0 ? void 0 : receiptFailure(
12924
+ "restore",
12925
+ CampReceiptFailureCode.unreadable,
12926
+ `durable command receipts were not restored (${restored.unreadable})`
12927
+ )
12928
+ );
12894
12929
  const changes = yield* PubSub_exports.sliding(1);
12895
12930
  const lane = yield* Effect_exports.makeSemaphore(1);
12896
12931
  const publish = PubSub_exports.publish(changes, void 0).pipe(Effect_exports.asVoid);
@@ -22416,7 +22451,7 @@ var Client = class extends Protocol {
22416
22451
  };
22417
22452
 
22418
22453
  // packages/mcp-backend/src/connections/clientIdentity.ts
22419
- var backendVersion = "0.1.7";
22454
+ var backendVersion = "0.1.9";
22420
22455
 
22421
22456
  // packages/mcp-backend/src/connections/mcpFailure.ts
22422
22457
  var McpFailure = class extends Data_exports.TaggedError("McpFailure") {
@@ -25096,7 +25131,7 @@ var configLoadError = (path) => new CampMcpError({
25096
25131
  });
25097
25132
  var acquireMcpHubBackendForConfig = (config2) => Effect_exports.gen(function* () {
25098
25133
  const fs = yield* FileSystem_exports.FileSystem;
25099
- const resolution = resolveCampMcpUnion(config2);
25134
+ const resolution = resolveCampMcpCatalog(config2);
25100
25135
  const servers = applyCampMcpRuntimeDefaults(resolution.servers);
25101
25136
  const credentials = yield* loadReferencedMcpCredentials(fs, resolution.referencedEnvNames).pipe(
25102
25137
  Effect_exports.mapError((cause) => configLoadError(cause.path))
@@ -25197,7 +25232,12 @@ var selectModel = (config2, requested, sources) => {
25197
25232
  };
25198
25233
  var selectThinking = (config2, requested, alias, sources) => {
25199
25234
  if (requested === void 0) {
25200
- return Effect_exports.succeed(sources.find((source) => source?.thinking !== void 0)?.thinking);
25235
+ const abstract = sources.find(
25236
+ (source) => source?.abstractThinking !== void 0
25237
+ )?.abstractThinking;
25238
+ return Effect_exports.succeed(
25239
+ abstract === void 0 || config2 === void 0 || alias === void 0 ? abstract : resolveThinkingForAlias(config2, alias, abstract) ?? abstract
25240
+ );
25201
25241
  }
25202
25242
  if (!Schema_exports.is(PiThinkingLevelSchema)(requested)) {
25203
25243
  return Effect_exports.fail(equipmentError("unknown_thinking_level", { thinkingLevel: requested }));
@@ -25233,8 +25273,18 @@ var makeHostToolRegistry = (options) => ({
25233
25273
  });
25234
25274
 
25235
25275
  // packages/host/src/equipment/configEquipmentResolver.ts
25236
- var makeConfigEquipmentResolver = (fs, path, config2, registry2 = makeHostToolRegistry()) => ({
25237
- resolve: (request) => Effect_exports.gen(function* () {
25276
+ var carriedTools = (current) => {
25277
+ const bins = [];
25278
+ const customToolNames = [];
25279
+ for (const name of current.customToolNames) {
25280
+ const bin = directToolBin(name);
25281
+ if (bin === void 0) customToolNames.push(name);
25282
+ else bins.push(bin);
25283
+ }
25284
+ return { bins, customToolNames };
25285
+ };
25286
+ var makeConfigEquipmentResolver = (fs, path, config2, registry2 = makeHostToolRegistry()) => {
25287
+ const resolve = (request) => Effect_exports.gen(function* () {
25238
25288
  const presetResolution = request.preset === void 0 ? void 0 : config2 === void 0 ? { found: false, reason: "not-found" } : resolveHirePreset(config2, request.preset);
25239
25289
  if (presetResolution !== void 0 && !presetResolution.found) {
25240
25290
  return yield* Effect_exports.fail(
@@ -25283,19 +25333,18 @@ var makeConfigEquipmentResolver = (fs, path, config2, registry2 = makeHostToolRe
25283
25333
  equipmentError("unknown_skill_groups", { groups: skillResolution.unknownGroups })
25284
25334
  );
25285
25335
  }
25286
- const namedSkills = [...request.overrides?.skillNames ?? skillResolution.skillNames];
25336
+ const requestedSkillNames = request.overrides?.skillNames;
25337
+ const requestedSkillPaths = request.overrides?.skillPaths;
25338
+ const namedSkills = requestedSkillNames ?? (requestedSkillPaths === void 0 ? skillResolution.skillNames : []);
25287
25339
  const skillPaths = [
25288
- ...request.overrides?.skillPaths ?? namedSkills.map((name) => path.join(resolveWorkerSkillsRoot(), name))
25340
+ .../* @__PURE__ */ new Set([
25341
+ ...namedSkills.map((name) => path.join(resolveWorkerSkillsRoot(), name)),
25342
+ ...requestedSkillPaths ?? []
25343
+ ])
25289
25344
  ];
25290
25345
  const skillNames = skillPaths.map((skillPath) => path.basename(skillPath, ".md"));
25291
25346
  yield* requirePaths(fs, skillPaths);
25292
25347
  const requestedMcp = request.overrides?.mcp;
25293
- const outsideUnion = resolveCampMcpOutsideUnion(config2, requestedMcp?.serverNames);
25294
- if (outsideUnion.length > 0) {
25295
- return yield* Effect_exports.fail(
25296
- equipmentError("mcp_outside_camp_catalog", { servers: outsideUnion })
25297
- );
25298
- }
25299
25348
  const mcpResolution = resolveMcpServers(config2, role, requestedMcp?.serverNames);
25300
25349
  if (mcpResolution.unknownServers.length > 0) {
25301
25350
  return yield* Effect_exports.fail(
@@ -25334,8 +25383,40 @@ var makeConfigEquipmentResolver = (fs, path, config2, registry2 = makeHostToolRe
25334
25383
  },
25335
25384
  ...request.overrides?.executionLimits === void 0 ? {} : { executionLimits: request.overrides.executionLimits }
25336
25385
  };
25337
- })
25338
- });
25386
+ });
25387
+ return {
25388
+ resolve,
25389
+ /*
25390
+ * The identity of a live worker travels unchanged, and every category the
25391
+ * change stays silent about keeps what the worker already carries. Rebuilding
25392
+ * the untouched ones from the role turned a single `--skill` into a silent
25393
+ * revoke of the servers and binaries the worker had been given at hire.
25394
+ */
25395
+ reresolve: (current, change) => {
25396
+ const carried = carriedTools(current);
25397
+ return resolve({
25398
+ ...current.role === void 0 ? {} : { role: current.role },
25399
+ ...current.preset === void 0 ? {} : { preset: current.preset },
25400
+ overrides: {
25401
+ ...current.model === void 0 ? {} : { model: current.model },
25402
+ ...current.thinkingLevel === void 0 ? {} : { thinkingLevel: current.thinkingLevel },
25403
+ readOnly: current.readOnly,
25404
+ builtinTools: change.builtinTools ?? current.builtinTools,
25405
+ customToolNames: change.customToolNames ?? carried.customToolNames,
25406
+ directTools: change.directTools ?? carried.bins,
25407
+ /*
25408
+ * Paths decide the set, so an unchanged worker keeps its exact paths
25409
+ * rather than names that would be re-resolved under the camp root.
25410
+ */
25411
+ ...change.skillNames === void 0 ? {} : { skillNames: change.skillNames },
25412
+ ...change.skillNames === void 0 && change.skillPaths === void 0 ? { skillPaths: current.skillPaths } : change.skillPaths === void 0 ? {} : { skillPaths: change.skillPaths },
25413
+ mcp: change.mcp ?? current.mcp,
25414
+ ...current.executionLimits === void 0 ? {} : { executionLimits: current.executionLimits }
25415
+ }
25416
+ });
25417
+ }
25418
+ };
25419
+ };
25339
25420
  var ConfigEquipmentResolverLive = Layer_exports.effect(
25340
25421
  EquipmentResolver,
25341
25422
  Effect_exports.gen(function* () {
@@ -25399,6 +25480,7 @@ var readSegmentText = (fs, path) => fs.readFileString(path).pipe(
25399
25480
  var loadJournalSegment = (fs, path, expected) => readSegmentText(fs, path).pipe(
25400
25481
  Effect_exports.flatMap((text) => {
25401
25482
  const totalBytes = Buffer.byteLength(text, "utf8");
25483
+ const endsWithNewline = text.endsWith("\n");
25402
25484
  const lines = text.split("\n");
25403
25485
  if (lines[lines.length - 1] === "") lines.pop();
25404
25486
  const headerLine = lines[0];
@@ -25408,7 +25490,8 @@ var loadJournalSegment = (fs, path, expected) => readSegmentText(fs, path).pipe(
25408
25490
  firstCursor: expected.firstCursor,
25409
25491
  events: [],
25410
25492
  validBytes: 0,
25411
- totalBytes
25493
+ totalBytes,
25494
+ truncatedTail: false
25412
25495
  });
25413
25496
  }
25414
25497
  const headerJson = parseJson(headerLine);
@@ -25419,7 +25502,9 @@ var loadJournalSegment = (fs, path, expected) => readSegmentText(fs, path).pipe(
25419
25502
  firstCursor: expected.firstCursor,
25420
25503
  events: [],
25421
25504
  validBytes: 0,
25422
- totalBytes
25505
+ totalBytes,
25506
+ /* Заголовок целиком записан, но нечитаем: это повреждение, не обрыв. */
25507
+ truncatedTail: lines.length === 1 && !endsWithNewline
25423
25508
  });
25424
25509
  }
25425
25510
  if (header.right.schemaVersion > CAMP_JOURNAL_SCHEMA_VERSION) {
@@ -25454,12 +25539,19 @@ var loadJournalSegment = (fs, path, expected) => readSegmentText(fs, path).pipe(
25454
25539
  }
25455
25540
  const events = [];
25456
25541
  let validBytes = lineBytes(headerLine);
25542
+ let stoppedAt;
25457
25543
  for (let index = 1; index < lines.length; index += 1) {
25458
25544
  const line = lines[index] ?? "";
25459
25545
  const parsed = parseJson(line);
25460
25546
  const decoded = parsed === void 0 ? void 0 : decodeEvent(parsed);
25461
- if (decoded === void 0 || Either_exports.isLeft(decoded)) break;
25462
- if (decoded.right.cursor !== expected.firstCursor + events.length) break;
25547
+ if (decoded === void 0 || Either_exports.isLeft(decoded)) {
25548
+ stoppedAt = index;
25549
+ break;
25550
+ }
25551
+ if (decoded.right.cursor !== expected.firstCursor + events.length) {
25552
+ stoppedAt = index;
25553
+ break;
25554
+ }
25463
25555
  events.push(decoded.right);
25464
25556
  validBytes += lineBytes(line);
25465
25557
  }
@@ -25468,7 +25560,14 @@ var loadJournalSegment = (fs, path, expected) => readSegmentText(fs, path).pipe(
25468
25560
  firstCursor: expected.firstCursor,
25469
25561
  events,
25470
25562
  validBytes,
25471
- totalBytes
25563
+ totalBytes,
25564
+ /*
25565
+ * Обрезать можно только оборванную последнюю запись: она одна осталась
25566
+ * после валидного префикса и не завершена переводом строки. Если после
25567
+ * сбойной записи есть другие или сама она дописана до конца, это
25568
+ * повреждение внутри файла, и обрезка стерла бы durable историю.
25569
+ */
25570
+ truncatedTail: stoppedAt === lines.length - 1 && !endsWithNewline
25472
25571
  });
25473
25572
  })
25474
25573
  );
@@ -25552,6 +25651,16 @@ var restoreCampJournal = (fs, options) => Effect_exports.gen(function* () {
25552
25651
  )
25553
25652
  );
25554
25653
  }
25654
+ if (!loaded.truncatedTail) {
25655
+ return yield* Effect_exports.fail(
25656
+ campJournalError(
25657
+ "open",
25658
+ CampJournalErrorCode.corrupted,
25659
+ "journal segment is damaged inside its last segment",
25660
+ { path }
25661
+ )
25662
+ );
25663
+ }
25555
25664
  yield* truncateSegment(fs, path, loaded.validBytes);
25556
25665
  }
25557
25666
  if (loaded.validBytes === 0) {
@@ -25683,10 +25792,9 @@ var makeCampJournalWriter = (fs, options, restored) => Effect_exports.gen(functi
25683
25792
  const event = CampEventDtoSchema.make({ ...draft, cursor });
25684
25793
  yield* writeLine(active.segment, journalEventLine(event));
25685
25794
  yield* SubscriptionRef_exports.update(state, (latest) => {
25686
- const { lastFailure: _lastFailure, ...healthy } = latest;
25687
25795
  const records = (active.segments[active.segments.length - 1]?.records ?? 0) + 1;
25688
25796
  return {
25689
- ...healthy,
25797
+ ...latest,
25690
25798
  segments: withRecords(active.segments, records),
25691
25799
  latestCursor: cursor
25692
25800
  };
@@ -26103,7 +26211,7 @@ var makeWorkerEquipmentRpcHandlers = ({
26103
26211
  },
26104
26212
  operations.equip(commandContext(request), {
26105
26213
  worker: workerIdentityFromDto(request.worker),
26106
- equipment: equipmentRequestFromDto(request.equipment)
26214
+ equipment: equipmentChangeFromDto(request.equipment)
26107
26215
  }).pipe(
26108
26216
  Effect_exports.map(workerDetailFromRecord),
26109
26217
  Effect_exports.mapError((error2) => failureFromHostOperation("equip", error2))
@@ -26259,13 +26367,26 @@ var CampRpcHandlersLive = CampProtocol.toLayer(
26259
26367
  )
26260
26368
  )
26261
26369
  ),
26370
+ /*
26371
+ * Interrupt is a mutating command like the rest, so it goes through the
26372
+ * receipt: a repeat of the same `commandId` answers with the recorded
26373
+ * result instead of aborting a turn twice, and a stale generation is
26374
+ * refused before the side effect (priiisk-nss.6.24).
26375
+ */
26262
26376
  Interrupt: (request) => validateReady(request).pipe(
26263
26377
  Effect_exports.zipRight(
26264
- operations.interrupt(commandContext(request), workerIdentityFromDto(request.worker))
26265
- ),
26266
- Effect_exports.as({ accepted: true }),
26267
- Effect_exports.mapError(
26268
- (error2) => error2 instanceof ProtocolVersionMismatch || error2 instanceof ProjectScopeMismatch ? error2 : failureFromKernel("interrupt", error2)
26378
+ receipts.run(
26379
+ {
26380
+ identity: commandIdentity(request),
26381
+ operation: "interrupt",
26382
+ payload: { worker: request.worker },
26383
+ schema: CampAckSchema
26384
+ },
26385
+ operations.interrupt(commandContext(request), workerIdentityFromDto(request.worker)).pipe(
26386
+ Effect_exports.as(CampAckSchema.make({ accepted: true })),
26387
+ Effect_exports.mapError((error2) => failureFromKernel("interrupt", error2))
26388
+ )
26389
+ )
26269
26390
  )
26270
26391
  ),
26271
26392
  OpenWorker: (request) => validateReady(request).pipe(
@@ -26428,6 +26549,8 @@ var directToolEnvironment = (source) => {
26428
26549
 
26429
26550
  // packages/host/src/tools/directTools.ts
26430
26551
  var DEFAULT_TIMEOUT_MS = 3e4;
26552
+ var TERMINATION_GRACE_MS = 2e3;
26553
+ var ABANDON_GRACE_MS = 2e3;
26431
26554
  var DEFAULT_MAX_OUTPUT_BYTES = 64 * 1024;
26432
26555
  var MAX_BUFFER_BYTES = 8 * 1024 * 1024;
26433
26556
  var truncate = (value, limit) => {
@@ -26464,8 +26587,15 @@ var runBinary = (executablePath, args, options, environment, signal) => {
26464
26587
  });
26465
26588
  let timedOut = false;
26466
26589
  let launchError;
26590
+ let settled = false;
26591
+ let killTimer;
26592
+ let abandonTimer;
26467
26593
  const stop = () => {
26468
26594
  child.kill("SIGTERM");
26595
+ killTimer ??= setTimeout(() => {
26596
+ child.kill("SIGKILL");
26597
+ abandonTimer = setTimeout(() => finish(void 0, "SIGKILL"), ABANDON_GRACE_MS);
26598
+ }, TERMINATION_GRACE_MS);
26469
26599
  };
26470
26600
  const stdout = collect(child.stdout, stop);
26471
26601
  const stderr = collect(child.stderr, stop);
@@ -26477,18 +26607,18 @@ var runBinary = (executablePath, args, options, environment, signal) => {
26477
26607
  timedOut = true;
26478
26608
  stop();
26479
26609
  }, options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
26480
- child.on("error", (cause) => {
26481
- if (signal?.aborted === true || cause.name === "AbortError") return;
26482
- launchError = `${cause.code ?? cause.name}: ${cause.message}`;
26483
- });
26484
- child.on("close", (code, terminatedBy) => {
26610
+ const finish = (code, terminatedBy) => {
26611
+ if (settled) return;
26612
+ settled = true;
26485
26613
  clearTimeout(timer);
26614
+ if (killTimer !== void 0) clearTimeout(killTimer);
26615
+ if (abandonTimer !== void 0) clearTimeout(abandonTimer);
26486
26616
  const sandboxStatus = sandboxed ? parseDirectToolSandboxStatus(status.text()) : void 0;
26487
26617
  resolve({
26488
26618
  stdout: stdout.text(),
26489
26619
  stderr: stderr.text(),
26490
26620
  exitCode: sandboxStatus?.exitCode ?? code ?? void 0,
26491
- signal: terminatedBy ?? void 0,
26621
+ signal: terminatedBy,
26492
26622
  timedOut,
26493
26623
  /*
26494
26624
  * A sandbox that never reached the command is only a refusal when the
@@ -26498,6 +26628,13 @@ var runBinary = (executablePath, args, options, environment, signal) => {
26498
26628
  ...sandboxStatus !== void 0 && !sandboxStatus.started && !timedOut && launchError === void 0 ? { sandboxFailed: true } : {},
26499
26629
  ...launchError === void 0 ? {} : { launchError }
26500
26630
  });
26631
+ };
26632
+ child.on("error", (cause) => {
26633
+ if (signal?.aborted === true || cause.name === "AbortError") return;
26634
+ launchError = `${cause.code ?? cause.name}: ${cause.message}`;
26635
+ });
26636
+ child.on("close", (code, terminatedBy) => {
26637
+ finish(code, terminatedBy ?? void 0);
26501
26638
  });
26502
26639
  });
26503
26640
  };
@@ -26721,6 +26858,26 @@ var acquireLiveCampHost = (options = {}) => Effect_exports.gen(function* () {
26721
26858
  piResources.modelRegistry,
26722
26859
  { authDiagnosticCodes: piResources.authDiagnosticCodes ?? [] }
26723
26860
  );
26861
+ const reportStartupJournalFailure = (cause) => cause instanceof CampJournalError ? Clock_exports.currentTimeMillis.pipe(
26862
+ Effect_exports.flatMap(
26863
+ (now) => saveCampHealth(fs, paths.healthPath, {
26864
+ ...initialCampHealthSnapshot(project.hash, "startup", now),
26865
+ overallStatus: CampHealthOverallStatus.failed,
26866
+ components: [
26867
+ {
26868
+ id: CAMP_JOURNAL_HEALTH_COMPONENT,
26869
+ category: CampHealthComponentCategory.controller,
26870
+ status: CampHealthComponentStatus.failed,
26871
+ code: cause.code,
26872
+ operation: "controller.journal.open",
26873
+ message: cause.message,
26874
+ updatedAt: now
26875
+ }
26876
+ ]
26877
+ })
26878
+ ),
26879
+ Effect_exports.ignore
26880
+ ) : Effect_exports.void;
26724
26881
  const context = yield* Layer_exports.build(
26725
26882
  makeLiveCampHostLayer({
26726
26883
  project,
@@ -26740,7 +26897,7 @@ var acquireLiveCampHost = (options = {}) => Effect_exports.gen(function* () {
26740
26897
  receiptsPath: campRunPaths(paths, options.manifestRunId).receiptsPath
26741
26898
  }
26742
26899
  })
26743
- );
26900
+ ).pipe(Effect_exports.tapError(reportStartupJournalFailure));
26744
26901
  const kernel = Context_exports.get(context, CampKernel);
26745
26902
  const asks = Context_exports.get(context, CampAskRouter);
26746
26903
  const health = Context_exports.get(context, CampHostHealth);
package/dist/priiisk.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  fromReadable,
6
6
  layer,
7
7
  runMain
8
- } from "./chunk-7U7PROSV.js";
8
+ } from "./chunk-IORSBZKU.js";
9
9
  import {
10
10
  CliCampLifecycleError,
11
11
  CliEquipmentConflict,
@@ -23,7 +23,7 @@ import {
23
23
  resolveCampSurface,
24
24
  withCampRpc,
25
25
  withCampRpcSession
26
- } from "./chunk-ZUREJQA6.js";
26
+ } from "./chunk-GEBZQLE7.js";
27
27
  import {
28
28
  CampCommandFailure,
29
29
  CampHostReadiness,
@@ -58,7 +58,7 @@ import {
58
58
  resolveProjectScopeSync,
59
59
  saveCampManifest,
60
60
  startingCampManifest
61
- } from "./chunk-JND6HOSJ.js";
61
+ } from "./chunk-LH753BUY.js";
62
62
  import {
63
63
  Cause_exports,
64
64
  CommitPrototype,
@@ -239,7 +239,7 @@ import {
239
239
  zipLeft,
240
240
  zipRight,
241
241
  zipWith
242
- } from "./chunk-3V5SHVCX.js";
242
+ } from "./chunk-F7LGUL2J.js";
243
243
 
244
244
  // node_modules/.pnpm/ini@4.1.3/node_modules/ini/lib/ini.js
245
245
  var require_ini = __commonJS({
@@ -18637,9 +18637,11 @@ var equipmentLines = (equipment, revision) => [
18637
18637
  ` mcp: ${mcpGrants(equipment.mcp)}`,
18638
18638
  ` skills: ${names([...equipment.skillNames])}`
18639
18639
  ];
18640
+ var WORKER_ERROR_LIMIT = 160;
18640
18641
  var formatWorker = (worker) => {
18641
18642
  const alias = worker.alias === void 0 ? "" : ` (${worker.alias})`;
18642
- const headline = `${worker.workerId}${alias}: ${worker.state}, session ${worker.sessionState}`;
18643
+ const failure2 = worker.error === void 0 ? "" : ` \u2014 \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u0438\u0439 \u0445\u043E\u0434: ${worker.error.code}: ${worker.error.message.slice(0, WORKER_ERROR_LIMIT)}`;
18644
+ const headline = `${worker.workerId}${alias}: ${worker.state}, session ${worker.sessionState}${failure2}`;
18643
18645
  return worker.equipment === void 0 ? headline : [headline, ...equipmentLines(worker.equipment, worker.equipmentVersion)].join("\n");
18644
18646
  };
18645
18647
  var printWorkers = (json) => (effect) => effect.pipe(
@@ -19094,7 +19096,9 @@ var resolveMessageText = (operation, text11, file6) => {
19094
19096
  );
19095
19097
  }
19096
19098
  if (Option_exports.isSome(file6)) return readMessageFile(operation, file6.value);
19097
- if (Option_exports.isSome(text11)) return Effect_exports.succeed(text11.value);
19099
+ if (Option_exports.isSome(text11)) {
19100
+ return text11.value.trim().length === 0 ? Effect_exports.fail(failure(operation, "message_empty", "\u0422\u0435\u043A\u0441\u0442 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F \u043F\u0443\u0441\u0442")) : Effect_exports.succeed(text11.value);
19101
+ }
19098
19102
  return Effect_exports.fail(
19099
19103
  failure(operation, "message_source_missing", "\u041D\u0443\u0436\u0435\u043D \u0442\u0435\u043A\u0441\u0442 \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442\u043E\u043C \u043B\u0438\u0431\u043E --file <path>")
19100
19104
  );
@@ -19948,7 +19952,7 @@ var campResumeListCommand = Command_exports.make(
19948
19952
  )
19949
19953
  ).pipe(Command_exports.withDescription("Lists saved runs of this project that resume can restore."));
19950
19954
  var runIdArgument = Args_exports.text({ name: "runId" }).pipe(Args_exports.optional);
19951
- var selectCampRunOnDemand = (items) => Effect_exports.promise(() => import("./chunk-VLP2ZKVV.js")).pipe(
19955
+ var selectCampRunOnDemand = (items) => Effect_exports.promise(() => import("./chunk-EHPEGFN2.js")).pipe(
19952
19956
  Effect_exports.flatMap((ui) => ui.selectCampRun({ items }))
19953
19957
  );
19954
19958
  var selectAndResume = (json) => {
@@ -20021,7 +20025,7 @@ var rootCommand = Command_exports.make(
20021
20025
  ).pipe(Command_exports.withDescription("Runs and observes a camp of collaborating workers."));
20022
20026
 
20023
20027
  // packages/cli/src/commands/doctorCommand.ts
20024
- var runDoctorOnDemand = Effect_exports.promise(() => import("./chunk-4VQ2KUN7.js")).pipe(
20028
+ var runDoctorOnDemand = Effect_exports.promise(() => import("./chunk-QQBVNDLC.js")).pipe(
20025
20029
  Effect_exports.flatMap((doctor) => doctor.runDoctor)
20026
20030
  );
20027
20031
  var statusLabel = {
@@ -20205,6 +20209,48 @@ var equipmentRequest = (role, preset, overrides) => ({
20205
20209
  ...Option_exports.isSome(preset) ? { preset: preset.value } : {},
20206
20210
  ...overrides === void 0 ? {} : { overrides }
20207
20211
  });
20212
+ var equipmentChangeOptions = {
20213
+ tools: toolOption,
20214
+ customTools: customToolOption,
20215
+ skills: skillOption,
20216
+ skillPaths: skillPathOption,
20217
+ directTools: directToolOption,
20218
+ mcp: mcpOption,
20219
+ mcpTools: mcpToolOption,
20220
+ noTools: noToolsOption,
20221
+ noCustomTools: noCustomToolsOption,
20222
+ noSkills: noSkillsOption,
20223
+ noDirectTools: noDirectToolsOption,
20224
+ noMcp: noMcpOption
20225
+ };
20226
+ var resolveEquipmentChange = (operation, input) => {
20227
+ const full = {
20228
+ ...input,
20229
+ model: Option_exports.none(),
20230
+ thinking: Option_exports.none(),
20231
+ access: Option_exports.none()
20232
+ };
20233
+ const categories = conflictingEquipmentCategories(full);
20234
+ if (categories.length > 0) {
20235
+ return Effect_exports.fail(
20236
+ new CliEquipmentConflict({
20237
+ operation,
20238
+ code: "equipment_flag_conflict",
20239
+ message: `granting and clearing the same equipment: ${categories.join(", ")}`,
20240
+ categories
20241
+ })
20242
+ );
20243
+ }
20244
+ const overrides = equipmentOverrides(full) ?? {};
20245
+ return Effect_exports.succeed({
20246
+ ...overrides.builtinTools === void 0 ? {} : { builtinTools: overrides.builtinTools },
20247
+ ...overrides.customToolNames === void 0 ? {} : { customToolNames: overrides.customToolNames },
20248
+ ...overrides.directTools === void 0 ? {} : { directTools: overrides.directTools },
20249
+ ...overrides.skillNames === void 0 ? {} : { skillNames: overrides.skillNames },
20250
+ ...overrides.skillPaths === void 0 ? {} : { skillPaths: overrides.skillPaths },
20251
+ ...overrides.mcp === void 0 ? {} : { mcp: overrides.mcp }
20252
+ });
20253
+ };
20208
20254
 
20209
20255
  // packages/cli/src/commands/equipCommand.ts
20210
20256
  var equipCommand = Command_exports.make(
@@ -20212,20 +20258,18 @@ var equipCommand = Command_exports.make(
20212
20258
  {
20213
20259
  worker: workerArgument,
20214
20260
  byId: byIdOption,
20215
- role: roleOption,
20216
- preset: presetOption,
20217
- ...equipmentOptions,
20261
+ ...equipmentChangeOptions,
20218
20262
  json: jsonOption
20219
20263
  },
20220
- ({ worker, byId, role, preset, json, ...equipment }) => resolveEquipmentOverrides("equip", equipment).pipe(
20264
+ ({ worker, byId, json, ...equipment }) => resolveEquipmentChange("equip", equipment).pipe(
20221
20265
  Effect_exports.flatMap(
20222
- (overrides) => withCampRpc(
20266
+ (change) => withCampRpc(
20223
20267
  ({ client, command: command2 }) => command2().pipe(
20224
20268
  Effect_exports.flatMap(
20225
20269
  (context) => client.Equip({
20226
20270
  ...context,
20227
20271
  worker: workerSelector(worker, byId),
20228
- equipment: equipmentRequest(role, preset, overrides)
20272
+ equipment: change
20229
20273
  })
20230
20274
  )
20231
20275
  ),
@@ -20235,7 +20279,9 @@ var equipCommand = Command_exports.make(
20235
20279
  printValue(json, formatWorker)
20236
20280
  )
20237
20281
  ).pipe(
20238
- Command_exports.withDescription("Changes the equipment of a live worker without recreating its session.")
20282
+ Command_exports.withDescription(
20283
+ "Hands a live worker skills, MCP servers, binaries and tools, or takes them back."
20284
+ )
20239
20285
  );
20240
20286
 
20241
20287
  // packages/cli/src/client/campStartupFlow.ts
@@ -20359,7 +20405,19 @@ var eventsCommand = Command_exports.make(
20359
20405
  if (follow) {
20360
20406
  yield* stream.pipe(
20361
20407
  Stream_exports.runForEach(
20362
- (event) => Console_exports.log(json ? JSON.stringify(event) : formatCampEvent(event))
20408
+ (event) => Console_exports.log(json ? JSON.stringify(event) : formatCampEvent(event)).pipe(
20409
+ Effect_exports.zipRight(
20410
+ ack ? client.AckEvents({
20411
+ ...leaseRequest,
20412
+ generation: event.generation,
20413
+ cursor: event.cursor
20414
+ }).pipe(Effect_exports.asVoid) : Effect_exports.void
20415
+ )
20416
+ )
20417
+ )
20418
+ ).pipe(
20419
+ Effect_exports.ensuring(
20420
+ release ? client.ReleaseConsumer(context).pipe(Effect_exports.ignore) : Effect_exports.void
20363
20421
  )
20364
20422
  );
20365
20423
  return [];
@@ -20719,7 +20777,7 @@ var command = rootCommand.pipe(
20719
20777
  );
20720
20778
  var cli = Command_exports.run(command, {
20721
20779
  name: "priiisk camp control",
20722
- version: "0.1.7"
20780
+ version: "0.1.9"
20723
20781
  });
20724
20782
  var runCliCommand = (argumentsList) => cli(argumentsList).pipe(
20725
20783
  Effect_exports.matchEffect({
package/package.json CHANGED
@@ -1,22 +1,22 @@
1
1
  {
2
2
  "name": "priiisk",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "CLI for running and observing a camp of collaborating agents",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "priiisk": "./dist/priiisk.js"
8
8
  },
9
9
  "files": [
10
- "dist/chunk-3V5SHVCX.js",
11
- "dist/chunk-4VQ2KUN7.js",
12
- "dist/chunk-7U7PROSV.js",
13
- "dist/chunk-JND6HOSJ.js",
14
- "dist/chunk-JND6HOSJ.js.LEGAL.txt",
15
- "dist/chunk-VLP2ZKVV.js",
16
- "dist/chunk-WEYE43UO.js",
17
- "dist/chunk-WEYE43UO.js.LEGAL.txt",
18
- "dist/chunk-YOW4MMBD.js",
19
- "dist/chunk-ZUREJQA6.js",
10
+ "dist/chunk-EHPEGFN2.js",
11
+ "dist/chunk-F7LGUL2J.js",
12
+ "dist/chunk-GEBZQLE7.js",
13
+ "dist/chunk-IORSBZKU.js",
14
+ "dist/chunk-LH753BUY.js",
15
+ "dist/chunk-LH753BUY.js.LEGAL.txt",
16
+ "dist/chunk-NIJ2J45R.js",
17
+ "dist/chunk-QEUSNJ3D.js",
18
+ "dist/chunk-QEUSNJ3D.js.LEGAL.txt",
19
+ "dist/chunk-QQBVNDLC.js",
20
20
  "dist/priiisk-host.js",
21
21
  "dist/priiisk.js",
22
22
  "profiles",