@cleocode/cleo 2026.6.3 → 2026.6.5

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/cli/index.js CHANGED
@@ -1219,6 +1219,7 @@ var init_tree = __esm({
1219
1219
  // packages/animations/src/render/index.ts
1220
1220
  var init_render = __esm({
1221
1221
  "packages/animations/src/render/index.ts"() {
1222
+ "use strict";
1222
1223
  init_legend();
1223
1224
  init_tree();
1224
1225
  }
@@ -1336,7 +1337,6 @@ var init_spinner_handle = __esm({
1336
1337
  var init_src = __esm({
1337
1338
  "packages/animations/src/index.ts"() {
1338
1339
  init_animate_context();
1339
- init_render();
1340
1340
  init_spinner_handle();
1341
1341
  }
1342
1342
  });
@@ -12302,6 +12302,13 @@ var init_plugin_llm = __esm({
12302
12302
  }
12303
12303
  });
12304
12304
 
12305
+ // packages/contracts/src/llm/system-resolver.ts
12306
+ var init_system_resolver = __esm({
12307
+ "packages/contracts/src/llm/system-resolver.ts"() {
12308
+ "use strict";
12309
+ }
12310
+ });
12311
+
12305
12312
  // packages/contracts/src/memory/observe.ts
12306
12313
  var init_observe = __esm({
12307
12314
  "packages/contracts/src/memory/observe.ts"() {
@@ -14224,6 +14231,7 @@ var init_src2 = __esm({
14224
14231
  init_invariants();
14225
14232
  init_lafs();
14226
14233
  init_plugin_llm();
14234
+ init_system_resolver();
14227
14235
  init_observe();
14228
14236
  init_migration_parity();
14229
14237
  init_mvi();
@@ -28898,12 +28906,12 @@ async function orchestrateClassify(request, context, projectRoot, taskId) {
28898
28906
  }
28899
28907
  try {
28900
28908
  const { getCleoCantWorkflowsDir } = await import("@cleocode/core/internal");
28901
- const { readFileSync: readFileSync22, readdirSync: readdirSync3, existsSync: existsSync21 } = await import("node:fs");
28909
+ const { readFileSync: readFileSync22, readdirSync: readdirSync3, existsSync: existsSync22 } = await import("node:fs");
28902
28910
  const { join: join38 } = await import("node:path");
28903
28911
  const workflowsDir = getCleoCantWorkflowsDir();
28904
28912
  const combined = `${request} ${context ?? ""}`.toLowerCase();
28905
28913
  const matches = [];
28906
- if (existsSync21(workflowsDir)) {
28914
+ if (existsSync22(workflowsDir)) {
28907
28915
  const files = readdirSync3(workflowsDir).filter((f) => f.endsWith(".cant"));
28908
28916
  for (const file of files) {
28909
28917
  try {
@@ -28923,7 +28931,7 @@ async function orchestrateClassify(request, context, projectRoot, taskId) {
28923
28931
  }
28924
28932
  }
28925
28933
  const localCantDir = join38(projectRoot, CLEO_DIR_NAME2, WORKFLOWS_SUBDIR);
28926
- if (existsSync21(localCantDir)) {
28934
+ if (existsSync22(localCantDir)) {
28927
28935
  const files = readdirSync3(localCantDir).filter((f) => f.endsWith(".cant"));
28928
28936
  for (const file of files) {
28929
28937
  try {
@@ -36988,12 +36996,12 @@ var init_agent = __esm({
36988
36996
  transportConfig: {},
36989
36997
  isActive: true
36990
36998
  });
36991
- const { existsSync: existsSync21, mkdirSync: mkdirSync7, writeFileSync: writeFileSync7 } = await import("node:fs");
36999
+ const { existsSync: existsSync22, mkdirSync: mkdirSync7, writeFileSync: writeFileSync7 } = await import("node:fs");
36992
37000
  const { join: join38 } = await import("node:path");
36993
37001
  const cantDir = join38(CLEO_DIR_NAME3, AGENTS_SUBDIR);
36994
37002
  const cantPath = join38(cantDir, `${agentId}.cant`);
36995
37003
  let cantScaffolded = false;
36996
- if (!existsSync21(cantPath)) {
37004
+ if (!existsSync22(cantPath)) {
36997
37005
  mkdirSync7(cantDir, { recursive: true });
36998
37006
  const role = classification ?? "specialist";
36999
37007
  const cantContent = `---
@@ -37053,7 +37061,7 @@ agent ${agentId}:
37053
37061
  data: {
37054
37062
  agentId: credential.agentId,
37055
37063
  displayName: credential.displayName,
37056
- cantFile: cantScaffolded ? cantPath : existsSync21(cantPath) ? cantPath : null,
37064
+ cantFile: cantScaffolded ? cantPath : existsSync22(cantPath) ? cantPath : null,
37057
37065
  cantScaffolded
37058
37066
  }
37059
37067
  },
@@ -37172,7 +37180,7 @@ agent ${agentId}:
37172
37180
  try {
37173
37181
  const { AgentRegistryAccessor } = await import("@cleocode/core/agents");
37174
37182
  const { createRuntime } = await import("@cleocode/runtime");
37175
- const { existsSync: existsSync21, readFileSync: readFileSync22 } = await import("node:fs");
37183
+ const { existsSync: existsSync22, readFileSync: readFileSync22 } = await import("node:fs");
37176
37184
  const { join: join38 } = await import("node:path");
37177
37185
  await openCleoDb("project");
37178
37186
  const registry = new AgentRegistryAccessor(getProjectRoot24());
@@ -37194,7 +37202,7 @@ agent ${agentId}:
37194
37202
  let profile = null;
37195
37203
  let cantValidation = null;
37196
37204
  const cantPath = args.cant ?? join38(CLEO_DIR_NAME3, AGENTS_SUBDIR, `${args.agentId}.cant`);
37197
- if (existsSync21(cantPath)) {
37205
+ if (existsSync22(cantPath)) {
37198
37206
  profile = readFileSync22(cantPath, "utf-8");
37199
37207
  try {
37200
37208
  const cantModule = await import("@cleocode/cant");
@@ -37718,7 +37726,7 @@ Task ${args.taskId} reassigned to you by ${active.agentId}. Run: cleo show ${arg
37718
37726
  try {
37719
37727
  const { AgentRegistryAccessor } = await import("@cleocode/core/agents");
37720
37728
  const { createRuntime } = await import("@cleocode/runtime");
37721
- const { existsSync: existsSync21 } = await import("node:fs");
37729
+ const { existsSync: existsSync22 } = await import("node:fs");
37722
37730
  const { join: join38 } = await import("node:path");
37723
37731
  await openCleoDb("project");
37724
37732
  const registry = new AgentRegistryAccessor(getProjectRoot24());
@@ -37737,7 +37745,7 @@ Task ${args.taskId} reassigned to you by ${active.agentId}. Run: cleo show ${arg
37737
37745
  await registry.update(args.agentId, { isActive: true });
37738
37746
  await registry.markUsed(args.agentId);
37739
37747
  const cantPath = join38(CLEO_DIR_NAME3, AGENTS_SUBDIR, `${args.agentId}.cant`);
37740
- const hasProfile = existsSync21(cantPath);
37748
+ const hasProfile = existsSync22(cantPath);
37741
37749
  const runtime = await createRuntime(registry, {
37742
37750
  agentId: args.agentId,
37743
37751
  pollIntervalMs: 5e3,
@@ -38530,10 +38538,10 @@ Task ${args.taskId} reassigned to you by ${active.agentId}. Run: cleo show ${arg
38530
38538
  async run({ args }) {
38531
38539
  let tempDir = null;
38532
38540
  try {
38533
- const { existsSync: existsSync21 } = await import("node:fs");
38541
+ const { existsSync: existsSync22 } = await import("node:fs");
38534
38542
  const { basename, resolve: resolve11 } = await import("node:path");
38535
38543
  const resolvedPath = resolve11(args.path);
38536
- if (!existsSync21(resolvedPath)) {
38544
+ if (!existsSync22(resolvedPath)) {
38537
38545
  cliOutput(
38538
38546
  {
38539
38547
  success: false,
@@ -38658,11 +38666,11 @@ Task ${args.taskId} reassigned to you by ${active.agentId}. Run: cleo show ${arg
38658
38666
  },
38659
38667
  async run({ args }) {
38660
38668
  try {
38661
- const { existsSync: existsSync21, statSync: statSync2 } = await import("node:fs");
38669
+ const { existsSync: existsSync22, statSync: statSync2 } = await import("node:fs");
38662
38670
  const { resolve: resolve11, basename, dirname: dirname12 } = await import("node:path");
38663
38671
  const { execFileSync: execFileSync5 } = await import("node:child_process");
38664
38672
  const resolvedDir = resolve11(args.dir);
38665
- if (!existsSync21(resolvedDir) || !statSync2(resolvedDir).isDirectory()) {
38673
+ if (!existsSync22(resolvedDir) || !statSync2(resolvedDir).isDirectory()) {
38666
38674
  cliOutput(
38667
38675
  {
38668
38676
  success: false,
@@ -38678,7 +38686,7 @@ Task ${args.taskId} reassigned to you by ${active.agentId}. Run: cleo show ${arg
38678
38686
  }
38679
38687
  const { join: join38 } = await import("node:path");
38680
38688
  const personaPath = join38(resolvedDir, "persona.cant");
38681
- if (!existsSync21(personaPath)) {
38689
+ if (!existsSync22(personaPath)) {
38682
38690
  cliOutput(
38683
38691
  {
38684
38692
  success: false,
@@ -38973,10 +38981,10 @@ Task ${args.taskId} reassigned to you by ${active.agentId}. Run: cleo show ${arg
38973
38981
  },
38974
38982
  async run({ args }) {
38975
38983
  try {
38976
- const { existsSync: existsSync21, readFileSync: readFileSync22, mkdirSync: mkdirSync7 } = await import("node:fs");
38984
+ const { existsSync: existsSync22, readFileSync: readFileSync22, mkdirSync: mkdirSync7 } = await import("node:fs");
38977
38985
  const { resolve: resolve11, join: join38 } = await import("node:path");
38978
38986
  const specPath = resolve11(args.spec);
38979
- if (!existsSync21(specPath)) {
38987
+ if (!existsSync22(specPath)) {
38980
38988
  cliError(`spec file not found: ${specPath}`, 4, { name: "E_NOT_FOUND" });
38981
38989
  process.exitCode = 4;
38982
38990
  return;
@@ -41928,11 +41936,11 @@ var init_caamp = __esm({
41928
41936
  }
41929
41937
  if (args["dry-run"]) {
41930
41938
  const { parseCaampBlocks } = await import("@cleocode/caamp");
41931
- const { existsSync: existsSync21 } = await import("node:fs");
41939
+ const { existsSync: existsSync22 } = await import("node:fs");
41932
41940
  const { readFile: readFile9 } = await import("node:fs/promises");
41933
41941
  const dryResults = [];
41934
41942
  for (const filePath of filePaths) {
41935
- if (!existsSync21(filePath)) {
41943
+ if (!existsSync22(filePath)) {
41936
41944
  dryResults.push({ filePath, exists: false, blockCount: 0, wouldRemove: 0 });
41937
41945
  continue;
41938
41946
  }
@@ -43026,7 +43034,7 @@ var init_check2 = __esm({
43026
43034
  },
43027
43035
  async run({ args }) {
43028
43036
  const { spawnSync } = await import("node:child_process");
43029
- const { existsSync: existsSync21 } = await import("node:fs");
43037
+ const { existsSync: existsSync22 } = await import("node:fs");
43030
43038
  const { join: join38, resolve: resolve11 } = await import("node:path");
43031
43039
  const strict = Boolean(args.strict);
43032
43040
  const jsonOnly = Boolean(args.json);
@@ -43068,7 +43076,7 @@ var init_check2 = __esm({
43068
43076
  let anyFailed = false;
43069
43077
  for (const gate of gates) {
43070
43078
  const scriptPath = join38(repoRoot, gate.script);
43071
- if (!existsSync21(scriptPath)) {
43079
+ if (!existsSync22(scriptPath)) {
43072
43080
  results.push({
43073
43081
  id: gate.id,
43074
43082
  task: gate.task,
@@ -50684,6 +50692,97 @@ ${this.prefix}: \u2717 ${message}
50684
50692
  }
50685
50693
  });
50686
50694
 
50695
+ // packages/cleo/src/cli/commands/doctor-exodus-residue.ts
50696
+ import {
50697
+ archiveStrandedResidue,
50698
+ buildExodusPlan,
50699
+ detectStrandedResidue
50700
+ } from "@cleocode/core/store/exodus/index.js";
50701
+ var doctorExodusResidueCommand;
50702
+ var init_doctor_exodus_residue = __esm({
50703
+ "packages/cleo/src/cli/commands/doctor-exodus-residue.ts"() {
50704
+ "use strict";
50705
+ init_define_cli_command();
50706
+ init_renderers();
50707
+ doctorExodusResidueCommand = defineCommand({
50708
+ meta: {
50709
+ name: "exodus-residue",
50710
+ description: "Detect legacy exodus source DBs still present after a cutover (stranded residue that re-arms the exodus-on-open corruption trigger). Use --fix to archive them into _archive/ (reversible move, never deletes)."
50711
+ },
50712
+ args: {
50713
+ fix: {
50714
+ type: "boolean",
50715
+ description: "Archive stranded legacy source DBs into _archive/ (move, never delete)",
50716
+ default: false
50717
+ }
50718
+ },
50719
+ run({ args }) {
50720
+ const fix = args.fix === true;
50721
+ const cwd = process.cwd();
50722
+ const plan = buildExodusPlan(cwd);
50723
+ const stranded = detectStrandedResidue(plan.sources, cwd);
50724
+ if (stranded.length === 0) {
50725
+ cliOutput(
50726
+ {
50727
+ kind: "generic",
50728
+ ok: true,
50729
+ strandedCount: 0,
50730
+ stranded: [],
50731
+ fixed: false
50732
+ },
50733
+ {
50734
+ command: "doctor exodus-residue",
50735
+ message: "No stranded legacy exodus source DBs (clean cutover or pre-migration install)."
50736
+ }
50737
+ );
50738
+ return;
50739
+ }
50740
+ for (const entry of stranded) {
50741
+ humanInfo(` STRANDED [${entry.scope}] ${entry.name} \u2192 ${entry.path}`);
50742
+ }
50743
+ if (!fix) {
50744
+ cliOutput(
50745
+ {
50746
+ kind: "generic",
50747
+ ok: false,
50748
+ strandedCount: stranded.length,
50749
+ stranded: stranded.map((s) => ({ name: s.name, path: s.path, scope: s.scope })),
50750
+ fixed: false
50751
+ },
50752
+ {
50753
+ command: "doctor exodus-residue",
50754
+ message: `${stranded.length} stranded legacy source DB(s) found. Run \`cleo doctor exodus-residue --fix\` to archive them.`
50755
+ }
50756
+ );
50757
+ process.exitCode = 1;
50758
+ return;
50759
+ }
50760
+ const archived = archiveStrandedResidue(stranded, plan.sources, cwd);
50761
+ const movedCount = archived.filter((a) => a.action === "archived").length;
50762
+ humanInfo(` Archived ${movedCount} stranded source DB(s) \u2192 _archive/.`);
50763
+ cliOutput(
50764
+ {
50765
+ kind: "generic",
50766
+ ok: true,
50767
+ strandedCount: stranded.length,
50768
+ stranded: stranded.map((s) => ({ name: s.name, path: s.path, scope: s.scope })),
50769
+ fixed: true,
50770
+ archived: archived.map((a) => ({
50771
+ name: a.name,
50772
+ action: a.action,
50773
+ archivedTo: a.archivedTo
50774
+ }))
50775
+ },
50776
+ {
50777
+ command: "doctor exodus-residue",
50778
+ message: `Archived ${movedCount} stranded legacy source DB(s) into _archive/.`
50779
+ }
50780
+ );
50781
+ }
50782
+ });
50783
+ }
50784
+ });
50785
+
50687
50786
  // packages/cleo/src/cli/commands/migrate-agents-v2.ts
50688
50787
  var migrate_agents_v2_exports = {};
50689
50788
  __export(migrate_agents_v2_exports, {
@@ -51048,6 +51147,7 @@ var init_doctor = __esm({
51048
51147
  init_progress();
51049
51148
  init_renderers();
51050
51149
  init_doctor_db_substrate();
51150
+ init_doctor_exodus_residue();
51051
51151
  init_doctor_legacy_backups();
51052
51152
  init_doctor_projects();
51053
51153
  init_doctor_release_readiness();
@@ -51066,6 +51166,8 @@ var init_doctor = __esm({
51066
51166
  "db-substrate": doctorDbSubstrateCommand,
51067
51167
  // T10309 / Saga T10281 / Epic T10282 — Legacy-backup walker
51068
51168
  "legacy-backups": doctorLegacyBackupsCommand,
51169
+ // T11777 / Saga T11242 / Epic T11249 — exodus stranded-residue check (+ --fix)
51170
+ "exodus-residue": doctorExodusResidueCommand,
51069
51171
  // T10458 / Saga T10431 / Epic T10436 — Release-readiness preflight
51070
51172
  "release-readiness": doctorReleaseReadinessCommand
51071
51173
  },
@@ -51268,7 +51370,7 @@ var init_doctor = __esm({
51268
51370
  if (args["check-worktree-config"]) {
51269
51371
  const { execFileSync: execFile2 } = await import("node:child_process");
51270
51372
  const { join: pathJoin } = await import("node:path");
51271
- const { existsSync: existsSync21 } = await import("node:fs");
51373
+ const { existsSync: existsSync22 } = await import("node:fs");
51272
51374
  const { detectAndHealCoreWorktreeLeak } = await import("@cleocode/worktree");
51273
51375
  const projectRoot = getProjectRoot42();
51274
51376
  let gitRoot = projectRoot;
@@ -51285,7 +51387,7 @@ var init_doctor = __esm({
51285
51387
  if (isDryRun) {
51286
51388
  const gitConfigPath = pathJoin(gitRoot, ".git", "config");
51287
51389
  let leakedValue;
51288
- if (existsSync21(gitConfigPath)) {
51390
+ if (existsSync22(gitConfigPath)) {
51289
51391
  try {
51290
51392
  leakedValue = execFile2("git", ["config", "--file", gitConfigPath, "--get", "core.worktree"], {
51291
51393
  encoding: "utf-8",
@@ -52188,14 +52290,18 @@ var exodus_exports = {};
52188
52290
  __export(exodus_exports, {
52189
52291
  exodusCommand: () => exodusCommand
52190
52292
  });
52293
+ import { existsSync as existsSync15 } from "node:fs";
52191
52294
  import { resolveDualScopeDbPath } from "@cleocode/core/store/dual-scope-db.js";
52192
52295
  import {
52193
- buildExodusPlan,
52296
+ archiveMigratedSources,
52297
+ buildExodusPlan as buildExodusPlan2,
52194
52298
  runExodusMigrate,
52195
52299
  runExodusStatus,
52196
52300
  runExodusVerify,
52197
- sourcesPresent
52301
+ sourcesPresent,
52302
+ verifyMigration
52198
52303
  } from "@cleocode/core/store/exodus/index.js";
52304
+ import { isDataContinuityOk } from "@cleocode/core/store/exodus/on-open.js";
52199
52305
  function fmtBytes2(n) {
52200
52306
  if (n < 1024) return `${n} B`;
52201
52307
  if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;
@@ -52249,7 +52355,7 @@ var init_exodus = __esm({
52249
52355
  async run({ args }) {
52250
52356
  const dryRun = args["dry-run"] === true;
52251
52357
  const forceCrossVersion = args["force-cross-version"] === true;
52252
- const plan = buildExodusPlan(process.cwd());
52358
+ const plan = buildExodusPlan2(process.cwd());
52253
52359
  humanInfo(`Exodus migration plan:`);
52254
52360
  humanInfo(
52255
52361
  ` Source DBs (${plan.sources.length} total, ${fmtBytes2(plan.totalSourceBytes)} combined):`
@@ -52323,6 +52429,25 @@ var init_exodus = __esm({
52323
52429
  }
52324
52430
  const copied = result.tables.filter((t) => !t.skipped).reduce((n, t) => n + t.rowsCopied, 0);
52325
52431
  const skipped = result.tables.filter((t) => t.skipped).length;
52432
+ const verifyResult = verifyMigration(
52433
+ plan.sources,
52434
+ plan.projectDbPath,
52435
+ plan.globalDbPath,
52436
+ (msg) => humanInfo(` verify: ${msg}`)
52437
+ );
52438
+ let archived = [];
52439
+ if (isDataContinuityOk(verifyResult)) {
52440
+ const consumed = plan.sources.filter((s) => existsSync15(s.path));
52441
+ const archiveResult = archiveMigratedSources(consumed, process.cwd());
52442
+ archived = archiveResult.sources.filter((s) => s.action === "archived").map((s) => s.name);
52443
+ humanInfo(
52444
+ ` Archived ${archived.length} legacy source DB(s) \u2192 _archive/ and sealed completion marker(s): ${archiveResult.markersWritten.join(", ")}`
52445
+ );
52446
+ } else {
52447
+ humanInfo(
52448
+ " Parity validation did NOT pass \u2014 legacy sources LEFT IN PLACE (not archived). Run `cleo exodus verify` to inspect."
52449
+ );
52450
+ }
52326
52451
  cliOutput(
52327
52452
  {
52328
52453
  kind: "generic",
@@ -52332,7 +52457,9 @@ var init_exodus = __esm({
52332
52457
  rowsCopied: copied,
52333
52458
  tablesSkipped: skipped,
52334
52459
  stagingDir: result.stagingDir,
52335
- backupCount: result.backupPaths.length
52460
+ backupCount: result.backupPaths.length,
52461
+ archivedSources: archived,
52462
+ archived: archived.length > 0
52336
52463
  },
52337
52464
  tables: result.tables
52338
52465
  },
@@ -52357,7 +52484,7 @@ var init_exodus = __esm({
52357
52484
  },
52358
52485
  run({ args }) {
52359
52486
  const showPassing = args["show-passing"] === true;
52360
- const plan = buildExodusPlan(process.cwd());
52487
+ const plan = buildExodusPlan2(process.cwd());
52361
52488
  const projectDbPath = resolveDualScopeDbPath("project", process.cwd());
52362
52489
  const globalDbPath = resolveDualScopeDbPath("global");
52363
52490
  humanInfo("Running equivalence verification\u2026");
@@ -54571,7 +54698,7 @@ __export(init_exports, {
54571
54698
  getWorkflowTemplatesDir: () => getWorkflowTemplatesDir2,
54572
54699
  initCommand: () => initCommand2
54573
54700
  });
54574
- import { existsSync as existsSync15, readFileSync as readFileSync14 } from "node:fs";
54701
+ import { existsSync as existsSync16, readFileSync as readFileSync14 } from "node:fs";
54575
54702
  import { join as join27 } from "node:path";
54576
54703
  import { fileURLToPath as fileURLToPath5 } from "node:url";
54577
54704
  import {
@@ -54588,8 +54715,8 @@ function getGitignoreTemplate() {
54588
54715
  const packageRoot = join27(thisFile, "..", "..", "..", "..");
54589
54716
  const localTemplatePath = join27(packageRoot, "templates", "cleo-gitignore");
54590
54717
  const monorepoTemplatePath = join27(packageRoot, "..", "..", "templates", "cleo-gitignore");
54591
- const templatePath = existsSync15(localTemplatePath) ? localTemplatePath : monorepoTemplatePath;
54592
- if (existsSync15(templatePath)) {
54718
+ const templatePath = existsSync16(localTemplatePath) ? localTemplatePath : monorepoTemplatePath;
54719
+ if (existsSync16(templatePath)) {
54593
54720
  return readFileSync14(templatePath, "utf-8");
54594
54721
  }
54595
54722
  } catch {
@@ -55927,9 +56054,11 @@ async function _runPkceLogin(provider, oauthCfg, opts, meta) {
55927
56054
  const state = _generateState();
55928
56055
  const isHeadless = opts.headless || process.env["CLEO_HEADLESS"] === "1";
55929
56056
  const fixedPort = isHeadless ? null : _parseFixedLoopbackPort(oauthCfg.redirectUri);
55930
- const port = isHeadless ? 0 : fixedPort ?? await _findFreePort();
56057
+ const isNonLoopbackPasteBack = !isHeadless && fixedPort === null && !_isLoopbackUri(oauthCfg.redirectUri);
56058
+ const effectiveHeadless = isHeadless || isNonLoopbackPasteBack;
56059
+ const port = effectiveHeadless ? 0 : fixedPort ?? await _findFreePort();
55931
56060
  const randomRedirect = `http://localhost:${port}/callback`;
55932
- const redirectUri = isHeadless ? oauthCfg.redirectUri ?? "http://localhost" : fixedPort != null ? oauthCfg.redirectUri ?? randomRedirect : randomRedirect;
56061
+ const redirectUri = effectiveHeadless ? oauthCfg.redirectUri ?? "http://localhost" : fixedPort != null ? oauthCfg.redirectUri ?? randomRedirect : randomRedirect;
55933
56062
  const authUrl = buildAuthorizationUrl({
55934
56063
  authorizationEndpoint: oauthCfg.authorizationEndpoint ?? "",
55935
56064
  clientId: oauthCfg.clientId,
@@ -55940,7 +56069,7 @@ async function _runPkceLogin(provider, oauthCfg, opts, meta) {
55940
56069
  extraParams: oauthCfg.extraAuthParams
55941
56070
  });
55942
56071
  let code;
55943
- if (isHeadless) {
56072
+ if (effectiveHeadless) {
55944
56073
  code = await _headlessPkceFlow(provider, authUrl);
55945
56074
  } else {
55946
56075
  const result = await _localCallbackPkceFlow(provider, authUrl, state, port);
@@ -56017,6 +56146,15 @@ function _parseFixedLoopbackPort(redirectUri) {
56017
56146
  return null;
56018
56147
  }
56019
56148
  }
56149
+ function _isLoopbackUri(redirectUri) {
56150
+ if (!redirectUri) return false;
56151
+ try {
56152
+ const u = new URL(redirectUri);
56153
+ return u.hostname === "localhost" || u.hostname === "127.0.0.1";
56154
+ } catch {
56155
+ return false;
56156
+ }
56157
+ }
56020
56158
  async function _headlessPkceFlow(provider, authUrl) {
56021
56159
  process.stderr.write("\n");
56022
56160
  process.stderr.write(` Provider: ${provider}
@@ -63420,7 +63558,7 @@ var project_exports = {};
63420
63558
  __export(project_exports, {
63421
63559
  projectCommand: () => projectCommand
63422
63560
  });
63423
- import { existsSync as existsSync16, statSync } from "node:fs";
63561
+ import { existsSync as existsSync17, statSync } from "node:fs";
63424
63562
  import { resolve as resolve7 } from "node:path";
63425
63563
  import { moveProject, projectLifecycle, renameProject } from "@cleocode/core";
63426
63564
  function formatSuccessSection(header, icon, items) {
@@ -63463,7 +63601,7 @@ var init_project = __esm({
63463
63601
  const newPathRaw = args["newPath"];
63464
63602
  const dryRun = args["dry-run"] ?? false;
63465
63603
  const newPath = resolve7(newPathRaw);
63466
- if (!dryRun && existsSync16(newPath) && statSync(newPath).isFile()) {
63604
+ if (!dryRun && existsSync17(newPath) && statSync(newPath).isFile()) {
63467
63605
  cliOutput(formatErrorSection("E_INVALID_PATH", `newPath is not a directory: ${newPath}`), {
63468
63606
  command: "project",
63469
63607
  operation: "project.move"
@@ -71549,7 +71687,7 @@ var init_lib = __esm({
71549
71687
  });
71550
71688
 
71551
71689
  // packages/cleo/src/cli/commands/templates/diff.ts
71552
- import { existsSync as existsSync17, readFileSync as readFileSync16 } from "node:fs";
71690
+ import { existsSync as existsSync18, readFileSync as readFileSync16 } from "node:fs";
71553
71691
  import { join as join31 } from "node:path";
71554
71692
  import { getTemplateById } from "@cleocode/core/templates/registry";
71555
71693
  function unifiedDiff(a, b) {
@@ -71631,7 +71769,7 @@ var init_diff = __esm({
71631
71769
  process.exit(1 /* GENERAL_ERROR */);
71632
71770
  return;
71633
71771
  }
71634
- if (!existsSync17(installPath)) {
71772
+ if (!existsSync18(installPath)) {
71635
71773
  const missingResult = {
71636
71774
  id,
71637
71775
  installPath,
@@ -71670,7 +71808,7 @@ ${unifiedDiff("", rendered)}`
71670
71808
  });
71671
71809
 
71672
71810
  // packages/cleo/src/cli/commands/templates/install.ts
71673
- import { existsSync as existsSync18, mkdirSync as mkdirSync5, readFileSync as readFileSync17, writeFileSync as writeFileSync5 } from "node:fs";
71811
+ import { existsSync as existsSync19, mkdirSync as mkdirSync5, readFileSync as readFileSync17, writeFileSync as writeFileSync5 } from "node:fs";
71674
71812
  import { dirname as dirname9, join as join32 } from "node:path";
71675
71813
  import { getTemplateById as getTemplateById2 } from "@cleocode/core/templates/registry";
71676
71814
  var templatesInstallCommand;
@@ -71738,7 +71876,7 @@ var init_install = __esm({
71738
71876
  process.exit(1 /* GENERAL_ERROR */);
71739
71877
  return;
71740
71878
  }
71741
- if (existsSync18(installPath)) {
71879
+ if (existsSync19(installPath)) {
71742
71880
  const current = readFileSync17(installPath, "utf8");
71743
71881
  if (current === rendered) {
71744
71882
  const noopResult = {
@@ -71887,7 +72025,7 @@ var init_show3 = __esm({
71887
72025
  });
71888
72026
 
71889
72027
  // packages/cleo/src/cli/commands/templates/upgrade.ts
71890
- import { existsSync as existsSync19, mkdirSync as mkdirSync6, readFileSync as readFileSync18, writeFileSync as writeFileSync6 } from "node:fs";
72028
+ import { existsSync as existsSync20, mkdirSync as mkdirSync6, readFileSync as readFileSync18, writeFileSync as writeFileSync6 } from "node:fs";
71891
72029
  import { dirname as dirname10, join as join33 } from "node:path";
71892
72030
  import { getTemplateById as getTemplateById4 } from "@cleocode/core/templates/registry";
71893
72031
  var templatesUpgradeCommand;
@@ -71963,7 +72101,7 @@ var init_upgrade2 = __esm({
71963
72101
  }
71964
72102
  const previewOnly = args["diff"] === true;
71965
72103
  const accept = args["accept"] === true;
71966
- const current = existsSync19(installPath) ? readFileSync18(installPath, "utf8") : null;
72104
+ const current = existsSync20(installPath) ? readFileSync18(installPath, "utf8") : null;
71967
72105
  const diffBody = current === null ? "" : current === rendered ? "" : unifiedDiff(current, rendered);
71968
72106
  let outcome;
71969
72107
  let reason;
@@ -75760,14 +75898,14 @@ function lazyCommand(meta, loader2) {
75760
75898
  init_did_you_mean();
75761
75899
 
75762
75900
  // packages/cleo/src/cli/lib/first-run-detection.ts
75763
- import { existsSync as existsSync20 } from "node:fs";
75901
+ import { existsSync as existsSync21 } from "node:fs";
75764
75902
  import { join as join36 } from "node:path";
75765
75903
  async function detectFirstRun() {
75766
75904
  const envKey = process.env["ANTHROPIC_API_KEY"];
75767
75905
  if (typeof envKey === "string" && envKey.length > 0) return false;
75768
75906
  const { getCleoPlatformPaths } = await import("@cleocode/paths");
75769
75907
  const configPath = join36(getCleoPlatformPaths().config, "config.json");
75770
- if (existsSync20(configPath)) return false;
75908
+ if (existsSync21(configPath)) return false;
75771
75909
  try {
75772
75910
  const { getCredentialPool } = await import("@cleocode/core/llm/credential-pool.js");
75773
75911
  const pool = getCredentialPool();