@cleocode/adapters 2026.9.26 → 2026.10.2

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/index.js CHANGED
@@ -14216,6 +14216,326 @@ var init_adr_073_saga = __esm({
14216
14216
  }
14217
14217
  });
14218
14218
 
14219
+ // packages/contracts/src/invariants/sync-write-invariants.ts
14220
+ function checkPending(task) {
14221
+ return { task, reason: "the post-apply check is not implemented yet (T12344 item)" };
14222
+ }
14223
+ function rulePending(task) {
14224
+ return { task, reason: "the typed merge-rule registry does not define it yet (T12344 item)" };
14225
+ }
14226
+ function trigger(id, tables, triggers, inventory, reason) {
14227
+ return { id, class: "trigger-covered", tables, sites: [], triggers, inventory, reason };
14228
+ }
14229
+ function pac(id, item, task, tables, footprint, reason) {
14230
+ return {
14231
+ id,
14232
+ class: "post-apply-check",
14233
+ tables,
14234
+ sites: [],
14235
+ check: { footprint },
14236
+ inventory: [item],
14237
+ pending: checkPending(task),
14238
+ reason
14239
+ };
14240
+ }
14241
+ function rule(id, task, table, columns, inventory, reason, tables = [table]) {
14242
+ return {
14243
+ id,
14244
+ class: "monotonic-merge-rule",
14245
+ tables,
14246
+ sites: [],
14247
+ mergeRule: { table, columns },
14248
+ inventory,
14249
+ pending: rulePending(task),
14250
+ reason
14251
+ };
14252
+ }
14253
+ var SYNC_WRITE_INVARIANTS;
14254
+ var init_sync_write_invariants = __esm({
14255
+ "packages/contracts/src/invariants/sync-write-invariants.ts"() {
14256
+ "use strict";
14257
+ SYNC_WRITE_INVARIANTS = Object.freeze([
14258
+ // §3.6.2: RAISE guards and UNIQUE indexes a migration creates on synced tables.
14259
+ trigger(
14260
+ "task.parent.no-cycle",
14261
+ ["tasks_tasks"],
14262
+ ["tasks_tasks_parent_cycle_guard_insert", "tasks_tasks_parent_cycle_guard_update"],
14263
+ ["V10", "V11"],
14264
+ "the parent chain is acyclic (the INSERT variant misses a self-parent, \xA73.6.3 item 2)"
14265
+ ),
14266
+ trigger(
14267
+ "task.parent.type-matrix",
14268
+ ["tasks_tasks"],
14269
+ ["tasks_tasks_parent_type_matrix_insert", "tasks_tasks_parent_type_matrix_update"],
14270
+ ["X1"],
14271
+ "parent/child type matrix; weaker than TypeScript (\xA73.6.3 item 1), the rest is PAC-01"
14272
+ ),
14273
+ trigger(
14274
+ "task.status.pipeline-consistency",
14275
+ ["tasks_tasks"],
14276
+ ["trg_tasks_tasks_status_pipeline_insert", "trg_tasks_tasks_status_pipeline_update"],
14277
+ ["V19", "C21"],
14278
+ "T877: status and pipeline_stage agree on one row"
14279
+ ),
14280
+ trigger(
14281
+ "task.relation.non-containment",
14282
+ ["tasks_task_relations"],
14283
+ ["tasks_task_relations_non_containment_insert", "tasks_task_relations_non_containment_update"],
14284
+ ["V31"],
14285
+ "no relation between a parent and its child, on relation writes only (\xA73.6.3 item 4)"
14286
+ ),
14287
+ trigger(
14288
+ "task.ac.child-target",
14289
+ ["tasks_task_acceptance_criteria"],
14290
+ ["tasks_task_acceptance_child_target_insert", "tasks_task_acceptance_child_target_update"],
14291
+ ["C28"],
14292
+ "a child_task AC targets a direct child, on AC writes only (\xA73.6.3 item 4)"
14293
+ ),
14294
+ trigger(
14295
+ "session.handoff.append-only",
14296
+ ["tasks_session_handoff_entries"],
14297
+ ["trg_tasks_session_handoff_no_update"],
14298
+ ["H2"],
14299
+ "handoff entries are never updated"
14300
+ ),
14301
+ trigger(
14302
+ "task.claim.lease-iso",
14303
+ ["tasks_tasks"],
14304
+ ["tasks_tasks_lease_iso_insert", "tasks_tasks_lease_iso_update"],
14305
+ [],
14306
+ "claim lease timestamps are ISO-8601 (t12736)"
14307
+ ),
14308
+ trigger(
14309
+ "task.ac-binding.unique",
14310
+ ["tasks_evidence_ac_bindings"],
14311
+ ["uq_tasks_evidence_ac_bindings_atom_ac_type"],
14312
+ ["C31"],
14313
+ "one binding per (evidence atom, AC, binding type)"
14314
+ ),
14315
+ trigger(
14316
+ "release.version.unique",
14317
+ ["tasks_releases"],
14318
+ ["uq_tasks_releases_version"],
14319
+ ["REL-1"],
14320
+ "one release row per version"
14321
+ ),
14322
+ trigger(
14323
+ "selfimprove.dhq.one-open",
14324
+ ["selfimprove_dhq"],
14325
+ ["ux_selfimprove_dhq_open"],
14326
+ ["D49"],
14327
+ "at most one open DHQ entry per question_hash"
14328
+ ),
14329
+ trigger(
14330
+ "account.one-active-per-provider",
14331
+ ["accounts"],
14332
+ ["ux_accounts_active_provider"],
14333
+ ["A40"],
14334
+ "at most one active account per provider (partial UNIQUE)"
14335
+ ),
14336
+ // §3.6.5: post-apply check families (T12344 items).
14337
+ pac(
14338
+ "task.tree.shape",
14339
+ "PAC-01",
14340
+ "T12922",
14341
+ ["tasks_tasks"],
14342
+ ["rows with a changed parent_id or type", "their direct children and ancestor chain"],
14343
+ "saga\u2192epic\u2192task\u2192subtask matrix, non-saga has a parent, depth \u2264 3, no self-parent"
14344
+ ),
14345
+ pac(
14346
+ "task.terminal-parent.live-children",
14347
+ "PAC-02",
14348
+ "T12923",
14349
+ ["tasks_tasks"],
14350
+ ["rows whose status, stage or parent changed", "their parent and siblings"],
14351
+ "no terminal parent with a live child; epic stage \u2265 children; rollup re-evaluated"
14352
+ ),
14353
+ pac(
14354
+ "task.dependency.graph",
14355
+ "PAC-03",
14356
+ "T12924",
14357
+ ["tasks_task_dependencies", "tasks_tasks"],
14358
+ ["dependency edges inserted in the page", "reachability from each depends_on"],
14359
+ "dependencies are acyclic, with no self-edge"
14360
+ ),
14361
+ pac(
14362
+ "task.done.evidence",
14363
+ "PAC-04",
14364
+ "T12925",
14365
+ ["tasks_tasks", "tasks_task_acceptance_criteria", "tasks_evidence_ac_bindings"],
14366
+ ["done rows in the page", "their AC rows, bindings, acceptance_json and verification_json"],
14367
+ "a done task has passed verification and every AC bound or waived"
14368
+ ),
14369
+ pac(
14370
+ "task.ac.integrity",
14371
+ "PAC-05",
14372
+ "T12926",
14373
+ ["tasks_tasks", "tasks_task_acceptance_criteria", "tasks_evidence_ac_bindings"],
14374
+ ["tasks whose AC rows, bindings, acceptance_json, parent_id or relations changed"],
14375
+ "acceptance_json \u21D4 AC rows, child_task ACs match children, bindings resolve"
14376
+ ),
14377
+ pac(
14378
+ "lifecycle.rows",
14379
+ "PAC-06",
14380
+ "T12927",
14381
+ ["tasks_lifecycle_pipelines", "tasks_lifecycle_stages", "tasks_tasks"],
14382
+ ["lifecycle pipeline, stage and gate rows in the page", "the owning task row"],
14383
+ "one pipeline per task, one stage row per name, pipeline_stage \u2265 completed stages"
14384
+ ),
14385
+ pac(
14386
+ "derived.mirrors",
14387
+ "PAC-07",
14388
+ "T12928",
14389
+ ["tasks_task_labels", "brain_sticky_tags", "docs_wikilinks", "tasks_tasks"],
14390
+ ["owning rows whose JSON or junction changed"],
14391
+ "junction tables equal their JSON source"
14392
+ ),
14393
+ pac(
14394
+ "session.goal.singletons",
14395
+ "PAC-08",
14396
+ "T12929",
14397
+ ["tasks_sessions", "tasks_task_work_history", "tasks_goal"],
14398
+ ["session rows whose status, scope or chain changed", "work-history rows per session"],
14399
+ "one active session per scope, reciprocal chain, one open interval, one live goal"
14400
+ ),
14401
+ pac(
14402
+ "audit.uniqueness",
14403
+ "PAC-09",
14404
+ "T12930",
14405
+ ["tasks_audit_log"],
14406
+ ["audit rows with a non-null idempotency key", "rollback audit rows"],
14407
+ "idempotency keys are unique across replicas; at most one rollback per receipt"
14408
+ ),
14409
+ pac(
14410
+ "identity.collisions",
14411
+ "PAC-10",
14412
+ "T12931",
14413
+ ["tasks_tasks", "tasks_sessions", "brain_observations", "docs_attachments"],
14414
+ ["inserted rows", "the natural key's index"],
14415
+ "display-id and natural-key clashes become an alias or re-mint (T12341)"
14416
+ ),
14417
+ pac(
14418
+ "dedupe.at-most-one",
14419
+ "PAC-11",
14420
+ "T12932",
14421
+ ["brain_decisions", "brain_learnings", "tasks_external_task_links"],
14422
+ ["inserted rows grouped by the natural key"],
14423
+ "duplicates created on two devices are merged"
14424
+ ),
14425
+ pac(
14426
+ "ref.soft-orphans",
14427
+ "PAC-12",
14428
+ "T12933",
14429
+ ["brain_memory_links", "brain_page_edges", "docs_attachment_refs", "tasks_task_commits"],
14430
+ ["reference columns of the rows in the page", "their targets"],
14431
+ "cross-DB and polymorphic references resolve"
14432
+ ),
14433
+ pac(
14434
+ "supersession.graph",
14435
+ "PAC-13",
14436
+ "T12934",
14437
+ ["brain_decisions", "docs_attachments", "tasks_architecture_decisions"],
14438
+ ["rows whose supersession columns changed", "a chain walk"],
14439
+ "supersession chains are acyclic with at most one successor"
14440
+ ),
14441
+ pac(
14442
+ "derived.counters",
14443
+ "PAC-14",
14444
+ "T12935",
14445
+ ["docs_attachments", "conduit_attachments", "docs_pipeline_manifest"],
14446
+ ["the owning rows"],
14447
+ "derived counters and cross-column facts agree with their rows"
14448
+ ),
14449
+ pac(
14450
+ "apply.preconditions",
14451
+ "PAC-15",
14452
+ "T12936",
14453
+ ["tasks_tasks"],
14454
+ ["the whole page"],
14455
+ "no apply while the local twin collapse has failed; restore is a re-baseline"
14456
+ ),
14457
+ // §3.6.6: typed merge rules (T12344).
14458
+ rule(
14459
+ "task.status.absorbing",
14460
+ "T12937",
14461
+ "tasks_tasks",
14462
+ ["status", "completed_at", "cancelled_at", "cancellation_reason", "pipeline_stage"],
14463
+ ["V18", "V20", "C22", "P40", "P46", "P47"],
14464
+ "done, cancelled and archived are absorbing; leaving them needs an explicit op"
14465
+ ),
14466
+ rule(
14467
+ "task.pipeline-stage.max",
14468
+ "T12938",
14469
+ "tasks_tasks",
14470
+ ["pipeline_stage"],
14471
+ ["V21", "C20", "P01", "F3"],
14472
+ "pipeline_stage is the maximum by STAGE_ORDER, except an explicit restore"
14473
+ ),
14474
+ rule(
14475
+ "task.verification.frozen-on-done",
14476
+ "T12939",
14477
+ "tasks_tasks",
14478
+ ["verification_json"],
14479
+ ["C01", "C02", "C03", "C17"],
14480
+ "verification is frozen once done; otherwise merged per gate"
14481
+ ),
14482
+ rule(
14483
+ "session.status.terminal",
14484
+ "T12940",
14485
+ "tasks_sessions",
14486
+ ["status", "ended_at"],
14487
+ ["S7", "S8", "S9", "S10", "S11", "S17", "S18", "SC2", "N1", "SK5", "P32"],
14488
+ "ended and orphaned are terminal except on an explicit resume"
14489
+ ),
14490
+ rule("audit.immutable", "T12941", "tasks_audit_log", ["*"], ["SA3"], "audit rows are immutable", [
14491
+ "tasks_audit_log",
14492
+ "audit_log"
14493
+ ]),
14494
+ rule(
14495
+ "sticky.status.one-way",
14496
+ "T12942",
14497
+ "brain_sticky_notes",
14498
+ ["status", "converted_to_json"],
14499
+ ["SK2", "SK3", "B24"],
14500
+ "active\u2192{converted, archived} is one-way; converted_to_json is write-once"
14501
+ ),
14502
+ rule(
14503
+ "release.status.absorbing",
14504
+ "T12943",
14505
+ "tasks_releases",
14506
+ ["status"],
14507
+ ["REL-2", "REL-3", "REL-4", "REL-5", "REL-6", "REL-7", "REL-8"],
14508
+ "shipped release statuses are absorbing"
14509
+ ),
14510
+ rule(
14511
+ "playbook.approval.once",
14512
+ "T12944",
14513
+ "tasks_playbook_approvals",
14514
+ ["status"],
14515
+ ["PB-1", "PB-4", "PB-7", "P33"],
14516
+ "an approval goes pending\u2192decided once"
14517
+ ),
14518
+ rule(
14519
+ "docs.lifecycle.transitions",
14520
+ "T12945",
14521
+ "docs_attachments",
14522
+ ["lifecycle_status"],
14523
+ ["D04", "D05", "D31", "D32", "D39", "D50"],
14524
+ "superseded is sticky; lifecycle transitions follow a matrix"
14525
+ ),
14526
+ // §3.6.0 identity-layer rows.
14527
+ {
14528
+ id: "identity.local-minting",
14529
+ class: "identity-layer",
14530
+ tables: ["tasks_tasks", "tasks_sessions"],
14531
+ sites: [],
14532
+ inventory: ["V12", "B07", "B12"],
14533
+ reason: "ids minted from local state (display ids, integer PKs, device-derived ids) collide across replicas; T12341 uids and re-minting own it, no validator port can"
14534
+ }
14535
+ ]);
14536
+ }
14537
+ });
14538
+
14219
14539
  // packages/contracts/src/invariants/index.ts
14220
14540
  function buildKey(invariant) {
14221
14541
  return `${invariant.adr}.${invariant.code}`;
@@ -14246,6 +14566,7 @@ var init_invariants = __esm({
14246
14566
  init_adr_056_release();
14247
14567
  init_adr_070_orchestration();
14248
14568
  init_adr_073_saga();
14569
+ init_sync_write_invariants();
14249
14570
  INVARIANTS_REGISTRY = buildRegistry();
14250
14571
  }
14251
14572
  });
@@ -16638,8 +16959,8 @@ var init_taxonomy = __esm({
16638
16959
  normalizeSet(labels) {
16639
16960
  const result = /* @__PURE__ */ new Set();
16640
16961
  for (const label of labels) {
16641
- const canonical = this.normalize(label);
16642
- result.add(canonical ?? label);
16962
+ const canonical2 = this.normalize(label);
16963
+ result.add(canonical2 ?? label);
16643
16964
  }
16644
16965
  return [...result];
16645
16966
  }
@@ -17669,6 +17990,311 @@ var init_nexus_account = __esm({
17669
17990
  }
17670
17991
  });
17671
17992
 
17993
+ // packages/contracts/src/nexus-cloud.ts
17994
+ import { z as z26 } from "zod";
17995
+ var NEXUS_DEVICE_STATES, NEXUS_CLOUD_PROFILES, NEXUS_DEVICE_STATE_UNKNOWN, isoTime, profile, deviceState, nexusCloudCredentialSchema, nexusCloudDeviceSchema, nexusCloudOrganizationSchema, nexusCloudUserSchema, nexusCloudWhoamiSchema, nexusCloudDevicePageSchema, nexusCloudPresenceSchema, nexusCloudReplicaSchema, nexusCloudDeviceCountsSchema, projectFields, nexusCloudProjectListItemSchema, nexusCloudProjectPageSchema, nexusCloudProjectDetailSchema, nexusCloudReplicaPageSchema, NEXUS_STATUS_CHECK_IDS, NEXUS_STATUS_VERDICTS, CLOUD_STATUS_VERDICTS, knownCheckId, nexusCloudStatusCheckSchema, nexusCloudStatusSchema, LOGIN, SESSION_EXPIRED_LOGIN, SERVER_REFUSED, NEXUS_FORBIDDEN_ERRORS;
17996
+ var init_nexus_cloud = __esm({
17997
+ "packages/contracts/src/nexus-cloud.ts"() {
17998
+ "use strict";
17999
+ NEXUS_DEVICE_STATES = ["active", "signed-out", "revoked"];
18000
+ NEXUS_CLOUD_PROFILES = ["device", "read-only"];
18001
+ NEXUS_DEVICE_STATE_UNKNOWN = "unknown";
18002
+ isoTime = z26.iso.datetime({ offset: true });
18003
+ profile = z26.enum(NEXUS_CLOUD_PROFILES).nullable().catch(null);
18004
+ deviceState = z26.enum([...NEXUS_DEVICE_STATES, NEXUS_DEVICE_STATE_UNKNOWN]).catch(NEXUS_DEVICE_STATE_UNKNOWN);
18005
+ nexusCloudCredentialSchema = z26.object({
18006
+ kind: z26.enum(["device", "session"]),
18007
+ credentialId: z26.string().nullable().optional(),
18008
+ profile: profile.optional(),
18009
+ scopes: z26.array(z26.string()).default([]),
18010
+ createdAt: isoTime.nullable().optional(),
18011
+ lastUsedAt: isoTime.nullable().optional(),
18012
+ /** When the credential expires if it is not used again; null for sessions. */
18013
+ idleExpiresAt: isoTime.nullable().optional()
18014
+ });
18015
+ nexusCloudDeviceSchema = z26.object({
18016
+ deviceId: z26.string(),
18017
+ name: z26.string(),
18018
+ platform: z26.string().optional(),
18019
+ arch: z26.string().nullable().optional(),
18020
+ cliVersion: z26.string().nullable().optional(),
18021
+ createdAt: isoTime.optional(),
18022
+ lastSeenAt: isoTime.nullable().optional(),
18023
+ state: deviceState,
18024
+ signedOutAt: isoTime.nullable().optional(),
18025
+ /** Base64 device certificate; null until the device holds a key grant. */
18026
+ certificate: z26.string().nullable().optional(),
18027
+ /** The current credential's profile, or null with none (signed out or revoked). */
18028
+ profile: profile.optional(),
18029
+ /** True for the device whose credential made this request. */
18030
+ current: z26.boolean().default(false),
18031
+ projects: z26.number().int().nonnegative().optional(),
18032
+ replicas: z26.number().int().nonnegative().optional(),
18033
+ lastSyncAt: isoTime.nullable().optional(),
18034
+ lastPresenceAt: isoTime.nullable().optional()
18035
+ });
18036
+ nexusCloudOrganizationSchema = z26.object({
18037
+ id: z26.string(),
18038
+ name: z26.string(),
18039
+ slug: z26.string().nullable().optional(),
18040
+ role: z26.string().optional(),
18041
+ personal: z26.boolean().optional()
18042
+ });
18043
+ nexusCloudUserSchema = z26.object({
18044
+ id: z26.string(),
18045
+ email: z26.string(),
18046
+ name: z26.string().nullable().optional()
18047
+ });
18048
+ nexusCloudWhoamiSchema = z26.object({
18049
+ serverTime: isoTime.optional(),
18050
+ user: nexusCloudUserSchema,
18051
+ organizations: z26.array(nexusCloudOrganizationSchema).default([]),
18052
+ credential: nexusCloudCredentialSchema,
18053
+ /** The calling device; null for a session caller. */
18054
+ device: nexusCloudDeviceSchema.nullable()
18055
+ });
18056
+ nexusCloudDevicePageSchema = z26.object({
18057
+ devices: z26.array(nexusCloudDeviceSchema),
18058
+ nextCursor: z26.string().max(512).nullable().default(null),
18059
+ truncated: z26.boolean().default(false)
18060
+ });
18061
+ nexusCloudPresenceSchema = z26.looseObject({
18062
+ observedAt: isoTime.optional(),
18063
+ sync: z26.object({ enabled: z26.boolean() }).optional()
18064
+ });
18065
+ nexusCloudReplicaSchema = z26.object({
18066
+ projectId: z26.string(),
18067
+ replicaId: z26.string(),
18068
+ deviceId: z26.string(),
18069
+ deviceName: z26.string(),
18070
+ deviceState: deviceState.optional(),
18071
+ attachedAt: isoTime.optional(),
18072
+ lastSyncAt: isoTime.nullable(),
18073
+ presence: nexusCloudPresenceSchema.nullable(),
18074
+ presenceAt: isoTime.nullable()
18075
+ });
18076
+ nexusCloudDeviceCountsSchema = z26.object({
18077
+ active: z26.number().int().nonnegative(),
18078
+ total: z26.number().int().nonnegative()
18079
+ });
18080
+ projectFields = {
18081
+ projectId: z26.string(),
18082
+ label: z26.string().nullable(),
18083
+ organizationId: z26.string(),
18084
+ organizationName: z26.string().optional(),
18085
+ remoteUrl: z26.string().nullable().optional(),
18086
+ createdAt: isoTime.optional()
18087
+ };
18088
+ nexusCloudProjectListItemSchema = z26.object({
18089
+ ...projectFields,
18090
+ role: z26.string(),
18091
+ streamId: z26.string().optional(),
18092
+ headSeq: z26.number().int().nonnegative().nullable().optional(),
18093
+ openConflicts: z26.number().int().nonnegative().optional(),
18094
+ replicas: z26.array(nexusCloudReplicaSchema).default([]),
18095
+ devices: nexusCloudDeviceCountsSchema.optional(),
18096
+ replicaCount: z26.number().int().nonnegative().optional(),
18097
+ lastSyncAt: isoTime.nullable().optional(),
18098
+ lastPresenceAt: isoTime.nullable().optional(),
18099
+ /** This project's replica list was cut at 50 (T12858). */
18100
+ replicasTruncated: z26.boolean().default(false)
18101
+ });
18102
+ nexusCloudProjectPageSchema = z26.object({
18103
+ projects: z26.array(nexusCloudProjectListItemSchema),
18104
+ nextCursor: z26.string().max(512).nullable().default(null),
18105
+ /** Anything in the page was cut (the project list or a replica list). */
18106
+ truncated: z26.boolean().default(false),
18107
+ /** The project list itself was cut at 1000 (T12858). */
18108
+ projectsTruncated: z26.boolean().default(false)
18109
+ });
18110
+ nexusCloudProjectDetailSchema = z26.object({
18111
+ project: z26.object({ ...projectFields, deletedAt: isoTime.nullable().optional() }),
18112
+ role: z26.string(),
18113
+ canTrash: z26.boolean().optional(),
18114
+ openConflicts: z26.number().int().nonnegative(),
18115
+ /** At most 50, oldest attachment first. */
18116
+ replicas: z26.array(nexusCloudReplicaSchema),
18117
+ devices: nexusCloudDeviceCountsSchema,
18118
+ replicaCount: z26.number().int().nonnegative().optional(),
18119
+ lastSyncAt: isoTime.nullable().optional(),
18120
+ /** `replicas` was cut at 50. */
18121
+ truncated: z26.boolean().default(false),
18122
+ stream: z26.object({
18123
+ streamId: z26.string(),
18124
+ headSeq: z26.number().int().nonnegative(),
18125
+ headCheckpointId: z26.string().nullable()
18126
+ }).nullable()
18127
+ });
18128
+ nexusCloudReplicaPageSchema = z26.object({
18129
+ replicas: z26.array(nexusCloudReplicaSchema),
18130
+ devices: nexusCloudDeviceCountsSchema.optional(),
18131
+ nextCursor: z26.string().max(512).nullable().default(null),
18132
+ truncated: z26.boolean().default(false)
18133
+ });
18134
+ NEXUS_STATUS_CHECK_IDS = [
18135
+ "credential.valid",
18136
+ "device.registered",
18137
+ "device.active",
18138
+ "device.certified",
18139
+ "project.registered",
18140
+ "project.writable",
18141
+ "replica.attached",
18142
+ "presence.fresh",
18143
+ "replica.synced",
18144
+ "conflicts.none"
18145
+ ];
18146
+ NEXUS_STATUS_VERDICTS = ["ok", "attention", "not-linked", "not-registered"];
18147
+ CLOUD_STATUS_VERDICTS = [...NEXUS_STATUS_VERDICTS, "not-signed-in"];
18148
+ knownCheckId = z26.enum(NEXUS_STATUS_CHECK_IDS);
18149
+ nexusCloudStatusCheckSchema = z26.object({
18150
+ id: z26.enum(NEXUS_STATUS_CHECK_IDS),
18151
+ ok: z26.boolean(),
18152
+ required: z26.boolean(),
18153
+ detail: z26.string()
18154
+ });
18155
+ nexusCloudStatusSchema = z26.object({
18156
+ serverTime: isoTime.optional(),
18157
+ apiVersion: z26.string().optional(),
18158
+ user: nexusCloudUserSchema,
18159
+ credential: nexusCloudCredentialSchema,
18160
+ device: nexusCloudDeviceSchema.nullable(),
18161
+ project: z26.object({
18162
+ projectId: z26.string(),
18163
+ registered: z26.boolean(),
18164
+ organizationId: z26.string().nullable(),
18165
+ organizationName: z26.string().nullable(),
18166
+ role: z26.string().nullable()
18167
+ }).nullable(),
18168
+ replica: z26.object({
18169
+ replicaId: z26.string(),
18170
+ attached: z26.boolean(),
18171
+ attachedElsewhere: z26.boolean(),
18172
+ attachedAt: isoTime.nullable(),
18173
+ lastSyncAt: isoTime.nullable(),
18174
+ presenceAt: isoTime.nullable(),
18175
+ lastReplicaSeq: z26.number().int().nonnegative().nullable().optional()
18176
+ }).nullable(),
18177
+ stream: z26.object({
18178
+ streamId: z26.string(),
18179
+ headSeq: z26.number().int().nonnegative(),
18180
+ headCheckpointId: z26.string().nullable(),
18181
+ openConflicts: z26.number().int().nonnegative(),
18182
+ devices: nexusCloudDeviceCountsSchema
18183
+ }).nullable(),
18184
+ /** Check ids added by a newer server are dropped, never a parse failure. */
18185
+ checks: z26.array(nexusCloudStatusCheckSchema.extend({ id: z26.string() })).transform(
18186
+ (list) => list.flatMap((c) => {
18187
+ const id = knownCheckId.safeParse(c.id);
18188
+ return id.success ? [{ ...c, id: id.data }] : [];
18189
+ })
18190
+ ),
18191
+ /** A verdict added by a newer server reads as `attention`: never `ok` by accident. */
18192
+ verdict: z26.enum(NEXUS_STATUS_VERDICTS).catch("attention")
18193
+ });
18194
+ LOGIN = "run `cleo login nexus`";
18195
+ SESSION_EXPIRED_LOGIN = {
18196
+ code: "E_NEXUS_SESSION_EXPIRED",
18197
+ message: "the session is too old for this request",
18198
+ fix: "run `cleo login nexus` (needs a browser: on a headless machine a human must complete the login)"
18199
+ };
18200
+ SERVER_REFUSED = {
18201
+ code: "E_NEXUS_REQUEST_FAILED",
18202
+ message: null,
18203
+ fix: null
18204
+ };
18205
+ NEXUS_FORBIDDEN_ERRORS = {
18206
+ "insufficient-scope": {
18207
+ code: "E_NEXUS_INSUFFICIENT_SCOPE",
18208
+ message: "this device's credential lacks the scope for that request",
18209
+ fix: "run `cleo login nexus` without --read-only to enrol with the full device profile"
18210
+ },
18211
+ "session-required": SERVER_REFUSED,
18212
+ "device-required": SERVER_REFUSED,
18213
+ "device-mismatch": SERVER_REFUSED,
18214
+ "not-self": SERVER_REFUSED,
18215
+ "project-role": SERVER_REFUSED,
18216
+ "route-undeclared": SERVER_REFUSED,
18217
+ "bearer-session-required": SESSION_EXPIRED_LOGIN,
18218
+ "session-not-fresh": SESSION_EXPIRED_LOGIN,
18219
+ "device-limit": {
18220
+ code: "E_NEXUS_REQUEST_FAILED",
18221
+ message: "the account has reached its device limit",
18222
+ fix: "revoke unused devices on cleocode.dev, then retry"
18223
+ },
18224
+ "device-flow-session-required": {
18225
+ code: "E_NEXUS_SESSION_EXPIRED",
18226
+ message: "this session was not issued to the CLI by `cleo login nexus`, so it cannot enrol a device",
18227
+ fix: SESSION_EXPIRED_LOGIN.fix
18228
+ },
18229
+ "device-not-enrolled": {
18230
+ code: "E_NEXUS_NOT_SIGNED_IN",
18231
+ message: "this device is not enrolled with Cleo Nexus",
18232
+ fix: LOGIN
18233
+ }
18234
+ };
18235
+ }
18236
+ });
18237
+
18238
+ // packages/contracts/src/nexus-vault.ts
18239
+ import { z as z27 } from "zod";
18240
+ var isoTime2, uuid, nexusUserKeysSchema, nexusProjectKeysSchema, nexusLeaseSchema, nexusLeaseAcquireSchema, nexusStreamHeadSchema, nexusActivityEventSchema, nexusActivityPageSchema;
18241
+ var init_nexus_vault = __esm({
18242
+ "packages/contracts/src/nexus-vault.ts"() {
18243
+ "use strict";
18244
+ isoTime2 = z27.iso.datetime({ offset: true });
18245
+ uuid = z27.string().regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i);
18246
+ nexusUserKeysSchema = z27.looseObject({
18247
+ keyVersion: z27.number().int().positive(),
18248
+ masterKeyVerifier: z27.string()
18249
+ });
18250
+ nexusProjectKeysSchema = z27.looseObject({
18251
+ keys: z27.array(
18252
+ z27.looseObject({ wrappedProjectKey: z27.string(), keyVersion: z27.number().int().positive() })
18253
+ )
18254
+ });
18255
+ nexusLeaseSchema = z27.looseObject({
18256
+ streamId: z27.string(),
18257
+ role: z27.string(),
18258
+ replicaId: uuid,
18259
+ expiresAt: isoTime2,
18260
+ forkedFromReplicaId: uuid.nullable().optional()
18261
+ });
18262
+ nexusLeaseAcquireSchema = z27.looseObject({ lease: nexusLeaseSchema });
18263
+ nexusStreamHeadSchema = z27.looseObject({
18264
+ streamId: z27.string(),
18265
+ kind: z27.string().optional(),
18266
+ headSeq: z27.number().int().nonnegative(),
18267
+ headCheckpointId: z27.string().nullable(),
18268
+ /**
18269
+ * The highest segment `schemaVersion` the stream holds (the server raises it on every append).
18270
+ * Absent from an older server.
18271
+ */
18272
+ maxSchemaVersion: z27.number().int().nonnegative().optional()
18273
+ });
18274
+ nexusActivityEventSchema = z27.looseObject({
18275
+ id: z27.union([z27.string(), z27.number()]),
18276
+ at: isoTime2,
18277
+ actorUserId: z27.string().nullable().optional(),
18278
+ actorDeviceId: z27.string().nullable().optional(),
18279
+ requestId: z27.string().nullable().optional(),
18280
+ action: z27.string(),
18281
+ target: z27.string().nullable().optional(),
18282
+ detail: z27.unknown().optional()
18283
+ });
18284
+ nexusActivityPageSchema = z27.looseObject({
18285
+ events: z27.array(nexusActivityEventSchema),
18286
+ nextBefore: z27.union([z27.string(), z27.number()]).nullable().optional()
18287
+ });
18288
+ }
18289
+ });
18290
+
18291
+ // packages/contracts/src/sync-schema.ts
18292
+ var init_sync_schema = __esm({
18293
+ "packages/contracts/src/sync-schema.ts"() {
18294
+ "use strict";
18295
+ }
18296
+ });
18297
+
17672
18298
  // packages/contracts/src/task-id.ts
17673
18299
  var init_task_id = __esm({
17674
18300
  "packages/contracts/src/task-id.ts"() {
@@ -17753,6 +18379,9 @@ var init_src = __esm({
17753
18379
  init_decide();
17754
18380
  init_decide_sites();
17755
18381
  init_nexus_account();
18382
+ init_nexus_cloud();
18383
+ init_nexus_vault();
18384
+ init_sync_schema();
17756
18385
  init_task_id();
17757
18386
  }
17758
18387
  });
@@ -19265,7 +19894,7 @@ __export(regexes_exports, {
19265
19894
  undefined: () => _undefined,
19266
19895
  unicodeEmail: () => unicodeEmail,
19267
19896
  uppercase: () => uppercase,
19268
- uuid: () => uuid,
19897
+ uuid: () => uuid2,
19269
19898
  uuid4: () => uuid4,
19270
19899
  uuid6: () => uuid6,
19271
19900
  uuid7: () => uuid7,
@@ -19298,7 +19927,7 @@ function fixedBase64(bodyLength, padding) {
19298
19927
  function fixedBase64url(length) {
19299
19928
  return new RegExp(`^[A-Za-z0-9_-]{${length}}$`);
19300
19929
  }
19301
- var cuid, cuid2, ulid, xid, ksuid, nanoid, duration, extendedDuration, guid, uuid, uuid4, uuid6, uuid7, email, html5Email, rfc5322Email, unicodeEmail, idnEmail, browserEmail, _emoji, ipv4, ipv6, mac, cidrv4, cidrv6, base64, base64url, hostname, domain, e164, dateSource, date, string, bigint, integer, number, boolean, _null, _undefined, lowercase, uppercase, hex, md5_hex, md5_base64, md5_base64url, sha1_hex, sha1_base64, sha1_base64url, sha256_hex, sha256_base64, sha256_base64url, sha384_hex, sha384_base64, sha384_base64url, sha512_hex, sha512_base64, sha512_base64url;
19930
+ var cuid, cuid2, ulid, xid, ksuid, nanoid, duration, extendedDuration, guid, uuid2, uuid4, uuid6, uuid7, email, html5Email, rfc5322Email, unicodeEmail, idnEmail, browserEmail, _emoji, ipv4, ipv6, mac, cidrv4, cidrv6, base64, base64url, hostname, domain, e164, dateSource, date, string, bigint, integer, number, boolean, _null, _undefined, lowercase, uppercase, hex, md5_hex, md5_base64, md5_base64url, sha1_hex, sha1_base64, sha1_base64url, sha256_hex, sha256_base64, sha256_base64url, sha384_hex, sha384_base64, sha384_base64url, sha512_hex, sha512_base64, sha512_base64url;
19302
19931
  var init_regexes = __esm({
19303
19932
  "node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/regexes.js"() {
19304
19933
  init_util();
@@ -19311,14 +19940,14 @@ var init_regexes = __esm({
19311
19940
  duration = /^P(?:(\d+W)|(?!.*W)(?=\d|T\d)(\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+([.,]\d+)?S)?)?)$/;
19312
19941
  extendedDuration = /^[-+]?P(?!$)(?:(?:[-+]?\d+Y)|(?:[-+]?\d+[.,]\d+Y$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:(?:[-+]?\d+W)|(?:[-+]?\d+[.,]\d+W$))?(?:(?:[-+]?\d+D)|(?:[-+]?\d+[.,]\d+D$))?(?:T(?=[\d+-])(?:(?:[-+]?\d+H)|(?:[-+]?\d+[.,]\d+H$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:[-+]?\d+(?:[.,]\d+)?S)?)??$/;
19313
19942
  guid = /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/;
19314
- uuid = (version2) => {
19943
+ uuid2 = (version2) => {
19315
19944
  if (!version2)
19316
19945
  return /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/;
19317
19946
  return new RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${version2}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`);
19318
19947
  };
19319
- uuid4 = /* @__PURE__ */ uuid(4);
19320
- uuid6 = /* @__PURE__ */ uuid(6);
19321
- uuid7 = /* @__PURE__ */ uuid(7);
19948
+ uuid4 = /* @__PURE__ */ uuid2(4);
19949
+ uuid6 = /* @__PURE__ */ uuid2(6);
19950
+ uuid7 = /* @__PURE__ */ uuid2(7);
19322
19951
  email = /^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$/;
19323
19952
  html5Email = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
19324
19953
  rfc5322Email = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
@@ -20502,9 +21131,9 @@ var init_schemas = __esm({
20502
21131
  const v = versionMap[def.version];
20503
21132
  if (v === void 0)
20504
21133
  throw new Error(`Invalid UUID version: "${def.version}"`);
20505
- def.pattern ?? (def.pattern = uuid(v));
21134
+ def.pattern ?? (def.pattern = uuid2(v));
20506
21135
  } else
20507
- def.pattern ?? (def.pattern = uuid());
21136
+ def.pattern ?? (def.pattern = uuid2());
20508
21137
  $ZodStringFormat.init(inst, def);
20509
21138
  });
20510
21139
  $ZodEmail = /* @__PURE__ */ $constructor("$ZodEmail", (inst, def) => {
@@ -30608,7 +31237,7 @@ __export(schemas_exports2, {
30608
31237
  union: () => union,
30609
31238
  unknown: () => unknown,
30610
31239
  url: () => url,
30611
- uuid: () => uuid2,
31240
+ uuid: () => uuid3,
30612
31241
  uuidv4: () => uuidv4,
30613
31242
  uuidv6: () => uuidv6,
30614
31243
  uuidv7: () => uuidv7,
@@ -30625,7 +31254,7 @@ function email2(params) {
30625
31254
  function guid2(params) {
30626
31255
  return _guid(ZodGUID, params);
30627
31256
  }
30628
- function uuid2(params) {
31257
+ function uuid3(params) {
30629
31258
  return _uuid(ZodUUID, params);
30630
31259
  }
30631
31260
  function uuidv4(params) {
@@ -31773,7 +32402,7 @@ function resolveRef(ref, ctx) {
31773
32402
  function convertBaseSchema(schema, ctx) {
31774
32403
  if (schema.not !== void 0) {
31775
32404
  if (typeof schema.not === "object" && Object.keys(schema.not).length === 0) {
31776
- return z26.never();
32405
+ return z28.never();
31777
32406
  }
31778
32407
  throw new Error("not is not supported in Zod (except { not: {} } for never)");
31779
32408
  }
@@ -31795,7 +32424,7 @@ function convertBaseSchema(schema, ctx) {
31795
32424
  return ctx.refs.get(refPath);
31796
32425
  }
31797
32426
  if (ctx.processing.has(refPath)) {
31798
- return z26.lazy(() => {
32427
+ return z28.lazy(() => {
31799
32428
  if (!ctx.refs.has(refPath)) {
31800
32429
  throw new Error(`Circular reference not resolved: ${refPath}`);
31801
32430
  }
@@ -31812,25 +32441,25 @@ function convertBaseSchema(schema, ctx) {
31812
32441
  if (schema.enum !== void 0) {
31813
32442
  const enumValues = schema.enum;
31814
32443
  if (ctx.version === "openapi-3.0" && schema.nullable === true && enumValues.length === 1 && enumValues[0] === null) {
31815
- return z26.null();
32444
+ return z28.null();
31816
32445
  }
31817
32446
  if (enumValues.length === 0) {
31818
- return z26.never();
32447
+ return z28.never();
31819
32448
  }
31820
32449
  if (enumValues.length === 1) {
31821
- return z26.literal(enumValues[0]);
32450
+ return z28.literal(enumValues[0]);
31822
32451
  }
31823
32452
  if (enumValues.every((v) => typeof v === "string")) {
31824
- return z26.enum(enumValues);
32453
+ return z28.enum(enumValues);
31825
32454
  }
31826
- const literalSchemas = enumValues.map((v) => z26.literal(v));
32455
+ const literalSchemas = enumValues.map((v) => z28.literal(v));
31827
32456
  if (literalSchemas.length < 2) {
31828
32457
  return literalSchemas[0];
31829
32458
  }
31830
- return z26.union([literalSchemas[0], literalSchemas[1], ...literalSchemas.slice(2)]);
32459
+ return z28.union([literalSchemas[0], literalSchemas[1], ...literalSchemas.slice(2)]);
31831
32460
  }
31832
32461
  if (schema.const !== void 0) {
31833
- return z26.literal(schema.const);
32462
+ return z28.literal(schema.const);
31834
32463
  }
31835
32464
  const type = schema.type;
31836
32465
  if (Array.isArray(type)) {
@@ -31839,68 +32468,68 @@ function convertBaseSchema(schema, ctx) {
31839
32468
  return convertBaseSchema(typeSchema, ctx);
31840
32469
  });
31841
32470
  if (typeSchemas.length === 0) {
31842
- return z26.never();
32471
+ return z28.never();
31843
32472
  }
31844
32473
  if (typeSchemas.length === 1) {
31845
32474
  return typeSchemas[0];
31846
32475
  }
31847
- return z26.union(typeSchemas);
32476
+ return z28.union(typeSchemas);
31848
32477
  }
31849
32478
  if (!type) {
31850
- return z26.any();
32479
+ return z28.any();
31851
32480
  }
31852
32481
  let zodSchema2;
31853
32482
  switch (type) {
31854
32483
  case "string": {
31855
- let stringSchema = z26.string();
32484
+ let stringSchema = z28.string();
31856
32485
  if (schema.format) {
31857
32486
  const format = schema.format;
31858
32487
  if (format === "email") {
31859
- stringSchema = stringSchema.check(z26.email());
32488
+ stringSchema = stringSchema.check(z28.email());
31860
32489
  } else if (format === "uri" || format === "uri-reference") {
31861
- stringSchema = stringSchema.check(z26.url());
32490
+ stringSchema = stringSchema.check(z28.url());
31862
32491
  } else if (format === "uuid" || format === "guid") {
31863
- stringSchema = stringSchema.check(z26.uuid());
32492
+ stringSchema = stringSchema.check(z28.uuid());
31864
32493
  } else if (format === "date-time") {
31865
- stringSchema = stringSchema.check(z26.iso.datetime());
32494
+ stringSchema = stringSchema.check(z28.iso.datetime());
31866
32495
  } else if (format === "date") {
31867
- stringSchema = stringSchema.check(z26.iso.date());
32496
+ stringSchema = stringSchema.check(z28.iso.date());
31868
32497
  } else if (format === "time") {
31869
- stringSchema = stringSchema.check(z26.iso.time());
32498
+ stringSchema = stringSchema.check(z28.iso.time());
31870
32499
  } else if (format === "duration") {
31871
- stringSchema = stringSchema.check(z26.iso.duration());
32500
+ stringSchema = stringSchema.check(z28.iso.duration());
31872
32501
  } else if (format === "ipv4") {
31873
- stringSchema = stringSchema.check(z26.ipv4());
32502
+ stringSchema = stringSchema.check(z28.ipv4());
31874
32503
  } else if (format === "ipv6") {
31875
- stringSchema = stringSchema.check(z26.ipv6());
32504
+ stringSchema = stringSchema.check(z28.ipv6());
31876
32505
  } else if (format === "mac") {
31877
- stringSchema = stringSchema.check(z26.mac());
32506
+ stringSchema = stringSchema.check(z28.mac());
31878
32507
  } else if (format === "cidr") {
31879
- stringSchema = stringSchema.check(z26.cidrv4());
32508
+ stringSchema = stringSchema.check(z28.cidrv4());
31880
32509
  } else if (format === "cidr-v6") {
31881
- stringSchema = stringSchema.check(z26.cidrv6());
32510
+ stringSchema = stringSchema.check(z28.cidrv6());
31882
32511
  } else if (format === "base64") {
31883
- stringSchema = stringSchema.check(z26.base64());
32512
+ stringSchema = stringSchema.check(z28.base64());
31884
32513
  } else if (format === "base64url") {
31885
- stringSchema = stringSchema.check(z26.base64url());
32514
+ stringSchema = stringSchema.check(z28.base64url());
31886
32515
  } else if (format === "e164") {
31887
- stringSchema = stringSchema.check(z26.e164());
32516
+ stringSchema = stringSchema.check(z28.e164());
31888
32517
  } else if (format === "jwt") {
31889
- stringSchema = stringSchema.check(z26.jwt());
32518
+ stringSchema = stringSchema.check(z28.jwt());
31890
32519
  } else if (format === "emoji") {
31891
- stringSchema = stringSchema.check(z26.emoji());
32520
+ stringSchema = stringSchema.check(z28.emoji());
31892
32521
  } else if (format === "nanoid") {
31893
- stringSchema = stringSchema.check(z26.nanoid());
32522
+ stringSchema = stringSchema.check(z28.nanoid());
31894
32523
  } else if (format === "cuid") {
31895
- stringSchema = stringSchema.check(z26.cuid());
32524
+ stringSchema = stringSchema.check(z28.cuid());
31896
32525
  } else if (format === "cuid2") {
31897
- stringSchema = stringSchema.check(z26.cuid2());
32526
+ stringSchema = stringSchema.check(z28.cuid2());
31898
32527
  } else if (format === "ulid") {
31899
- stringSchema = stringSchema.check(z26.ulid());
32528
+ stringSchema = stringSchema.check(z28.ulid());
31900
32529
  } else if (format === "xid") {
31901
- stringSchema = stringSchema.check(z26.xid());
32530
+ stringSchema = stringSchema.check(z28.xid());
31902
32531
  } else if (format === "ksuid") {
31903
- stringSchema = stringSchema.check(z26.ksuid());
32532
+ stringSchema = stringSchema.check(z28.ksuid());
31904
32533
  }
31905
32534
  }
31906
32535
  if (typeof schema.minLength === "number") {
@@ -31917,7 +32546,7 @@ function convertBaseSchema(schema, ctx) {
31917
32546
  }
31918
32547
  case "number":
31919
32548
  case "integer": {
31920
- let numberSchema = type === "integer" ? z26.number().int() : z26.number();
32549
+ let numberSchema = type === "integer" ? z28.number().int() : z28.number();
31921
32550
  if (typeof schema.minimum === "number") {
31922
32551
  numberSchema = numberSchema.min(schema.minimum);
31923
32552
  }
@@ -31941,11 +32570,11 @@ function convertBaseSchema(schema, ctx) {
31941
32570
  break;
31942
32571
  }
31943
32572
  case "boolean": {
31944
- zodSchema2 = z26.boolean();
32573
+ zodSchema2 = z28.boolean();
31945
32574
  break;
31946
32575
  }
31947
32576
  case "null": {
31948
- zodSchema2 = z26.null();
32577
+ zodSchema2 = z28.null();
31949
32578
  break;
31950
32579
  }
31951
32580
  case "object": {
@@ -31958,14 +32587,14 @@ function convertBaseSchema(schema, ctx) {
31958
32587
  }
31959
32588
  if (schema.propertyNames) {
31960
32589
  const keySchema = convertSchema(schema.propertyNames, ctx);
31961
- const valueSchema = schema.additionalProperties && typeof schema.additionalProperties === "object" ? convertSchema(schema.additionalProperties, ctx) : z26.any();
32590
+ const valueSchema = schema.additionalProperties && typeof schema.additionalProperties === "object" ? convertSchema(schema.additionalProperties, ctx) : z28.any();
31962
32591
  if (Object.keys(shape).length === 0) {
31963
- zodSchema2 = z26.record(keySchema, valueSchema);
32592
+ zodSchema2 = z28.record(keySchema, valueSchema);
31964
32593
  break;
31965
32594
  }
31966
- const objectSchema2 = z26.object(shape).passthrough();
31967
- const recordSchema = z26.looseRecord(keySchema, valueSchema);
31968
- zodSchema2 = z26.intersection(objectSchema2, recordSchema);
32595
+ const objectSchema2 = z28.object(shape).passthrough();
32596
+ const recordSchema = z28.looseRecord(keySchema, valueSchema);
32597
+ zodSchema2 = z28.intersection(objectSchema2, recordSchema);
31969
32598
  break;
31970
32599
  }
31971
32600
  if (schema.patternProperties) {
@@ -31974,28 +32603,28 @@ function convertBaseSchema(schema, ctx) {
31974
32603
  const looseRecords = [];
31975
32604
  for (const pattern of patternKeys) {
31976
32605
  const patternValue = convertSchema(patternProps[pattern], ctx);
31977
- const keySchema = z26.string().regex(new RegExp(pattern));
31978
- looseRecords.push(z26.looseRecord(keySchema, patternValue));
32606
+ const keySchema = z28.string().regex(new RegExp(pattern));
32607
+ looseRecords.push(z28.looseRecord(keySchema, patternValue));
31979
32608
  }
31980
32609
  const schemasToIntersect = [];
31981
32610
  if (Object.keys(shape).length > 0) {
31982
- schemasToIntersect.push(z26.object(shape).passthrough());
32611
+ schemasToIntersect.push(z28.object(shape).passthrough());
31983
32612
  }
31984
32613
  schemasToIntersect.push(...looseRecords);
31985
32614
  if (schemasToIntersect.length === 0) {
31986
- zodSchema2 = z26.object({}).passthrough();
32615
+ zodSchema2 = z28.object({}).passthrough();
31987
32616
  } else if (schemasToIntersect.length === 1) {
31988
32617
  zodSchema2 = schemasToIntersect[0];
31989
32618
  } else {
31990
- let result = z26.intersection(schemasToIntersect[0], schemasToIntersect[1]);
32619
+ let result = z28.intersection(schemasToIntersect[0], schemasToIntersect[1]);
31991
32620
  for (let i = 2; i < schemasToIntersect.length; i++) {
31992
- result = z26.intersection(result, schemasToIntersect[i]);
32621
+ result = z28.intersection(result, schemasToIntersect[i]);
31993
32622
  }
31994
32623
  zodSchema2 = result;
31995
32624
  }
31996
32625
  break;
31997
32626
  }
31998
- const objectSchema = z26.object(shape);
32627
+ const objectSchema = z28.object(shape);
31999
32628
  if (schema.additionalProperties === false) {
32000
32629
  zodSchema2 = objectSchema.strict();
32001
32630
  } else if (typeof schema.additionalProperties === "object") {
@@ -32012,33 +32641,33 @@ function convertBaseSchema(schema, ctx) {
32012
32641
  const tupleItems = prefixItems.map((item) => convertSchema(item, ctx));
32013
32642
  const rest = items && typeof items === "object" && !Array.isArray(items) ? convertSchema(items, ctx) : void 0;
32014
32643
  if (rest) {
32015
- zodSchema2 = z26.tuple(tupleItems).rest(rest);
32644
+ zodSchema2 = z28.tuple(tupleItems).rest(rest);
32016
32645
  } else {
32017
- zodSchema2 = z26.tuple(tupleItems);
32646
+ zodSchema2 = z28.tuple(tupleItems);
32018
32647
  }
32019
32648
  if (typeof schema.minItems === "number") {
32020
- zodSchema2 = zodSchema2.check(z26.minLength(schema.minItems));
32649
+ zodSchema2 = zodSchema2.check(z28.minLength(schema.minItems));
32021
32650
  }
32022
32651
  if (typeof schema.maxItems === "number") {
32023
- zodSchema2 = zodSchema2.check(z26.maxLength(schema.maxItems));
32652
+ zodSchema2 = zodSchema2.check(z28.maxLength(schema.maxItems));
32024
32653
  }
32025
32654
  } else if (Array.isArray(items)) {
32026
32655
  const tupleItems = items.map((item) => convertSchema(item, ctx));
32027
32656
  const rest = schema.additionalItems && typeof schema.additionalItems === "object" ? convertSchema(schema.additionalItems, ctx) : void 0;
32028
32657
  if (rest) {
32029
- zodSchema2 = z26.tuple(tupleItems).rest(rest);
32658
+ zodSchema2 = z28.tuple(tupleItems).rest(rest);
32030
32659
  } else {
32031
- zodSchema2 = z26.tuple(tupleItems);
32660
+ zodSchema2 = z28.tuple(tupleItems);
32032
32661
  }
32033
32662
  if (typeof schema.minItems === "number") {
32034
- zodSchema2 = zodSchema2.check(z26.minLength(schema.minItems));
32663
+ zodSchema2 = zodSchema2.check(z28.minLength(schema.minItems));
32035
32664
  }
32036
32665
  if (typeof schema.maxItems === "number") {
32037
- zodSchema2 = zodSchema2.check(z26.maxLength(schema.maxItems));
32666
+ zodSchema2 = zodSchema2.check(z28.maxLength(schema.maxItems));
32038
32667
  }
32039
32668
  } else if (items !== void 0) {
32040
32669
  const element = convertSchema(items, ctx);
32041
- let arraySchema = z26.array(element);
32670
+ let arraySchema = z28.array(element);
32042
32671
  if (typeof schema.minItems === "number") {
32043
32672
  arraySchema = arraySchema.min(schema.minItems);
32044
32673
  }
@@ -32047,7 +32676,7 @@ function convertBaseSchema(schema, ctx) {
32047
32676
  }
32048
32677
  zodSchema2 = arraySchema;
32049
32678
  } else {
32050
- zodSchema2 = z26.array(z26.any());
32679
+ zodSchema2 = z28.array(z28.any());
32051
32680
  }
32052
32681
  break;
32053
32682
  }
@@ -32064,37 +32693,37 @@ function convertBaseSchema(schema, ctx) {
32064
32693
  }
32065
32694
  function convertSchema(schema, ctx) {
32066
32695
  if (typeof schema === "boolean") {
32067
- return schema ? z26.any() : z26.never();
32696
+ return schema ? z28.any() : z28.never();
32068
32697
  }
32069
32698
  let baseSchema = convertBaseSchema(schema, ctx);
32070
32699
  const hasExplicitType = schema.type || schema.enum !== void 0 || schema.const !== void 0;
32071
32700
  if (schema.anyOf && Array.isArray(schema.anyOf)) {
32072
32701
  const options = schema.anyOf.map((s) => convertSchema(s, ctx));
32073
- const anyOfUnion = z26.union(options);
32074
- baseSchema = hasExplicitType ? z26.intersection(baseSchema, anyOfUnion) : anyOfUnion;
32702
+ const anyOfUnion = z28.union(options);
32703
+ baseSchema = hasExplicitType ? z28.intersection(baseSchema, anyOfUnion) : anyOfUnion;
32075
32704
  }
32076
32705
  if (schema.oneOf && Array.isArray(schema.oneOf)) {
32077
32706
  const options = schema.oneOf.map((s) => convertSchema(s, ctx));
32078
- const oneOfUnion = z26.xor(options);
32079
- baseSchema = hasExplicitType ? z26.intersection(baseSchema, oneOfUnion) : oneOfUnion;
32707
+ const oneOfUnion = z28.xor(options);
32708
+ baseSchema = hasExplicitType ? z28.intersection(baseSchema, oneOfUnion) : oneOfUnion;
32080
32709
  }
32081
32710
  if (schema.allOf && Array.isArray(schema.allOf)) {
32082
32711
  if (schema.allOf.length === 0) {
32083
- baseSchema = hasExplicitType ? baseSchema : z26.any();
32712
+ baseSchema = hasExplicitType ? baseSchema : z28.any();
32084
32713
  } else {
32085
32714
  let result = hasExplicitType ? baseSchema : convertSchema(schema.allOf[0], ctx);
32086
32715
  const startIdx = hasExplicitType ? 0 : 1;
32087
32716
  for (let i = startIdx; i < schema.allOf.length; i++) {
32088
- result = z26.intersection(result, convertSchema(schema.allOf[i], ctx));
32717
+ result = z28.intersection(result, convertSchema(schema.allOf[i], ctx));
32089
32718
  }
32090
32719
  baseSchema = result;
32091
32720
  }
32092
32721
  }
32093
32722
  if (schema.nullable === true && ctx.version === "openapi-3.0") {
32094
- baseSchema = z26.nullable(baseSchema);
32723
+ baseSchema = z28.nullable(baseSchema);
32095
32724
  }
32096
32725
  if (schema.readOnly === true) {
32097
- baseSchema = z26.readonly(baseSchema);
32726
+ baseSchema = z28.readonly(baseSchema);
32098
32727
  }
32099
32728
  const extraMeta = {};
32100
32729
  const coreMetadataKeys = ["$id", "id", "$comment", "$anchor", "$vocabulary", "$dynamicRef", "$dynamicAnchor"];
@@ -32121,7 +32750,7 @@ function convertSchema(schema, ctx) {
32121
32750
  }
32122
32751
  function fromJSONSchema(schema, params) {
32123
32752
  if (typeof schema === "boolean") {
32124
- return schema ? z26.any() : z26.never();
32753
+ return schema ? z28.any() : z28.never();
32125
32754
  }
32126
32755
  const version2 = detectVersion(schema, params?.defaultTarget);
32127
32756
  const defs = schema.$defs || schema.definitions || {};
@@ -32135,14 +32764,14 @@ function fromJSONSchema(schema, params) {
32135
32764
  };
32136
32765
  return convertSchema(schema, ctx);
32137
32766
  }
32138
- var z26, RECOGNIZED_KEYS;
32767
+ var z28, RECOGNIZED_KEYS;
32139
32768
  var init_from_json_schema = __esm({
32140
32769
  "node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/classic/from-json-schema.js"() {
32141
32770
  init_registries();
32142
32771
  init_checks2();
32143
32772
  init_iso();
32144
32773
  init_schemas2();
32145
- z26 = {
32774
+ z28 = {
32146
32775
  ...schemas_exports2,
32147
32776
  ...checks_exports2,
32148
32777
  iso: iso_exports
@@ -32484,7 +33113,7 @@ __export(external_exports, {
32484
33113
  uppercase: () => _uppercase,
32485
33114
  url: () => url,
32486
33115
  util: () => util_exports,
32487
- uuid: () => uuid2,
33116
+ uuid: () => uuid3,
32488
33117
  uuidv4: () => uuidv4,
32489
33118
  uuidv6: () => uuidv6,
32490
33119
  uuidv7: () => uuidv7,
@@ -43781,12 +44410,7 @@ var init_spawn = __esm({
43781
44410
  }
43782
44411
  });
43783
44412
 
43784
- // packages/adapters/src/providers/claude-code/paths.ts
43785
- import { homedir as homedir2 } from "node:os";
43786
- import { join as join3 } from "node:path";
43787
- function claudeSettingsPath() {
43788
- return new ClaudeCodePathProvider().getSettingsPath() ?? join3(homedir2(), ".claude", "settings.json");
43789
- }
44413
+ // packages/adapters/src/providers/shared/hook-config.ts
43790
44414
  function isPlainObject2(value) {
43791
44415
  return typeof value === "object" && value !== null && !Array.isArray(value);
43792
44416
  }
@@ -43830,10 +44454,25 @@ function removeCleoHookEntries(hooks) {
43830
44454
  }
43831
44455
  return changed;
43832
44456
  }
43833
- var ClaudeCodePathProvider, CLEO_HOOK_MARKER;
44457
+ var CLEO_HOOK_MARKER;
44458
+ var init_hook_config = __esm({
44459
+ "packages/adapters/src/providers/shared/hook-config.ts"() {
44460
+ "use strict";
44461
+ CLEO_HOOK_MARKER = "# cleo-hook";
44462
+ }
44463
+ });
44464
+
44465
+ // packages/adapters/src/providers/claude-code/paths.ts
44466
+ import { homedir as homedir2 } from "node:os";
44467
+ import { join as join3 } from "node:path";
44468
+ function claudeSettingsPath() {
44469
+ return new ClaudeCodePathProvider().getSettingsPath() ?? join3(homedir2(), ".claude", "settings.json");
44470
+ }
44471
+ var ClaudeCodePathProvider;
43834
44472
  var init_paths = __esm({
43835
44473
  "packages/adapters/src/providers/claude-code/paths.ts"() {
43836
44474
  "use strict";
44475
+ init_hook_config();
43837
44476
  ClaudeCodePathProvider = class {
43838
44477
  /** Get the provider's root configuration directory. */
43839
44478
  getProviderDir() {
@@ -43852,7 +44491,6 @@ var init_paths = __esm({
43852
44491
  return process.env["CLAUDE_MEM_DB"] ?? join3(homedir2(), ".claude-mem", "claude-mem.db");
43853
44492
  }
43854
44493
  };
43855
- CLEO_HOOK_MARKER = "# cleo-hook";
43856
44494
  }
43857
44495
  });
43858
44496
 
@@ -44213,12 +44851,12 @@ var init_hooks = __esm({
44213
44851
  * @returns Claude Code native event name or null
44214
44852
  * @task T164
44215
44853
  */
44216
- async toNativeEvent(canonical) {
44854
+ async toNativeEvent(canonical2) {
44217
44855
  try {
44218
44856
  const { toNative } = await import("@cleocode/caamp");
44219
- return toNative(canonical, PROVIDER_ID);
44857
+ return toNative(canonical2, PROVIDER_ID);
44220
44858
  } catch {
44221
- const entry = Object.entries(CLAUDE_CODE_EVENT_MAP).find(([, v]) => v === canonical);
44859
+ const entry = Object.entries(CLAUDE_CODE_EVENT_MAP).find(([, v]) => v === canonical2);
44222
44860
  return entry?.[0] ?? null;
44223
44861
  }
44224
44862
  }
@@ -44313,23 +44951,354 @@ var init_hooks = __esm({
44313
44951
  }
44314
44952
  });
44315
44953
 
44954
+ // packages/adapters/src/providers/shared/heavy-command-hook-install.ts
44955
+ import { execFileSync } from "node:child_process";
44956
+ import {
44957
+ existsSync as existsSync5,
44958
+ mkdirSync,
44959
+ readdirSync as readdirSync2,
44960
+ readFileSync as readFileSync4,
44961
+ realpathSync,
44962
+ rmSync,
44963
+ writeFileSync as writeFileSync2
44964
+ } from "node:fs";
44965
+ import { homedir as homedir4, tmpdir } from "node:os";
44966
+ import { dirname as dirname2, isAbsolute, join as join6, resolve as resolve2 } from "node:path";
44967
+ import { updateJsonConfigFile as updateJsonConfigFile2 } from "@cleocode/caamp";
44968
+ function canonical(path) {
44969
+ try {
44970
+ return realpathSync(path);
44971
+ } catch {
44972
+ return resolve2(path);
44973
+ }
44974
+ }
44975
+ function isUserHomeDir(projectDir, home = homedir4()) {
44976
+ return canonical(projectDir) === canonical(home);
44977
+ }
44978
+ function clearOlderCleoMarkers(dir = process.env.XDG_RUNTIME_DIR || tmpdir()) {
44979
+ let removed = 0;
44980
+ let names;
44981
+ try {
44982
+ names = readdirSync2(dir);
44983
+ } catch {
44984
+ return 0;
44985
+ }
44986
+ for (const name15 of names) {
44987
+ if (!name15.startsWith(OLDER_CLEO_MARKER_PREFIX)) continue;
44988
+ try {
44989
+ rmSync(join6(dir, name15), { force: true });
44990
+ removed++;
44991
+ } catch {
44992
+ }
44993
+ }
44994
+ return removed;
44995
+ }
44996
+ function shellWord(text) {
44997
+ return `'${text.replace(/'/g, `'\\''`)}'`;
44998
+ }
44999
+ function heavyCommandGuardScript(provider) {
45000
+ const words = HEAVY_TOOL_WORDS.join("|");
45001
+ const old = `printf '%s\\n' '${OLDER_CLEO_HOOK_ANSWER}'`;
45002
+ return [
45003
+ "command -v cleo >/dev/null 2>&1 || exit 0",
45004
+ 'in="$(cat)"',
45005
+ "set -f",
45006
+ "hit=",
45007
+ // `[\]` (not `\\`) matches a backslash: it survives fish's quoting under Codex.
45008
+ `for w in $(printf '%s' "$in" | sed 's/[\\][nrt]/ /g; s/[^A-Za-z0-9_./@+-]/ /g'); do case "\${w##*/}" in ${words}) hit=1; break;; esac; done`,
45009
+ '[ -n "$hit" ] || exit 0',
45010
+ 'p="$(command -v cleo)"',
45011
+ `d="\${XDG_RUNTIME_DIR:-\${TMPDIR:-/tmp}}"`,
45012
+ `k="$d/${OLDER_CLEO_MARKER_PREFIX}$(printf '%s|%s' "$p" "$PWD" | cksum | tr -c '0-9' '-')"`,
45013
+ `if [ -f "$k" ] && [ ! -L "$k" ] && [ -O "$k" ] && ! [ "$p" -nt "$k" ] && [ -n "$(find "$k" -mmin -60 2>/dev/null)" ]; then ${old}; exit 0; fi`,
45014
+ 'e="$(mktemp 2>/dev/null)" || e=',
45015
+ // Only the older-CLEO signature (exit 127, "Unknown command hook") writes the
45016
+ // marker; a crash or kill of a current CLEO fails open and asks again next time.
45017
+ `if out="$(printf '%s' "$in" | ${HEAVY_COMMAND_HOOK_ID} --provider ${provider} 2>"\${e:-/dev/null}")"; then case "$out" in "{"*) printf '%s\\n' "$out";; esac; else rc=$?; if [ "$rc" = 127 ] && [ -n "$e" ] && grep -q 'Unknown command' "$e" 2>/dev/null; then t="$(mktemp "$k.XXXXXX" 2>/dev/null)" && mv -f "$t" "$k"; ${old}; fi; fi`,
45018
+ '[ -z "$e" ] || rm -f "$e"',
45019
+ "exit 0"
45020
+ ].join("; ");
45021
+ }
45022
+ function heavyCommandHookCommand(provider) {
45023
+ const script = heavyCommandGuardScript(provider);
45024
+ const line = provider === "codex" ? `/bin/sh -c ${shellWord(script)}` : script;
45025
+ return `${line} ${CLEO_HOOK_MARKER}`;
45026
+ }
45027
+ function heavyCommandHookObject(provider) {
45028
+ return {
45029
+ type: "command",
45030
+ command: heavyCommandHookCommand(provider),
45031
+ timeout: HEAVY_COMMAND_HOOK_TIMEOUT_SEC
45032
+ };
45033
+ }
45034
+ function heavyCommandHookEntry(provider) {
45035
+ return { matcher: "Bash", hooks: [heavyCommandHookObject(provider)] };
45036
+ }
45037
+ function isHeavyHookObject(hook) {
45038
+ return isPlainObject2(hook) && typeof hook.command === "string" && hook.command.includes(CLEO_HOOK_MARKER) && hook.command.includes(HEAVY_COMMAND_HOOK_ID);
45039
+ }
45040
+ function placeHeavyHook(hooks, desired) {
45041
+ const groups = hooks.PreToolUse;
45042
+ if (groups === void 0) return { changed: false, found: false };
45043
+ if (!Array.isArray(groups)) {
45044
+ throw new Error('hooks "PreToolUse" is not an array; not modifying it');
45045
+ }
45046
+ let changed = false;
45047
+ let found = false;
45048
+ const next = [];
45049
+ for (const group of groups) {
45050
+ if (!isPlainObject2(group) || !Array.isArray(group.hooks)) {
45051
+ next.push(group);
45052
+ continue;
45053
+ }
45054
+ const kept = [];
45055
+ let groupChanged = false;
45056
+ for (const hook of group.hooks) {
45057
+ if (!isHeavyHookObject(hook)) {
45058
+ kept.push(hook);
45059
+ } else if (desired !== null && !found) {
45060
+ found = true;
45061
+ if (JSON.stringify(hook) !== JSON.stringify(desired)) groupChanged = true;
45062
+ kept.push(desired);
45063
+ } else {
45064
+ groupChanged = true;
45065
+ }
45066
+ }
45067
+ if (!groupChanged) {
45068
+ next.push(group);
45069
+ continue;
45070
+ }
45071
+ changed = true;
45072
+ if (kept.length > 0) next.push({ ...group, hooks: kept });
45073
+ }
45074
+ if (changed) hooks.PreToolUse = next;
45075
+ return { changed, found };
45076
+ }
45077
+ async function syncJsonHeavyCommandHook(configPath, provider, mode) {
45078
+ if (mode === "off") {
45079
+ if (!existsSync5(configPath)) return "unchanged";
45080
+ const removed = await updateJsonConfigFile2(configPath, (config2) => {
45081
+ if (config2.hooks === void 0) return false;
45082
+ return placeHeavyHook(hookMap(config2), null).changed;
45083
+ });
45084
+ return removed ? "removed" : "unchanged";
45085
+ }
45086
+ mkdirSync(dirname2(configPath), { recursive: true });
45087
+ clearOlderCleoMarkers();
45088
+ let result = "unchanged";
45089
+ await updateJsonConfigFile2(configPath, (config2) => {
45090
+ const hooks = hookMap(config2);
45091
+ const placed = placeHeavyHook(hooks, heavyCommandHookObject(provider));
45092
+ if (placed.found) {
45093
+ if (placed.changed) result = "updated";
45094
+ return placed.changed;
45095
+ }
45096
+ const existing = hooks.PreToolUse;
45097
+ hooks.PreToolUse = [
45098
+ ...Array.isArray(existing) ? existing : [],
45099
+ heavyCommandHookEntry(provider)
45100
+ ];
45101
+ result = "installed";
45102
+ return true;
45103
+ });
45104
+ return result;
45105
+ }
45106
+ function gitOutput(projectDir, args) {
45107
+ try {
45108
+ return execFileSync("git", ["-C", projectDir, ...args], {
45109
+ encoding: "utf-8",
45110
+ stdio: ["ignore", "pipe", "ignore"],
45111
+ timeout: 5e3
45112
+ }).trim();
45113
+ } catch {
45114
+ return null;
45115
+ }
45116
+ }
45117
+ function excludeFile(projectDir) {
45118
+ if (gitOutput(projectDir, ["rev-parse", "--is-inside-work-tree"]) !== "true") return null;
45119
+ const path = gitOutput(projectDir, ["rev-parse", "--git-path", "info/exclude"]);
45120
+ if (path === null || path === "") return null;
45121
+ return isAbsolute(path) ? path : join6(projectDir, path);
45122
+ }
45123
+ function excludeLine(projectDir) {
45124
+ const prefix = gitOutput(projectDir, ["rev-parse", "--show-prefix"]) ?? "";
45125
+ return `/${prefix}${CLAUDE_LOCAL_SETTINGS}`;
45126
+ }
45127
+ function excludeLocalSettingsFromGit(projectDir) {
45128
+ const exclude = excludeFile(projectDir);
45129
+ if (exclude === null) return false;
45130
+ if (gitOutput(projectDir, ["check-ignore", CLAUDE_LOCAL_SETTINGS]) !== null) return false;
45131
+ const line = excludeLine(projectDir);
45132
+ const text = existsSync5(exclude) ? readFileSync4(exclude, "utf-8") : "";
45133
+ if (text.split("\n").includes(line)) return false;
45134
+ const block = `${LOCAL_SETTINGS_EXCLUDE_MARKER}
45135
+ ${line}
45136
+ `;
45137
+ mkdirSync(dirname2(exclude), { recursive: true });
45138
+ writeFileSync2(exclude, text === "" || text.endsWith("\n") ? text + block : `${text}
45139
+ ${block}`);
45140
+ return true;
45141
+ }
45142
+ function unexcludeLocalSettingsFromGit(projectDir) {
45143
+ const exclude = excludeFile(projectDir);
45144
+ if (exclude === null || !existsSync5(exclude)) return false;
45145
+ const lines = readFileSync4(exclude, "utf-8").split("\n");
45146
+ const at = lines.indexOf(excludeLine(projectDir));
45147
+ if (at < 1 || lines[at - 1] !== LOCAL_SETTINGS_EXCLUDE_MARKER) return false;
45148
+ lines.splice(at - 1, 2);
45149
+ writeFileSync2(exclude, lines.join("\n"));
45150
+ return true;
45151
+ }
45152
+ async function syncClaudeCodeHeavyCommandHook(projectDir, mode) {
45153
+ const result = await syncJsonHeavyCommandHook(
45154
+ join6(projectDir, CLAUDE_LOCAL_SETTINGS),
45155
+ "claude-code",
45156
+ mode
45157
+ );
45158
+ if (mode === "off") unexcludeLocalSettingsFromGit(projectDir);
45159
+ else excludeLocalSettingsFromGit(projectDir);
45160
+ await syncJsonHeavyCommandHook(
45161
+ join6(projectDir, ".claude", "settings.json"),
45162
+ "claude-code",
45163
+ "off"
45164
+ );
45165
+ return result;
45166
+ }
45167
+ function opencodeHeavyCommandPluginSource() {
45168
+ return [
45169
+ "// CLEO heavy-command plugin for OpenCode (generated by @cleocode/adapters, T12983).",
45170
+ "// Routes heavy shell commands (tests, builds, typechecks, installs) through",
45171
+ "// `cleo run`, the machine-wide resource budget. Opt out with",
45172
+ '// CLEO_HEAVY_COMMAND_HOOK=off, or set resources.heavyCommandHook to "off" and',
45173
+ "// run `cleo upgrade` (which deletes this file). Fails open: on any error the",
45174
+ "// command runs unchanged.",
45175
+ "",
45176
+ "import { execFile } from 'node:child_process';",
45177
+ "",
45178
+ `const HEAVY = /(?:^|[^A-Za-z0-9_.@+-])(?:${HEAVY_TOOL_WORDS.join("|")})(?=$|[^A-Za-z0-9_.@+-])/;`,
45179
+ "const contexts = new Map();",
45180
+ "",
45181
+ "function ask(payload) {",
45182
+ " return new Promise((done) => {",
45183
+ " const child = execFile(",
45184
+ " 'cleo',",
45185
+ " ['hook', 'heavy-command', '--provider', 'opencode'],",
45186
+ ` { timeout: ${HEAVY_COMMAND_HOOK_TIMEOUT_SEC * 1e3} },`,
45187
+ " (err, stdout) => done(err ? '' : stdout),",
45188
+ " );",
45189
+ " child.on('error', () => done(''));",
45190
+ " child.stdin?.end(JSON.stringify(payload));",
45191
+ " });",
45192
+ "}",
45193
+ "",
45194
+ "export const CleoHeavyCommand = async ({ directory }) => ({",
45195
+ " 'tool.execute.before': async (input, output) => {",
45196
+ " if (input?.tool !== 'bash' || typeof output?.args?.command !== 'string') return;",
45197
+ " if (process.env.CLEO_HEAVY_COMMAND_HOOK === 'off') return;",
45198
+ " if (!HEAVY.test(output.args.command)) return;",
45199
+ " try {",
45200
+ " const text = await ask({ tool_name: 'bash', tool_input: output.args, cwd: directory });",
45201
+ " const answer = JSON.parse(text || '{}');",
45202
+ " if (typeof answer.command === 'string') output.args.command = answer.command;",
45203
+ " if (typeof answer.timeout === 'number') output.args.timeout = answer.timeout;",
45204
+ " if (typeof answer.context === 'string' && input.callID) contexts.set(input.callID, answer.context);",
45205
+ " } catch {",
45206
+ " // Fail open.",
45207
+ " }",
45208
+ " },",
45209
+ " 'tool.execute.after': async (input, output) => {",
45210
+ " const context = input?.callID ? contexts.get(input.callID) : undefined;",
45211
+ " if (context === undefined) return;",
45212
+ " contexts.delete(input.callID);",
45213
+ " if (typeof output?.output === 'string') output.output += '\\n\\n' + context;",
45214
+ " },",
45215
+ "});",
45216
+ ""
45217
+ ].join("\n");
45218
+ }
45219
+ function syncOpencodeHeavyCommandPlugin(projectDir, mode) {
45220
+ const pluginPath = join6(projectDir, ".opencode", "plugins", OPENCODE_HEAVY_COMMAND_PLUGIN);
45221
+ const exists = existsSync5(pluginPath);
45222
+ if (mode === "off") {
45223
+ if (!exists) return "unchanged";
45224
+ rmSync(pluginPath, { force: true });
45225
+ return "removed";
45226
+ }
45227
+ const source = opencodeHeavyCommandPluginSource();
45228
+ if (exists && readFileSync4(pluginPath, "utf-8") === source) return "unchanged";
45229
+ mkdirSync(dirname2(pluginPath), { recursive: true });
45230
+ writeFileSync2(pluginPath, source, "utf-8");
45231
+ return exists ? "updated" : "installed";
45232
+ }
45233
+ var HEAVY_COMMAND_HOOK_ID, HEAVY_COMMAND_HOOK_TIMEOUT_SEC, OPENCODE_HEAVY_COMMAND_PLUGIN, HEAVY_TOOL_WORDS, OLDER_CLEO_HOOK_ANSWER, OLDER_CLEO_MARKER_PREFIX, CLAUDE_LOCAL_SETTINGS, LOCAL_SETTINGS_EXCLUDE_MARKER;
45234
+ var init_heavy_command_hook_install = __esm({
45235
+ "packages/adapters/src/providers/shared/heavy-command-hook-install.ts"() {
45236
+ "use strict";
45237
+ init_hook_config();
45238
+ HEAVY_COMMAND_HOOK_ID = "cleo hook heavy-command";
45239
+ HEAVY_COMMAND_HOOK_TIMEOUT_SEC = 20;
45240
+ OPENCODE_HEAVY_COMMAND_PLUGIN = "cleo-heavy-command.js";
45241
+ HEAVY_TOOL_WORDS = Object.freeze([
45242
+ "vitest",
45243
+ "jest",
45244
+ "mocha",
45245
+ "ava",
45246
+ "tap",
45247
+ "playwright",
45248
+ "pytest",
45249
+ "rspec",
45250
+ "phpunit",
45251
+ "tsc",
45252
+ "tsup",
45253
+ "turbo",
45254
+ "vite",
45255
+ "esbuild",
45256
+ "webpack",
45257
+ "rollup",
45258
+ "next",
45259
+ "nx",
45260
+ "biome",
45261
+ "eslint",
45262
+ "svelte-check",
45263
+ "npm",
45264
+ "pnpm",
45265
+ "yarn",
45266
+ "bun",
45267
+ "npx",
45268
+ "pnpx",
45269
+ "bunx",
45270
+ "cargo",
45271
+ "go"
45272
+ ]);
45273
+ OLDER_CLEO_HOOK_ANSWER = JSON.stringify({
45274
+ hookSpecificOutput: {
45275
+ hookEventName: "PreToolUse",
45276
+ additionalContext: "[cleo] This may be a heavy command, but the cleo on PATH predates cleo hook and cleo run, so it runs outside the machine-wide resource budget. Upgrade CLEO to govern it."
45277
+ }
45278
+ });
45279
+ OLDER_CLEO_MARKER_PREFIX = "cleo-hook-unsupported-";
45280
+ CLAUDE_LOCAL_SETTINGS = ".claude/settings.local.json";
45281
+ LOCAL_SETTINGS_EXCLUDE_MARKER = "# cleo-hook: keep the per-machine heavy-command hook settings out of git (T12983)";
45282
+ }
45283
+ });
45284
+
44316
45285
  // packages/adapters/src/providers/shared/hook-template-installer.ts
44317
- import { copyFileSync, existsSync as existsSync5, mkdirSync, statSync } from "node:fs";
44318
- import { dirname as dirname2, join as join6 } from "node:path";
45286
+ import { copyFileSync, existsSync as existsSync6, mkdirSync as mkdirSync2, statSync } from "node:fs";
45287
+ import { dirname as dirname3, join as join7 } from "node:path";
44319
45288
  import { fileURLToPath } from "node:url";
44320
45289
  function resolveProviderCandidates() {
44321
- const thisDir = dirname2(fileURLToPath(import.meta.url));
44322
- const here = dirname2(thisDir);
44323
- const fromDist = join6(here, "..", "..", "src", "providers");
45290
+ const thisDir = dirname3(fileURLToPath(import.meta.url));
45291
+ const here = dirname3(thisDir);
45292
+ const fromDist = join7(here, "..", "..", "src", "providers");
44324
45293
  return [here, fromDist];
44325
45294
  }
44326
45295
  function findTemplateFile(relativeSegments) {
44327
45296
  for (const base of resolveProviderCandidates()) {
44328
- const candidate = join6(base, ...relativeSegments);
44329
- if (existsSync5(candidate)) return candidate;
45297
+ const candidate = join7(base, ...relativeSegments);
45298
+ if (existsSync6(candidate)) return candidate;
44330
45299
  }
44331
45300
  const [first] = resolveProviderCandidates();
44332
- return join6(first ?? "", ...relativeSegments);
45301
+ return join7(first ?? "", ...relativeSegments);
44333
45302
  }
44334
45303
  function providerShimSource(provider) {
44335
45304
  return findTemplateFile([provider, "templates", "hooks", PROVIDER_SHIM[provider]]);
@@ -44338,17 +45307,17 @@ function sharedCoreSource() {
44338
45307
  return findTemplateFile(["shared", "templates", "hooks", SHARED_CORE_FILE]);
44339
45308
  }
44340
45309
  function copyTemplate(src, dest, force) {
44341
- if (!existsSync5(src)) {
45310
+ if (!existsSync6(src)) {
44342
45311
  throw new Error(`CLEO hook template missing at source: ${src}`);
44343
45312
  }
44344
- if (!force && existsSync5(dest)) {
45313
+ if (!force && existsSync6(dest)) {
44345
45314
  const srcStat = statSync(src);
44346
45315
  const destStat = statSync(dest);
44347
45316
  if (srcStat.size === destStat.size && srcStat.mtimeMs <= destStat.mtimeMs) {
44348
45317
  return { wrote: false };
44349
45318
  }
44350
45319
  }
44351
- mkdirSync(dirname2(dest), { recursive: true });
45320
+ mkdirSync2(dirname3(dest), { recursive: true });
44352
45321
  copyFileSync(src, dest);
44353
45322
  return { wrote: true };
44354
45323
  }
@@ -44360,13 +45329,13 @@ function installProviderHookTemplates(options) {
44360
45329
  installedFiles: [],
44361
45330
  skipped: []
44362
45331
  };
44363
- mkdirSync(targetDir, { recursive: true });
44364
- const coreDest = join6(targetDir, SHARED_CORE_FILE);
45332
+ mkdirSync2(targetDir, { recursive: true });
45333
+ const coreDest = join7(targetDir, SHARED_CORE_FILE);
44365
45334
  const coreOutcome = copyTemplate(sharedCoreSource(), coreDest, force);
44366
45335
  if (coreOutcome.wrote) result.installedFiles.push(coreDest);
44367
45336
  else result.skipped.push(coreDest);
44368
45337
  const shimName = PROVIDER_SHIM[provider];
44369
- const shimDest = join6(targetDir, shimName);
45338
+ const shimDest = join7(targetDir, shimName);
44370
45339
  const shimOutcome = copyTemplate(providerShimSource(provider), shimDest, force);
44371
45340
  if (shimOutcome.wrote) result.installedFiles.push(shimDest);
44372
45341
  else result.skipped.push(shimDest);
@@ -44393,22 +45362,23 @@ var init_hook_template_installer = __esm({
44393
45362
  });
44394
45363
 
44395
45364
  // packages/adapters/src/providers/claude-code/install.ts
44396
- import { copyFileSync as copyFileSync2, existsSync as existsSync6, mkdirSync as mkdirSync2, readdirSync as readdirSync2, readFileSync as readFileSync4 } from "node:fs";
44397
- import { homedir as homedir4 } from "node:os";
44398
- import { dirname as dirname3, join as join7 } from "node:path";
45365
+ import { copyFileSync as copyFileSync2, existsSync as existsSync7, mkdirSync as mkdirSync3, readdirSync as readdirSync3, readFileSync as readFileSync5 } from "node:fs";
45366
+ import { homedir as homedir5 } from "node:os";
45367
+ import { dirname as dirname4, join as join8, resolve as resolve3 } from "node:path";
44399
45368
  import { fileURLToPath as fileURLToPath2 } from "node:url";
44400
- import { ensureProviderInstructionFile, updateJsonConfigFile as updateJsonConfigFile2 } from "@cleocode/caamp";
45369
+ import { ensureProviderInstructionFile, updateJsonConfigFile as updateJsonConfigFile3 } from "@cleocode/caamp";
44401
45370
  function getClaudeConfigDir() {
44402
- return process.env["CLAUDE_HOME"] ?? join7(homedir4(), ".claude");
45371
+ return process.env["CLAUDE_HOME"] ?? join8(homedir5(), ".claude");
44403
45372
  }
44404
45373
  function getAdapterCommandsDir() {
44405
- const thisDir = dirname3(fileURLToPath2(import.meta.url));
44406
- return join7(thisDir, "commands");
45374
+ const thisDir = dirname4(fileURLToPath2(import.meta.url));
45375
+ return join8(thisDir, "commands");
44407
45376
  }
44408
45377
  var ClaudeCodeInstallProvider;
44409
45378
  var init_install = __esm({
44410
45379
  "packages/adapters/src/providers/claude-code/install.ts"() {
44411
45380
  "use strict";
45381
+ init_heavy_command_hook_install();
44412
45382
  init_hook_template_installer();
44413
45383
  init_paths();
44414
45384
  ClaudeCodeInstallProvider = class {
@@ -44449,6 +45419,21 @@ var init_install = __esm({
44449
45419
  } catch (err) {
44450
45420
  settingsErrors.push(err instanceof Error ? err.message : String(err));
44451
45421
  }
45422
+ if (options.heavyCommandHook !== void 0) {
45423
+ const projectSettings = join8(projectDir, ".claude", "settings.json");
45424
+ if (isUserHomeDir(projectDir) || resolve3(projectSettings) === resolve3(claudeSettingsPath())) {
45425
+ details.heavyCommandHook = "skipped";
45426
+ } else {
45427
+ try {
45428
+ details.heavyCommandHook = await syncClaudeCodeHeavyCommandHook(
45429
+ projectDir,
45430
+ options.heavyCommandHook
45431
+ );
45432
+ } catch (err) {
45433
+ settingsErrors.push(err instanceof Error ? err.message : String(err));
45434
+ }
45435
+ }
45436
+ }
44452
45437
  if (settingsErrors.length > 0) {
44453
45438
  details.settingsErrors = settingsErrors;
44454
45439
  }
@@ -44473,9 +45458,9 @@ var init_install = __esm({
44473
45458
  */
44474
45459
  async isInstalled() {
44475
45460
  const settingsPath = claudeSettingsPath();
44476
- if (existsSync6(settingsPath)) {
45461
+ if (existsSync7(settingsPath)) {
44477
45462
  try {
44478
- const settings = JSON.parse(readFileSync4(settingsPath, "utf-8"));
45463
+ const settings = JSON.parse(readFileSync5(settingsPath, "utf-8"));
44479
45464
  const plugins = settings.enabledPlugins;
44480
45465
  if (plugins && plugins["cleo@cleocode"] === true) {
44481
45466
  return true;
@@ -44507,16 +45492,16 @@ var init_install = __esm({
44507
45492
  */
44508
45493
  installCommands(projectDir) {
44509
45494
  const adapterCommandsDir = getAdapterCommandsDir();
44510
- if (!existsSync6(adapterCommandsDir)) {
45495
+ if (!existsSync7(adapterCommandsDir)) {
44511
45496
  return [];
44512
45497
  }
44513
- const targetDir = join7(projectDir, ".claude", "commands");
44514
- mkdirSync2(targetDir, { recursive: true });
45498
+ const targetDir = join8(projectDir, ".claude", "commands");
45499
+ mkdirSync3(targetDir, { recursive: true });
44515
45500
  const installed = [];
44516
- const files = readdirSync2(adapterCommandsDir).filter((f) => f.endsWith(".md"));
45501
+ const files = readdirSync3(adapterCommandsDir).filter((f) => f.endsWith(".md"));
44517
45502
  for (const file2 of files) {
44518
- const src = join7(adapterCommandsDir, file2);
44519
- const dest = join7(targetDir, file2);
45503
+ const src = join8(adapterCommandsDir, file2);
45504
+ const dest = join8(targetDir, file2);
44520
45505
  copyFileSync2(src, dest);
44521
45506
  installed.push(file2);
44522
45507
  }
@@ -44529,7 +45514,7 @@ var init_install = __esm({
44529
45514
  */
44530
45515
  async registerPlugin() {
44531
45516
  const pluginKey = "cleo@cleocode";
44532
- const wrote = await updateJsonConfigFile2(claudeSettingsPath(), (settings) => {
45517
+ const wrote = await updateJsonConfigFile3(claudeSettingsPath(), (settings) => {
44533
45518
  const enabledPlugins = settings.enabledPlugins ?? {};
44534
45519
  if (!isPlainObject2(enabledPlugins)) {
44535
45520
  throw new Error('settings.json "enabledPlugins" is not an object; not modifying it');
@@ -44568,7 +45553,7 @@ var init_install = __esm({
44568
45553
  */
44569
45554
  async installHookTemplates() {
44570
45555
  const claudeDir = getClaudeConfigDir();
44571
- const hooksDir = join7(claudeDir, "hooks");
45556
+ const hooksDir = join8(claudeDir, "hooks");
44572
45557
  let templates;
44573
45558
  try {
44574
45559
  templates = installProviderHookTemplates({
@@ -44579,7 +45564,7 @@ var init_install = __esm({
44579
45564
  return null;
44580
45565
  }
44581
45566
  const settingsEntryAdded = await this.registerPreCompactHook(
44582
- join7(hooksDir, "precompact-safestop.sh")
45567
+ join8(hooksDir, "precompact-safestop.sh")
44583
45568
  );
44584
45569
  if (templates.installedFiles.length === 0 && !settingsEntryAdded) {
44585
45570
  return null;
@@ -44601,7 +45586,7 @@ var init_install = __esm({
44601
45586
  * @task T1013
44602
45587
  */
44603
45588
  async registerPreCompactHook(shimPath) {
44604
- return updateJsonConfigFile2(claudeSettingsPath(), (settings) => {
45589
+ return updateJsonConfigFile3(claudeSettingsPath(), (settings) => {
44605
45590
  const hooks = hookMap(settings);
44606
45591
  if (hasCleoHook(hooks.PreCompact, "precompact-safestop.sh")) {
44607
45592
  return false;
@@ -44625,7 +45610,7 @@ var init_install = __esm({
44625
45610
 
44626
45611
  // packages/adapters/src/providers/shared/agent-spawn-wrapper.ts
44627
45612
  import { spawnSync } from "node:child_process";
44628
- import { readFileSync as readFileSync5 } from "node:fs";
45613
+ import { readFileSync as readFileSync6 } from "node:fs";
44629
45614
  import { resolveSpawnInvocation } from "@cleocode/paths";
44630
45615
  function hasSystemdRun() {
44631
45616
  if (_systemdRunAvailable !== void 0) return _systemdRunAvailable;
@@ -44640,7 +45625,7 @@ function hasSystemdRun() {
44640
45625
  function readMemTotalBytes() {
44641
45626
  if (process.platform !== "linux") return 32 * 1024 * 1024 * 1024;
44642
45627
  try {
44643
- const raw = readFileSync5("/proc/meminfo", "utf8");
45628
+ const raw = readFileSync6("/proc/meminfo", "utf8");
44644
45629
  const m = raw.match(/^MemTotal:\s+(\d+)\s+kB/m);
44645
45630
  if (m?.[1]) return parseInt(m[1], 10) * 1024;
44646
45631
  } catch {
@@ -44723,16 +45708,16 @@ var init_agent_spawn_wrapper = __esm({
44723
45708
 
44724
45709
  // packages/adapters/src/providers/shared/prompt-file.ts
44725
45710
  import { mkdtemp, rm, writeFile } from "node:fs/promises";
44726
- import { tmpdir } from "node:os";
44727
- import { dirname as dirname4, join as join8 } from "node:path";
45711
+ import { tmpdir as tmpdir2 } from "node:os";
45712
+ import { dirname as dirname5, join as join9 } from "node:path";
44728
45713
  async function writeSpawnPromptFile(prefix, prompt) {
44729
- const dir = await mkdtemp(join8(tmpdir(), `cleo-${prefix}-`));
44730
- const file2 = join8(dir, "prompt.txt");
45714
+ const dir = await mkdtemp(join9(tmpdir2(), `cleo-${prefix}-`));
45715
+ const file2 = join9(dir, "prompt.txt");
44731
45716
  await writeFile(file2, prompt, "utf-8");
44732
45717
  return file2;
44733
45718
  }
44734
45719
  async function removeSpawnPromptFile(file2) {
44735
- await rm(dirname4(file2), { recursive: true, force: true }).catch(() => void 0);
45720
+ await rm(dirname5(file2), { recursive: true, force: true }).catch(() => void 0);
44736
45721
  }
44737
45722
  var init_prompt_file = __esm({
44738
45723
  "packages/adapters/src/providers/shared/prompt-file.ts"() {
@@ -44824,7 +45809,7 @@ function isEsrch(err) {
44824
45809
  return false;
44825
45810
  }
44826
45811
  function sleep(ms) {
44827
- return new Promise((resolve3) => setTimeout(resolve3, ms));
45812
+ return new Promise((resolve5) => setTimeout(resolve5, ms));
44828
45813
  }
44829
45814
  var SIGTERM_GRACE_MS;
44830
45815
  var init_suite_reaper = __esm({
@@ -45025,7 +46010,7 @@ var init_spawn2 = __esm({
45025
46010
 
45026
46011
  // packages/adapters/src/providers/claude-code/task-sync.ts
45027
46012
  import { readFile as readFile2, stat } from "node:fs/promises";
45028
- import { join as join9 } from "node:path";
46013
+ import { join as join10 } from "node:path";
45029
46014
  function parseTaskId(content) {
45030
46015
  const match = content.match(/^\[T(\d+)\]/);
45031
46016
  return match ? `T${match[1]}` : null;
@@ -45046,7 +46031,7 @@ function mapStatus(twStatus) {
45046
46031
  }
45047
46032
  }
45048
46033
  function getTodoWriteFilePath(projectDir) {
45049
- return join9(projectDir, ".cleo", "sync", "todowrite-state.json");
46034
+ return join10(projectDir, ".cleo", "sync", "todowrite-state.json");
45050
46035
  }
45051
46036
  var ClaudeCodeTaskSyncProvider;
45052
46037
  var init_task_sync = __esm({
@@ -45117,9 +46102,9 @@ var init_transport = __esm({
45117
46102
  });
45118
46103
 
45119
46104
  // packages/adapters/src/providers/claude-code/adapter.ts
45120
- import { existsSync as existsSync7 } from "node:fs";
45121
- import { homedir as homedir5 } from "node:os";
45122
- import { join as join10 } from "node:path";
46105
+ import { existsSync as existsSync8 } from "node:fs";
46106
+ import { homedir as homedir6 } from "node:os";
46107
+ import { join as join11 } from "node:path";
45123
46108
  import { findOnPath as findOnPath2 } from "@cleocode/paths";
45124
46109
  var ClaudeCodeAdapter;
45125
46110
  var init_adapter = __esm({
@@ -45272,8 +46257,8 @@ var init_adapter = __esm({
45272
46257
  cliAvailable = resolvedCli !== null;
45273
46258
  if (resolvedCli) details.cliPath = resolvedCli;
45274
46259
  else details.cliAvailable = false;
45275
- const claudeConfigDir = join10(homedir5(), ".claude");
45276
- const configExists = existsSync7(claudeConfigDir);
46260
+ const claudeConfigDir = join11(homedir6(), ".claude");
46261
+ const configExists = existsSync8(claudeConfigDir);
45277
46262
  details.configDirExists = configExists;
45278
46263
  const entrypointSet = process.env.CLAUDE_CODE_ENTRYPOINT !== void 0;
45279
46264
  details.entrypointEnvSet = entrypointSet;
@@ -45302,17 +46287,17 @@ var init_adapter = __esm({
45302
46287
  });
45303
46288
 
45304
46289
  // packages/adapters/src/providers/claude-code/statusline.ts
45305
- import { existsSync as existsSync8, readFileSync as readFileSync6 } from "node:fs";
45306
- import { homedir as homedir6 } from "node:os";
45307
- import { join as join11 } from "node:path";
46290
+ import { existsSync as existsSync9, readFileSync as readFileSync7 } from "node:fs";
46291
+ import { homedir as homedir7 } from "node:os";
46292
+ import { join as join12 } from "node:path";
45308
46293
  function getClaudeSettingsPath() {
45309
- return process.env["CLAUDE_SETTINGS"] ?? join11(process.env["CLAUDE_HOME"] ?? join11(homedir6(), ".claude"), "settings.json");
46294
+ return process.env["CLAUDE_SETTINGS"] ?? join12(process.env["CLAUDE_HOME"] ?? join12(homedir7(), ".claude"), "settings.json");
45310
46295
  }
45311
46296
  function checkStatuslineIntegration() {
45312
46297
  const settingsPath = getClaudeSettingsPath();
45313
- if (!existsSync8(settingsPath)) return "no_settings";
46298
+ if (!existsSync9(settingsPath)) return "no_settings";
45314
46299
  try {
45315
- const settings = JSON.parse(readFileSync6(settingsPath, "utf-8"));
46300
+ const settings = JSON.parse(readFileSync7(settingsPath, "utf-8"));
45316
46301
  const statusLine = settings.statusLine;
45317
46302
  if (!statusLine?.type) return "not_configured";
45318
46303
  if (statusLine.type !== "command") return "custom_no_cleo";
@@ -45320,10 +46305,10 @@ function checkStatuslineIntegration() {
45320
46305
  if (cmd.includes("context-monitor.sh") || cmd.includes("cleo-statusline") || cmd.includes(".context-state.json") || cmd.includes("context-states")) {
45321
46306
  return "configured";
45322
46307
  }
45323
- const scriptPath = cmd.startsWith("~") ? cmd.replace("~", homedir6()) : cmd;
45324
- if (existsSync8(scriptPath)) {
46308
+ const scriptPath = cmd.startsWith("~") ? cmd.replace("~", homedir7()) : cmd;
46309
+ if (existsSync9(scriptPath)) {
45325
46310
  try {
45326
- const content = readFileSync6(scriptPath, "utf-8");
46311
+ const content = readFileSync7(scriptPath, "utf-8");
45327
46312
  if (content.includes("context-state.json")) return "configured";
45328
46313
  } catch {
45329
46314
  }
@@ -45337,7 +46322,7 @@ function getStatuslineConfig(cleoHome) {
45337
46322
  return {
45338
46323
  statusLine: {
45339
46324
  type: "command",
45340
- command: join11(cleoHome, "lib", "session", "context-monitor.sh")
46325
+ command: join12(cleoHome, "lib", "session", "context-monitor.sh")
45341
46326
  }
45342
46327
  };
45343
46328
  }
@@ -45559,12 +46544,12 @@ var init_hooks2 = __esm({
45559
46544
  * @returns Cursor native event name (e.g. "preToolUse") or null
45560
46545
  * @task T165
45561
46546
  */
45562
- async toNativeEvent(canonical) {
46547
+ async toNativeEvent(canonical2) {
45563
46548
  try {
45564
46549
  const { toNative } = await import("@cleocode/caamp");
45565
- return toNative(canonical, PROVIDER_ID2);
46550
+ return toNative(canonical2, PROVIDER_ID2);
45566
46551
  } catch {
45567
- const entry = Object.entries(CURSOR_EVENT_MAP).find(([, v]) => v === canonical);
46552
+ const entry = Object.entries(CURSOR_EVENT_MAP).find(([, v]) => v === canonical2);
45568
46553
  return entry?.[0] ?? null;
45569
46554
  }
45570
46555
  }
@@ -45573,12 +46558,12 @@ var init_hooks2 = __esm({
45573
46558
  });
45574
46559
 
45575
46560
  // packages/adapters/src/providers/cursor/install.ts
45576
- import { existsSync as existsSync11, readFileSync as readFileSync7 } from "node:fs";
45577
- import { join as join17 } from "node:path";
46561
+ import { existsSync as existsSync12, readFileSync as readFileSync8 } from "node:fs";
46562
+ import { join as join18 } from "node:path";
45578
46563
  import {
45579
46564
  ensureProviderInstructionFile as ensureProviderInstructionFile3,
45580
46565
  ensureProviderRuleFile,
45581
- updateJsonConfigFile as updateJsonConfigFile3
46566
+ updateJsonConfigFile as updateJsonConfigFile4
45582
46567
  } from "@cleocode/caamp";
45583
46568
  function isRecord(value) {
45584
46569
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -45645,14 +46630,14 @@ var init_install2 = __esm({
45645
46630
  * Checks for .cursor/rules/cleo.mdc or .cursorrules with CLEO references.
45646
46631
  */
45647
46632
  async isInstalled() {
45648
- const mdcPath = join17(process.cwd(), ".cursor", "rules", "cleo.mdc");
45649
- if (existsSync11(mdcPath)) {
46633
+ const mdcPath = join18(process.cwd(), ".cursor", "rules", "cleo.mdc");
46634
+ if (existsSync12(mdcPath)) {
45650
46635
  return true;
45651
46636
  }
45652
- const rulesPath = join17(process.cwd(), ".cursorrules");
45653
- if (existsSync11(rulesPath)) {
46637
+ const rulesPath = join18(process.cwd(), ".cursorrules");
46638
+ if (existsSync12(rulesPath)) {
45654
46639
  try {
45655
- const content = readFileSync7(rulesPath, "utf-8");
46640
+ const content = readFileSync8(rulesPath, "utf-8");
45656
46641
  const injectionRef = `@${getCleoTemplatesTildePath()}/CLEO-INJECTION.md`;
45657
46642
  if (content.includes(injectionRef) || content.includes("@.cleo/memory-bridge.md")) {
45658
46643
  return true;
@@ -45697,7 +46682,7 @@ var init_install2 = __esm({
45697
46682
  onlyIfExists: true
45698
46683
  }),
45699
46684
  await ensureProviderRuleFile("cursor", projectDir, {
45700
- relativePath: join17(".cursor", "rules", "cleo.mdc"),
46685
+ relativePath: join18(".cursor", "rules", "cleo.mdc"),
45701
46686
  preamble: CLEO_MDC_FRONTMATTER
45702
46687
  })
45703
46688
  ];
@@ -45708,10 +46693,10 @@ var init_install2 = __esm({
45708
46693
  */
45709
46694
  getUpdatedFileList(projectDir) {
45710
46695
  const files = [];
45711
- if (existsSync11(join17(projectDir, ".cursorrules"))) {
45712
- files.push(join17(projectDir, ".cursorrules"));
46696
+ if (existsSync12(join18(projectDir, ".cursorrules"))) {
46697
+ files.push(join18(projectDir, ".cursorrules"));
45713
46698
  }
45714
- files.push(join17(projectDir, ".cursor", "rules", "cleo.mdc"));
46699
+ files.push(join18(projectDir, ".cursor", "rules", "cleo.mdc"));
45715
46700
  return files;
45716
46701
  }
45717
46702
  /**
@@ -45733,7 +46718,7 @@ var init_install2 = __esm({
45733
46718
  * @task T1013
45734
46719
  */
45735
46720
  async installHookTemplates(projectDir) {
45736
- const hooksDir = join17(projectDir, ".cursor", "hooks");
46721
+ const hooksDir = join18(projectDir, ".cursor", "hooks");
45737
46722
  let templates;
45738
46723
  try {
45739
46724
  templates = installProviderHookTemplates({
@@ -45745,7 +46730,7 @@ var init_install2 = __esm({
45745
46730
  }
45746
46731
  const hooksJsonEntryAdded = await this.registerPreCompactHook(
45747
46732
  projectDir,
45748
- join17(hooksDir, "precompact.sh")
46733
+ join18(hooksDir, "precompact.sh")
45749
46734
  );
45750
46735
  if (templates.installedFiles.length === 0 && !hooksJsonEntryAdded) {
45751
46736
  return null;
@@ -45766,8 +46751,8 @@ var init_install2 = __esm({
45766
46751
  * @task T1013
45767
46752
  */
45768
46753
  async registerPreCompactHook(projectDir, shimPath) {
45769
- const hooksJsonPath = join17(projectDir, ".cursor", "hooks.json");
45770
- return updateJsonConfigFile3(hooksJsonPath, (config2) => {
46754
+ const hooksJsonPath = join18(projectDir, ".cursor", "hooks.json");
46755
+ return updateJsonConfigFile4(hooksJsonPath, (config2) => {
45771
46756
  const hooks = config2.hooks ?? {};
45772
46757
  if (!isRecord(hooks)) {
45773
46758
  throw new Error('.cursor/hooks.json "hooks" is not an object; not modifying it');
@@ -45795,8 +46780,8 @@ var init_install2 = __esm({
45795
46780
  });
45796
46781
 
45797
46782
  // packages/adapters/src/providers/cursor/adapter.ts
45798
- import { existsSync as existsSync12 } from "node:fs";
45799
- import { join as join18 } from "node:path";
46783
+ import { existsSync as existsSync13 } from "node:fs";
46784
+ import { join as join19 } from "node:path";
45800
46785
  var CursorAdapter;
45801
46786
  var init_adapter2 = __esm({
45802
46787
  "packages/adapters/src/providers/cursor/adapter.ts"() {
@@ -45890,14 +46875,14 @@ var init_adapter2 = __esm({
45890
46875
  }
45891
46876
  let configExists = false;
45892
46877
  if (this.projectDir) {
45893
- const cursorConfigDir = join18(this.projectDir, ".cursor");
45894
- configExists = existsSync12(cursorConfigDir);
46878
+ const cursorConfigDir = join19(this.projectDir, ".cursor");
46879
+ configExists = existsSync13(cursorConfigDir);
45895
46880
  details.configDirExists = configExists;
45896
46881
  }
45897
46882
  const editorEnvSet = process.env.CURSOR_EDITOR !== void 0;
45898
46883
  details.editorEnvSet = editorEnvSet;
45899
46884
  if (this.projectDir) {
45900
- const legacyRulesExist = existsSync12(join18(this.projectDir, ".cursorrules"));
46885
+ const legacyRulesExist = existsSync13(join19(this.projectDir, ".cursorrules"));
45901
46886
  details.legacyRulesExist = legacyRulesExist;
45902
46887
  }
45903
46888
  const healthy = configExists || editorEnvSet;
@@ -46087,12 +47072,12 @@ var init_hooks3 = __esm({
46087
47072
  * @returns OpenCode native event name or null
46088
47073
  * @task T164
46089
47074
  */
46090
- async toNativeEvent(canonical) {
47075
+ async toNativeEvent(canonical2) {
46091
47076
  try {
46092
47077
  const { toNative } = await import("@cleocode/caamp");
46093
- return toNative(canonical, PROVIDER_ID3);
47078
+ return toNative(canonical2, PROVIDER_ID3);
46094
47079
  } catch {
46095
- const entry = Object.entries(OPENCODE_EVENT_MAP).find(([, v]) => v === canonical);
47080
+ const entry = Object.entries(OPENCODE_EVENT_MAP).find(([, v]) => v === canonical2);
46096
47081
  return entry?.[0] ?? null;
46097
47082
  }
46098
47083
  }
@@ -46101,13 +47086,14 @@ var init_hooks3 = __esm({
46101
47086
  });
46102
47087
 
46103
47088
  // packages/adapters/src/providers/opencode/install.ts
46104
- import { existsSync as existsSync17, mkdirSync as mkdirSync3, readFileSync as readFileSync10, writeFileSync as writeFileSync2 } from "node:fs";
46105
- import { join as join24 } from "node:path";
47089
+ import { existsSync as existsSync18, mkdirSync as mkdirSync4, readFileSync as readFileSync11, writeFileSync as writeFileSync3 } from "node:fs";
47090
+ import { join as join25 } from "node:path";
46106
47091
  import { ensureProviderInstructionFile as ensureProviderInstructionFile6 } from "@cleocode/caamp";
46107
47092
  var OpenCodeInstallProvider;
46108
47093
  var init_install3 = __esm({
46109
47094
  "packages/adapters/src/providers/opencode/install.ts"() {
46110
47095
  "use strict";
47096
+ init_heavy_command_hook_install();
46111
47097
  init_hook_template_installer();
46112
47098
  init_paths2();
46113
47099
  OpenCodeInstallProvider = class {
@@ -46127,14 +47113,28 @@ var init_install3 = __esm({
46127
47113
  });
46128
47114
  const instructionFileUpdated = instructResult.action !== "intact";
46129
47115
  if (instructionFileUpdated) {
46130
- details.instructionFile = join24(projectDir, instructResult.instructFile);
47116
+ details.instructionFile = join25(projectDir, instructResult.instructFile);
46131
47117
  }
46132
47118
  const hookResult = this.installHookTemplates(projectDir);
46133
47119
  if (hookResult) {
46134
47120
  details.hookTemplates = hookResult;
46135
47121
  }
47122
+ let success2 = true;
47123
+ if (options.heavyCommandHook !== void 0 && isUserHomeDir(projectDir)) {
47124
+ details.heavyCommandHook = "skipped";
47125
+ } else if (options.heavyCommandHook !== void 0) {
47126
+ try {
47127
+ details.heavyCommandHook = syncOpencodeHeavyCommandPlugin(
47128
+ projectDir,
47129
+ options.heavyCommandHook
47130
+ );
47131
+ } catch (err) {
47132
+ details.settingsErrors = [err instanceof Error ? err.message : String(err)];
47133
+ success2 = false;
47134
+ }
47135
+ }
46136
47136
  return {
46137
- success: true,
47137
+ success: success2,
46138
47138
  installedAt,
46139
47139
  instructionFileUpdated,
46140
47140
  details
@@ -46200,8 +47200,8 @@ var init_install3 = __esm({
46200
47200
  * @task T1013
46201
47201
  */
46202
47202
  installHookTemplates(projectDir) {
46203
- const pluginsDir = join24(projectDir, ".opencode", "plugins");
46204
- const hooksDir = join24(pluginsDir, "hooks");
47203
+ const pluginsDir = join25(projectDir, ".opencode", "plugins");
47204
+ const hooksDir = join25(pluginsDir, "hooks");
46205
47205
  let templates;
46206
47206
  try {
46207
47207
  templates = installProviderHookTemplates({
@@ -46213,7 +47213,7 @@ var init_install3 = __esm({
46213
47213
  }
46214
47214
  let pluginWritten = false;
46215
47215
  try {
46216
- pluginWritten = this.writePrecompactPlugin(pluginsDir, join24(hooksDir, "precompact.sh"));
47216
+ pluginWritten = this.writePrecompactPlugin(pluginsDir, join25(hooksDir, "precompact.sh"));
46217
47217
  } catch {
46218
47218
  }
46219
47219
  if (templates.installedFiles.length === 0 && !pluginWritten) {
@@ -46237,7 +47237,7 @@ var init_install3 = __esm({
46237
47237
  * @task T1013
46238
47238
  */
46239
47239
  writePrecompactPlugin(pluginsDir, shimPath) {
46240
- const pluginPath = join24(pluginsDir, "cleo-precompact.js");
47240
+ const pluginPath = join25(pluginsDir, "cleo-precompact.js");
46241
47241
  const generated = [
46242
47242
  "// CLEO PreCompact plugin for OpenCode (generated by @cleocode/adapters).",
46243
47243
  "// Bridges the canonical CAAMP `PreCompact` event",
@@ -46263,16 +47263,16 @@ var init_install3 = __esm({
46263
47263
  "}",
46264
47264
  ""
46265
47265
  ].join("\n");
46266
- if (existsSync17(pluginPath)) {
47266
+ if (existsSync18(pluginPath)) {
46267
47267
  try {
46268
- if (readFileSync10(pluginPath, "utf-8") === generated) {
47268
+ if (readFileSync11(pluginPath, "utf-8") === generated) {
46269
47269
  return false;
46270
47270
  }
46271
47271
  } catch {
46272
47272
  }
46273
47273
  }
46274
- mkdirSync3(pluginsDir, { recursive: true });
46275
- writeFileSync2(pluginPath, generated, "utf-8");
47274
+ mkdirSync4(pluginsDir, { recursive: true });
47275
+ writeFileSync3(pluginPath, generated, "utf-8");
46276
47276
  return true;
46277
47277
  }
46278
47278
  };
@@ -46281,7 +47281,7 @@ var init_install3 = __esm({
46281
47281
 
46282
47282
  // packages/adapters/src/providers/opencode/spawn.ts
46283
47283
  import { mkdir as mkdir2, readFile as readFile4, writeFile as writeFile2 } from "node:fs/promises";
46284
- import { join as join25 } from "node:path";
47284
+ import { join as join26 } from "node:path";
46285
47285
  import { findOnPath as findOnPath9 } from "@cleocode/paths";
46286
47286
  function buildOpenCodeAgentMarkdown(description, instructions) {
46287
47287
  const normalizedDesc = description.replace(/\s+/g, " ").trim();
@@ -46297,8 +47297,8 @@ function buildOpenCodeAgentMarkdown(description, instructions) {
46297
47297
  ].join("\n");
46298
47298
  }
46299
47299
  async function ensureSubagentDefinition(workingDirectory, enrichedInstructions) {
46300
- const agentDir = join25(workingDirectory, ".opencode", "agent");
46301
- const agentPath = join25(agentDir, `${OPENCODE_SUBAGENT_NAME}.md`);
47300
+ const agentDir = join26(workingDirectory, ".opencode", "agent");
47301
+ const agentPath = join26(agentDir, `${OPENCODE_SUBAGENT_NAME}.md`);
46302
47302
  const description = "CLEO task executor with protocol compliance and CANT context.";
46303
47303
  const instructions = enrichedInstructions ?? [
46304
47304
  "# CLEO Subagent",
@@ -46462,8 +47462,8 @@ var init_spawn3 = __esm({
46462
47462
  });
46463
47463
 
46464
47464
  // packages/adapters/src/providers/opencode/adapter.ts
46465
- import { existsSync as existsSync18 } from "node:fs";
46466
- import { join as join26 } from "node:path";
47465
+ import { existsSync as existsSync19 } from "node:fs";
47466
+ import { join as join27 } from "node:path";
46467
47467
  import { findOnPath as findOnPath10 } from "@cleocode/paths";
46468
47468
  var OpenCodeAdapter;
46469
47469
  var init_adapter3 = __esm({
@@ -46571,8 +47571,8 @@ var init_adapter3 = __esm({
46571
47571
  if (resolvedCli) details.cliPath = resolvedCli;
46572
47572
  else details.cliAvailable = false;
46573
47573
  if (this.projectDir) {
46574
- const openCodeConfigDir = join26(this.projectDir, ".opencode");
46575
- const configExists = existsSync18(openCodeConfigDir);
47574
+ const openCodeConfigDir = join27(this.projectDir, ".opencode");
47575
+ const configExists = existsSync19(openCodeConfigDir);
46576
47576
  details.configDirExists = configExists;
46577
47577
  }
46578
47578
  const versionEnvSet = process.env.OPENCODE_VERSION !== void 0;
@@ -46767,12 +47767,12 @@ var init_hooks4 = __esm({
46767
47767
  * @returns Pi native event name or null
46768
47768
  * @task T553
46769
47769
  */
46770
- async toNativeEvent(canonical) {
47770
+ async toNativeEvent(canonical2) {
46771
47771
  try {
46772
47772
  const { toNative } = await import("@cleocode/caamp");
46773
- return toNative(canonical, PROVIDER_ID4);
47773
+ return toNative(canonical2, PROVIDER_ID4);
46774
47774
  } catch {
46775
- const entry = Object.entries(PI_EVENT_MAP).find(([, v]) => v === canonical);
47775
+ const entry = Object.entries(PI_EVENT_MAP).find(([, v]) => v === canonical2);
46776
47776
  return entry?.[0] ?? null;
46777
47777
  }
46778
47778
  }
@@ -46781,7 +47781,7 @@ var init_hooks4 = __esm({
46781
47781
  });
46782
47782
 
46783
47783
  // packages/adapters/src/providers/pi/install.ts
46784
- import { join as join27 } from "node:path";
47784
+ import { join as join28 } from "node:path";
46785
47785
  import { ensureProviderInstructionFile as ensureProviderInstructionFile7 } from "@cleocode/caamp";
46786
47786
  function getCleoReferences() {
46787
47787
  return [`@${getCleoTemplatesTildePath()}/CLEO-INJECTION.md`, "@.cleo/memory-bridge.md"];
@@ -46808,7 +47808,7 @@ var init_install4 = __esm({
46808
47808
  });
46809
47809
  const projectUpdated = projectResult.action !== "intact";
46810
47810
  if (projectUpdated) {
46811
- details.instructionFile = join27(projectDir, projectResult.instructFile);
47811
+ details.instructionFile = join28(projectDir, projectResult.instructFile);
46812
47812
  }
46813
47813
  let globalUpdated = false;
46814
47814
  try {
@@ -47013,22 +48013,22 @@ var init_spawn4 = __esm({
47013
48013
  });
47014
48014
 
47015
48015
  // packages/adapters/src/providers/pi/adapter.ts
47016
- import { existsSync as existsSync19 } from "node:fs";
47017
- import { homedir as homedir12 } from "node:os";
47018
- import { join as join28 } from "node:path";
48016
+ import { existsSync as existsSync20 } from "node:fs";
48017
+ import { homedir as homedir13 } from "node:os";
48018
+ import { join as join29 } from "node:path";
47019
48019
  import { findOnPath as findOnPath12 } from "@cleocode/paths";
47020
48020
  function getPiAgentDir() {
47021
48021
  const env = process.env["PI_CODING_AGENT_DIR"];
47022
48022
  if (env !== void 0 && env.length > 0) {
47023
- if (env === "~") return homedir12();
47024
- if (env.startsWith("~/")) return join28(homedir12(), env.slice(2));
48023
+ if (env === "~") return homedir13();
48024
+ if (env.startsWith("~/")) return join29(homedir13(), env.slice(2));
47025
48025
  return env;
47026
48026
  }
47027
48027
  const piHome = process.env["PI_HOME"];
47028
48028
  if (piHome !== void 0 && piHome.length > 0) {
47029
- return join28(piHome, "agent");
48029
+ return join29(piHome, "agent");
47030
48030
  }
47031
- return join28(homedir12(), ".pi", "agent");
48031
+ return join29(homedir13(), ".pi", "agent");
47032
48032
  }
47033
48033
  var PiAdapter;
47034
48034
  var init_adapter4 = __esm({
@@ -47136,12 +48136,12 @@ var init_adapter4 = __esm({
47136
48136
  if (resolvedCli) details.cliPath = cliPath === "pi" ? resolvedCli : cliPath;
47137
48137
  else details.cliAvailable = false;
47138
48138
  const agentDir = getPiAgentDir();
47139
- const agentDirExists = existsSync19(agentDir);
48139
+ const agentDirExists = existsSync20(agentDir);
47140
48140
  details.agentDirExists = agentDirExists;
47141
48141
  details.agentDir = agentDir;
47142
48142
  if (this.projectDir) {
47143
- const projectPiDir = join28(this.projectDir, ".pi");
47144
- details.projectPiDirExists = existsSync19(projectPiDir);
48143
+ const projectPiDir = join29(this.projectDir, ".pi");
48144
+ details.projectPiDirExists = existsSync20(projectPiDir);
47145
48145
  }
47146
48146
  details.piCodingAgentDirSet = process.env["PI_CODING_AGENT_DIR"] !== void 0;
47147
48147
  details.piHomeSet = process.env["PI_HOME"] !== void 0;
@@ -47314,16 +48314,16 @@ var ClaudeSDKAdapter = class {
47314
48314
  };
47315
48315
 
47316
48316
  // packages/adapters/src/providers/claude-sdk/mcp-registry.ts
47317
- import { existsSync as existsSync9 } from "node:fs";
47318
- import { join as join12 } from "node:path";
48317
+ import { existsSync as existsSync10 } from "node:fs";
48318
+ import { join as join13 } from "node:path";
47319
48319
  var CLEO_MCP_CANDIDATES = [
47320
48320
  { name: "brain", binary: "cleo-mcp-brain" },
47321
48321
  { name: "nexus", binary: "cleo-mcp-nexus" },
47322
48322
  { name: "tasks", binary: "cleo-mcp-tasks" }
47323
48323
  ];
47324
48324
  function findInNodeModules(binary, workingDir) {
47325
- const binPath = join12(workingDir, "node_modules", ".bin", binary);
47326
- if (existsSync9(binPath)) {
48325
+ const binPath = join13(workingDir, "node_modules", ".bin", binary);
48326
+ if (existsSync10(binPath)) {
47327
48327
  return binPath;
47328
48328
  }
47329
48329
  return void 0;
@@ -47352,18 +48352,18 @@ function createAdapter2() {
47352
48352
  }
47353
48353
 
47354
48354
  // packages/adapters/src/providers/codex/adapter.ts
47355
- import { existsSync as existsSync10 } from "node:fs";
47356
- import { homedir as homedir8 } from "node:os";
47357
- import { join as join16 } from "node:path";
48355
+ import { existsSync as existsSync11 } from "node:fs";
48356
+ import { homedir as homedir9 } from "node:os";
48357
+ import { join as join17 } from "node:path";
47358
48358
  import { findOnPath as findOnPath3 } from "@cleocode/paths";
47359
48359
 
47360
48360
  // packages/adapters/src/providers/codex/hooks.ts
47361
- import { homedir as homedir7 } from "node:os";
47362
- import { join as join14 } from "node:path";
48361
+ import { homedir as homedir8 } from "node:os";
48362
+ import { join as join15 } from "node:path";
47363
48363
 
47364
48364
  // packages/adapters/src/providers/shared/transcript-reader.ts
47365
48365
  import { readdir as readdir2, readFile as readFile3 } from "node:fs/promises";
47366
- import { join as join13 } from "node:path";
48366
+ import { join as join14 } from "node:path";
47367
48367
  function parseTranscriptLines(raw) {
47368
48368
  const turns = [];
47369
48369
  const lines = raw.split("\n").filter((l) => l.trim());
@@ -47388,7 +48388,7 @@ async function readLatestTranscript(providerDir) {
47388
48388
  if (!entry.isFile()) continue;
47389
48389
  const name15 = entry.name;
47390
48390
  if (name15.endsWith(".json") || name15.endsWith(".jsonl")) {
47391
- allFiles.push(join13(providerDir, name15));
48391
+ allFiles.push(join14(providerDir, name15));
47392
48392
  }
47393
48393
  }
47394
48394
  } catch {
@@ -47478,13 +48478,14 @@ var CodexHookProvider = class {
47478
48478
  * @task T162 @epic T134
47479
48479
  */
47480
48480
  async getTranscript(_sessionId, _projectDir) {
47481
- return readLatestTranscript(join14(homedir7(), ".codex"));
48481
+ return readLatestTranscript(join15(homedir8(), ".codex"));
47482
48482
  }
47483
48483
  };
47484
48484
 
47485
48485
  // packages/adapters/src/providers/codex/install.ts
48486
+ init_heavy_command_hook_install();
47486
48487
  init_paths2();
47487
- import { join as join15 } from "node:path";
48488
+ import { join as join16 } from "node:path";
47488
48489
  import { ensureProviderInstructionFile as ensureProviderInstructionFile2 } from "@cleocode/caamp";
47489
48490
  var CodexInstallProvider = class {
47490
48491
  /**
@@ -47504,10 +48505,25 @@ var CodexInstallProvider = class {
47504
48505
  });
47505
48506
  const instructionFileUpdated = result.action !== "intact";
47506
48507
  if (instructionFileUpdated) {
47507
- details.instructionFile = join15(projectDir, result.instructFile);
48508
+ details.instructionFile = join16(projectDir, result.instructFile);
48509
+ }
48510
+ let success2 = true;
48511
+ if (options.heavyCommandHook !== void 0 && isUserHomeDir(projectDir)) {
48512
+ details.heavyCommandHook = "skipped";
48513
+ } else if (options.heavyCommandHook !== void 0) {
48514
+ try {
48515
+ details.heavyCommandHook = await syncJsonHeavyCommandHook(
48516
+ join16(projectDir, ".codex", "hooks.json"),
48517
+ "codex",
48518
+ options.heavyCommandHook
48519
+ );
48520
+ } catch (err) {
48521
+ details.settingsErrors = [err instanceof Error ? err.message : String(err)];
48522
+ success2 = false;
48523
+ }
47508
48524
  }
47509
48525
  return {
47510
- success: true,
48526
+ success: success2,
47511
48527
  installedAt,
47512
48528
  instructionFileUpdated,
47513
48529
  details
@@ -47638,8 +48654,8 @@ var CodexAdapter = class {
47638
48654
  cliAvailable = resolvedCli !== null;
47639
48655
  if (resolvedCli) details.cliPath = resolvedCli;
47640
48656
  else details.cliAvailable = false;
47641
- const codexConfigDir = join16(homedir8(), ".codex");
47642
- const configExists = existsSync10(codexConfigDir);
48657
+ const codexConfigDir = join17(homedir9(), ".codex");
48658
+ const configExists = existsSync11(codexConfigDir);
47643
48659
  details.configDirExists = configExists;
47644
48660
  const healthy = cliAvailable;
47645
48661
  details.cliAvailable = cliAvailable;
@@ -47680,14 +48696,14 @@ function createAdapter3() {
47680
48696
  init_cursor();
47681
48697
 
47682
48698
  // packages/adapters/src/providers/gemini-cli/adapter.ts
47683
- import { existsSync as existsSync14 } from "node:fs";
47684
- import { homedir as homedir10 } from "node:os";
47685
- import { join as join21 } from "node:path";
48699
+ import { existsSync as existsSync15 } from "node:fs";
48700
+ import { homedir as homedir11 } from "node:os";
48701
+ import { join as join22 } from "node:path";
47686
48702
  import { findOnPath as findOnPath5 } from "@cleocode/paths";
47687
48703
 
47688
48704
  // packages/adapters/src/providers/gemini-cli/hooks.ts
47689
- import { homedir as homedir9 } from "node:os";
47690
- import { join as join19 } from "node:path";
48705
+ import { homedir as homedir10 } from "node:os";
48706
+ import { join as join20 } from "node:path";
47691
48707
  var GEMINI_CLI_EVENT_MAP = {
47692
48708
  SessionStart: "SessionStart",
47693
48709
  SessionEnd: "SessionEnd",
@@ -47765,14 +48781,14 @@ var GeminiCliHookProvider = class {
47765
48781
  * @task T161 @epic T134
47766
48782
  */
47767
48783
  async getTranscript(_sessionId, _projectDir) {
47768
- return readLatestTranscript(join19(homedir9(), ".gemini"));
48784
+ return readLatestTranscript(join20(homedir10(), ".gemini"));
47769
48785
  }
47770
48786
  };
47771
48787
 
47772
48788
  // packages/adapters/src/providers/gemini-cli/install.ts
47773
48789
  init_paths2();
47774
- import { existsSync as existsSync13, readFileSync as readFileSync8 } from "node:fs";
47775
- import { join as join20 } from "node:path";
48790
+ import { existsSync as existsSync14, readFileSync as readFileSync9 } from "node:fs";
48791
+ import { join as join21 } from "node:path";
47776
48792
  import { ensureProviderInstructionFile as ensureProviderInstructionFile4 } from "@cleocode/caamp";
47777
48793
  var GeminiCliInstallProvider = class {
47778
48794
  /**
@@ -47817,10 +48833,10 @@ var GeminiCliInstallProvider = class {
47817
48833
  */
47818
48834
  async isInstalled() {
47819
48835
  const instructionRef = `@${getCleoTemplatesTildePath()}/CLEO-INJECTION.md`;
47820
- const geminiMdPath = join20(process.cwd(), "GEMINI.md");
47821
- if (existsSync13(geminiMdPath)) {
48836
+ const geminiMdPath = join21(process.cwd(), "GEMINI.md");
48837
+ if (existsSync14(geminiMdPath)) {
47822
48838
  try {
47823
- const content = readFileSync8(geminiMdPath, "utf-8");
48839
+ const content = readFileSync9(geminiMdPath, "utf-8");
47824
48840
  if (content.includes(instructionRef)) {
47825
48841
  return true;
47826
48842
  }
@@ -47937,8 +48953,8 @@ var GeminiCliAdapter = class {
47937
48953
  cliAvailable = resolvedCli !== null;
47938
48954
  if (resolvedCli) details.cliPath = resolvedCli;
47939
48955
  else details.cliAvailable = false;
47940
- const geminiConfigDir = join21(homedir10(), ".gemini");
47941
- const configExists = existsSync14(geminiConfigDir);
48956
+ const geminiConfigDir = join22(homedir11(), ".gemini");
48957
+ const configExists = existsSync15(geminiConfigDir);
47942
48958
  details.configDirExists = configExists;
47943
48959
  const healthy = cliAvailable;
47944
48960
  details.cliAvailable = cliAvailable;
@@ -47975,9 +48991,9 @@ function createAdapter5() {
47975
48991
  }
47976
48992
 
47977
48993
  // packages/adapters/src/providers/kimi/adapter.ts
47978
- import { existsSync as existsSync16 } from "node:fs";
47979
- import { homedir as homedir11 } from "node:os";
47980
- import { join as join23 } from "node:path";
48994
+ import { existsSync as existsSync17 } from "node:fs";
48995
+ import { homedir as homedir12 } from "node:os";
48996
+ import { join as join24 } from "node:path";
47981
48997
  import { findOnPath as findOnPath7 } from "@cleocode/paths";
47982
48998
 
47983
48999
  // packages/adapters/src/providers/kimi/hooks.ts
@@ -48037,8 +49053,8 @@ var KimiHookProvider = class {
48037
49053
 
48038
49054
  // packages/adapters/src/providers/kimi/install.ts
48039
49055
  init_paths2();
48040
- import { existsSync as existsSync15, readFileSync as readFileSync9 } from "node:fs";
48041
- import { join as join22 } from "node:path";
49056
+ import { existsSync as existsSync16, readFileSync as readFileSync10 } from "node:fs";
49057
+ import { join as join23 } from "node:path";
48042
49058
  import { ensureProviderInstructionFile as ensureProviderInstructionFile5 } from "@cleocode/caamp";
48043
49059
  var KimiInstallProvider = class {
48044
49060
  /**
@@ -48083,10 +49099,10 @@ var KimiInstallProvider = class {
48083
49099
  */
48084
49100
  async isInstalled() {
48085
49101
  const instructionRef = `@${getCleoTemplatesTildePath()}/CLEO-INJECTION.md`;
48086
- const agentsMdPath = join22(process.cwd(), "AGENTS.md");
48087
- if (existsSync15(agentsMdPath)) {
49102
+ const agentsMdPath = join23(process.cwd(), "AGENTS.md");
49103
+ if (existsSync16(agentsMdPath)) {
48088
49104
  try {
48089
- const content = readFileSync9(agentsMdPath, "utf-8");
49105
+ const content = readFileSync10(agentsMdPath, "utf-8");
48090
49106
  if (content.includes(instructionRef)) {
48091
49107
  return true;
48092
49108
  }
@@ -48190,8 +49206,8 @@ var KimiAdapter = class {
48190
49206
  cliAvailable = resolvedCli !== null;
48191
49207
  if (resolvedCli) details.cliPath = resolvedCli;
48192
49208
  else details.cliAvailable = false;
48193
- const kimiConfigDir = join23(homedir11(), ".kimi");
48194
- const configExists = existsSync16(kimiConfigDir);
49209
+ const kimiConfigDir = join24(homedir12(), ".kimi");
49210
+ const configExists = existsSync17(kimiConfigDir);
48195
49211
  details.configDirExists = configExists;
48196
49212
  const healthy = cliAvailable;
48197
49213
  details.cliAvailable = cliAvailable;
@@ -48231,17 +49247,17 @@ init_opencode();
48231
49247
  init_hook_template_installer();
48232
49248
 
48233
49249
  // packages/adapters/src/registry.ts
48234
- import { readFileSync as readFileSync11 } from "node:fs";
48235
- import { dirname as dirname5, join as join29, resolve as resolve2 } from "node:path";
49250
+ import { readFileSync as readFileSync12 } from "node:fs";
49251
+ import { dirname as dirname6, join as join30, resolve as resolve4 } from "node:path";
48236
49252
  import { fileURLToPath as fileURLToPath3 } from "node:url";
48237
49253
  var PROVIDER_IDS = ["claude-code", "opencode", "cursor", "pi"];
48238
49254
  function getProviderManifests() {
48239
49255
  const manifests = [];
48240
- const baseDir = resolve2(dirname5(fileURLToPath3(import.meta.url)), "providers");
49256
+ const baseDir = resolve4(dirname6(fileURLToPath3(import.meta.url)), "providers");
48241
49257
  for (const providerId of PROVIDER_IDS) {
48242
49258
  try {
48243
- const manifestPath = join29(baseDir, providerId, "manifest.json");
48244
- const raw = readFileSync11(manifestPath, "utf-8");
49259
+ const manifestPath = join30(baseDir, providerId, "manifest.json");
49260
+ const raw = readFileSync12(manifestPath, "utf-8");
48245
49261
  manifests.push(JSON.parse(raw));
48246
49262
  } catch {
48247
49263
  }