@cleocode/adapters 2026.9.20 → 2026.9.21

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.
Files changed (56) hide show
  1. package/dist/cant-context.d.ts +7 -5
  2. package/dist/cant-context.d.ts.map +1 -1
  3. package/dist/index.js +501 -328
  4. package/dist/index.js.map +3 -3
  5. package/dist/providers/claude-code/adapter.d.ts.map +1 -1
  6. package/dist/providers/claude-code/spawn.d.ts +2 -2
  7. package/dist/providers/claude-code/spawn.d.ts.map +1 -1
  8. package/dist/providers/claude-sdk/spawn.d.ts +1 -1
  9. package/dist/providers/codex/adapter.d.ts.map +1 -1
  10. package/dist/providers/codex/spawn.d.ts +1 -1
  11. package/dist/providers/codex/spawn.d.ts.map +1 -1
  12. package/dist/providers/gemini-cli/adapter.d.ts.map +1 -1
  13. package/dist/providers/gemini-cli/spawn.d.ts +1 -1
  14. package/dist/providers/gemini-cli/spawn.d.ts.map +1 -1
  15. package/dist/providers/kimi/adapter.d.ts.map +1 -1
  16. package/dist/providers/kimi/spawn.d.ts.map +1 -1
  17. package/dist/providers/opencode/adapter.d.ts.map +1 -1
  18. package/dist/providers/opencode/spawn.d.ts +3 -2
  19. package/dist/providers/opencode/spawn.d.ts.map +1 -1
  20. package/dist/providers/pi/adapter.d.ts +1 -1
  21. package/dist/providers/pi/adapter.d.ts.map +1 -1
  22. package/dist/providers/pi/spawn.d.ts +3 -3
  23. package/dist/providers/pi/spawn.d.ts.map +1 -1
  24. package/dist/providers/shared/agent-spawn-wrapper.d.ts +5 -0
  25. package/dist/providers/shared/agent-spawn-wrapper.d.ts.map +1 -1
  26. package/dist/providers/shared/cli-spawn.d.ts +28 -0
  27. package/dist/providers/shared/cli-spawn.d.ts.map +1 -0
  28. package/dist/providers/shared/credentials.d.ts +2 -2
  29. package/dist/providers/shared/credentials.d.ts.map +1 -1
  30. package/dist/providers/shared/prompt-file.d.ts +32 -0
  31. package/dist/providers/shared/prompt-file.d.ts.map +1 -0
  32. package/package.json +5 -5
  33. package/src/__tests__/agent-spawn-wrapper-win32.test.ts +42 -0
  34. package/src/__tests__/cant-context.test.ts +89 -37
  35. package/src/__tests__/cli-spawn-win32.test.ts +105 -0
  36. package/src/__tests__/spawn-prompt-file.test.ts +37 -0
  37. package/src/cant-context.ts +11 -15
  38. package/src/providers/claude-code/adapter.ts +6 -11
  39. package/src/providers/claude-code/spawn.ts +11 -25
  40. package/src/providers/claude-sdk/spawn.ts +1 -1
  41. package/src/providers/codex/adapter.ts +6 -11
  42. package/src/providers/codex/spawn.ts +17 -31
  43. package/src/providers/gemini-cli/adapter.ts +6 -11
  44. package/src/providers/gemini-cli/spawn.ts +13 -18
  45. package/src/providers/kimi/adapter.ts +6 -11
  46. package/src/providers/kimi/spawn.ts +3 -11
  47. package/src/providers/opencode/__tests__/spawn-prompt-delivery.test.ts +123 -0
  48. package/src/providers/opencode/adapter.ts +6 -11
  49. package/src/providers/opencode/spawn.ts +23 -25
  50. package/src/providers/pi/adapter.ts +8 -18
  51. package/src/providers/pi/spawn.ts +15 -33
  52. package/src/providers/shared/__tests__/credentials-cleo-home.test.ts +42 -0
  53. package/src/providers/shared/agent-spawn-wrapper.ts +22 -2
  54. package/src/providers/shared/cli-spawn.ts +41 -0
  55. package/src/providers/shared/credentials.ts +6 -5
  56. package/src/providers/shared/prompt-file.ts +44 -0
package/dist/index.js CHANGED
@@ -28,9 +28,9 @@ __export(cant_context_exports, {
28
28
  });
29
29
  import { execFile } from "node:child_process";
30
30
  import { existsSync, readdirSync, readFileSync } from "node:fs";
31
- import { homedir } from "node:os";
32
31
  import { basename, join } from "node:path";
33
32
  import { promisify } from "node:util";
33
+ import { getCleoHome, getCleoPlatformPaths } from "@cleocode/paths";
34
34
  function discoverCantFiles(dir) {
35
35
  try {
36
36
  const entries = readdirSync(dir, { recursive: true, withFileTypes: true });
@@ -47,12 +47,9 @@ function discoverCantFiles(dir) {
47
47
  }
48
48
  }
49
49
  function resolveThreeTierPaths(projectDir) {
50
- const home = homedir();
51
- const xdgData = process.env["XDG_DATA_HOME"] ?? join(home, ".local", "share");
52
- const xdgConfig = process.env["XDG_CONFIG_HOME"] ?? join(home, ".config");
53
50
  return {
54
- global: join(xdgData, "cleo", "cant"),
55
- user: join(xdgConfig, "cleo", "cant"),
51
+ global: join(getCleoHome(), "cant"),
52
+ user: join(getCleoPlatformPaths().config, "cant"),
56
53
  project: join(projectDir, ".cleo", "cant")
57
54
  };
58
55
  }
@@ -139,9 +136,7 @@ function readIdentityFile(projectDir) {
139
136
  } catch {
140
137
  }
141
138
  }
142
- const home = homedir();
143
- const xdgData = process.env["XDG_DATA_HOME"] ?? join(home, ".local", "share");
144
- const globalPath = join(xdgData, "cleo", "CLEOOS-IDENTITY.md");
139
+ const globalPath = join(getCleoHome(), "CLEOOS-IDENTITY.md");
145
140
  if (existsSync(globalPath)) {
146
141
  try {
147
142
  const content = readFileSync(globalPath, "utf-8");
@@ -747,7 +742,17 @@ var init_acceptance_gate_schema = __esm({
747
742
  message: "Absent input requires both null digest and size"
748
743
  });
749
744
  })
750
- )
745
+ ),
746
+ tree: z.object({
747
+ headSha: z.string().regex(/^[0-9a-f]{40}$/),
748
+ clean: z.boolean(),
749
+ cwd: z.string().min(1).refine(
750
+ (v) => !/^(?:\/|[A-Za-z]:[\\/]|\\\\)/.test(v) && !v.split(/[\\/]/).includes(".."),
751
+ "Tree-relative cwd must be relative and stay inside the tree"
752
+ ),
753
+ inputsHash: z.string().regex(/^[a-f0-9]{64}$/),
754
+ baseSha: z.string().regex(/^[0-9a-f]{40}$/).optional()
755
+ }).strict().optional()
751
756
  }).strict().superRefine((binding, context) => {
752
757
  if (new Set(binding.artifacts.map(({ path }) => path)).size !== binding.artifacts.length)
753
758
  context.addIssue({
@@ -777,8 +782,18 @@ var init_acceptance_gate_schema = __esm({
777
782
  errorMessage: z.string().optional(),
778
783
  /** ISO 8601 timestamp. */
779
784
  checkedAt: z.string().datetime(),
780
- checkedBy: z.string().min(1)
785
+ checkedBy: z.string().min(1),
786
+ /** T12621: `executed` in this run, or an authenticated pass reused from the cache. */
787
+ source: z.enum(["executed", "cache"]).optional(),
788
+ /** T12621: creation time of the reused cache entry. */
789
+ cachedAt: z.string().datetime().optional()
781
790
  }).superRefine((result, context) => {
791
+ if (result.source === "cache" !== (result.cachedAt !== void 0))
792
+ context.addIssue({
793
+ code: "custom",
794
+ path: ["cachedAt"],
795
+ message: "A cached result carries its cache time, and only a cached result does"
796
+ });
782
797
  const binding = result.binding;
783
798
  if (binding) {
784
799
  if (binding.identity.actor !== result.checkedBy)
@@ -2778,7 +2793,8 @@ var init_tasks = __esm({
2778
2793
  }
2779
2794
  }
2780
2795
  },
2781
- removeRelates: { type: "array", items: { type: "string" } }
2796
+ removeRelates: { type: "array", items: { type: "string" } },
2797
+ expectedUpdatedAt: { type: "string", minLength: 1 }
2782
2798
  }
2783
2799
  };
2784
2800
  tasksUpdateInputContract = {
@@ -5735,6 +5751,13 @@ var init_operations_registry = __esm({
5735
5751
  required: false,
5736
5752
  description: "Disable automatic parent completion",
5737
5753
  cli: { flag: "no-auto-complete" }
5754
+ },
5755
+ {
5756
+ name: "expectedUpdatedAt",
5757
+ type: "string",
5758
+ required: false,
5759
+ description: "Optimistic-concurrency guard: fail with E_CONFLICT unless the task updatedAt still equals this value",
5760
+ cli: { flag: "expected-updated-at" }
5738
5761
  }
5739
5762
  ],
5740
5763
  inputSchema: tasksUpdateInputContract,
@@ -9513,6 +9536,42 @@ var init_operations_registry = __esm({
9513
9536
  }
9514
9537
  ]
9515
9538
  },
9539
+ {
9540
+ gateway: "mutate",
9541
+ domain: "nexus",
9542
+ operation: "projects.status",
9543
+ description: "nexus.projects.status (mutate) \u2014 probe and record git state of every project location on this device (bounded, parallel; no network unless fetch)",
9544
+ tier: 1,
9545
+ idempotent: true,
9546
+ sessionRequired: false,
9547
+ requiredParams: [],
9548
+ params: [
9549
+ {
9550
+ name: "fetch",
9551
+ type: "boolean",
9552
+ required: false,
9553
+ description: "Run git fetch per location first (network; off by default)"
9554
+ },
9555
+ {
9556
+ name: "concurrency",
9557
+ type: "number",
9558
+ required: false,
9559
+ description: "Locations probed at once (default 8, max 64)"
9560
+ },
9561
+ {
9562
+ name: "timeoutMs",
9563
+ type: "number",
9564
+ required: false,
9565
+ description: "Per-location git budget in ms (default 10000; 30000 with fetch)"
9566
+ },
9567
+ {
9568
+ name: "staleAfterMs",
9569
+ type: "number",
9570
+ required: false,
9571
+ description: "A fetch older than this marks remote state stale (default 24h)"
9572
+ }
9573
+ ]
9574
+ },
9516
9575
  {
9517
9576
  gateway: "mutate",
9518
9577
  domain: "nexus",
@@ -10688,7 +10747,13 @@ var init_operations_registry = __esm({
10688
10747
  },
10689
10748
  { name: "title", type: "string", required: false, description: "Override PR title" },
10690
10749
  { name: "body", type: "string", required: false, description: "Override PR body" },
10691
- { name: "base", type: "string", required: false, description: "PR base branch" }
10750
+ { name: "base", type: "string", required: false, description: "PR base branch" },
10751
+ {
10752
+ name: "taskId",
10753
+ type: "string",
10754
+ required: false,
10755
+ description: "Owning task id (T####) for the PR commit subject"
10756
+ }
10692
10757
  ]
10693
10758
  },
10694
10759
  {
@@ -10721,7 +10786,13 @@ var init_operations_registry = __esm({
10721
10786
  },
10722
10787
  { name: "title", type: "string", required: false, description: "Override PR title" },
10723
10788
  { name: "body", type: "string", required: false, description: "Override PR body" },
10724
- { name: "base", type: "string", required: false, description: "PR base branch" }
10789
+ { name: "base", type: "string", required: false, description: "PR base branch" },
10790
+ {
10791
+ name: "taskId",
10792
+ type: "string",
10793
+ required: false,
10794
+ description: "Owning task id (T####) for the PR commit subject"
10795
+ }
10725
10796
  ]
10726
10797
  },
10727
10798
  {
@@ -13237,7 +13308,7 @@ var init_errors = __esm({
13237
13308
 
13238
13309
  // packages/contracts/src/evidence-atom-schema.ts
13239
13310
  import { z as z10 } from "zod";
13240
- var EVIDENCE_ATOM_KINDS, PARSER_PREFIXES, KIND_BOUNDARY_REGEX, commitAtomSchema, filesAtomSchema, testRunAtomSchema, toolAtomSchema, urlAtomSchema, noteAtomSchema, decisionAtomSchema, prAtomSchema, locDropAtomSchema, callsiteCoverageAtomSchema, AC_UUID_REGEX, AC_ALIAS_REGEX, SATISFIES_TASK_ID_REGEX, SATISFIES_VERSION_PIN_REGEX, satisfiesAtomSchema, EvidenceAtomSchema, GATE_EVIDENCE_REQUIREMENTS, ATOM_EXAMPLES;
13311
+ var EVIDENCE_ATOM_KINDS, PARSER_PREFIXES, KIND_BOUNDARY_REGEX, commitAtomSchema, filesAtomSchema, testRunAtomSchema, toolAtomSchema, urlAtomSchema, noteAtomSchema, decisionAtomSchema, prAtomSchema, ciAtomSchema, locDropAtomSchema, callsiteCoverageAtomSchema, AC_UUID_REGEX, AC_ALIAS_REGEX, SATISFIES_TASK_ID_REGEX, SATISFIES_VERSION_PIN_REGEX, satisfiesAtomSchema, EvidenceAtomSchema, GATE_EVIDENCE_REQUIREMENTS, ATOM_EXAMPLES;
13241
13312
  var init_evidence_atom_schema = __esm({
13242
13313
  "packages/contracts/src/evidence-atom-schema.ts"() {
13243
13314
  "use strict";
@@ -13250,6 +13321,7 @@ var init_evidence_atom_schema = __esm({
13250
13321
  "note",
13251
13322
  "decision",
13252
13323
  "pr",
13324
+ "ci",
13253
13325
  "loc-drop",
13254
13326
  "callsite-coverage",
13255
13327
  "satisfies"
@@ -13288,6 +13360,10 @@ var init_evidence_atom_schema = __esm({
13288
13360
  kind: z10.literal("pr"),
13289
13361
  prNumber: z10.number().int().positive("pr atom requires a positive integer PR number")
13290
13362
  });
13363
+ ciAtomSchema = z10.object({
13364
+ kind: z10.literal("ci"),
13365
+ prNumber: z10.number().int().positive("ci atom requires a positive integer PR number")
13366
+ });
13291
13367
  locDropAtomSchema = z10.object({
13292
13368
  kind: z10.literal("loc-drop"),
13293
13369
  fromLines: z10.number().int().nonnegative("loc-drop fromLines must be \u2265 0"),
@@ -13325,6 +13401,7 @@ var init_evidence_atom_schema = __esm({
13325
13401
  noteAtomSchema,
13326
13402
  decisionAtomSchema,
13327
13403
  prAtomSchema,
13404
+ ciAtomSchema,
13328
13405
  locDropAtomSchema,
13329
13406
  callsiteCoverageAtomSchema,
13330
13407
  satisfiesAtomSchema
@@ -13339,8 +13416,8 @@ var init_evidence_atom_schema = __esm({
13339
13416
  ["pr", "files"]
13340
13417
  ]
13341
13418
  },
13342
- testsPassed: { oneOf: [["test-run"], ["tool"]] },
13343
- qaPassed: { oneOf: [["tool"]] },
13419
+ testsPassed: { oneOf: [["test-run"], ["tool"], ["ci"]] },
13420
+ qaPassed: { oneOf: [["tool"], ["ci"]] },
13344
13421
  documented: { oneOf: [["files"], ["url"]] },
13345
13422
  securityPassed: { oneOf: [["tool"], ["note"]] },
13346
13423
  cleanupDone: { oneOf: [["note"]] },
@@ -13355,6 +13432,7 @@ var init_evidence_atom_schema = __esm({
13355
13432
  note: "note:<short description>",
13356
13433
  decision: "decision:D-arch-001",
13357
13434
  pr: "pr:357",
13435
+ ci: "ci:357",
13358
13436
  "loc-drop": "loc-drop:<fromLines>:<toLines>",
13359
13437
  "callsite-coverage": "callsite-coverage:<symbolName>:<relativeSourcePath>",
13360
13438
  satisfies: "satisfies:T1234#AC2"
@@ -15163,6 +15241,13 @@ var init_peer = __esm({
15163
15241
  }
15164
15242
  });
15165
15243
 
15244
+ // packages/contracts/src/process-probe.ts
15245
+ var init_process_probe = __esm({
15246
+ "packages/contracts/src/process-probe.ts"() {
15247
+ "use strict";
15248
+ }
15249
+ });
15250
+
15166
15251
  // packages/contracts/src/release/evidence-atoms.ts
15167
15252
  import { z as z16 } from "zod";
15168
15253
  var parsedPrEvidenceAtomSchema, prEvidenceStateModifierSchema, ghPrViewSchema, PR_REQUIRED_WORKFLOWS;
@@ -15249,7 +15334,12 @@ var init_plan = __esm({
15249
15334
  "hotfix"
15250
15335
  ];
15251
15336
  IMPACT = ["major", "minor", "patch"];
15252
- RESOLVED_SOURCE = ["project-context", "language-default", "legacy-alias"];
15337
+ RESOLVED_SOURCE = [
15338
+ "project-context",
15339
+ "package-script",
15340
+ "language-default",
15341
+ "legacy-alias"
15342
+ ];
15253
15343
  ReleaseChannelSchema = z17.enum(RELEASE_CHANNEL);
15254
15344
  ReleaseSchemeSchema = z17.enum(RELEASE_SCHEME);
15255
15345
  ReleaseKindSchema = z17.enum(RELEASE_KIND);
@@ -17165,6 +17255,117 @@ var init_collection_keys = __esm({
17165
17255
  }
17166
17256
  });
17167
17257
 
17258
+ // packages/contracts/src/decide.ts
17259
+ import { z as z24 } from "zod";
17260
+ var DECISION_QUESTION_TYPES, DECISION_OUTCOME_SOURCES, DECISION_REQUEST_LIMITS, decisionQuestionTypeSchema, decisionOutcomeSourceSchema, decisionInstructionsSchema, unitIntervalSchema, decisionStateSchema, noulDecisionQuestionSchema, choiceDecisionQuestionSchema, scoreDecisionQuestionSchema, decisionQuestionSchema, decisionRequestSchema, noulDecisionAnswerSchema, choiceDecisionAnswerSchema, scoreDecisionAnswerSchema, decisionAnswerSchema, decisionOutcomeSchema, decisionProviderConfigSchema;
17261
+ var init_decide = __esm({
17262
+ "packages/contracts/src/decide.ts"() {
17263
+ "use strict";
17264
+ DECISION_QUESTION_TYPES = ["noul", "choice", "score"];
17265
+ DECISION_OUTCOME_SOURCES = ["provider", "cache", "fallback"];
17266
+ DECISION_REQUEST_LIMITS = {
17267
+ /**
17268
+ * Maximum size of `state`, in UTF-16 characters. A string state is measured
17269
+ * directly; a structured (object/array) state is measured on its
17270
+ * `JSON.stringify` serialization, which is what goes over the wire.
17271
+ */
17272
+ maxStateChars: 32e3,
17273
+ /** Minimum number of questions in one request. */
17274
+ minQuestions: 1,
17275
+ /** Maximum number of questions in one request. */
17276
+ maxQuestions: 32,
17277
+ /** Minimum number of options a `choice` question must offer. */
17278
+ minChoiceOptions: 2,
17279
+ /** Minimum number of levels on a `score` question's scale. */
17280
+ minScoreLevels: 2,
17281
+ /** Maximum number of levels on a `score` question's scale. */
17282
+ maxScoreLevels: 10
17283
+ };
17284
+ decisionQuestionTypeSchema = z24.enum(DECISION_QUESTION_TYPES);
17285
+ decisionOutcomeSourceSchema = z24.enum(DECISION_OUTCOME_SOURCES);
17286
+ decisionInstructionsSchema = z24.union([z24.string(), z24.record(z24.string(), z24.json())]);
17287
+ unitIntervalSchema = z24.number().min(0).max(1);
17288
+ decisionStateSchema = z24.union([z24.string(), z24.array(z24.json()), z24.record(z24.string(), z24.json())]).superRefine((state, context) => {
17289
+ const size = typeof state === "string" ? state.length : JSON.stringify(state).length;
17290
+ if (size > DECISION_REQUEST_LIMITS.maxStateChars) {
17291
+ context.addIssue({
17292
+ code: "custom",
17293
+ message: `state is ${size} characters; the limit is ${DECISION_REQUEST_LIMITS.maxStateChars}`
17294
+ });
17295
+ }
17296
+ });
17297
+ noulDecisionQuestionSchema = z24.object({
17298
+ type: z24.literal("noul"),
17299
+ instructions: decisionInstructionsSchema.optional(),
17300
+ criteria: z24.string().min(1)
17301
+ });
17302
+ choiceDecisionQuestionSchema = z24.object({
17303
+ type: z24.literal("choice"),
17304
+ instructions: decisionInstructionsSchema.optional(),
17305
+ criteria: z24.record(z24.string().min(1), z24.string()).refine((options) => Object.keys(options).length >= DECISION_REQUEST_LIMITS.minChoiceOptions, {
17306
+ message: `a choice question needs at least ${DECISION_REQUEST_LIMITS.minChoiceOptions} options`
17307
+ })
17308
+ });
17309
+ scoreDecisionQuestionSchema = z24.object({
17310
+ type: z24.literal("score"),
17311
+ instructions: decisionInstructionsSchema.optional(),
17312
+ criteria: z24.array(z24.string()).min(DECISION_REQUEST_LIMITS.minScoreLevels).max(DECISION_REQUEST_LIMITS.maxScoreLevels)
17313
+ });
17314
+ decisionQuestionSchema = z24.discriminatedUnion("type", [
17315
+ noulDecisionQuestionSchema,
17316
+ choiceDecisionQuestionSchema,
17317
+ scoreDecisionQuestionSchema
17318
+ ]);
17319
+ decisionRequestSchema = z24.object({
17320
+ model: z24.string().min(1).optional(),
17321
+ state: decisionStateSchema,
17322
+ questions: z24.record(z24.string().min(1), decisionQuestionSchema).refine(
17323
+ (questions) => {
17324
+ const count = Object.keys(questions).length;
17325
+ return count >= DECISION_REQUEST_LIMITS.minQuestions && count <= DECISION_REQUEST_LIMITS.maxQuestions;
17326
+ },
17327
+ {
17328
+ message: `a request needs ${DECISION_REQUEST_LIMITS.minQuestions}\u2013${DECISION_REQUEST_LIMITS.maxQuestions} questions`
17329
+ }
17330
+ )
17331
+ });
17332
+ noulDecisionAnswerSchema = z24.object({
17333
+ type: z24.literal("noul"),
17334
+ value: z24.boolean(),
17335
+ probability: unitIntervalSchema,
17336
+ confidence: unitIntervalSchema
17337
+ });
17338
+ choiceDecisionAnswerSchema = z24.object({
17339
+ type: z24.literal("choice"),
17340
+ value: z24.string().min(1),
17341
+ probabilities: z24.record(z24.string().min(1), unitIntervalSchema),
17342
+ confidence: unitIntervalSchema
17343
+ });
17344
+ scoreDecisionAnswerSchema = z24.object({
17345
+ type: z24.literal("score"),
17346
+ value: z24.number().int().nonnegative(),
17347
+ probabilities: z24.array(unitIntervalSchema).min(DECISION_REQUEST_LIMITS.minScoreLevels).max(DECISION_REQUEST_LIMITS.maxScoreLevels),
17348
+ confidence: unitIntervalSchema
17349
+ });
17350
+ decisionAnswerSchema = z24.discriminatedUnion("type", [
17351
+ noulDecisionAnswerSchema,
17352
+ choiceDecisionAnswerSchema,
17353
+ scoreDecisionAnswerSchema
17354
+ ]);
17355
+ decisionOutcomeSchema = z24.object({
17356
+ answers: z24.record(z24.string().min(1), decisionAnswerSchema),
17357
+ source: decisionOutcomeSourceSchema,
17358
+ requestId: z24.string().min(1).optional(),
17359
+ latencyMs: z24.number().nonnegative(),
17360
+ costUsd: z24.number().nonnegative().optional(),
17361
+ inputTokens: z24.number().int().nonnegative().optional()
17362
+ });
17363
+ decisionProviderConfigSchema = z24.object({
17364
+ baseUrl: z24.url()
17365
+ });
17366
+ }
17367
+ });
17368
+
17168
17369
  // packages/contracts/src/task-id.ts
17169
17370
  var init_task_id = __esm({
17170
17371
  "packages/contracts/src/task-id.ts"() {
@@ -17219,11 +17420,13 @@ var init_src = __esm({
17219
17420
  init_entities();
17220
17421
  init_operations();
17221
17422
  init_nexus_scope_map();
17423
+ init_nexus_user_profile();
17222
17424
  init_output_contracts_data();
17223
17425
  init_params();
17224
17426
  init_service();
17225
17427
  init_tasks();
17226
17428
  init_peer();
17429
+ init_process_probe();
17227
17430
  init_evidence_atoms();
17228
17431
  init_plan();
17229
17432
  init_render();
@@ -17243,20 +17446,21 @@ var init_src = __esm({
17243
17446
  init_workgraph();
17244
17447
  init_caamp_markers();
17245
17448
  init_collection_keys();
17449
+ init_decide();
17246
17450
  init_task_id();
17247
17451
  }
17248
17452
  });
17249
17453
 
17250
17454
  // packages/adapters/src/providers/shared/credentials.ts
17251
17455
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
17252
- import { homedir as homedir2 } from "node:os";
17456
+ import { homedir } from "node:os";
17253
17457
  import { join as join2 } from "node:path";
17458
+ import { getCleoHome as getCleoHome2 } from "@cleocode/paths";
17254
17459
  function resolveCredentials(_provider) {
17255
17460
  const envKey = process.env["ANTHROPIC_API_KEY"];
17256
17461
  if (envKey?.trim()) return { apiKey: envKey.trim() };
17257
17462
  try {
17258
- const xdg = process.env["XDG_DATA_HOME"] ?? join2(homedir2(), ".local", "share");
17259
- const keyFile = join2(xdg, "cleo", "anthropic-key");
17463
+ const keyFile = join2(getCleoHome2(), "anthropic-key");
17260
17464
  if (existsSync2(keyFile)) {
17261
17465
  const stored = readFileSync2(keyFile, "utf-8").trim();
17262
17466
  if (stored) return { apiKey: stored };
@@ -17264,7 +17468,7 @@ function resolveCredentials(_provider) {
17264
17468
  } catch {
17265
17469
  }
17266
17470
  try {
17267
- const credPath = join2(homedir2(), ".claude", ".credentials.json");
17471
+ const credPath = join2(homedir(), ".claude", ".credentials.json");
17268
17472
  if (!existsSync2(credPath)) return { apiKey: null };
17269
17473
  const raw = readFileSync2(credPath, "utf-8");
17270
17474
  const cred = parseClaudeCodeCredentials(raw);
@@ -31263,7 +31467,7 @@ function resolveRef(ref, ctx) {
31263
31467
  function convertBaseSchema(schema, ctx) {
31264
31468
  if (schema.not !== void 0) {
31265
31469
  if (typeof schema.not === "object" && Object.keys(schema.not).length === 0) {
31266
- return z24.never();
31470
+ return z25.never();
31267
31471
  }
31268
31472
  throw new Error("not is not supported in Zod (except { not: {} } for never)");
31269
31473
  }
@@ -31285,7 +31489,7 @@ function convertBaseSchema(schema, ctx) {
31285
31489
  return ctx.refs.get(refPath);
31286
31490
  }
31287
31491
  if (ctx.processing.has(refPath)) {
31288
- return z24.lazy(() => {
31492
+ return z25.lazy(() => {
31289
31493
  if (!ctx.refs.has(refPath)) {
31290
31494
  throw new Error(`Circular reference not resolved: ${refPath}`);
31291
31495
  }
@@ -31302,25 +31506,25 @@ function convertBaseSchema(schema, ctx) {
31302
31506
  if (schema.enum !== void 0) {
31303
31507
  const enumValues = schema.enum;
31304
31508
  if (ctx.version === "openapi-3.0" && schema.nullable === true && enumValues.length === 1 && enumValues[0] === null) {
31305
- return z24.null();
31509
+ return z25.null();
31306
31510
  }
31307
31511
  if (enumValues.length === 0) {
31308
- return z24.never();
31512
+ return z25.never();
31309
31513
  }
31310
31514
  if (enumValues.length === 1) {
31311
- return z24.literal(enumValues[0]);
31515
+ return z25.literal(enumValues[0]);
31312
31516
  }
31313
31517
  if (enumValues.every((v) => typeof v === "string")) {
31314
- return z24.enum(enumValues);
31518
+ return z25.enum(enumValues);
31315
31519
  }
31316
- const literalSchemas = enumValues.map((v) => z24.literal(v));
31520
+ const literalSchemas = enumValues.map((v) => z25.literal(v));
31317
31521
  if (literalSchemas.length < 2) {
31318
31522
  return literalSchemas[0];
31319
31523
  }
31320
- return z24.union([literalSchemas[0], literalSchemas[1], ...literalSchemas.slice(2)]);
31524
+ return z25.union([literalSchemas[0], literalSchemas[1], ...literalSchemas.slice(2)]);
31321
31525
  }
31322
31526
  if (schema.const !== void 0) {
31323
- return z24.literal(schema.const);
31527
+ return z25.literal(schema.const);
31324
31528
  }
31325
31529
  const type = schema.type;
31326
31530
  if (Array.isArray(type)) {
@@ -31329,68 +31533,68 @@ function convertBaseSchema(schema, ctx) {
31329
31533
  return convertBaseSchema(typeSchema, ctx);
31330
31534
  });
31331
31535
  if (typeSchemas.length === 0) {
31332
- return z24.never();
31536
+ return z25.never();
31333
31537
  }
31334
31538
  if (typeSchemas.length === 1) {
31335
31539
  return typeSchemas[0];
31336
31540
  }
31337
- return z24.union(typeSchemas);
31541
+ return z25.union(typeSchemas);
31338
31542
  }
31339
31543
  if (!type) {
31340
- return z24.any();
31544
+ return z25.any();
31341
31545
  }
31342
31546
  let zodSchema2;
31343
31547
  switch (type) {
31344
31548
  case "string": {
31345
- let stringSchema = z24.string();
31549
+ let stringSchema = z25.string();
31346
31550
  if (schema.format) {
31347
31551
  const format = schema.format;
31348
31552
  if (format === "email") {
31349
- stringSchema = stringSchema.check(z24.email());
31553
+ stringSchema = stringSchema.check(z25.email());
31350
31554
  } else if (format === "uri" || format === "uri-reference") {
31351
- stringSchema = stringSchema.check(z24.url());
31555
+ stringSchema = stringSchema.check(z25.url());
31352
31556
  } else if (format === "uuid" || format === "guid") {
31353
- stringSchema = stringSchema.check(z24.uuid());
31557
+ stringSchema = stringSchema.check(z25.uuid());
31354
31558
  } else if (format === "date-time") {
31355
- stringSchema = stringSchema.check(z24.iso.datetime());
31559
+ stringSchema = stringSchema.check(z25.iso.datetime());
31356
31560
  } else if (format === "date") {
31357
- stringSchema = stringSchema.check(z24.iso.date());
31561
+ stringSchema = stringSchema.check(z25.iso.date());
31358
31562
  } else if (format === "time") {
31359
- stringSchema = stringSchema.check(z24.iso.time());
31563
+ stringSchema = stringSchema.check(z25.iso.time());
31360
31564
  } else if (format === "duration") {
31361
- stringSchema = stringSchema.check(z24.iso.duration());
31565
+ stringSchema = stringSchema.check(z25.iso.duration());
31362
31566
  } else if (format === "ipv4") {
31363
- stringSchema = stringSchema.check(z24.ipv4());
31567
+ stringSchema = stringSchema.check(z25.ipv4());
31364
31568
  } else if (format === "ipv6") {
31365
- stringSchema = stringSchema.check(z24.ipv6());
31569
+ stringSchema = stringSchema.check(z25.ipv6());
31366
31570
  } else if (format === "mac") {
31367
- stringSchema = stringSchema.check(z24.mac());
31571
+ stringSchema = stringSchema.check(z25.mac());
31368
31572
  } else if (format === "cidr") {
31369
- stringSchema = stringSchema.check(z24.cidrv4());
31573
+ stringSchema = stringSchema.check(z25.cidrv4());
31370
31574
  } else if (format === "cidr-v6") {
31371
- stringSchema = stringSchema.check(z24.cidrv6());
31575
+ stringSchema = stringSchema.check(z25.cidrv6());
31372
31576
  } else if (format === "base64") {
31373
- stringSchema = stringSchema.check(z24.base64());
31577
+ stringSchema = stringSchema.check(z25.base64());
31374
31578
  } else if (format === "base64url") {
31375
- stringSchema = stringSchema.check(z24.base64url());
31579
+ stringSchema = stringSchema.check(z25.base64url());
31376
31580
  } else if (format === "e164") {
31377
- stringSchema = stringSchema.check(z24.e164());
31581
+ stringSchema = stringSchema.check(z25.e164());
31378
31582
  } else if (format === "jwt") {
31379
- stringSchema = stringSchema.check(z24.jwt());
31583
+ stringSchema = stringSchema.check(z25.jwt());
31380
31584
  } else if (format === "emoji") {
31381
- stringSchema = stringSchema.check(z24.emoji());
31585
+ stringSchema = stringSchema.check(z25.emoji());
31382
31586
  } else if (format === "nanoid") {
31383
- stringSchema = stringSchema.check(z24.nanoid());
31587
+ stringSchema = stringSchema.check(z25.nanoid());
31384
31588
  } else if (format === "cuid") {
31385
- stringSchema = stringSchema.check(z24.cuid());
31589
+ stringSchema = stringSchema.check(z25.cuid());
31386
31590
  } else if (format === "cuid2") {
31387
- stringSchema = stringSchema.check(z24.cuid2());
31591
+ stringSchema = stringSchema.check(z25.cuid2());
31388
31592
  } else if (format === "ulid") {
31389
- stringSchema = stringSchema.check(z24.ulid());
31593
+ stringSchema = stringSchema.check(z25.ulid());
31390
31594
  } else if (format === "xid") {
31391
- stringSchema = stringSchema.check(z24.xid());
31595
+ stringSchema = stringSchema.check(z25.xid());
31392
31596
  } else if (format === "ksuid") {
31393
- stringSchema = stringSchema.check(z24.ksuid());
31597
+ stringSchema = stringSchema.check(z25.ksuid());
31394
31598
  }
31395
31599
  }
31396
31600
  if (typeof schema.minLength === "number") {
@@ -31407,7 +31611,7 @@ function convertBaseSchema(schema, ctx) {
31407
31611
  }
31408
31612
  case "number":
31409
31613
  case "integer": {
31410
- let numberSchema = type === "integer" ? z24.number().int() : z24.number();
31614
+ let numberSchema = type === "integer" ? z25.number().int() : z25.number();
31411
31615
  if (typeof schema.minimum === "number") {
31412
31616
  numberSchema = numberSchema.min(schema.minimum);
31413
31617
  }
@@ -31431,11 +31635,11 @@ function convertBaseSchema(schema, ctx) {
31431
31635
  break;
31432
31636
  }
31433
31637
  case "boolean": {
31434
- zodSchema2 = z24.boolean();
31638
+ zodSchema2 = z25.boolean();
31435
31639
  break;
31436
31640
  }
31437
31641
  case "null": {
31438
- zodSchema2 = z24.null();
31642
+ zodSchema2 = z25.null();
31439
31643
  break;
31440
31644
  }
31441
31645
  case "object": {
@@ -31448,14 +31652,14 @@ function convertBaseSchema(schema, ctx) {
31448
31652
  }
31449
31653
  if (schema.propertyNames) {
31450
31654
  const keySchema = convertSchema(schema.propertyNames, ctx);
31451
- const valueSchema = schema.additionalProperties && typeof schema.additionalProperties === "object" ? convertSchema(schema.additionalProperties, ctx) : z24.any();
31655
+ const valueSchema = schema.additionalProperties && typeof schema.additionalProperties === "object" ? convertSchema(schema.additionalProperties, ctx) : z25.any();
31452
31656
  if (Object.keys(shape).length === 0) {
31453
- zodSchema2 = z24.record(keySchema, valueSchema);
31657
+ zodSchema2 = z25.record(keySchema, valueSchema);
31454
31658
  break;
31455
31659
  }
31456
- const objectSchema2 = z24.object(shape).passthrough();
31457
- const recordSchema = z24.looseRecord(keySchema, valueSchema);
31458
- zodSchema2 = z24.intersection(objectSchema2, recordSchema);
31660
+ const objectSchema2 = z25.object(shape).passthrough();
31661
+ const recordSchema = z25.looseRecord(keySchema, valueSchema);
31662
+ zodSchema2 = z25.intersection(objectSchema2, recordSchema);
31459
31663
  break;
31460
31664
  }
31461
31665
  if (schema.patternProperties) {
@@ -31464,28 +31668,28 @@ function convertBaseSchema(schema, ctx) {
31464
31668
  const looseRecords = [];
31465
31669
  for (const pattern of patternKeys) {
31466
31670
  const patternValue = convertSchema(patternProps[pattern], ctx);
31467
- const keySchema = z24.string().regex(new RegExp(pattern));
31468
- looseRecords.push(z24.looseRecord(keySchema, patternValue));
31671
+ const keySchema = z25.string().regex(new RegExp(pattern));
31672
+ looseRecords.push(z25.looseRecord(keySchema, patternValue));
31469
31673
  }
31470
31674
  const schemasToIntersect = [];
31471
31675
  if (Object.keys(shape).length > 0) {
31472
- schemasToIntersect.push(z24.object(shape).passthrough());
31676
+ schemasToIntersect.push(z25.object(shape).passthrough());
31473
31677
  }
31474
31678
  schemasToIntersect.push(...looseRecords);
31475
31679
  if (schemasToIntersect.length === 0) {
31476
- zodSchema2 = z24.object({}).passthrough();
31680
+ zodSchema2 = z25.object({}).passthrough();
31477
31681
  } else if (schemasToIntersect.length === 1) {
31478
31682
  zodSchema2 = schemasToIntersect[0];
31479
31683
  } else {
31480
- let result = z24.intersection(schemasToIntersect[0], schemasToIntersect[1]);
31684
+ let result = z25.intersection(schemasToIntersect[0], schemasToIntersect[1]);
31481
31685
  for (let i = 2; i < schemasToIntersect.length; i++) {
31482
- result = z24.intersection(result, schemasToIntersect[i]);
31686
+ result = z25.intersection(result, schemasToIntersect[i]);
31483
31687
  }
31484
31688
  zodSchema2 = result;
31485
31689
  }
31486
31690
  break;
31487
31691
  }
31488
- const objectSchema = z24.object(shape);
31692
+ const objectSchema = z25.object(shape);
31489
31693
  if (schema.additionalProperties === false) {
31490
31694
  zodSchema2 = objectSchema.strict();
31491
31695
  } else if (typeof schema.additionalProperties === "object") {
@@ -31502,33 +31706,33 @@ function convertBaseSchema(schema, ctx) {
31502
31706
  const tupleItems = prefixItems.map((item) => convertSchema(item, ctx));
31503
31707
  const rest = items && typeof items === "object" && !Array.isArray(items) ? convertSchema(items, ctx) : void 0;
31504
31708
  if (rest) {
31505
- zodSchema2 = z24.tuple(tupleItems).rest(rest);
31709
+ zodSchema2 = z25.tuple(tupleItems).rest(rest);
31506
31710
  } else {
31507
- zodSchema2 = z24.tuple(tupleItems);
31711
+ zodSchema2 = z25.tuple(tupleItems);
31508
31712
  }
31509
31713
  if (typeof schema.minItems === "number") {
31510
- zodSchema2 = zodSchema2.check(z24.minLength(schema.minItems));
31714
+ zodSchema2 = zodSchema2.check(z25.minLength(schema.minItems));
31511
31715
  }
31512
31716
  if (typeof schema.maxItems === "number") {
31513
- zodSchema2 = zodSchema2.check(z24.maxLength(schema.maxItems));
31717
+ zodSchema2 = zodSchema2.check(z25.maxLength(schema.maxItems));
31514
31718
  }
31515
31719
  } else if (Array.isArray(items)) {
31516
31720
  const tupleItems = items.map((item) => convertSchema(item, ctx));
31517
31721
  const rest = schema.additionalItems && typeof schema.additionalItems === "object" ? convertSchema(schema.additionalItems, ctx) : void 0;
31518
31722
  if (rest) {
31519
- zodSchema2 = z24.tuple(tupleItems).rest(rest);
31723
+ zodSchema2 = z25.tuple(tupleItems).rest(rest);
31520
31724
  } else {
31521
- zodSchema2 = z24.tuple(tupleItems);
31725
+ zodSchema2 = z25.tuple(tupleItems);
31522
31726
  }
31523
31727
  if (typeof schema.minItems === "number") {
31524
- zodSchema2 = zodSchema2.check(z24.minLength(schema.minItems));
31728
+ zodSchema2 = zodSchema2.check(z25.minLength(schema.minItems));
31525
31729
  }
31526
31730
  if (typeof schema.maxItems === "number") {
31527
- zodSchema2 = zodSchema2.check(z24.maxLength(schema.maxItems));
31731
+ zodSchema2 = zodSchema2.check(z25.maxLength(schema.maxItems));
31528
31732
  }
31529
31733
  } else if (items !== void 0) {
31530
31734
  const element = convertSchema(items, ctx);
31531
- let arraySchema = z24.array(element);
31735
+ let arraySchema = z25.array(element);
31532
31736
  if (typeof schema.minItems === "number") {
31533
31737
  arraySchema = arraySchema.min(schema.minItems);
31534
31738
  }
@@ -31537,7 +31741,7 @@ function convertBaseSchema(schema, ctx) {
31537
31741
  }
31538
31742
  zodSchema2 = arraySchema;
31539
31743
  } else {
31540
- zodSchema2 = z24.array(z24.any());
31744
+ zodSchema2 = z25.array(z25.any());
31541
31745
  }
31542
31746
  break;
31543
31747
  }
@@ -31554,37 +31758,37 @@ function convertBaseSchema(schema, ctx) {
31554
31758
  }
31555
31759
  function convertSchema(schema, ctx) {
31556
31760
  if (typeof schema === "boolean") {
31557
- return schema ? z24.any() : z24.never();
31761
+ return schema ? z25.any() : z25.never();
31558
31762
  }
31559
31763
  let baseSchema = convertBaseSchema(schema, ctx);
31560
31764
  const hasExplicitType = schema.type || schema.enum !== void 0 || schema.const !== void 0;
31561
31765
  if (schema.anyOf && Array.isArray(schema.anyOf)) {
31562
31766
  const options = schema.anyOf.map((s) => convertSchema(s, ctx));
31563
- const anyOfUnion = z24.union(options);
31564
- baseSchema = hasExplicitType ? z24.intersection(baseSchema, anyOfUnion) : anyOfUnion;
31767
+ const anyOfUnion = z25.union(options);
31768
+ baseSchema = hasExplicitType ? z25.intersection(baseSchema, anyOfUnion) : anyOfUnion;
31565
31769
  }
31566
31770
  if (schema.oneOf && Array.isArray(schema.oneOf)) {
31567
31771
  const options = schema.oneOf.map((s) => convertSchema(s, ctx));
31568
- const oneOfUnion = z24.xor(options);
31569
- baseSchema = hasExplicitType ? z24.intersection(baseSchema, oneOfUnion) : oneOfUnion;
31772
+ const oneOfUnion = z25.xor(options);
31773
+ baseSchema = hasExplicitType ? z25.intersection(baseSchema, oneOfUnion) : oneOfUnion;
31570
31774
  }
31571
31775
  if (schema.allOf && Array.isArray(schema.allOf)) {
31572
31776
  if (schema.allOf.length === 0) {
31573
- baseSchema = hasExplicitType ? baseSchema : z24.any();
31777
+ baseSchema = hasExplicitType ? baseSchema : z25.any();
31574
31778
  } else {
31575
31779
  let result = hasExplicitType ? baseSchema : convertSchema(schema.allOf[0], ctx);
31576
31780
  const startIdx = hasExplicitType ? 0 : 1;
31577
31781
  for (let i = startIdx; i < schema.allOf.length; i++) {
31578
- result = z24.intersection(result, convertSchema(schema.allOf[i], ctx));
31782
+ result = z25.intersection(result, convertSchema(schema.allOf[i], ctx));
31579
31783
  }
31580
31784
  baseSchema = result;
31581
31785
  }
31582
31786
  }
31583
31787
  if (schema.nullable === true && ctx.version === "openapi-3.0") {
31584
- baseSchema = z24.nullable(baseSchema);
31788
+ baseSchema = z25.nullable(baseSchema);
31585
31789
  }
31586
31790
  if (schema.readOnly === true) {
31587
- baseSchema = z24.readonly(baseSchema);
31791
+ baseSchema = z25.readonly(baseSchema);
31588
31792
  }
31589
31793
  const extraMeta = {};
31590
31794
  const coreMetadataKeys = ["$id", "id", "$comment", "$anchor", "$vocabulary", "$dynamicRef", "$dynamicAnchor"];
@@ -31611,7 +31815,7 @@ function convertSchema(schema, ctx) {
31611
31815
  }
31612
31816
  function fromJSONSchema(schema, params) {
31613
31817
  if (typeof schema === "boolean") {
31614
- return schema ? z24.any() : z24.never();
31818
+ return schema ? z25.any() : z25.never();
31615
31819
  }
31616
31820
  const version2 = detectVersion(schema, params?.defaultTarget);
31617
31821
  const defs = schema.$defs || schema.definitions || {};
@@ -31625,14 +31829,14 @@ function fromJSONSchema(schema, params) {
31625
31829
  };
31626
31830
  return convertSchema(schema, ctx);
31627
31831
  }
31628
- var z24, RECOGNIZED_KEYS;
31832
+ var z25, RECOGNIZED_KEYS;
31629
31833
  var init_from_json_schema = __esm({
31630
31834
  "node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/classic/from-json-schema.js"() {
31631
31835
  init_registries();
31632
31836
  init_checks2();
31633
31837
  init_iso();
31634
31838
  init_schemas2();
31635
- z24 = {
31839
+ z25 = {
31636
31840
  ...schemas_exports2,
31637
31841
  ...checks_exports2,
31638
31842
  iso: iso_exports
@@ -43141,7 +43345,7 @@ var init_spawn = __esm({
43141
43345
  *
43142
43346
  * Uses 3-tier key resolution so the provider works with:
43143
43347
  * - `ANTHROPIC_API_KEY` environment variable (explicit)
43144
- * - `~/.local/share/cleo/anthropic-key` (user-stored via cleo config)
43348
+ * - `<getCleoHome()>/anthropic-key` (user-stored via cleo config)
43145
43349
  * - Claude Code OAuth token (zero-config for Claude Code users)
43146
43350
  *
43147
43351
  * @returns `true` when any Anthropic credential is available
@@ -43272,10 +43476,10 @@ var init_spawn = __esm({
43272
43476
  });
43273
43477
 
43274
43478
  // packages/adapters/src/providers/claude-code/paths.ts
43275
- import { homedir as homedir3 } from "node:os";
43479
+ import { homedir as homedir2 } from "node:os";
43276
43480
  import { join as join3 } from "node:path";
43277
43481
  function claudeSettingsPath() {
43278
- return new ClaudeCodePathProvider().getSettingsPath() ?? join3(homedir3(), ".claude", "settings.json");
43482
+ return new ClaudeCodePathProvider().getSettingsPath() ?? join3(homedir2(), ".claude", "settings.json");
43279
43483
  }
43280
43484
  function isPlainObject2(value) {
43281
43485
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -43327,7 +43531,7 @@ var init_paths = __esm({
43327
43531
  ClaudeCodePathProvider = class {
43328
43532
  /** Get the provider's root configuration directory. */
43329
43533
  getProviderDir() {
43330
- return process.env["CLAUDE_HOME"] ?? join3(homedir3(), ".claude");
43534
+ return process.env["CLAUDE_HOME"] ?? join3(homedir2(), ".claude");
43331
43535
  }
43332
43536
  /** Get the path to the provider's settings file, or null if unavailable. */
43333
43537
  getSettingsPath() {
@@ -43339,7 +43543,7 @@ var init_paths = __esm({
43339
43543
  }
43340
43544
  /** Get the path to the provider's memory database, or null if unsupported. */
43341
43545
  getMemoryDbPath() {
43342
- return process.env["CLAUDE_MEM_DB"] ?? join3(homedir3(), ".claude-mem", "claude-mem.db");
43546
+ return process.env["CLAUDE_MEM_DB"] ?? join3(homedir2(), ".claude-mem", "claude-mem.db");
43343
43547
  }
43344
43548
  };
43345
43549
  CLEO_HOOK_MARKER = "# cleo-hook";
@@ -43349,7 +43553,7 @@ var init_paths = __esm({
43349
43553
  // packages/adapters/src/providers/claude-code/context-monitor.ts
43350
43554
  import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync } from "node:fs";
43351
43555
  import { mkdir } from "node:fs/promises";
43352
- import { homedir as homedir4 } from "node:os";
43556
+ import { homedir as homedir3 } from "node:os";
43353
43557
  import { dirname, join as join4 } from "node:path";
43354
43558
  import { resolveLegacyCleoDir } from "@cleocode/paths";
43355
43559
  function getContextStatusFromPercentage(percentage) {
@@ -43435,7 +43639,7 @@ var init_context_monitor = __esm({
43435
43639
  if (cmd.includes("context-monitor.sh") || cmd.includes("cleo-statusline") || cmd.includes(".context-state.json") || cmd.includes("context-states")) {
43436
43640
  return "configured";
43437
43641
  }
43438
- const scriptPath = cmd.startsWith("~") ? cmd.replace("~", homedir4()) : cmd;
43642
+ const scriptPath = cmd.startsWith("~") ? cmd.replace("~", homedir3()) : cmd;
43439
43643
  if (existsSync3(scriptPath)) {
43440
43644
  try {
43441
43645
  const content = readFileSync3(scriptPath, "utf-8");
@@ -43884,12 +44088,12 @@ var init_hook_template_installer = __esm({
43884
44088
 
43885
44089
  // packages/adapters/src/providers/claude-code/install.ts
43886
44090
  import { copyFileSync as copyFileSync2, existsSync as existsSync6, mkdirSync as mkdirSync2, readdirSync as readdirSync2, readFileSync as readFileSync4 } from "node:fs";
43887
- import { homedir as homedir5 } from "node:os";
44091
+ import { homedir as homedir4 } from "node:os";
43888
44092
  import { dirname as dirname3, join as join7 } from "node:path";
43889
44093
  import { fileURLToPath as fileURLToPath2 } from "node:url";
43890
44094
  import { ensureProviderInstructionFile, updateJsonConfigFile as updateJsonConfigFile2 } from "@cleocode/caamp";
43891
44095
  function getClaudeConfigDir() {
43892
- return process.env["CLAUDE_HOME"] ?? join7(homedir5(), ".claude");
44096
+ return process.env["CLAUDE_HOME"] ?? join7(homedir4(), ".claude");
43893
44097
  }
43894
44098
  function getAdapterCommandsDir() {
43895
44099
  const thisDir = dirname3(fileURLToPath2(import.meta.url));
@@ -44116,6 +44320,7 @@ var init_install = __esm({
44116
44320
  // packages/adapters/src/providers/shared/agent-spawn-wrapper.ts
44117
44321
  import { spawnSync } from "node:child_process";
44118
44322
  import { readFileSync as readFileSync5 } from "node:fs";
44323
+ import { resolveSpawnInvocation } from "@cleocode/paths";
44119
44324
  function hasSystemdRun() {
44120
44325
  if (_systemdRunAvailable !== void 0) return _systemdRunAvailable;
44121
44326
  if (process.platform !== "linux") {
@@ -44138,12 +44343,21 @@ function readMemTotalBytes() {
44138
44343
  }
44139
44344
  function buildAgentSpawnArgs(command, args, scopeId) {
44140
44345
  if (!hasSystemdRun()) {
44141
- if (!_demotionLogged) {
44346
+ if (!_demotionLogged && process.platform === "linux" && process.env["CLEO_DEBUG"]) {
44142
44347
  _demotionLogged = true;
44143
44348
  process.stderr.write(
44144
44349
  "[cleo:agent-spawn-wrapper] systemd-run unavailable \u2014 falling back to plain pgid (detached) spawn; no cgroup containment\n"
44145
44350
  );
44146
44351
  }
44352
+ if (process.platform === "win32") {
44353
+ const inv = resolveSpawnInvocation(command, args);
44354
+ return {
44355
+ command: inv.file,
44356
+ args: inv.args,
44357
+ ...inv.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {},
44358
+ ownership: { mode: "pgid" }
44359
+ };
44360
+ }
44147
44361
  return {
44148
44362
  command: "sh",
44149
44363
  args: ["-c", 'ulimit -c 0; exec "$@"', "sh", command, ...args],
@@ -44201,6 +44415,25 @@ var init_agent_spawn_wrapper = __esm({
44201
44415
  }
44202
44416
  });
44203
44417
 
44418
+ // packages/adapters/src/providers/shared/prompt-file.ts
44419
+ import { mkdtemp, rm, writeFile } from "node:fs/promises";
44420
+ import { tmpdir } from "node:os";
44421
+ import { dirname as dirname4, join as join8 } from "node:path";
44422
+ async function writeSpawnPromptFile(prefix, prompt) {
44423
+ const dir = await mkdtemp(join8(tmpdir(), `cleo-${prefix}-`));
44424
+ const file2 = join8(dir, "prompt.txt");
44425
+ await writeFile(file2, prompt, "utf-8");
44426
+ return file2;
44427
+ }
44428
+ async function removeSpawnPromptFile(file2) {
44429
+ await rm(dirname4(file2), { recursive: true, force: true }).catch(() => void 0);
44430
+ }
44431
+ var init_prompt_file = __esm({
44432
+ "packages/adapters/src/providers/shared/prompt-file.ts"() {
44433
+ "use strict";
44434
+ }
44435
+ });
44436
+
44204
44437
  // packages/adapters/src/providers/claude-code/suite-reaper.ts
44205
44438
  import { spawnSync as spawnSync2 } from "node:child_process";
44206
44439
  async function reapAgentSuite(ownership) {
@@ -44296,32 +44529,26 @@ var init_suite_reaper = __esm({
44296
44529
  });
44297
44530
 
44298
44531
  // packages/adapters/src/providers/claude-code/spawn.ts
44299
- import { exec, spawn as nodeSpawn } from "node:child_process";
44300
- import { unlink, writeFile } from "node:fs/promises";
44301
- import { promisify as promisify2 } from "node:util";
44302
- var execAsync, ClaudeCodeSpawnProvider;
44532
+ import { spawn as nodeSpawn } from "node:child_process";
44533
+ import { findOnPath } from "@cleocode/paths";
44534
+ var ClaudeCodeSpawnProvider;
44303
44535
  var init_spawn2 = __esm({
44304
44536
  "packages/adapters/src/providers/claude-code/spawn.ts"() {
44305
44537
  "use strict";
44306
44538
  init_src();
44307
44539
  init_agent_spawn_wrapper();
44540
+ init_prompt_file();
44308
44541
  init_suite_reaper();
44309
- execAsync = promisify2(exec);
44310
44542
  ClaudeCodeSpawnProvider = class {
44311
44543
  /** Map of instance IDs to tracked process info. */
44312
44544
  processMap = /* @__PURE__ */ new Map();
44313
44545
  /**
44314
44546
  * Check if the Claude CLI is available in PATH.
44315
44547
  *
44316
- * @returns true if `claude` is found via `which`
44548
+ * @returns true if `claude` is found on PATH (PATHEXT-aware on Windows)
44317
44549
  */
44318
44550
  async canSpawn() {
44319
- try {
44320
- await execAsync("which claude");
44321
- return true;
44322
- } catch {
44323
- return false;
44324
- }
44551
+ return findOnPath("claude") !== null;
44325
44552
  }
44326
44553
  /**
44327
44554
  * Spawn a subagent via Claude CLI.
@@ -44351,8 +44578,7 @@ var init_spawn2 = __esm({
44351
44578
  });
44352
44579
  } catch {
44353
44580
  }
44354
- tmpFile = `/tmp/claude-spawn-${instanceId}.txt`;
44355
- await writeFile(tmpFile, enrichedPrompt, "utf-8");
44581
+ tmpFile = await writeSpawnPromptFile("claude-spawn", enrichedPrompt);
44356
44582
  const claudeArgs = [
44357
44583
  "--print",
44358
44584
  "--dangerously-skip-permissions",
@@ -44364,7 +44590,9 @@ var init_spawn2 = __esm({
44364
44590
  const isSystemd = spawnBuild.ownership.mode === "systemd";
44365
44591
  const spawnOpts = {
44366
44592
  detached: !isSystemd,
44367
- stdio: ["ignore", "pipe", "pipe"]
44593
+ stdio: ["ignore", "pipe", "pipe"],
44594
+ // win32 `.cmd` shim routed through cmd.exe: keep its quoting (T12618).
44595
+ ...spawnBuild.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
44368
44596
  };
44369
44597
  if (context.workingDirectory) {
44370
44598
  spawnOpts.cwd = context.workingDirectory;
@@ -44391,10 +44619,7 @@ var init_spawn2 = __esm({
44391
44619
  const capturedTmpFile = tmpFile;
44392
44620
  child.on("exit", async () => {
44393
44621
  this.processMap.delete(instanceId);
44394
- try {
44395
- await unlink(capturedTmpFile);
44396
- } catch {
44397
- }
44622
+ await removeSpawnPromptFile(capturedTmpFile);
44398
44623
  });
44399
44624
  return {
44400
44625
  instanceId,
@@ -44409,10 +44634,7 @@ var init_spawn2 = __esm({
44409
44634
  } catch (error48) {
44410
44635
  console.error(`[ClaudeCodeSpawnProvider] Failed to spawn: ${getErrorMessage(error48)}`);
44411
44636
  if (tmpFile) {
44412
- try {
44413
- await unlink(tmpFile);
44414
- } catch {
44415
- }
44637
+ await removeSpawnPromptFile(tmpFile);
44416
44638
  }
44417
44639
  return {
44418
44640
  instanceId,
@@ -44497,7 +44719,7 @@ var init_spawn2 = __esm({
44497
44719
 
44498
44720
  // packages/adapters/src/providers/claude-code/task-sync.ts
44499
44721
  import { readFile as readFile2, stat } from "node:fs/promises";
44500
- import { join as join8 } from "node:path";
44722
+ import { join as join9 } from "node:path";
44501
44723
  function parseTaskId(content) {
44502
44724
  const match = content.match(/^\[T(\d+)\]/);
44503
44725
  return match ? `T${match[1]}` : null;
@@ -44518,7 +44740,7 @@ function mapStatus(twStatus) {
44518
44740
  }
44519
44741
  }
44520
44742
  function getTodoWriteFilePath(projectDir) {
44521
- return join8(projectDir, ".cleo", "sync", "todowrite-state.json");
44743
+ return join9(projectDir, ".cleo", "sync", "todowrite-state.json");
44522
44744
  }
44523
44745
  var ClaudeCodeTaskSyncProvider;
44524
44746
  var init_task_sync = __esm({
@@ -44589,12 +44811,11 @@ var init_transport = __esm({
44589
44811
  });
44590
44812
 
44591
44813
  // packages/adapters/src/providers/claude-code/adapter.ts
44592
- import { exec as exec2 } from "node:child_process";
44593
44814
  import { existsSync as existsSync7 } from "node:fs";
44594
- import { homedir as homedir6 } from "node:os";
44595
- import { join as join9 } from "node:path";
44596
- import { promisify as promisify3 } from "node:util";
44597
- var execAsync2, ClaudeCodeAdapter;
44815
+ import { homedir as homedir5 } from "node:os";
44816
+ import { join as join10 } from "node:path";
44817
+ import { findOnPath as findOnPath2 } from "@cleocode/paths";
44818
+ var ClaudeCodeAdapter;
44598
44819
  var init_adapter = __esm({
44599
44820
  "packages/adapters/src/providers/claude-code/adapter.ts"() {
44600
44821
  "use strict";
@@ -44606,7 +44827,6 @@ var init_adapter = __esm({
44606
44827
  init_spawn2();
44607
44828
  init_task_sync();
44608
44829
  init_transport();
44609
- execAsync2 = promisify3(exec2);
44610
44830
  ClaudeCodeAdapter = class {
44611
44831
  /** Unique provider identifier. */
44612
44832
  id = "claude-code";
@@ -44742,14 +44962,11 @@ var init_adapter = __esm({
44742
44962
  };
44743
44963
  }
44744
44964
  let cliAvailable = false;
44745
- try {
44746
- const { stdout } = await execAsync2("which claude");
44747
- cliAvailable = stdout.trim().length > 0;
44748
- details.cliPath = stdout.trim();
44749
- } catch {
44750
- details.cliAvailable = false;
44751
- }
44752
- const claudeConfigDir = join9(homedir6(), ".claude");
44965
+ const resolvedCli = findOnPath2("claude");
44966
+ cliAvailable = resolvedCli !== null;
44967
+ if (resolvedCli) details.cliPath = resolvedCli;
44968
+ else details.cliAvailable = false;
44969
+ const claudeConfigDir = join10(homedir5(), ".claude");
44753
44970
  const configExists = existsSync7(claudeConfigDir);
44754
44971
  details.configDirExists = configExists;
44755
44972
  const entrypointSet = process.env.CLAUDE_CODE_ENTRYPOINT !== void 0;
@@ -44780,10 +44997,10 @@ var init_adapter = __esm({
44780
44997
 
44781
44998
  // packages/adapters/src/providers/claude-code/statusline.ts
44782
44999
  import { existsSync as existsSync8, readFileSync as readFileSync6 } from "node:fs";
44783
- import { homedir as homedir7 } from "node:os";
44784
- import { join as join10 } from "node:path";
45000
+ import { homedir as homedir6 } from "node:os";
45001
+ import { join as join11 } from "node:path";
44785
45002
  function getClaudeSettingsPath() {
44786
- return process.env["CLAUDE_SETTINGS"] ?? join10(process.env["CLAUDE_HOME"] ?? join10(homedir7(), ".claude"), "settings.json");
45003
+ return process.env["CLAUDE_SETTINGS"] ?? join11(process.env["CLAUDE_HOME"] ?? join11(homedir6(), ".claude"), "settings.json");
44787
45004
  }
44788
45005
  function checkStatuslineIntegration() {
44789
45006
  const settingsPath = getClaudeSettingsPath();
@@ -44797,7 +45014,7 @@ function checkStatuslineIntegration() {
44797
45014
  if (cmd.includes("context-monitor.sh") || cmd.includes("cleo-statusline") || cmd.includes(".context-state.json") || cmd.includes("context-states")) {
44798
45015
  return "configured";
44799
45016
  }
44800
- const scriptPath = cmd.startsWith("~") ? cmd.replace("~", homedir7()) : cmd;
45017
+ const scriptPath = cmd.startsWith("~") ? cmd.replace("~", homedir6()) : cmd;
44801
45018
  if (existsSync8(scriptPath)) {
44802
45019
  try {
44803
45020
  const content = readFileSync6(scriptPath, "utf-8");
@@ -44814,7 +45031,7 @@ function getStatuslineConfig(cleoHome) {
44814
45031
  return {
44815
45032
  statusLine: {
44816
45033
  type: "command",
44817
- command: join10(cleoHome, "lib", "session", "context-monitor.sh")
45034
+ command: join11(cleoHome, "lib", "session", "context-monitor.sh")
44818
45035
  }
44819
45036
  };
44820
45037
  }
@@ -44879,6 +45096,23 @@ var init_paths2 = __esm({
44879
45096
  }
44880
45097
  });
44881
45098
 
45099
+ // packages/adapters/src/providers/shared/cli-spawn.ts
45100
+ import { spawn } from "node:child_process";
45101
+ import { resolveSpawnInvocation as resolveSpawnInvocation2 } from "@cleocode/paths";
45102
+ function spawnCli(command, args, options) {
45103
+ const inv = resolveSpawnInvocation2(command, args);
45104
+ return spawn(
45105
+ inv.file,
45106
+ inv.args,
45107
+ inv.windowsVerbatimArguments ? { ...options, windowsVerbatimArguments: true } : options
45108
+ );
45109
+ }
45110
+ var init_cli_spawn = __esm({
45111
+ "packages/adapters/src/providers/shared/cli-spawn.ts"() {
45112
+ "use strict";
45113
+ }
45114
+ });
45115
+
44882
45116
  // packages/adapters/src/providers/cursor/hooks.ts
44883
45117
  var PROVIDER_ID2, CURSOR_EVENT_MAP, CursorHookProvider;
44884
45118
  var init_hooks2 = __esm({
@@ -45034,7 +45268,7 @@ var init_hooks2 = __esm({
45034
45268
 
45035
45269
  // packages/adapters/src/providers/cursor/install.ts
45036
45270
  import { existsSync as existsSync11, readFileSync as readFileSync7 } from "node:fs";
45037
- import { join as join16 } from "node:path";
45271
+ import { join as join17 } from "node:path";
45038
45272
  import {
45039
45273
  ensureProviderInstructionFile as ensureProviderInstructionFile3,
45040
45274
  ensureProviderRuleFile,
@@ -45105,11 +45339,11 @@ var init_install2 = __esm({
45105
45339
  * Checks for .cursor/rules/cleo.mdc or .cursorrules with CLEO references.
45106
45340
  */
45107
45341
  async isInstalled() {
45108
- const mdcPath = join16(process.cwd(), ".cursor", "rules", "cleo.mdc");
45342
+ const mdcPath = join17(process.cwd(), ".cursor", "rules", "cleo.mdc");
45109
45343
  if (existsSync11(mdcPath)) {
45110
45344
  return true;
45111
45345
  }
45112
- const rulesPath = join16(process.cwd(), ".cursorrules");
45346
+ const rulesPath = join17(process.cwd(), ".cursorrules");
45113
45347
  if (existsSync11(rulesPath)) {
45114
45348
  try {
45115
45349
  const content = readFileSync7(rulesPath, "utf-8");
@@ -45157,7 +45391,7 @@ var init_install2 = __esm({
45157
45391
  onlyIfExists: true
45158
45392
  }),
45159
45393
  await ensureProviderRuleFile("cursor", projectDir, {
45160
- relativePath: join16(".cursor", "rules", "cleo.mdc"),
45394
+ relativePath: join17(".cursor", "rules", "cleo.mdc"),
45161
45395
  preamble: CLEO_MDC_FRONTMATTER
45162
45396
  })
45163
45397
  ];
@@ -45168,10 +45402,10 @@ var init_install2 = __esm({
45168
45402
  */
45169
45403
  getUpdatedFileList(projectDir) {
45170
45404
  const files = [];
45171
- if (existsSync11(join16(projectDir, ".cursorrules"))) {
45172
- files.push(join16(projectDir, ".cursorrules"));
45405
+ if (existsSync11(join17(projectDir, ".cursorrules"))) {
45406
+ files.push(join17(projectDir, ".cursorrules"));
45173
45407
  }
45174
- files.push(join16(projectDir, ".cursor", "rules", "cleo.mdc"));
45408
+ files.push(join17(projectDir, ".cursor", "rules", "cleo.mdc"));
45175
45409
  return files;
45176
45410
  }
45177
45411
  /**
@@ -45193,7 +45427,7 @@ var init_install2 = __esm({
45193
45427
  * @task T1013
45194
45428
  */
45195
45429
  async installHookTemplates(projectDir) {
45196
- const hooksDir = join16(projectDir, ".cursor", "hooks");
45430
+ const hooksDir = join17(projectDir, ".cursor", "hooks");
45197
45431
  let templates;
45198
45432
  try {
45199
45433
  templates = installProviderHookTemplates({
@@ -45205,7 +45439,7 @@ var init_install2 = __esm({
45205
45439
  }
45206
45440
  const hooksJsonEntryAdded = await this.registerPreCompactHook(
45207
45441
  projectDir,
45208
- join16(hooksDir, "precompact.sh")
45442
+ join17(hooksDir, "precompact.sh")
45209
45443
  );
45210
45444
  if (templates.installedFiles.length === 0 && !hooksJsonEntryAdded) {
45211
45445
  return null;
@@ -45226,7 +45460,7 @@ var init_install2 = __esm({
45226
45460
  * @task T1013
45227
45461
  */
45228
45462
  async registerPreCompactHook(projectDir, shimPath) {
45229
- const hooksJsonPath = join16(projectDir, ".cursor", "hooks.json");
45463
+ const hooksJsonPath = join17(projectDir, ".cursor", "hooks.json");
45230
45464
  return updateJsonConfigFile3(hooksJsonPath, (config2) => {
45231
45465
  const hooks = config2.hooks ?? {};
45232
45466
  if (!isRecord(hooks)) {
@@ -45256,7 +45490,7 @@ var init_install2 = __esm({
45256
45490
 
45257
45491
  // packages/adapters/src/providers/cursor/adapter.ts
45258
45492
  import { existsSync as existsSync12 } from "node:fs";
45259
- import { join as join17 } from "node:path";
45493
+ import { join as join18 } from "node:path";
45260
45494
  var CursorAdapter;
45261
45495
  var init_adapter2 = __esm({
45262
45496
  "packages/adapters/src/providers/cursor/adapter.ts"() {
@@ -45350,14 +45584,14 @@ var init_adapter2 = __esm({
45350
45584
  }
45351
45585
  let configExists = false;
45352
45586
  if (this.projectDir) {
45353
- const cursorConfigDir = join17(this.projectDir, ".cursor");
45587
+ const cursorConfigDir = join18(this.projectDir, ".cursor");
45354
45588
  configExists = existsSync12(cursorConfigDir);
45355
45589
  details.configDirExists = configExists;
45356
45590
  }
45357
45591
  const editorEnvSet = process.env.CURSOR_EDITOR !== void 0;
45358
45592
  details.editorEnvSet = editorEnvSet;
45359
45593
  if (this.projectDir) {
45360
- const legacyRulesExist = existsSync12(join17(this.projectDir, ".cursorrules"));
45594
+ const legacyRulesExist = existsSync12(join18(this.projectDir, ".cursorrules"));
45361
45595
  details.legacyRulesExist = legacyRulesExist;
45362
45596
  }
45363
45597
  const healthy = configExists || editorEnvSet;
@@ -45562,7 +45796,7 @@ var init_hooks3 = __esm({
45562
45796
 
45563
45797
  // packages/adapters/src/providers/opencode/install.ts
45564
45798
  import { existsSync as existsSync17, mkdirSync as mkdirSync3, readFileSync as readFileSync10, writeFileSync as writeFileSync2 } from "node:fs";
45565
- import { join as join23 } from "node:path";
45799
+ import { join as join24 } from "node:path";
45566
45800
  import { ensureProviderInstructionFile as ensureProviderInstructionFile6 } from "@cleocode/caamp";
45567
45801
  var OpenCodeInstallProvider;
45568
45802
  var init_install3 = __esm({
@@ -45587,7 +45821,7 @@ var init_install3 = __esm({
45587
45821
  });
45588
45822
  const instructionFileUpdated = instructResult.action !== "intact";
45589
45823
  if (instructionFileUpdated) {
45590
- details.instructionFile = join23(projectDir, instructResult.instructFile);
45824
+ details.instructionFile = join24(projectDir, instructResult.instructFile);
45591
45825
  }
45592
45826
  const hookResult = this.installHookTemplates(projectDir);
45593
45827
  if (hookResult) {
@@ -45660,8 +45894,8 @@ var init_install3 = __esm({
45660
45894
  * @task T1013
45661
45895
  */
45662
45896
  installHookTemplates(projectDir) {
45663
- const pluginsDir = join23(projectDir, ".opencode", "plugins");
45664
- const hooksDir = join23(pluginsDir, "hooks");
45897
+ const pluginsDir = join24(projectDir, ".opencode", "plugins");
45898
+ const hooksDir = join24(pluginsDir, "hooks");
45665
45899
  let templates;
45666
45900
  try {
45667
45901
  templates = installProviderHookTemplates({
@@ -45673,7 +45907,7 @@ var init_install3 = __esm({
45673
45907
  }
45674
45908
  let pluginWritten = false;
45675
45909
  try {
45676
- pluginWritten = this.writePrecompactPlugin(pluginsDir, join23(hooksDir, "precompact.sh"));
45910
+ pluginWritten = this.writePrecompactPlugin(pluginsDir, join24(hooksDir, "precompact.sh"));
45677
45911
  } catch {
45678
45912
  }
45679
45913
  if (templates.installedFiles.length === 0 && !pluginWritten) {
@@ -45697,7 +45931,7 @@ var init_install3 = __esm({
45697
45931
  * @task T1013
45698
45932
  */
45699
45933
  writePrecompactPlugin(pluginsDir, shimPath) {
45700
- const pluginPath = join23(pluginsDir, "cleo-precompact.js");
45934
+ const pluginPath = join24(pluginsDir, "cleo-precompact.js");
45701
45935
  const generated = [
45702
45936
  "// CLEO PreCompact plugin for OpenCode (generated by @cleocode/adapters).",
45703
45937
  "// Bridges the canonical CAAMP `PreCompact` event",
@@ -45740,10 +45974,9 @@ var init_install3 = __esm({
45740
45974
  });
45741
45975
 
45742
45976
  // packages/adapters/src/providers/opencode/spawn.ts
45743
- import { exec as exec9, spawn as nodeSpawn4 } from "node:child_process";
45744
45977
  import { mkdir as mkdir2, readFile as readFile4, writeFile as writeFile2 } from "node:fs/promises";
45745
- import { join as join24 } from "node:path";
45746
- import { promisify as promisify10 } from "node:util";
45978
+ import { join as join25 } from "node:path";
45979
+ import { findOnPath as findOnPath9 } from "@cleocode/paths";
45747
45980
  function buildOpenCodeAgentMarkdown(description, instructions) {
45748
45981
  const normalizedDesc = description.replace(/\s+/g, " ").trim();
45749
45982
  return [
@@ -45758,8 +45991,8 @@ function buildOpenCodeAgentMarkdown(description, instructions) {
45758
45991
  ].join("\n");
45759
45992
  }
45760
45993
  async function ensureSubagentDefinition(workingDirectory, enrichedInstructions) {
45761
- const agentDir = join24(workingDirectory, ".opencode", "agent");
45762
- const agentPath = join24(agentDir, `${OPENCODE_SUBAGENT_NAME}.md`);
45994
+ const agentDir = join25(workingDirectory, ".opencode", "agent");
45995
+ const agentPath = join25(agentDir, `${OPENCODE_SUBAGENT_NAME}.md`);
45763
45996
  const description = "CLEO task executor with protocol compliance and CANT context.";
45764
45997
  const instructions = enrichedInstructions ?? [
45765
45998
  "# CLEO Subagent",
@@ -45782,12 +46015,12 @@ async function ensureSubagentDefinition(workingDirectory, enrichedInstructions)
45782
46015
  }
45783
46016
  return OPENCODE_SUBAGENT_NAME;
45784
46017
  }
45785
- var execAsync9, OPENCODE_SUBAGENT_NAME, OPENCODE_FALLBACK_AGENT, OpenCodeSpawnProvider;
46018
+ var OPENCODE_SUBAGENT_NAME, OPENCODE_FALLBACK_AGENT, OpenCodeSpawnProvider;
45786
46019
  var init_spawn3 = __esm({
45787
46020
  "packages/adapters/src/providers/opencode/spawn.ts"() {
45788
46021
  "use strict";
46022
+ init_cli_spawn();
45789
46023
  init_paths2();
45790
- execAsync9 = promisify10(exec9);
45791
46024
  OPENCODE_SUBAGENT_NAME = "cleo-subagent";
45792
46025
  OPENCODE_FALLBACK_AGENT = "general";
45793
46026
  OpenCodeSpawnProvider = class {
@@ -45796,15 +46029,10 @@ var init_spawn3 = __esm({
45796
46029
  /**
45797
46030
  * Check if the OpenCode CLI is available in PATH.
45798
46031
  *
45799
- * @returns true if `opencode` is found via `which`
46032
+ * @returns true if `opencode` is found on PATH (PATHEXT-aware on Windows)
45800
46033
  */
45801
46034
  async canSpawn() {
45802
- try {
45803
- await execAsync9("which opencode");
45804
- return true;
45805
- } catch {
45806
- return false;
45807
- }
46035
+ return findOnPath9("opencode") !== null;
45808
46036
  }
45809
46037
  /**
45810
46038
  * Spawn a subagent via OpenCode CLI.
@@ -45837,24 +46065,17 @@ var init_spawn3 = __esm({
45837
46065
  } catch {
45838
46066
  agentName = OPENCODE_FALLBACK_AGENT;
45839
46067
  }
45840
- const child = nodeSpawn4(
46068
+ const child = spawnCli(
45841
46069
  "opencode",
45842
- [
45843
- "run",
45844
- "--format",
45845
- "json",
45846
- "--agent",
45847
- agentName,
45848
- "--title",
45849
- `CLEO ${context.taskId}`,
45850
- context.prompt
45851
- ],
46070
+ ["run", "--format", "json", "--agent", agentName, "--title", `CLEO ${context.taskId}`],
45852
46071
  {
45853
46072
  cwd: workingDirectory,
45854
46073
  detached: true,
45855
- stdio: "ignore"
46074
+ stdio: ["pipe", "ignore", "ignore"]
45856
46075
  }
45857
46076
  );
46077
+ child.stdin?.on("error", () => void 0);
46078
+ child.stdin?.end(context.prompt, "utf-8");
45858
46079
  child.unref();
45859
46080
  if (child.pid) {
45860
46081
  this.processMap.set(instanceId, {
@@ -45866,6 +46087,9 @@ var init_spawn3 = __esm({
45866
46087
  child.on("exit", () => {
45867
46088
  this.processMap.delete(instanceId);
45868
46089
  });
46090
+ child.on("error", () => {
46091
+ this.processMap.delete(instanceId);
46092
+ });
45869
46093
  return {
45870
46094
  instanceId,
45871
46095
  taskId: context.taskId,
@@ -45932,18 +46156,16 @@ var init_spawn3 = __esm({
45932
46156
  });
45933
46157
 
45934
46158
  // packages/adapters/src/providers/opencode/adapter.ts
45935
- import { exec as exec10 } from "node:child_process";
45936
46159
  import { existsSync as existsSync18 } from "node:fs";
45937
- import { join as join25 } from "node:path";
45938
- import { promisify as promisify11 } from "node:util";
45939
- var execAsync10, OpenCodeAdapter;
46160
+ import { join as join26 } from "node:path";
46161
+ import { findOnPath as findOnPath10 } from "@cleocode/paths";
46162
+ var OpenCodeAdapter;
45940
46163
  var init_adapter3 = __esm({
45941
46164
  "packages/adapters/src/providers/opencode/adapter.ts"() {
45942
46165
  "use strict";
45943
46166
  init_hooks3();
45944
46167
  init_install3();
45945
46168
  init_spawn3();
45946
- execAsync10 = promisify11(exec10);
45947
46169
  OpenCodeAdapter = class {
45948
46170
  /** Unique provider identifier. */
45949
46171
  id = "opencode";
@@ -46038,15 +46260,12 @@ var init_adapter3 = __esm({
46038
46260
  };
46039
46261
  }
46040
46262
  let cliAvailable = false;
46041
- try {
46042
- const { stdout } = await execAsync10("which opencode");
46043
- cliAvailable = stdout.trim().length > 0;
46044
- details.cliPath = stdout.trim();
46045
- } catch {
46046
- details.cliAvailable = false;
46047
- }
46263
+ const resolvedCli = findOnPath10("opencode");
46264
+ cliAvailable = resolvedCli !== null;
46265
+ if (resolvedCli) details.cliPath = resolvedCli;
46266
+ else details.cliAvailable = false;
46048
46267
  if (this.projectDir) {
46049
- const openCodeConfigDir = join25(this.projectDir, ".opencode");
46268
+ const openCodeConfigDir = join26(this.projectDir, ".opencode");
46050
46269
  const configExists = existsSync18(openCodeConfigDir);
46051
46270
  details.configDirExists = configExists;
46052
46271
  }
@@ -46256,7 +46475,7 @@ var init_hooks4 = __esm({
46256
46475
  });
46257
46476
 
46258
46477
  // packages/adapters/src/providers/pi/install.ts
46259
- import { join as join26 } from "node:path";
46478
+ import { join as join27 } from "node:path";
46260
46479
  import { ensureProviderInstructionFile as ensureProviderInstructionFile7 } from "@cleocode/caamp";
46261
46480
  function getCleoReferences() {
46262
46481
  return [`@${getCleoTemplatesTildePath()}/CLEO-INJECTION.md`, "@.cleo/memory-bridge.md"];
@@ -46283,7 +46502,7 @@ var init_install4 = __esm({
46283
46502
  });
46284
46503
  const projectUpdated = projectResult.action !== "intact";
46285
46504
  if (projectUpdated) {
46286
- details.instructionFile = join26(projectDir, projectResult.instructFile);
46505
+ details.instructionFile = join27(projectDir, projectResult.instructFile);
46287
46506
  }
46288
46507
  let globalUpdated = false;
46289
46508
  try {
@@ -46354,40 +46573,30 @@ var init_install4 = __esm({
46354
46573
  });
46355
46574
 
46356
46575
  // packages/adapters/src/providers/pi/spawn.ts
46357
- import { exec as exec11, spawn as nodeSpawn5 } from "node:child_process";
46358
- import { unlink as unlink2, writeFile as writeFile3 } from "node:fs/promises";
46359
- import { promisify as promisify12 } from "node:util";
46576
+ import { findOnPath as findOnPath11 } from "@cleocode/paths";
46360
46577
  function getPiCliPath() {
46361
46578
  return process.env["PI_CLI_PATH"] ?? "pi";
46362
46579
  }
46363
- var execAsync11, PiSpawnProvider;
46580
+ var PiSpawnProvider;
46364
46581
  var init_spawn4 = __esm({
46365
46582
  "packages/adapters/src/providers/pi/spawn.ts"() {
46366
46583
  "use strict";
46367
46584
  init_src();
46368
- execAsync11 = promisify12(exec11);
46585
+ init_cli_spawn();
46586
+ init_prompt_file();
46369
46587
  PiSpawnProvider = class {
46370
46588
  /** Map of instance IDs to tracked process info. */
46371
46589
  processMap = /* @__PURE__ */ new Map();
46372
46590
  /**
46373
46591
  * Check if the Pi CLI is available.
46374
46592
  *
46375
- * Checks `PI_CLI_PATH` env var first, then tries `which pi`.
46593
+ * Checks `PI_CLI_PATH` env var first, then searches PATH for `pi`.
46376
46594
  *
46377
46595
  * @returns true if the Pi CLI is accessible
46378
46596
  */
46379
46597
  async canSpawn() {
46380
46598
  const cliPath = getPiCliPath();
46381
- try {
46382
- if (cliPath !== "pi") {
46383
- const { stdout } = await execAsync11(`test -x "${cliPath}" && echo ok`);
46384
- return stdout.trim() === "ok";
46385
- }
46386
- await execAsync11("which pi");
46387
- return true;
46388
- } catch {
46389
- return false;
46390
- }
46599
+ return findOnPath11(cliPath) !== null;
46391
46600
  }
46392
46601
  /**
46393
46602
  * Spawn a subagent via Pi CLI.
@@ -46403,8 +46612,7 @@ var init_spawn4 = __esm({
46403
46612
  const startTime = (/* @__PURE__ */ new Date()).toISOString();
46404
46613
  let tmpFile;
46405
46614
  try {
46406
- tmpFile = `/tmp/pi-spawn-${instanceId}.txt`;
46407
- await writeFile3(tmpFile, context.prompt, "utf-8");
46615
+ tmpFile = await writeSpawnPromptFile("pi-spawn", context.prompt);
46408
46616
  const cliPath = getPiCliPath();
46409
46617
  const args = [tmpFile];
46410
46618
  const spawnOpts = {
@@ -46414,7 +46622,7 @@ var init_spawn4 = __esm({
46414
46622
  if (context.workingDirectory) {
46415
46623
  spawnOpts.cwd = context.workingDirectory;
46416
46624
  }
46417
- const child = nodeSpawn5(cliPath, args, spawnOpts);
46625
+ const child = spawnCli(cliPath, args, spawnOpts);
46418
46626
  child.unref();
46419
46627
  if (child.pid) {
46420
46628
  this.processMap.set(instanceId, {
@@ -46426,10 +46634,7 @@ var init_spawn4 = __esm({
46426
46634
  const capturedTmpFile = tmpFile;
46427
46635
  child.on("exit", async () => {
46428
46636
  this.processMap.delete(instanceId);
46429
- try {
46430
- await unlink2(capturedTmpFile);
46431
- } catch {
46432
- }
46637
+ await removeSpawnPromptFile(capturedTmpFile);
46433
46638
  });
46434
46639
  return {
46435
46640
  instanceId,
@@ -46441,10 +46646,7 @@ var init_spawn4 = __esm({
46441
46646
  } catch (error48) {
46442
46647
  console.error(`[PiSpawnProvider] Failed to spawn: ${getErrorMessage(error48)}`);
46443
46648
  if (tmpFile) {
46444
- try {
46445
- await unlink2(tmpFile);
46446
- } catch {
46447
- }
46649
+ await removeSpawnPromptFile(tmpFile);
46448
46650
  }
46449
46651
  return {
46450
46652
  instanceId,
@@ -46505,32 +46707,30 @@ var init_spawn4 = __esm({
46505
46707
  });
46506
46708
 
46507
46709
  // packages/adapters/src/providers/pi/adapter.ts
46508
- import { exec as exec12 } from "node:child_process";
46509
46710
  import { existsSync as existsSync19 } from "node:fs";
46510
- import { homedir as homedir13 } from "node:os";
46511
- import { join as join27 } from "node:path";
46512
- import { promisify as promisify13 } from "node:util";
46711
+ import { homedir as homedir12 } from "node:os";
46712
+ import { join as join28 } from "node:path";
46713
+ import { findOnPath as findOnPath12 } from "@cleocode/paths";
46513
46714
  function getPiAgentDir() {
46514
46715
  const env = process.env["PI_CODING_AGENT_DIR"];
46515
46716
  if (env !== void 0 && env.length > 0) {
46516
- if (env === "~") return homedir13();
46517
- if (env.startsWith("~/")) return join27(homedir13(), env.slice(2));
46717
+ if (env === "~") return homedir12();
46718
+ if (env.startsWith("~/")) return join28(homedir12(), env.slice(2));
46518
46719
  return env;
46519
46720
  }
46520
46721
  const piHome = process.env["PI_HOME"];
46521
46722
  if (piHome !== void 0 && piHome.length > 0) {
46522
- return join27(piHome, "agent");
46723
+ return join28(piHome, "agent");
46523
46724
  }
46524
- return join27(homedir13(), ".pi", "agent");
46725
+ return join28(homedir12(), ".pi", "agent");
46525
46726
  }
46526
- var execAsync12, PiAdapter;
46727
+ var PiAdapter;
46527
46728
  var init_adapter4 = __esm({
46528
46729
  "packages/adapters/src/providers/pi/adapter.ts"() {
46529
46730
  "use strict";
46530
46731
  init_hooks4();
46531
46732
  init_install4();
46532
46733
  init_spawn4();
46533
- execAsync12 = promisify13(exec12);
46534
46734
  PiAdapter = class {
46535
46735
  /** Unique provider identifier. */
46536
46736
  id = "pi";
@@ -46609,7 +46809,7 @@ var init_adapter4 = __esm({
46609
46809
  *
46610
46810
  * Checks:
46611
46811
  * 1. Adapter has been initialized
46612
- * 2. Pi CLI is available (via PI_CLI_PATH or `which pi`)
46812
+ * 2. Pi CLI is available (via PI_CLI_PATH or a PATH search for `pi`)
46613
46813
  * 3. Pi global state root (~/.pi/agent/ or PI_CODING_AGENT_DIR) exists
46614
46814
  *
46615
46815
  * @returns Health status with details about each check
@@ -46625,25 +46825,16 @@ var init_adapter4 = __esm({
46625
46825
  }
46626
46826
  let cliAvailable = false;
46627
46827
  const cliPath = process.env["PI_CLI_PATH"] ?? "pi";
46628
- try {
46629
- if (cliPath !== "pi") {
46630
- const { stdout } = await execAsync12(`test -x "${cliPath}" && echo ok`);
46631
- cliAvailable = stdout.trim() === "ok";
46632
- details.cliPath = cliPath;
46633
- } else {
46634
- const { stdout } = await execAsync12("which pi");
46635
- cliAvailable = stdout.trim().length > 0;
46636
- details.cliPath = stdout.trim();
46637
- }
46638
- } catch {
46639
- details.cliAvailable = false;
46640
- }
46828
+ const resolvedCli = findOnPath12(cliPath);
46829
+ cliAvailable = resolvedCli !== null;
46830
+ if (resolvedCli) details.cliPath = cliPath === "pi" ? resolvedCli : cliPath;
46831
+ else details.cliAvailable = false;
46641
46832
  const agentDir = getPiAgentDir();
46642
46833
  const agentDirExists = existsSync19(agentDir);
46643
46834
  details.agentDirExists = agentDirExists;
46644
46835
  details.agentDir = agentDir;
46645
46836
  if (this.projectDir) {
46646
- const projectPiDir = join27(this.projectDir, ".pi");
46837
+ const projectPiDir = join28(this.projectDir, ".pi");
46647
46838
  details.projectPiDirExists = existsSync19(projectPiDir);
46648
46839
  }
46649
46840
  details.piCodingAgentDirSet = process.env["PI_CODING_AGENT_DIR"] !== void 0;
@@ -46818,14 +47009,14 @@ var ClaudeSDKAdapter = class {
46818
47009
 
46819
47010
  // packages/adapters/src/providers/claude-sdk/mcp-registry.ts
46820
47011
  import { existsSync as existsSync9 } from "node:fs";
46821
- import { join as join11 } from "node:path";
47012
+ import { join as join12 } from "node:path";
46822
47013
  var CLEO_MCP_CANDIDATES = [
46823
47014
  { name: "brain", binary: "cleo-mcp-brain" },
46824
47015
  { name: "nexus", binary: "cleo-mcp-nexus" },
46825
47016
  { name: "tasks", binary: "cleo-mcp-tasks" }
46826
47017
  ];
46827
47018
  function findInNodeModules(binary, workingDir) {
46828
- const binPath = join11(workingDir, "node_modules", ".bin", binary);
47019
+ const binPath = join12(workingDir, "node_modules", ".bin", binary);
46829
47020
  if (existsSync9(binPath)) {
46830
47021
  return binPath;
46831
47022
  }
@@ -46855,19 +47046,18 @@ function createAdapter2() {
46855
47046
  }
46856
47047
 
46857
47048
  // packages/adapters/src/providers/codex/adapter.ts
46858
- import { exec as exec3 } from "node:child_process";
46859
47049
  import { existsSync as existsSync10 } from "node:fs";
46860
- import { homedir as homedir9 } from "node:os";
46861
- import { join as join15 } from "node:path";
46862
- import { promisify as promisify4 } from "node:util";
47050
+ import { homedir as homedir8 } from "node:os";
47051
+ import { join as join16 } from "node:path";
47052
+ import { findOnPath as findOnPath3 } from "@cleocode/paths";
46863
47053
 
46864
47054
  // packages/adapters/src/providers/codex/hooks.ts
46865
- import { homedir as homedir8 } from "node:os";
46866
- import { join as join13 } from "node:path";
47055
+ import { homedir as homedir7 } from "node:os";
47056
+ import { join as join14 } from "node:path";
46867
47057
 
46868
47058
  // packages/adapters/src/providers/shared/transcript-reader.ts
46869
47059
  import { readdir as readdir2, readFile as readFile3 } from "node:fs/promises";
46870
- import { join as join12 } from "node:path";
47060
+ import { join as join13 } from "node:path";
46871
47061
  function parseTranscriptLines(raw) {
46872
47062
  const turns = [];
46873
47063
  const lines = raw.split("\n").filter((l) => l.trim());
@@ -46892,7 +47082,7 @@ async function readLatestTranscript(providerDir) {
46892
47082
  if (!entry.isFile()) continue;
46893
47083
  const name15 = entry.name;
46894
47084
  if (name15.endsWith(".json") || name15.endsWith(".jsonl")) {
46895
- allFiles.push(join12(providerDir, name15));
47085
+ allFiles.push(join13(providerDir, name15));
46896
47086
  }
46897
47087
  }
46898
47088
  } catch {
@@ -46982,13 +47172,13 @@ var CodexHookProvider = class {
46982
47172
  * @task T162 @epic T134
46983
47173
  */
46984
47174
  async getTranscript(_sessionId, _projectDir) {
46985
- return readLatestTranscript(join13(homedir8(), ".codex"));
47175
+ return readLatestTranscript(join14(homedir7(), ".codex"));
46986
47176
  }
46987
47177
  };
46988
47178
 
46989
47179
  // packages/adapters/src/providers/codex/install.ts
46990
47180
  init_paths2();
46991
- import { join as join14 } from "node:path";
47181
+ import { join as join15 } from "node:path";
46992
47182
  import { ensureProviderInstructionFile as ensureProviderInstructionFile2 } from "@cleocode/caamp";
46993
47183
  var CodexInstallProvider = class {
46994
47184
  /**
@@ -47008,7 +47198,7 @@ var CodexInstallProvider = class {
47008
47198
  });
47009
47199
  const instructionFileUpdated = result.action !== "intact";
47010
47200
  if (instructionFileUpdated) {
47011
- details.instructionFile = join14(projectDir, result.instructFile);
47201
+ details.instructionFile = join15(projectDir, result.instructFile);
47012
47202
  }
47013
47203
  return {
47014
47204
  success: true,
@@ -47062,7 +47252,6 @@ var CodexInstallProvider = class {
47062
47252
  };
47063
47253
 
47064
47254
  // packages/adapters/src/providers/codex/adapter.ts
47065
- var execAsync3 = promisify4(exec3);
47066
47255
  var CodexAdapter = class {
47067
47256
  /** Unique provider identifier. */
47068
47257
  id = "codex";
@@ -47139,14 +47328,11 @@ var CodexAdapter = class {
47139
47328
  };
47140
47329
  }
47141
47330
  let cliAvailable = false;
47142
- try {
47143
- const { stdout } = await execAsync3("which codex");
47144
- cliAvailable = stdout.trim().length > 0;
47145
- details.cliPath = stdout.trim();
47146
- } catch {
47147
- details.cliAvailable = false;
47148
- }
47149
- const codexConfigDir = join15(homedir9(), ".codex");
47331
+ const resolvedCli = findOnPath3("codex");
47332
+ cliAvailable = resolvedCli !== null;
47333
+ if (resolvedCli) details.cliPath = resolvedCli;
47334
+ else details.cliAvailable = false;
47335
+ const codexConfigDir = join16(homedir8(), ".codex");
47150
47336
  const configExists = existsSync10(codexConfigDir);
47151
47337
  details.configDirExists = configExists;
47152
47338
  const healthy = cliAvailable;
@@ -47174,10 +47360,10 @@ var CodexAdapter = class {
47174
47360
  };
47175
47361
 
47176
47362
  // packages/adapters/src/providers/codex/spawn.ts
47177
- import { exec as exec4, spawn as nodeSpawn2 } from "node:child_process";
47178
47363
  init_src();
47179
- import { promisify as promisify5 } from "node:util";
47180
- var execAsync4 = promisify5(exec4);
47364
+ init_cli_spawn();
47365
+ init_prompt_file();
47366
+ import { findOnPath as findOnPath4 } from "@cleocode/paths";
47181
47367
 
47182
47368
  // packages/adapters/src/providers/codex/index.ts
47183
47369
  function createAdapter3() {
@@ -47188,15 +47374,14 @@ function createAdapter3() {
47188
47374
  init_cursor();
47189
47375
 
47190
47376
  // packages/adapters/src/providers/gemini-cli/adapter.ts
47191
- import { exec as exec5 } from "node:child_process";
47192
47377
  import { existsSync as existsSync14 } from "node:fs";
47193
- import { homedir as homedir11 } from "node:os";
47194
- import { join as join20 } from "node:path";
47195
- import { promisify as promisify6 } from "node:util";
47378
+ import { homedir as homedir10 } from "node:os";
47379
+ import { join as join21 } from "node:path";
47380
+ import { findOnPath as findOnPath5 } from "@cleocode/paths";
47196
47381
 
47197
47382
  // packages/adapters/src/providers/gemini-cli/hooks.ts
47198
- import { homedir as homedir10 } from "node:os";
47199
- import { join as join18 } from "node:path";
47383
+ import { homedir as homedir9 } from "node:os";
47384
+ import { join as join19 } from "node:path";
47200
47385
  var GEMINI_CLI_EVENT_MAP = {
47201
47386
  SessionStart: "SessionStart",
47202
47387
  SessionEnd: "SessionEnd",
@@ -47274,14 +47459,14 @@ var GeminiCliHookProvider = class {
47274
47459
  * @task T161 @epic T134
47275
47460
  */
47276
47461
  async getTranscript(_sessionId, _projectDir) {
47277
- return readLatestTranscript(join18(homedir10(), ".gemini"));
47462
+ return readLatestTranscript(join19(homedir9(), ".gemini"));
47278
47463
  }
47279
47464
  };
47280
47465
 
47281
47466
  // packages/adapters/src/providers/gemini-cli/install.ts
47282
47467
  init_paths2();
47283
47468
  import { existsSync as existsSync13, readFileSync as readFileSync8 } from "node:fs";
47284
- import { join as join19 } from "node:path";
47469
+ import { join as join20 } from "node:path";
47285
47470
  import { ensureProviderInstructionFile as ensureProviderInstructionFile4 } from "@cleocode/caamp";
47286
47471
  var GeminiCliInstallProvider = class {
47287
47472
  /**
@@ -47326,7 +47511,7 @@ var GeminiCliInstallProvider = class {
47326
47511
  */
47327
47512
  async isInstalled() {
47328
47513
  const instructionRef = `@${getCleoTemplatesTildePath()}/CLEO-INJECTION.md`;
47329
- const geminiMdPath = join19(process.cwd(), "GEMINI.md");
47514
+ const geminiMdPath = join20(process.cwd(), "GEMINI.md");
47330
47515
  if (existsSync13(geminiMdPath)) {
47331
47516
  try {
47332
47517
  const content = readFileSync8(geminiMdPath, "utf-8");
@@ -47355,7 +47540,6 @@ var GeminiCliInstallProvider = class {
47355
47540
  };
47356
47541
 
47357
47542
  // packages/adapters/src/providers/gemini-cli/adapter.ts
47358
- var execAsync5 = promisify6(exec5);
47359
47543
  var GeminiCliAdapter = class {
47360
47544
  /** Unique provider identifier. */
47361
47545
  id = "gemini-cli";
@@ -47443,14 +47627,11 @@ var GeminiCliAdapter = class {
47443
47627
  };
47444
47628
  }
47445
47629
  let cliAvailable = false;
47446
- try {
47447
- const { stdout } = await execAsync5("which gemini");
47448
- cliAvailable = stdout.trim().length > 0;
47449
- details.cliPath = stdout.trim();
47450
- } catch {
47451
- details.cliAvailable = false;
47452
- }
47453
- const geminiConfigDir = join20(homedir11(), ".gemini");
47630
+ const resolvedCli = findOnPath5("gemini");
47631
+ cliAvailable = resolvedCli !== null;
47632
+ if (resolvedCli) details.cliPath = resolvedCli;
47633
+ else details.cliAvailable = false;
47634
+ const geminiConfigDir = join21(homedir10(), ".gemini");
47454
47635
  const configExists = existsSync14(geminiConfigDir);
47455
47636
  details.configDirExists = configExists;
47456
47637
  const healthy = cliAvailable;
@@ -47479,9 +47660,8 @@ var GeminiCliAdapter = class {
47479
47660
 
47480
47661
  // packages/adapters/src/providers/gemini-cli/spawn.ts
47481
47662
  init_src();
47482
- import { exec as exec6, spawn as nodeSpawn3 } from "node:child_process";
47483
- import { promisify as promisify7 } from "node:util";
47484
- var execAsync6 = promisify7(exec6);
47663
+ init_cli_spawn();
47664
+ import { findOnPath as findOnPath6 } from "@cleocode/paths";
47485
47665
 
47486
47666
  // packages/adapters/src/providers/gemini-cli/index.ts
47487
47667
  function createAdapter5() {
@@ -47489,11 +47669,10 @@ function createAdapter5() {
47489
47669
  }
47490
47670
 
47491
47671
  // packages/adapters/src/providers/kimi/adapter.ts
47492
- import { exec as exec7 } from "node:child_process";
47493
47672
  import { existsSync as existsSync16 } from "node:fs";
47494
- import { homedir as homedir12 } from "node:os";
47495
- import { join as join22 } from "node:path";
47496
- import { promisify as promisify8 } from "node:util";
47673
+ import { homedir as homedir11 } from "node:os";
47674
+ import { join as join23 } from "node:path";
47675
+ import { findOnPath as findOnPath7 } from "@cleocode/paths";
47497
47676
 
47498
47677
  // packages/adapters/src/providers/kimi/hooks.ts
47499
47678
  var KimiHookProvider = class {
@@ -47553,7 +47732,7 @@ var KimiHookProvider = class {
47553
47732
  // packages/adapters/src/providers/kimi/install.ts
47554
47733
  init_paths2();
47555
47734
  import { existsSync as existsSync15, readFileSync as readFileSync9 } from "node:fs";
47556
- import { join as join21 } from "node:path";
47735
+ import { join as join22 } from "node:path";
47557
47736
  import { ensureProviderInstructionFile as ensureProviderInstructionFile5 } from "@cleocode/caamp";
47558
47737
  var KimiInstallProvider = class {
47559
47738
  /**
@@ -47598,7 +47777,7 @@ var KimiInstallProvider = class {
47598
47777
  */
47599
47778
  async isInstalled() {
47600
47779
  const instructionRef = `@${getCleoTemplatesTildePath()}/CLEO-INJECTION.md`;
47601
- const agentsMdPath = join21(process.cwd(), "AGENTS.md");
47780
+ const agentsMdPath = join22(process.cwd(), "AGENTS.md");
47602
47781
  if (existsSync15(agentsMdPath)) {
47603
47782
  try {
47604
47783
  const content = readFileSync9(agentsMdPath, "utf-8");
@@ -47627,7 +47806,6 @@ var KimiInstallProvider = class {
47627
47806
  };
47628
47807
 
47629
47808
  // packages/adapters/src/providers/kimi/adapter.ts
47630
- var execAsync7 = promisify8(exec7);
47631
47809
  var KimiAdapter = class {
47632
47810
  /** Unique provider identifier. */
47633
47811
  id = "kimi";
@@ -47702,14 +47880,11 @@ var KimiAdapter = class {
47702
47880
  };
47703
47881
  }
47704
47882
  let cliAvailable = false;
47705
- try {
47706
- const { stdout } = await execAsync7("which kimi");
47707
- cliAvailable = stdout.trim().length > 0;
47708
- details.cliPath = stdout.trim();
47709
- } catch {
47710
- details.cliAvailable = false;
47711
- }
47712
- const kimiConfigDir = join22(homedir12(), ".kimi");
47883
+ const resolvedCli = findOnPath7("kimi");
47884
+ cliAvailable = resolvedCli !== null;
47885
+ if (resolvedCli) details.cliPath = resolvedCli;
47886
+ else details.cliAvailable = false;
47887
+ const kimiConfigDir = join23(homedir11(), ".kimi");
47713
47888
  const configExists = existsSync16(kimiConfigDir);
47714
47889
  details.configDirExists = configExists;
47715
47890
  const healthy = cliAvailable;
@@ -47738,9 +47913,7 @@ var KimiAdapter = class {
47738
47913
 
47739
47914
  // packages/adapters/src/providers/kimi/spawn.ts
47740
47915
  init_src();
47741
- import { exec as exec8 } from "node:child_process";
47742
- import { promisify as promisify9 } from "node:util";
47743
- var execAsync8 = promisify9(exec8);
47916
+ import { findOnPath as findOnPath8 } from "@cleocode/paths";
47744
47917
 
47745
47918
  // packages/adapters/src/providers/kimi/index.ts
47746
47919
  function createAdapter6() {
@@ -47753,15 +47926,15 @@ init_hook_template_installer();
47753
47926
 
47754
47927
  // packages/adapters/src/registry.ts
47755
47928
  import { readFileSync as readFileSync11 } from "node:fs";
47756
- import { dirname as dirname4, join as join28, resolve as resolve2 } from "node:path";
47929
+ import { dirname as dirname5, join as join29, resolve as resolve2 } from "node:path";
47757
47930
  import { fileURLToPath as fileURLToPath3 } from "node:url";
47758
47931
  var PROVIDER_IDS = ["claude-code", "opencode", "cursor", "pi"];
47759
47932
  function getProviderManifests() {
47760
47933
  const manifests = [];
47761
- const baseDir = resolve2(dirname4(fileURLToPath3(import.meta.url)), "providers");
47934
+ const baseDir = resolve2(dirname5(fileURLToPath3(import.meta.url)), "providers");
47762
47935
  for (const providerId of PROVIDER_IDS) {
47763
47936
  try {
47764
- const manifestPath = join28(baseDir, providerId, "manifest.json");
47937
+ const manifestPath = join29(baseDir, providerId, "manifest.json");
47765
47938
  const raw = readFileSync11(manifestPath, "utf-8");
47766
47939
  manifests.push(JSON.parse(raw));
47767
47940
  } catch {