poe-code 3.0.101 → 3.0.103

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -714,16 +714,16 @@ function getConfigFormat(pathOrFormat) {
714
714
  }
715
715
  return formatRegistry[formatName];
716
716
  }
717
- function detectFormat(path24) {
718
- const ext = getExtension(path24);
717
+ function detectFormat(path27) {
718
+ const ext = getExtension(path27);
719
719
  return extensionMap[ext];
720
720
  }
721
- function getExtension(path24) {
722
- const lastDot = path24.lastIndexOf(".");
721
+ function getExtension(path27) {
722
+ const lastDot = path27.lastIndexOf(".");
723
723
  if (lastDot === -1) {
724
724
  return "";
725
725
  }
726
- return path24.slice(lastDot).toLowerCase();
726
+ return path27.slice(lastDot).toLowerCase();
727
727
  }
728
728
  var formatRegistry, extensionMap;
729
729
  var init_formats = __esm({
@@ -1054,8 +1054,8 @@ async function applyChmod(mutation, context, options) {
1054
1054
  };
1055
1055
  }
1056
1056
  try {
1057
- const stat6 = await context.fs.stat(targetPath);
1058
- const currentMode = typeof stat6.mode === "number" ? stat6.mode & 511 : null;
1057
+ const stat8 = await context.fs.stat(targetPath);
1058
+ const currentMode = typeof stat8.mode === "number" ? stat8.mode & 511 : null;
1059
1059
  if (currentMode === mutation.mode) {
1060
1060
  return {
1061
1061
  outcome: { changed: false, effect: "none", detail: "noop" },
@@ -1450,38 +1450,38 @@ import { createTwoFilesPatch } from "diff";
1450
1450
  import chalk from "chalk";
1451
1451
  function createDryRunFileSystem(base, recorder) {
1452
1452
  const proxy = {
1453
- async readFile(path24, encoding) {
1453
+ async readFile(path27, encoding) {
1454
1454
  if (encoding) {
1455
- return base.readFile(path24, encoding);
1455
+ return base.readFile(path27, encoding);
1456
1456
  }
1457
- return base.readFile(path24);
1457
+ return base.readFile(path27);
1458
1458
  },
1459
- async writeFile(path24, data, options) {
1460
- const previousContent = await tryReadText(base, path24);
1459
+ async writeFile(path27, data, options) {
1460
+ const previousContent = await tryReadText(base, path27);
1461
1461
  const nextContent = formatData(data, options?.encoding);
1462
1462
  recorder.record({
1463
1463
  type: "writeFile",
1464
- path: path24,
1464
+ path: path27,
1465
1465
  nextContent,
1466
1466
  previousContent
1467
1467
  });
1468
1468
  },
1469
- async mkdir(path24, options) {
1470
- recorder.record({ type: "mkdir", path: path24, options });
1469
+ async mkdir(path27, options) {
1470
+ recorder.record({ type: "mkdir", path: path27, options });
1471
1471
  },
1472
- async stat(path24) {
1473
- return base.stat(path24);
1472
+ async stat(path27) {
1473
+ return base.stat(path27);
1474
1474
  },
1475
- async unlink(path24) {
1476
- recorder.record({ type: "unlink", path: path24 });
1475
+ async unlink(path27) {
1476
+ recorder.record({ type: "unlink", path: path27 });
1477
1477
  },
1478
- async readdir(path24) {
1479
- return base.readdir(path24);
1478
+ async readdir(path27) {
1479
+ return base.readdir(path27);
1480
1480
  }
1481
1481
  };
1482
1482
  if (typeof base.rm === "function") {
1483
- proxy.rm = async (path24, options) => {
1484
- recorder.record({ type: "rm", path: path24, options });
1483
+ proxy.rm = async (path27, options) => {
1484
+ recorder.record({ type: "rm", path: path27, options });
1485
1485
  };
1486
1486
  }
1487
1487
  if (typeof base.copyFile === "function") {
@@ -1571,8 +1571,8 @@ function describeWriteChange(previous, next) {
1571
1571
  }
1572
1572
  return "update";
1573
1573
  }
1574
- function renderWriteCommand(path24, change) {
1575
- const command = `cat > ${path24}`;
1574
+ function renderWriteCommand(path27, change) {
1575
+ const command = `cat > ${path27}`;
1576
1576
  if (change === "create") {
1577
1577
  return renderOperationCommand(command, chalk.green, "# create");
1578
1578
  }
@@ -1734,9 +1734,9 @@ function redactTomlLine(line) {
1734
1734
  }
1735
1735
  return line;
1736
1736
  }
1737
- async function tryReadText(base, path24) {
1737
+ async function tryReadText(base, path27) {
1738
1738
  try {
1739
- return await base.readFile(path24, "utf8");
1739
+ return await base.readFile(path27, "utf8");
1740
1740
  } catch (error2) {
1741
1741
  if (isNotFound(error2)) {
1742
1742
  return null;
@@ -3730,21 +3730,21 @@ async function* adaptClaude(lines) {
3730
3730
  if (blockType !== "tool_result") continue;
3731
3731
  const kind = toolKindsById.get(item.tool_use_id);
3732
3732
  toolKindsById.delete(item.tool_use_id);
3733
- let path24;
3733
+ let path27;
3734
3734
  if (typeof item.content === "string") {
3735
- path24 = item.content;
3735
+ path27 = item.content;
3736
3736
  } else {
3737
3737
  try {
3738
- path24 = JSON.stringify(item.content);
3738
+ path27 = JSON.stringify(item.content);
3739
3739
  } catch {
3740
- path24 = String(item.content);
3740
+ path27 = String(item.content);
3741
3741
  }
3742
3742
  }
3743
3743
  yield {
3744
3744
  event: "tool_complete",
3745
3745
  id: item.tool_use_id,
3746
3746
  kind,
3747
- path: path24
3747
+ path: path27
3748
3748
  };
3749
3749
  }
3750
3750
  }
@@ -3866,10 +3866,10 @@ async function* adaptCodex(lines) {
3866
3866
  const kindFromStart = toolKindById.get(item.id);
3867
3867
  const kind = kindFromStart ?? (itemType === "command_execution" ? "exec" : itemType === "file_edit" ? "edit" : "other");
3868
3868
  const titleFromEvent = isNonEmptyString(item.path) ? item.path : itemType === "mcp_tool_call" ? `${isNonEmptyString(item.server) ? item.server : "unknown"}.${isNonEmptyString(item.tool) ? item.tool : "unknown"}` : void 0;
3869
- const path24 = titleFromEvent ?? toolTitleById.get(item.id) ?? "";
3869
+ const path27 = titleFromEvent ?? toolTitleById.get(item.id) ?? "";
3870
3870
  toolTitleById.delete(item.id);
3871
3871
  toolKindById.delete(item.id);
3872
- yield { event: "tool_complete", id: item.id, kind, path: path24 };
3872
+ yield { event: "tool_complete", id: item.id, kind, path: path27 };
3873
3873
  }
3874
3874
  }
3875
3875
  }
@@ -4311,7 +4311,7 @@ function updateSessionFromEvent(ctx, event, toolCallsById) {
4311
4311
  }
4312
4312
  const id = readString(event.id);
4313
4313
  const kind = readString(event.kind);
4314
- const path24 = readString(event.path);
4314
+ const path27 = readString(event.path);
4315
4315
  let toolCall = id ? toolCallsById.get(id) : void 0;
4316
4316
  if (!toolCall) {
4317
4317
  toolCall = {};
@@ -4326,8 +4326,8 @@ function updateSessionFromEvent(ctx, event, toolCallsById) {
4326
4326
  if (kind) {
4327
4327
  toolCall.kind = kind;
4328
4328
  }
4329
- if (path24) {
4330
- toolCall.path = path24;
4329
+ if (path27) {
4330
+ toolCall.path = path27;
4331
4331
  }
4332
4332
  }
4333
4333
  var sessionCapture;
@@ -4835,15 +4835,142 @@ var init_spawn_core = __esm({
4835
4835
  }
4836
4836
  });
4837
4837
 
4838
- // src/cli/environment.ts
4838
+ // packages/poe-code-config/src/schema.ts
4839
+ var init_schema = __esm({
4840
+ "packages/poe-code-config/src/schema.ts"() {
4841
+ "use strict";
4842
+ }
4843
+ });
4844
+
4845
+ // packages/poe-code-config/src/store.ts
4839
4846
  import path7 from "node:path";
4847
+ async function readDocument(fs3, filePath) {
4848
+ try {
4849
+ const raw = await fs3.readFile(filePath, "utf8");
4850
+ return await parseDocument(fs3, filePath, raw);
4851
+ } catch (error2) {
4852
+ if (isNotFound(error2)) {
4853
+ return {};
4854
+ }
4855
+ throw error2;
4856
+ }
4857
+ }
4858
+ async function writeScope(fs3, filePath, scope, values) {
4859
+ const document = await readDocument(fs3, filePath);
4860
+ const normalizedValues = normalizeScopeValues(values);
4861
+ if (Object.keys(normalizedValues).length === 0) {
4862
+ delete document[scope];
4863
+ } else {
4864
+ document[scope] = normalizedValues;
4865
+ }
4866
+ await writeDocument(fs3, filePath, document);
4867
+ }
4868
+ async function parseDocument(fs3, filePath, raw) {
4869
+ try {
4870
+ return normalizeDocument(JSON.parse(raw));
4871
+ } catch (error2) {
4872
+ if (error2 instanceof SyntaxError) {
4873
+ await recoverInvalidDocument(fs3, filePath, raw);
4874
+ return {};
4875
+ }
4876
+ throw error2;
4877
+ }
4878
+ }
4879
+ function normalizeDocument(value) {
4880
+ if (!isRecord2(value)) {
4881
+ return {};
4882
+ }
4883
+ const document = {};
4884
+ for (const [scope, scopeValues] of Object.entries(value)) {
4885
+ const normalizedValues = normalizeScopeValues(scopeValues);
4886
+ if (Object.keys(normalizedValues).length > 0) {
4887
+ document[scope] = normalizedValues;
4888
+ }
4889
+ }
4890
+ return document;
4891
+ }
4892
+ function normalizeScopeValues(value) {
4893
+ if (!isRecord2(value)) {
4894
+ return {};
4895
+ }
4896
+ const normalized = {};
4897
+ for (const [key, entry] of Object.entries(value)) {
4898
+ if (entry !== void 0) {
4899
+ normalized[key] = entry;
4900
+ }
4901
+ }
4902
+ return normalized;
4903
+ }
4904
+ async function writeDocument(fs3, filePath, document) {
4905
+ await fs3.mkdir(path7.dirname(filePath), { recursive: true });
4906
+ await fs3.writeFile(filePath, `${JSON.stringify(document, null, 2)}
4907
+ `, {
4908
+ encoding: "utf8"
4909
+ });
4910
+ }
4911
+ async function recoverInvalidDocument(fs3, filePath, content) {
4912
+ await fs3.mkdir(path7.dirname(filePath), { recursive: true });
4913
+ const backupPath = createInvalidBackupPath(filePath);
4914
+ await fs3.writeFile(backupPath, content, { encoding: "utf8" });
4915
+ await fs3.writeFile(filePath, EMPTY_DOCUMENT, { encoding: "utf8" });
4916
+ }
4917
+ function createInvalidBackupPath(filePath) {
4918
+ const directory = path7.dirname(filePath);
4919
+ const baseName = path7.basename(filePath);
4920
+ return path7.join(directory, `${baseName}.invalid-${createTimestamp()}.json`);
4921
+ }
4922
+ function isRecord2(value) {
4923
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
4924
+ }
4925
+ function resolveConfigPath(homeDir) {
4926
+ return path7.join(homeDir, ".poe-code", "config.json");
4927
+ }
4928
+ var EMPTY_DOCUMENT;
4929
+ var init_store = __esm({
4930
+ "packages/poe-code-config/src/store.ts"() {
4931
+ "use strict";
4932
+ init_src2();
4933
+ EMPTY_DOCUMENT = `${JSON.stringify({}, null, 2)}
4934
+ `;
4935
+ }
4936
+ });
4937
+
4938
+ // packages/poe-code-config/src/resolve.ts
4939
+ var init_resolve = __esm({
4940
+ "packages/poe-code-config/src/resolve.ts"() {
4941
+ "use strict";
4942
+ }
4943
+ });
4944
+
4945
+ // packages/poe-code-config/src/config.ts
4946
+ var init_config = __esm({
4947
+ "packages/poe-code-config/src/config.ts"() {
4948
+ "use strict";
4949
+ init_store();
4950
+ init_resolve();
4951
+ }
4952
+ });
4953
+
4954
+ // packages/poe-code-config/src/index.ts
4955
+ var init_src6 = __esm({
4956
+ "packages/poe-code-config/src/index.ts"() {
4957
+ "use strict";
4958
+ init_schema();
4959
+ init_config();
4960
+ init_resolve();
4961
+ init_store();
4962
+ }
4963
+ });
4964
+
4965
+ // src/cli/environment.ts
4966
+ import path8 from "node:path";
4840
4967
  function createCliEnvironment(init) {
4841
4968
  const platform = init.platform ?? process.platform;
4842
4969
  const variables = init.variables ?? process.env;
4843
4970
  const configPath = resolveConfigPath(init.homeDir);
4844
4971
  const logDir = resolveLogDir(init.homeDir);
4845
4972
  const { poeApiBaseUrl, poeBaseUrl } = resolvePoeBaseUrls(variables);
4846
- const resolveHomePath = (...segments) => path7.join(init.homeDir, ...segments);
4973
+ const resolveHomePath = (...segments) => path8.join(init.homeDir, ...segments);
4847
4974
  const getVariable = (name) => variables[name];
4848
4975
  return {
4849
4976
  cwd: init.cwd,
@@ -4858,11 +4985,8 @@ function createCliEnvironment(init) {
4858
4985
  getVariable
4859
4986
  };
4860
4987
  }
4861
- function resolveConfigPath(homeDir) {
4862
- return path7.join(homeDir, ".poe-code", "config.json");
4863
- }
4864
4988
  function resolveLogDir(homeDir) {
4865
- return path7.join(homeDir, ".poe-code", "logs");
4989
+ return path8.join(homeDir, ".poe-code", "logs");
4866
4990
  }
4867
4991
  function resolvePoeBaseUrls(variables) {
4868
4992
  const raw = variables.POE_BASE_URL;
@@ -4941,6 +5065,7 @@ var DEFAULT_POE_API_BASE_URL;
4941
5065
  var init_environment = __esm({
4942
5066
  "src/cli/environment.ts"() {
4943
5067
  "use strict";
5068
+ init_src6();
4944
5069
  DEFAULT_POE_API_BASE_URL = "https://api.poe.com/v1";
4945
5070
  }
4946
5071
  });
@@ -5085,33 +5210,251 @@ var init_prompts2 = __esm({
5085
5210
  }
5086
5211
  });
5087
5212
 
5088
- // src/cli/options.ts
5089
- function stripBracketedPaste(value) {
5090
- return value.replace(/\x1b\[200~/g, "").replace(/\x1b\[201~/g, "").replace(/undefinedndefined$/, "").replace(/undefined$/, "").replace(/ndefined$/, "");
5213
+ // packages/poe-oauth/src/check-auth.ts
5214
+ async function checkAuth(options) {
5215
+ try {
5216
+ const fetchImplementation = options.fetch ?? globalThis.fetch;
5217
+ const response = await fetchImplementation(
5218
+ createCurrentBalanceUrl(options.baseUrl ?? DEFAULT_BASE_URL),
5219
+ {
5220
+ method: "GET",
5221
+ headers: {
5222
+ Authorization: `Bearer ${options.apiKey}`
5223
+ }
5224
+ }
5225
+ );
5226
+ if (!response.ok) {
5227
+ return null;
5228
+ }
5229
+ const data = await response.json();
5230
+ if (typeof data.email !== "string" || data.email.length === 0) {
5231
+ return null;
5232
+ }
5233
+ return {
5234
+ email: data.email,
5235
+ balance: typeof data.current_point_balance === "number" ? data.current_point_balance : null
5236
+ };
5237
+ } catch {
5238
+ return null;
5239
+ }
5091
5240
  }
5092
- function isAlphanumericWithSeparators(value) {
5093
- for (let i = 0; i < value.length; i++) {
5094
- const code = value.charCodeAt(i);
5095
- const isDigit = code >= 48 && code <= 57;
5096
- const isUpper = code >= 65 && code <= 90;
5097
- const isLower = code >= 97 && code <= 122;
5098
- const isHyphen = code === 45;
5099
- const isUnderscore = code === 95;
5100
- if (!isDigit && !isUpper && !isLower && !isHyphen && !isUnderscore)
5101
- return false;
5241
+ function createCurrentBalanceUrl(baseUrl) {
5242
+ const normalizedBaseUrl = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
5243
+ return `${normalizedBaseUrl}/usage/current_balance`;
5244
+ }
5245
+ var DEFAULT_BASE_URL;
5246
+ var init_check_auth = __esm({
5247
+ "packages/poe-oauth/src/check-auth.ts"() {
5248
+ "use strict";
5249
+ DEFAULT_BASE_URL = "https://poe.com";
5102
5250
  }
5103
- return value.length > 0;
5251
+ });
5252
+
5253
+ // packages/poe-oauth/src/oauth-client.ts
5254
+ import http from "node:http";
5255
+ import crypto from "node:crypto";
5256
+ function createOAuthClient(config2) {
5257
+ const fetchFn = config2.fetch ?? globalThis.fetch;
5258
+ return {
5259
+ authorize: () => startAuthorization(config2, fetchFn)
5260
+ };
5261
+ }
5262
+ function generateCodeVerifier() {
5263
+ return crypto.randomBytes(32).toString("base64url");
5104
5264
  }
5105
- function hasMinimumApiKeyLength(value) {
5106
- return value.length >= MIN_API_KEY_LENGTH;
5265
+ function generateCodeChallenge(verifier) {
5266
+ return crypto.createHash("sha256").update(verifier).digest("base64url");
5107
5267
  }
5108
- function isValidApiKeyFormat(key) {
5109
- if (key.length === 0) return false;
5110
- if (key.startsWith("sk-poe-")) {
5111
- const hash2 = key.slice(7);
5112
- return hasMinimumApiKeyLength(hash2) && isAlphanumericWithSeparators(hash2);
5268
+ async function startAuthorization(config2, fetchFn) {
5269
+ const authorizationEndpoint = config2.authorizationEndpoint ?? DEFAULT_AUTHORIZATION_ENDPOINT;
5270
+ const tokenEndpoint = config2.tokenEndpoint ?? DEFAULT_TOKEN_ENDPOINT;
5271
+ const codeVerifier = generateCodeVerifier();
5272
+ const codeChallenge = generateCodeChallenge(codeVerifier);
5273
+ const server = config2.createServer ? config2.createServer() : http.createServer();
5274
+ const port = await startServer(server);
5275
+ const redirectUri = `http://127.0.0.1:${port}/callback`;
5276
+ const authorizationUrl = buildAuthorizationUrl({
5277
+ endpoint: authorizationEndpoint,
5278
+ clientId: config2.clientId,
5279
+ redirectUri,
5280
+ codeChallenge
5281
+ });
5282
+ const waitForResult = async () => {
5283
+ try {
5284
+ const code = await waitForAuthorizationCode(server, config2, authorizationUrl);
5285
+ return await exchangeCodeForApiKey({
5286
+ tokenEndpoint,
5287
+ code,
5288
+ codeVerifier,
5289
+ clientId: config2.clientId,
5290
+ redirectUri,
5291
+ fetchFn
5292
+ });
5293
+ } finally {
5294
+ server.closeAllConnections?.();
5295
+ server.close();
5296
+ }
5297
+ };
5298
+ return { authorizationUrl, waitForResult };
5299
+ }
5300
+ function startServer(server) {
5301
+ return new Promise((resolve) => {
5302
+ server.listen(0, "127.0.0.1", () => {
5303
+ const address = server.address();
5304
+ resolve(address.port);
5305
+ });
5306
+ });
5307
+ }
5308
+ function buildAuthorizationUrl(params) {
5309
+ const url2 = new URL(params.endpoint);
5310
+ url2.searchParams.set("response_type", "code");
5311
+ url2.searchParams.set("client_id", params.clientId);
5312
+ url2.searchParams.set("scope", "apikey:create");
5313
+ url2.searchParams.set("code_challenge", params.codeChallenge);
5314
+ url2.searchParams.set("code_challenge_method", "S256");
5315
+ url2.searchParams.set("redirect_uri", params.redirectUri);
5316
+ return url2.toString();
5317
+ }
5318
+ function waitForAuthorizationCode(server, config2, authorizationUrl) {
5319
+ return new Promise((resolve, reject) => {
5320
+ let settled = false;
5321
+ const settle = (fn) => {
5322
+ if (!settled) {
5323
+ settled = true;
5324
+ fn();
5325
+ }
5326
+ };
5327
+ server.on("request", (req, res) => {
5328
+ const url2 = new URL(req.url, `http://127.0.0.1`);
5329
+ if (url2.pathname !== "/callback") {
5330
+ res.writeHead(404);
5331
+ res.end("Not found");
5332
+ return;
5333
+ }
5334
+ const error2 = url2.searchParams.get("error");
5335
+ if (error2) {
5336
+ const description = url2.searchParams.get("error_description") ?? error2;
5337
+ res.writeHead(400);
5338
+ res.end(`Authorization failed: ${description}`);
5339
+ settle(() => reject(new Error(`OAuth authorization failed: ${error2} \u2014 ${description}`)));
5340
+ return;
5341
+ }
5342
+ const code = url2.searchParams.get("code");
5343
+ if (!code) {
5344
+ res.writeHead(400);
5345
+ res.end("Missing authorization code");
5346
+ settle(() => reject(new Error("OAuth callback missing authorization code")));
5347
+ return;
5348
+ }
5349
+ res.writeHead(200, { "Content-Type": "text/html" });
5350
+ res.end(buildSuccessPage(config2.landingPage));
5351
+ settle(() => resolve(code));
5352
+ });
5353
+ if (config2.readLine) {
5354
+ config2.readLine().then((input) => {
5355
+ const code = extractCodeFromInput(input);
5356
+ if (code) {
5357
+ settle(() => resolve(code));
5358
+ }
5359
+ }).catch(() => {
5360
+ });
5361
+ }
5362
+ if (config2.openBrowser) {
5363
+ config2.openBrowser(authorizationUrl).catch(
5364
+ (err) => settle(() => reject(err))
5365
+ );
5366
+ }
5367
+ });
5368
+ }
5369
+ function extractCodeFromInput(input) {
5370
+ const trimmed = input.replace(/[\r\n]/g, "").trim();
5371
+ if (trimmed.length === 0) {
5372
+ return null;
5113
5373
  }
5114
- return hasMinimumApiKeyLength(key) && isAlphanumericWithSeparators(key);
5374
+ try {
5375
+ const url2 = new URL(trimmed);
5376
+ return url2.searchParams.get("code");
5377
+ } catch {
5378
+ return trimmed;
5379
+ }
5380
+ }
5381
+ async function exchangeCodeForApiKey(params) {
5382
+ const body = new URLSearchParams({
5383
+ grant_type: "authorization_code",
5384
+ code: params.code,
5385
+ code_verifier: params.codeVerifier,
5386
+ client_id: params.clientId,
5387
+ redirect_uri: params.redirectUri
5388
+ });
5389
+ const response = await params.fetchFn(params.tokenEndpoint, {
5390
+ method: "POST",
5391
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
5392
+ body: body.toString()
5393
+ });
5394
+ if (!response.ok) {
5395
+ const text4 = await response.text();
5396
+ const description = parseErrorDescription(text4);
5397
+ throw new Error(description ?? `Token exchange failed (${response.status}): ${text4}`);
5398
+ }
5399
+ const data = await response.json();
5400
+ if (typeof data.api_key !== "string" || data.api_key.length === 0) {
5401
+ throw new Error("Token response missing api_key field");
5402
+ }
5403
+ return {
5404
+ apiKey: data.api_key,
5405
+ expiresIn: typeof data.api_key_expires_in === "number" ? data.api_key_expires_in : null
5406
+ };
5407
+ }
5408
+ function parseErrorDescription(text4) {
5409
+ try {
5410
+ const data = JSON.parse(text4);
5411
+ if (typeof data.error_description === "string") {
5412
+ return data.error_description;
5413
+ }
5414
+ if (typeof data.error === "string") {
5415
+ return data.error;
5416
+ }
5417
+ } catch {
5418
+ }
5419
+ return null;
5420
+ }
5421
+ function escapeHtml(text4) {
5422
+ return text4.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
5423
+ }
5424
+ function buildSuccessPage(landingPage) {
5425
+ const title = landingPage?.title ?? "Connected to Poe";
5426
+ const body = landingPage?.body ?? "You can close this tab and return to your terminal.";
5427
+ return [
5428
+ "<!DOCTYPE html>",
5429
+ `<html><head><meta charset=utf-8><title>${escapeHtml(title)}</title></head>`,
5430
+ '<body style="font-family:system-ui,sans-serif;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0">',
5431
+ '<div style="text-align:center">',
5432
+ `<h1>${escapeHtml(title)}</h1>`,
5433
+ `<p style="color:#666">${escapeHtml(body)}</p>`,
5434
+ "</div></body></html>"
5435
+ ].join("");
5436
+ }
5437
+ var DEFAULT_AUTHORIZATION_ENDPOINT, DEFAULT_TOKEN_ENDPOINT;
5438
+ var init_oauth_client = __esm({
5439
+ "packages/poe-oauth/src/oauth-client.ts"() {
5440
+ "use strict";
5441
+ DEFAULT_AUTHORIZATION_ENDPOINT = "https://poe.com/oauth/authorize";
5442
+ DEFAULT_TOKEN_ENDPOINT = "https://api.poe.com/token";
5443
+ }
5444
+ });
5445
+
5446
+ // packages/poe-oauth/src/index.ts
5447
+ var init_src7 = __esm({
5448
+ "packages/poe-oauth/src/index.ts"() {
5449
+ "use strict";
5450
+ init_check_auth();
5451
+ init_oauth_client();
5452
+ }
5453
+ });
5454
+
5455
+ // src/cli/options.ts
5456
+ function stripBracketedPaste(value) {
5457
+ return value.replace(/\x1b\[200~/g, "").replace(/\x1b\[201~/g, "").replace(/undefinedndefined$/, "").replace(/undefined$/, "").replace(/ndefined$/, "");
5115
5458
  }
5116
5459
  function createOptionResolvers(init) {
5117
5460
  const ensure = async (input) => {
@@ -5128,7 +5471,7 @@ function createOptionResolvers(init) {
5128
5471
  }
5129
5472
  return result;
5130
5473
  };
5131
- const normalizeApiKey2 = (value) => {
5474
+ const normalizeApiKey = (value) => {
5132
5475
  const sanitized = stripBracketedPaste(value);
5133
5476
  const trimmed = sanitized.trim();
5134
5477
  if (trimmed.length === 0) {
@@ -5136,20 +5479,15 @@ function createOptionResolvers(init) {
5136
5479
  }
5137
5480
  return trimmed;
5138
5481
  };
5139
- const confirmKeyFormat = async (apiKey, assumeYes) => {
5140
- if (isValidApiKeyFormat(apiKey)) return true;
5141
- if (assumeYes) return false;
5142
- return await init.confirm(
5143
- "Key doesn't match expected API key format. Use it anyway?"
5144
- );
5482
+ const validateApiKey = async (apiKey) => {
5483
+ return await init.checkAuth(apiKey);
5145
5484
  };
5146
5485
  const resolveApiKey2 = async (input) => {
5147
5486
  const assumeYes = input.assumeYes ?? false;
5148
5487
  const allowStored = input.allowStored ?? true;
5149
5488
  if (input.value != null) {
5150
- const apiKey = normalizeApiKey2(input.value);
5151
- const accepted = await confirmKeyFormat(apiKey, assumeYes);
5152
- if (!accepted) {
5489
+ const apiKey = normalizeApiKey(input.value);
5490
+ if (!await validateApiKey(apiKey)) {
5153
5491
  throw new Error("API key rejected.");
5154
5492
  }
5155
5493
  if (!input.dryRun) {
@@ -5163,9 +5501,8 @@ function createOptionResolvers(init) {
5163
5501
  "Use API key from POE_API_KEY environment variable?"
5164
5502
  );
5165
5503
  if (useEnv) {
5166
- const apiKey = normalizeApiKey2(envValue);
5167
- const accepted = await confirmKeyFormat(apiKey, assumeYes);
5168
- if (accepted) {
5504
+ const apiKey = normalizeApiKey(envValue);
5505
+ if (await validateApiKey(apiKey)) {
5169
5506
  if (!input.dryRun) {
5170
5507
  await init.apiKeyStore.write(apiKey);
5171
5508
  }
@@ -5179,12 +5516,12 @@ function createOptionResolvers(init) {
5179
5516
  if (allowStored) {
5180
5517
  const stored = await init.apiKeyStore.read();
5181
5518
  if (stored) {
5182
- return normalizeApiKey2(stored);
5519
+ return normalizeApiKey(stored);
5183
5520
  }
5184
5521
  }
5185
5522
  if (init.loginViaOAuth) {
5186
5523
  const apiKey = await init.loginViaOAuth();
5187
- const normalized = normalizeApiKey2(apiKey);
5524
+ const normalized = normalizeApiKey(apiKey);
5188
5525
  if (!input.dryRun) {
5189
5526
  await init.apiKeyStore.write(normalized);
5190
5527
  }
@@ -5199,15 +5536,14 @@ function createOptionResolvers(init) {
5199
5536
  }
5200
5537
  let apiKey;
5201
5538
  try {
5202
- apiKey = normalizeApiKey2(result);
5539
+ apiKey = normalizeApiKey(result);
5203
5540
  } catch (error2) {
5204
5541
  if (error2 instanceof Error && error2.message === "POE API key cannot be empty.") {
5205
5542
  continue;
5206
5543
  }
5207
5544
  throw error2;
5208
5545
  }
5209
- const accepted = await confirmKeyFormat(apiKey, assumeYes);
5210
- if (!accepted) {
5546
+ if (!await validateApiKey(apiKey)) {
5211
5547
  continue;
5212
5548
  }
5213
5549
  if (!input.dryRun) {
@@ -5270,19 +5606,12 @@ function createOptionResolvers(init) {
5270
5606
  resolveModel: resolveModel2,
5271
5607
  resolveReasoning,
5272
5608
  resolveConfigName,
5273
- resolveApiKey: resolveApiKey2,
5274
- normalizeApiKey: normalizeApiKey2
5609
+ resolveApiKey: resolveApiKey2
5275
5610
  };
5276
5611
  }
5277
- var API_KEY_REFERENCE_LENGTH, API_KEY_MIN_LENGTH_RATIO, MIN_API_KEY_LENGTH;
5278
5612
  var init_options = __esm({
5279
5613
  "src/cli/options.ts"() {
5280
5614
  "use strict";
5281
- API_KEY_REFERENCE_LENGTH = 43;
5282
- API_KEY_MIN_LENGTH_RATIO = 0.8;
5283
- MIN_API_KEY_LENGTH = Math.ceil(
5284
- API_KEY_REFERENCE_LENGTH * API_KEY_MIN_LENGTH_RATIO
5285
- );
5286
5615
  }
5287
5616
  });
5288
5617
 
@@ -5555,7 +5884,7 @@ var init_logger2 = __esm({
5555
5884
  });
5556
5885
 
5557
5886
  // src/cli/error-logger.ts
5558
- import path8 from "node:path";
5887
+ import path9 from "node:path";
5559
5888
  var DEFAULT_MAX_SIZE, DEFAULT_MAX_BACKUPS, ErrorLogger;
5560
5889
  var init_error_logger = __esm({
5561
5890
  "src/cli/error-logger.ts"() {
@@ -5572,7 +5901,7 @@ var init_error_logger = __esm({
5572
5901
  fileLoggingAvailable;
5573
5902
  constructor(options) {
5574
5903
  this.fs = options.fs;
5575
- this.logFilePath = path8.join(options.logDir, "errors.log");
5904
+ this.logFilePath = path9.join(options.logDir, "errors.log");
5576
5905
  this.logToStderr = options.logToStderr ?? true;
5577
5906
  this.maxSize = options.maxSize ?? DEFAULT_MAX_SIZE;
5578
5907
  this.maxBackups = options.maxBackups ?? DEFAULT_MAX_BACKUPS;
@@ -5691,7 +6020,7 @@ ${entry.stack}`);
5691
6020
  return `${this.logFilePath}.${index}`;
5692
6021
  }
5693
6022
  ensureLogDirectory() {
5694
- const directory = path8.dirname(this.logFilePath);
6023
+ const directory = path9.dirname(this.logFilePath);
5695
6024
  try {
5696
6025
  if (!this.fs.existsSync(directory)) {
5697
6026
  this.fs.mkdirSync(directory, { recursive: true });
@@ -5709,7 +6038,7 @@ ${entry.stack}`);
5709
6038
  });
5710
6039
 
5711
6040
  // src/providers/index.ts
5712
- import path9 from "node:path";
6041
+ import path10 from "node:path";
5713
6042
  import { readdir } from "node:fs/promises";
5714
6043
  import { fileURLToPath, pathToFileURL } from "node:url";
5715
6044
  function isProviderModule(filename) {
@@ -5736,7 +6065,7 @@ async function loadProviders() {
5736
6065
  for (const entry of entries) {
5737
6066
  if (!entry.isFile()) continue;
5738
6067
  if (!isProviderModule(entry.name)) continue;
5739
- const moduleUrl = pathToFileURL(path9.join(currentDir, entry.name)).href;
6068
+ const moduleUrl = pathToFileURL(path10.join(currentDir, entry.name)).href;
5740
6069
  const moduleExports = await import(moduleUrl);
5741
6070
  if (!moduleExports.provider) {
5742
6071
  throw new Error(`Provider module "${entry.name}" must export "provider".`);
@@ -5752,8 +6081,8 @@ var moduleDir, currentDir, defaultProviders;
5752
6081
  var init_providers = __esm({
5753
6082
  async "src/providers/index.ts"() {
5754
6083
  "use strict";
5755
- moduleDir = path9.dirname(fileURLToPath(import.meta.url));
5756
- currentDir = path9.basename(moduleDir) === "providers" ? moduleDir : path9.join(moduleDir, "providers");
6084
+ moduleDir = path10.dirname(fileURLToPath(import.meta.url));
6085
+ currentDir = path10.basename(moduleDir) === "providers" ? moduleDir : path10.join(moduleDir, "providers");
5757
6086
  defaultProviders = await loadProviders();
5758
6087
  }
5759
6088
  });
@@ -6095,21 +6424,21 @@ function createSdkContainer(options) {
6095
6424
  });
6096
6425
  loggerFactory.setErrorLogger(errorLogger);
6097
6426
  const asyncFs = {
6098
- readFile: ((path24, encoding) => {
6427
+ readFile: ((path27, encoding) => {
6099
6428
  if (encoding) {
6100
- return fs2.readFile(path24, encoding);
6429
+ return fs2.readFile(path27, encoding);
6101
6430
  }
6102
- return fs2.readFile(path24);
6431
+ return fs2.readFile(path27);
6103
6432
  }),
6104
- writeFile: (path24, data, opts) => fs2.writeFile(path24, data, opts),
6105
- mkdir: (path24, opts) => fs2.mkdir(path24, opts).then(() => {
6433
+ writeFile: (path27, data, opts) => fs2.writeFile(path27, data, opts),
6434
+ mkdir: (path27, opts) => fs2.mkdir(path27, opts).then(() => {
6106
6435
  }),
6107
- stat: (path24) => fs2.stat(path24),
6108
- rm: (path24, opts) => fs2.rm(path24, opts),
6109
- unlink: (path24) => fs2.unlink(path24),
6110
- readdir: (path24) => fs2.readdir(path24),
6436
+ stat: (path27) => fs2.stat(path27),
6437
+ rm: (path27, opts) => fs2.rm(path27, opts),
6438
+ unlink: (path27) => fs2.unlink(path27),
6439
+ readdir: (path27) => fs2.readdir(path27),
6111
6440
  copyFile: (src, dest) => fs2.copyFile(src, dest),
6112
- chmod: (path24, mode) => fs2.chmod(path24, mode)
6441
+ chmod: (path27, mode) => fs2.chmod(path27, mode)
6113
6442
  };
6114
6443
  const contextFactory = createCommandContextFactory({ fs: asyncFs });
6115
6444
  const authFs = {
@@ -6145,7 +6474,8 @@ function createSdkContainer(options) {
6145
6474
  read: readApiKey,
6146
6475
  write: writeApiKey
6147
6476
  },
6148
- confirm: async () => true
6477
+ confirm: async () => true,
6478
+ checkAuth: async (apiKey) => await checkAuth({ apiKey }) !== null
6149
6479
  });
6150
6480
  const registry2 = createServiceRegistry();
6151
6481
  const providers = getDefaultProviders().filter((adapter) => !adapter.disabled);
@@ -6202,6 +6532,7 @@ var init_container = __esm({
6202
6532
  init_service_registry();
6203
6533
  init_context();
6204
6534
  init_prompts2();
6535
+ init_src7();
6205
6536
  init_options();
6206
6537
  init_logger2();
6207
6538
  init_error_logger();
@@ -6811,8 +7142,8 @@ function resourceNotFound(resource) {
6811
7142
  `Resource not found: ${resource}`
6812
7143
  );
6813
7144
  }
6814
- function assertAbsolutePath(path24) {
6815
- if (!isAbsolute(path24)) {
7145
+ function assertAbsolutePath(path27) {
7146
+ if (!isAbsolute(path27)) {
6816
7147
  throw invalidParams('"path" must be an absolute path');
6817
7148
  }
6818
7149
  }
@@ -7546,7 +7877,7 @@ var init_run_report = __esm({
7546
7877
  });
7547
7878
 
7548
7879
  // packages/poe-acp-client/src/index.ts
7549
- var init_src6 = __esm({
7880
+ var init_src8 = __esm({
7550
7881
  "packages/poe-acp-client/src/index.ts"() {
7551
7882
  "use strict";
7552
7883
  init_acp_client();
@@ -8573,7 +8904,7 @@ var init_acp_core = __esm({
8573
8904
  });
8574
8905
 
8575
8906
  // packages/poe-agent/src/plugins/plugin-args.ts
8576
- import path10 from "node:path";
8907
+ import path11 from "node:path";
8577
8908
  function isObjectRecord3(value) {
8578
8909
  return typeof value === "object" && value !== null && !Array.isArray(value);
8579
8910
  }
@@ -8604,13 +8935,13 @@ function getOptionalString(args, key) {
8604
8935
  return value;
8605
8936
  }
8606
8937
  function resolveAllowedPath(cwd, allowedPaths, inputPath) {
8607
- const resolvedPath = path10.resolve(cwd, inputPath);
8938
+ const resolvedPath = path11.resolve(cwd, inputPath);
8608
8939
  const isAllowed = allowedPaths.some((allowedPath) => {
8609
8940
  if (allowedPath === resolvedPath) {
8610
8941
  return true;
8611
8942
  }
8612
- const rel = path10.relative(allowedPath, resolvedPath);
8613
- return rel.length > 0 && !rel.startsWith("..") && !path10.isAbsolute(rel);
8943
+ const rel = path11.relative(allowedPath, resolvedPath);
8944
+ return rel.length > 0 && !rel.startsWith("..") && !path11.isAbsolute(rel);
8614
8945
  });
8615
8946
  if (!isAllowed) {
8616
8947
  throw new Error(`Path is outside allowed paths: ${inputPath}`);
@@ -8625,7 +8956,7 @@ var init_plugin_args = __esm({
8625
8956
 
8626
8957
  // packages/poe-agent/src/plugins/poe-agent-plugin-files.ts
8627
8958
  import fsPromises2 from "node:fs/promises";
8628
- import path11 from "node:path";
8959
+ import path12 from "node:path";
8629
8960
  async function fileExists(fs3, filePath) {
8630
8961
  try {
8631
8962
  await fs3.readFile(filePath, "utf8");
@@ -8649,9 +8980,9 @@ var init_poe_agent_plugin_files = __esm({
8649
8980
  "use strict";
8650
8981
  init_plugin_args();
8651
8982
  filesPlugin = (options = {}) => {
8652
- const cwd = path11.resolve(options.cwd ?? process.cwd());
8983
+ const cwd = path12.resolve(options.cwd ?? process.cwd());
8653
8984
  const allowedPaths = (options.allowedPaths ?? [cwd]).map(
8654
- (allowedPath) => path11.resolve(cwd, allowedPath)
8985
+ (allowedPath) => path12.resolve(cwd, allowedPath)
8655
8986
  );
8656
8987
  const fs3 = options.fs ?? fsPromises2;
8657
8988
  const readFileTool = {
@@ -8705,7 +9036,7 @@ var init_poe_agent_plugin_files = __esm({
8705
9036
  async call(args) {
8706
9037
  const command = getRequiredString(args, "command");
8707
9038
  const filePath = resolveAllowedPath(cwd, allowedPaths, getRequiredString(args, "path"));
8708
- const displayedPath = path11.relative(cwd, filePath) || path11.basename(filePath);
9039
+ const displayedPath = path12.relative(cwd, filePath) || path12.basename(filePath);
8709
9040
  if (command === "str_replace") {
8710
9041
  const oldStr = getRequiredString(args, "old_str", true);
8711
9042
  const newStr = getRequiredString(args, "new_str", true);
@@ -8725,7 +9056,7 @@ var init_poe_agent_plugin_files = __esm({
8725
9056
  if (await fileExists(fs3, filePath)) {
8726
9057
  throw new Error("File already exists \u2014 use str_replace to edit");
8727
9058
  }
8728
- await fs3.mkdir(path11.dirname(filePath), { recursive: true });
9059
+ await fs3.mkdir(path12.dirname(filePath), { recursive: true });
8729
9060
  await fs3.writeFile(filePath, fileText, "utf8");
8730
9061
  return `Created file: ${displayedPath}`;
8731
9062
  }
@@ -8766,7 +9097,7 @@ var init_poe_agent_plugin_files = __esm({
8766
9097
 
8767
9098
  // packages/poe-agent/src/plugins/poe-agent-plugin-shell.ts
8768
9099
  import { exec as execCallback } from "node:child_process";
8769
- import path12 from "node:path";
9100
+ import path13 from "node:path";
8770
9101
  import { promisify } from "node:util";
8771
9102
  async function defaultRunCommand(command, cwd) {
8772
9103
  try {
@@ -8799,9 +9130,9 @@ var init_poe_agent_plugin_shell = __esm({
8799
9130
  init_plugin_args();
8800
9131
  exec = promisify(execCallback);
8801
9132
  shellPlugin = (options = {}) => {
8802
- const cwd = path12.resolve(options.cwd ?? process.cwd());
9133
+ const cwd = path13.resolve(options.cwd ?? process.cwd());
8803
9134
  const allowedPaths = (options.allowedPaths ?? [cwd]).map(
8804
- (allowedPath) => path12.resolve(cwd, allowedPath)
9135
+ (allowedPath) => path13.resolve(cwd, allowedPath)
8805
9136
  );
8806
9137
  const runCommand2 = options.runCommand ?? defaultRunCommand;
8807
9138
  const runCommandTool = {
@@ -9585,7 +9916,7 @@ var AgentHost;
9585
9916
  var init_agent_host = __esm({
9586
9917
  "packages/poe-agent/src/runtime/agent-host.ts"() {
9587
9918
  "use strict";
9588
- init_src6();
9919
+ init_src8();
9589
9920
  init_agent_session();
9590
9921
  init_acp_core();
9591
9922
  init_run_context();
@@ -9945,7 +10276,7 @@ function readDependencies(plugin) {
9945
10276
  }
9946
10277
  return normalized;
9947
10278
  }
9948
- var init_config = __esm({
10279
+ var init_config2 = __esm({
9949
10280
  "packages/poe-agent/src/runtime/config.ts"() {
9950
10281
  "use strict";
9951
10282
  }
@@ -10872,7 +11203,7 @@ var init_internal = __esm({
10872
11203
  });
10873
11204
 
10874
11205
  // packages/tiny-mcp-client/src/index.ts
10875
- var init_src7 = __esm({
11206
+ var init_src9 = __esm({
10876
11207
  "packages/tiny-mcp-client/src/index.ts"() {
10877
11208
  "use strict";
10878
11209
  init_internal();
@@ -10921,7 +11252,7 @@ var DEFAULT_MCP_CLIENT_INFO, PluginApiImpl;
10921
11252
  var init_plugin_api_impl = __esm({
10922
11253
  "packages/poe-agent/src/runtime/plugin-api-impl.ts"() {
10923
11254
  "use strict";
10924
- init_src7();
11255
+ init_src9();
10925
11256
  init_hooks();
10926
11257
  DEFAULT_MCP_CLIENT_INFO = {
10927
11258
  name: "poe-agent",
@@ -11252,7 +11583,7 @@ var init_agent = __esm({
11252
11583
  init_acp_core();
11253
11584
  init_agent_host();
11254
11585
  init_hooks();
11255
- init_config();
11586
+ init_config2();
11256
11587
  init_plugin_setup();
11257
11588
  init_run_context();
11258
11589
  ImmutableAgentBuilder = class _ImmutableAgentBuilder {
@@ -11488,7 +11819,7 @@ __export(src_exports, {
11488
11819
  agent: () => agent,
11489
11820
  createAgentSession: () => createAgentSession
11490
11821
  });
11491
- var init_src8 = __esm({
11822
+ var init_src10 = __esm({
11492
11823
  "packages/poe-agent/src/index.ts"() {
11493
11824
  "use strict";
11494
11825
  init_agent();
@@ -11826,7 +12157,7 @@ function createInMemoryAcpTransport2(options) {
11826
12157
  }
11827
12158
  if (method === "session/new") {
11828
12159
  const request = params;
11829
- const { createAgentSession: createAgentSession2 } = await Promise.resolve().then(() => (init_src8(), src_exports));
12160
+ const { createAgentSession: createAgentSession2 } = await Promise.resolve().then(() => (init_src10(), src_exports));
11830
12161
  const session = await createAgentSession2({
11831
12162
  model: options.model,
11832
12163
  cwd: request.cwd || options.cwd,
@@ -11976,7 +12307,7 @@ var init_poe_agent = __esm({
11976
12307
  "src/providers/poe-agent.ts"() {
11977
12308
  "use strict";
11978
12309
  init_constants();
11979
- init_src6();
12310
+ init_src8();
11980
12311
  init_create_provider();
11981
12312
  poeAgentService = createProvider({
11982
12313
  id: "poe-agent",
@@ -12145,7 +12476,7 @@ var init_spawn3 = __esm({
12145
12476
  });
12146
12477
 
12147
12478
  // packages/pipeline/src/utils.ts
12148
- function isRecord2(value) {
12479
+ function isRecord3(value) {
12149
12480
  return typeof value === "object" && value !== null && !Array.isArray(value);
12150
12481
  }
12151
12482
  function isNotFound2(error2) {
@@ -12179,7 +12510,7 @@ var init_utils2 = __esm({
12179
12510
  });
12180
12511
 
12181
12512
  // packages/pipeline/src/config/loader.ts
12182
- import path13 from "node:path";
12513
+ import path14 from "node:path";
12183
12514
  import { parse as parse4 } from "yaml";
12184
12515
  function asStepMode(value) {
12185
12516
  if (value === void 0 || value === null) {
@@ -12203,19 +12534,19 @@ function parseStepConfigDocument(filePath, content) {
12203
12534
  if (document === null || document === void 0) {
12204
12535
  return {};
12205
12536
  }
12206
- if (!isRecord2(document)) {
12537
+ if (!isRecord3(document)) {
12207
12538
  throw new Error(`Invalid pipeline step config in "${filePath}": expected a top-level object.`);
12208
12539
  }
12209
12540
  const stepsValue = document.steps;
12210
12541
  if (stepsValue === void 0 || stepsValue === null) {
12211
12542
  return {};
12212
12543
  }
12213
- if (!isRecord2(stepsValue)) {
12544
+ if (!isRecord3(stepsValue)) {
12214
12545
  throw new Error(`Invalid pipeline step config in "${filePath}": "steps" must be an object.`);
12215
12546
  }
12216
12547
  const steps = {};
12217
12548
  for (const [stepName, value] of Object.entries(stepsValue)) {
12218
- if (!isRecord2(value)) {
12549
+ if (!isRecord3(value)) {
12219
12550
  throw new Error(`Invalid step "${stepName}" in "${filePath}": expected an object.`);
12220
12551
  }
12221
12552
  const instruction = value.instruction;
@@ -12237,7 +12568,7 @@ function parseConfigDocument(filePath, content) {
12237
12568
  if (document === null || document === void 0) {
12238
12569
  return {};
12239
12570
  }
12240
- if (!isRecord2(document)) {
12571
+ if (!isRecord3(document)) {
12241
12572
  throw new Error(`Invalid pipeline config in "${filePath}": expected a top-level object.`);
12242
12573
  }
12243
12574
  const planPath = document.planPath;
@@ -12263,8 +12594,8 @@ async function loadStepsFile(fs3, filePath) {
12263
12594
  return parseStepConfigDocument(filePath, content);
12264
12595
  }
12265
12596
  async function loadPipelineConfig(options) {
12266
- const globalPath = path13.join(options.homeDir, ".poe-code", "pipeline", "config.yaml");
12267
- const projectPath = path13.join(options.cwd, ".poe-code", "pipeline", "config.yaml");
12597
+ const globalPath = path14.join(options.homeDir, ".poe-code", "pipeline", "config.yaml");
12598
+ const projectPath = path14.join(options.cwd, ".poe-code", "pipeline", "config.yaml");
12268
12599
  const [globalConfig2, projectConfig] = await Promise.all([
12269
12600
  loadConfigFile(options.fs, globalPath),
12270
12601
  loadConfigFile(options.fs, projectPath)
@@ -12275,8 +12606,8 @@ async function loadPipelineConfig(options) {
12275
12606
  };
12276
12607
  }
12277
12608
  async function loadResolvedSteps(options) {
12278
- const globalPath = path13.join(options.homeDir, ".poe-code", "pipeline", "steps.yaml");
12279
- const projectPath = path13.join(options.cwd, ".poe-code", "pipeline", "steps.yaml");
12609
+ const globalPath = path14.join(options.homeDir, ".poe-code", "pipeline", "steps.yaml");
12610
+ const projectPath = path14.join(options.cwd, ".poe-code", "pipeline", "steps.yaml");
12280
12611
  const [globalSteps, projectSteps] = await Promise.all([
12281
12612
  loadStepsFile(options.fs, globalPath),
12282
12613
  loadStepsFile(options.fs, projectPath)
@@ -12315,7 +12646,7 @@ function parseTaskStatus(value, availableSteps, taskId) {
12315
12646
  if (typeof value === "string") {
12316
12647
  return normalizeStatus(value, "task status");
12317
12648
  }
12318
- if (!isRecord2(value)) {
12649
+ if (!isRecord3(value)) {
12319
12650
  throw new Error(`Invalid status for task "${taskId}": expected a string or step-status map.`);
12320
12651
  }
12321
12652
  const statusMap = {};
@@ -12335,7 +12666,7 @@ function parsePlan(yamlContent, options = {}) {
12335
12666
  const message = error2 instanceof Error ? error2.message : String(error2);
12336
12667
  throw new Error(`Invalid plan YAML: ${message}`);
12337
12668
  }
12338
- if (!isRecord2(document)) {
12669
+ if (!isRecord3(document)) {
12339
12670
  throw new Error("Invalid plan YAML: expected a top-level object.");
12340
12671
  }
12341
12672
  const tasksValue = document.tasks;
@@ -12344,7 +12675,7 @@ function parsePlan(yamlContent, options = {}) {
12344
12675
  }
12345
12676
  const ids = /* @__PURE__ */ new Set();
12346
12677
  const tasks = tasksValue.map((value, index) => {
12347
- if (!isRecord2(value)) {
12678
+ if (!isRecord3(value)) {
12348
12679
  throw new Error(`Invalid tasks[${index}]: expected an object.`);
12349
12680
  }
12350
12681
  const id = asRequiredString(value.id, `tasks[${index}].id`);
@@ -12369,18 +12700,18 @@ var init_parser = __esm({
12369
12700
  });
12370
12701
 
12371
12702
  // packages/pipeline/src/plan/discovery.ts
12372
- import path14 from "node:path";
12703
+ import path15 from "node:path";
12373
12704
  import * as fsPromises3 from "node:fs/promises";
12374
12705
  function createDefaultFs() {
12375
12706
  return {
12376
12707
  readFile: fsPromises3.readFile,
12377
12708
  readdir: fsPromises3.readdir,
12378
12709
  stat: async (filePath) => {
12379
- const stat6 = await fsPromises3.stat(filePath);
12710
+ const stat8 = await fsPromises3.stat(filePath);
12380
12711
  return {
12381
- isFile: () => stat6.isFile(),
12382
- isDirectory: () => stat6.isDirectory(),
12383
- mtimeMs: stat6.mtimeMs
12712
+ isFile: () => stat8.isFile(),
12713
+ isDirectory: () => stat8.isDirectory(),
12714
+ mtimeMs: stat8.mtimeMs
12384
12715
  };
12385
12716
  }
12386
12717
  };
@@ -12405,10 +12736,10 @@ function countCompletedTasks(planPath, content) {
12405
12736
  };
12406
12737
  }
12407
12738
  async function ensurePlanExists(fs3, cwd, planPath) {
12408
- const absolutePath = path14.isAbsolute(planPath) ? planPath : path14.resolve(cwd, planPath);
12739
+ const absolutePath = path15.isAbsolute(planPath) ? planPath : path15.resolve(cwd, planPath);
12409
12740
  try {
12410
- const stat6 = await fs3.stat(absolutePath);
12411
- if (!stat6.isFile()) {
12741
+ const stat8 = await fs3.stat(absolutePath);
12742
+ if (!stat8.isFile()) {
12412
12743
  throw new Error(`Plan not found at "${planPath}".`);
12413
12744
  }
12414
12745
  } catch (error2) {
@@ -12433,20 +12764,20 @@ async function scanPlansDir(fs3, plansDir, displayPrefix) {
12433
12764
  if (!isPlanCandidateFile(entry)) {
12434
12765
  continue;
12435
12766
  }
12436
- const absolutePath = path14.join(plansDir, entry);
12437
- const stat6 = await fs3.stat(absolutePath);
12438
- if (!stat6.isFile()) {
12767
+ const absolutePath = path15.join(plansDir, entry);
12768
+ const stat8 = await fs3.stat(absolutePath);
12769
+ if (!stat8.isFile()) {
12439
12770
  continue;
12440
12771
  }
12441
- const displayPath = path14.join(displayPrefix, entry);
12772
+ const displayPath = path15.join(displayPrefix, entry);
12442
12773
  const content = await fs3.readFile(absolutePath, "utf8");
12443
12774
  candidates.push(countCompletedTasks(displayPath, content));
12444
12775
  }
12445
12776
  return candidates;
12446
12777
  }
12447
12778
  async function listPlanCandidates(fs3, cwd, homeDir) {
12448
- const projectDir = path14.join(cwd, ".poe-code", "pipeline", "plans");
12449
- const globalDir = path14.join(homeDir, ".poe-code", "pipeline", "plans");
12779
+ const projectDir = path15.join(cwd, ".poe-code", "pipeline", "plans");
12780
+ const globalDir = path15.join(homeDir, ".poe-code", "pipeline", "plans");
12450
12781
  const [projectCandidates, globalCandidates] = await Promise.all([
12451
12782
  scanPlansDir(fs3, projectDir, ".poe-code/pipeline/plans"),
12452
12783
  scanPlansDir(fs3, globalDir, "~/.poe-code/pipeline/plans")
@@ -12457,9 +12788,9 @@ async function listPlanCandidates(fs3, cwd, homeDir) {
12457
12788
  }
12458
12789
  function resolveAbsolutePlanPath(planPath, cwd, homeDir) {
12459
12790
  if (planPath.startsWith("~/")) {
12460
- return path14.join(homeDir, planPath.slice(2));
12791
+ return path15.join(homeDir, planPath.slice(2));
12461
12792
  }
12462
- return path14.isAbsolute(planPath) ? planPath : path14.resolve(cwd, planPath);
12793
+ return path15.isAbsolute(planPath) ? planPath : path15.resolve(cwd, planPath);
12463
12794
  }
12464
12795
  async function resolvePlanPath(options) {
12465
12796
  const fs3 = options.fs ?? createDefaultFs();
@@ -12516,7 +12847,7 @@ var init_discovery = __esm({
12516
12847
  });
12517
12848
 
12518
12849
  // packages/pipeline/src/plan/writer.ts
12519
- import { parseDocument, isMap, isSeq } from "yaml";
12850
+ import { parseDocument as parseDocument2, isMap, isSeq } from "yaml";
12520
12851
  function getTasksNode(document) {
12521
12852
  const tasksNode = document.get("tasks", true);
12522
12853
  if (!tasksNode || !isSeq(tasksNode)) {
@@ -12540,7 +12871,7 @@ async function readPlanFile(fs3, planPath) {
12540
12871
  }
12541
12872
  async function writeTaskStatus(options) {
12542
12873
  const content = await readPlanFile(options.fs, options.planPath);
12543
- const document = parseDocument(content);
12874
+ const document = parseDocument2(content);
12544
12875
  const tasksNode = getTasksNode(document);
12545
12876
  const taskNode = getTaskNode(tasksNode, options.taskId);
12546
12877
  if (options.stepName) {
@@ -12646,11 +12977,11 @@ function createDefaultFs2() {
12646
12977
  },
12647
12978
  rmdir: fsPromises4.rmdir,
12648
12979
  stat: async (filePath) => {
12649
- const stat6 = await fsPromises4.stat(filePath);
12980
+ const stat8 = await fsPromises4.stat(filePath);
12650
12981
  return {
12651
- isFile: () => stat6.isFile(),
12652
- isDirectory: () => stat6.isDirectory(),
12653
- mtimeMs: stat6.mtimeMs
12982
+ isFile: () => stat8.isFile(),
12983
+ isDirectory: () => stat8.isDirectory(),
12984
+ mtimeMs: stat8.mtimeMs
12654
12985
  };
12655
12986
  }
12656
12987
  };
@@ -12683,8 +13014,8 @@ async function lockFile(filePath, options = {}) {
12683
13014
  if (!error2 || typeof error2 !== "object" || !("code" in error2) || error2.code !== "EEXIST") {
12684
13015
  throw error2;
12685
13016
  }
12686
- const stat6 = await fs3.stat(lockPath);
12687
- if (Date.now() - stat6.mtimeMs > staleMs) {
13017
+ const stat8 = await fs3.stat(lockPath);
13018
+ if (Date.now() - stat8.mtimeMs > staleMs) {
12688
13019
  await fs3.rmdir(lockPath);
12689
13020
  continue;
12690
13021
  }
@@ -12702,7 +13033,7 @@ var init_lock = __esm({
12702
13033
  });
12703
13034
 
12704
13035
  // packages/pipeline/src/run/pipeline.ts
12705
- import path15 from "node:path";
13036
+ import path16 from "node:path";
12706
13037
  import * as fsPromises5 from "node:fs/promises";
12707
13038
  function createDefaultFs3() {
12708
13039
  return {
@@ -12710,11 +13041,11 @@ function createDefaultFs3() {
12710
13041
  writeFile: fsPromises5.writeFile,
12711
13042
  readdir: fsPromises5.readdir,
12712
13043
  stat: async (filePath) => {
12713
- const stat6 = await fsPromises5.stat(filePath);
13044
+ const stat8 = await fsPromises5.stat(filePath);
12714
13045
  return {
12715
- isFile: () => stat6.isFile(),
12716
- isDirectory: () => stat6.isDirectory(),
12717
- mtimeMs: stat6.mtimeMs
13046
+ isFile: () => stat8.isFile(),
13047
+ isDirectory: () => stat8.isDirectory(),
13048
+ mtimeMs: stat8.mtimeMs
12718
13049
  };
12719
13050
  },
12720
13051
  mkdir: async (filePath, options) => {
@@ -12738,9 +13069,9 @@ function resolveMode(stepName, steps) {
12738
13069
  return step.mode;
12739
13070
  }
12740
13071
  async function archivePlan(fs3, absolutePlanPath) {
12741
- const dir = path15.dirname(absolutePlanPath);
12742
- const archiveDir = path15.join(dir, "archive");
12743
- const archivePath = path15.join(archiveDir, path15.basename(absolutePlanPath));
13072
+ const dir = path16.dirname(absolutePlanPath);
13073
+ const archiveDir = path16.join(dir, "archive");
13074
+ const archivePath = path16.join(archiveDir, path16.basename(absolutePlanPath));
12744
13075
  await fs3.mkdir(archiveDir, { recursive: true });
12745
13076
  await fs3.rename(absolutePlanPath, archivePath);
12746
13077
  }
@@ -12975,7 +13306,7 @@ var init_pipeline = __esm({
12975
13306
  });
12976
13307
 
12977
13308
  // packages/pipeline/src/index.ts
12978
- var init_src9 = __esm({
13309
+ var init_src11 = __esm({
12979
13310
  "packages/pipeline/src/index.ts"() {
12980
13311
  "use strict";
12981
13312
  init_loader();
@@ -13007,7 +13338,286 @@ async function runPipeline2(options) {
13007
13338
  var init_pipeline2 = __esm({
13008
13339
  async "src/sdk/pipeline.ts"() {
13009
13340
  "use strict";
13010
- init_src9();
13341
+ init_src11();
13342
+ init_src5();
13343
+ await init_spawn3();
13344
+ }
13345
+ });
13346
+
13347
+ // packages/ralph/src/discovery/discovery.ts
13348
+ import path17 from "node:path";
13349
+ import * as fsPromises6 from "node:fs/promises";
13350
+ function createDefaultFs4() {
13351
+ return {
13352
+ readFile: fsPromises6.readFile,
13353
+ readdir: fsPromises6.readdir,
13354
+ stat: async (filePath) => {
13355
+ const stat8 = await fsPromises6.stat(filePath);
13356
+ return {
13357
+ isFile: () => stat8.isFile(),
13358
+ mtimeMs: stat8.mtimeMs
13359
+ };
13360
+ }
13361
+ };
13362
+ }
13363
+ function isNotFound3(error2) {
13364
+ return !!error2 && typeof error2 === "object" && "code" in error2 && error2.code === "ENOENT";
13365
+ }
13366
+ function isMarkdownFile(entry) {
13367
+ return entry.toLowerCase().endsWith(".md");
13368
+ }
13369
+ async function scanDir(fs3, absoluteDir, displayDir) {
13370
+ let entries;
13371
+ try {
13372
+ entries = await fs3.readdir(absoluteDir);
13373
+ } catch (error2) {
13374
+ if (isNotFound3(error2)) {
13375
+ return [];
13376
+ }
13377
+ throw error2;
13378
+ }
13379
+ const docs = [];
13380
+ for (const entry of entries) {
13381
+ if (!isMarkdownFile(entry)) {
13382
+ continue;
13383
+ }
13384
+ const absolutePath = path17.join(absoluteDir, entry);
13385
+ const stat8 = await fs3.stat(absolutePath);
13386
+ if (!stat8.isFile()) {
13387
+ continue;
13388
+ }
13389
+ const displayPath = path17.join(displayDir, entry);
13390
+ docs.push({
13391
+ path: displayPath,
13392
+ displayPath
13393
+ });
13394
+ }
13395
+ return docs;
13396
+ }
13397
+ async function discoverDocs(options) {
13398
+ const fs3 = options.fs ?? createDefaultFs4();
13399
+ const [localDocs, globalDocs] = await Promise.all([
13400
+ scanDir(
13401
+ fs3,
13402
+ path17.join(options.cwd, ".poe-code", "ralph", "plans"),
13403
+ ".poe-code/ralph/plans"
13404
+ ),
13405
+ scanDir(
13406
+ fs3,
13407
+ path17.join(options.homeDir, ".poe-code", "ralph", "plans"),
13408
+ "~/.poe-code/ralph/plans"
13409
+ )
13410
+ ]);
13411
+ return [...localDocs, ...globalDocs].sort((left, right) => {
13412
+ const leftName = path17.basename(left.displayPath).toLowerCase();
13413
+ const rightName = path17.basename(right.displayPath).toLowerCase();
13414
+ return leftName === rightName ? left.displayPath.localeCompare(right.displayPath) : leftName.localeCompare(rightName);
13415
+ });
13416
+ }
13417
+ var init_discovery2 = __esm({
13418
+ "packages/ralph/src/discovery/discovery.ts"() {
13419
+ "use strict";
13420
+ }
13421
+ });
13422
+
13423
+ // packages/ralph/src/overbaking/detector.ts
13424
+ var OverbakingDetector;
13425
+ var init_detector = __esm({
13426
+ "packages/ralph/src/overbaking/detector.ts"() {
13427
+ "use strict";
13428
+ OverbakingDetector = class {
13429
+ threshold;
13430
+ consecutiveFailures = 0;
13431
+ constructor(threshold) {
13432
+ this.threshold = threshold;
13433
+ }
13434
+ record(_success) {
13435
+ if (_success) {
13436
+ this.consecutiveFailures = 0;
13437
+ return {
13438
+ consecutiveFailures: 0,
13439
+ overbaked: false,
13440
+ shouldWarn: false
13441
+ };
13442
+ }
13443
+ this.consecutiveFailures += 1;
13444
+ return {
13445
+ consecutiveFailures: this.consecutiveFailures,
13446
+ overbaked: this.consecutiveFailures >= this.threshold,
13447
+ shouldWarn: this.consecutiveFailures === this.threshold
13448
+ };
13449
+ }
13450
+ };
13451
+ }
13452
+ });
13453
+
13454
+ // packages/ralph/src/run/ralph.ts
13455
+ import path18 from "node:path";
13456
+ import * as fsPromises7 from "node:fs/promises";
13457
+ async function runRalph(options) {
13458
+ const fs3 = options.fs ?? createDefaultFs5();
13459
+ const runAgent = options.runAgent;
13460
+ if (!runAgent) {
13461
+ throw new Error("runRalph requires a runAgent implementation.");
13462
+ }
13463
+ if (!Number.isInteger(options.maxIterations) || options.maxIterations < 1) {
13464
+ throw new Error("maxIterations must be a positive integer.");
13465
+ }
13466
+ const threshold = options.maxFailures ?? 3;
13467
+ if (!Number.isInteger(threshold) || threshold < 1) {
13468
+ throw new Error("maxFailures must be a positive integer.");
13469
+ }
13470
+ const absoluteDocPath = resolveAbsoluteDocPath(
13471
+ options.docPath,
13472
+ options.cwd,
13473
+ options.homeDir
13474
+ );
13475
+ const prompt = await fs3.readFile(absoluteDocPath, "utf8");
13476
+ const detector = new OverbakingDetector(threshold);
13477
+ const startTime = Date.now();
13478
+ let iterationsCompleted = 0;
13479
+ try {
13480
+ for (let iteration = 1; iteration <= options.maxIterations; iteration += 1) {
13481
+ assertNotAborted5(options.signal);
13482
+ options.onIterationStart?.(iteration, options.maxIterations);
13483
+ const iterationStart = Date.now();
13484
+ let result;
13485
+ try {
13486
+ result = await runAgent({
13487
+ agent: options.agent,
13488
+ prompt,
13489
+ cwd: options.cwd,
13490
+ ...options.model ? { model: options.model } : {},
13491
+ ...options.signal ? { signal: options.signal } : {}
13492
+ });
13493
+ } catch (error2) {
13494
+ if (isAbortError2(error2)) {
13495
+ return {
13496
+ stopReason: "cancelled",
13497
+ docPath: options.docPath,
13498
+ iterationsCompleted,
13499
+ totalDurationMs: Date.now() - startTime
13500
+ };
13501
+ }
13502
+ throw error2;
13503
+ }
13504
+ const success2 = result.exitCode === 0;
13505
+ iterationsCompleted += 1;
13506
+ options.onIterationComplete?.(
13507
+ iteration,
13508
+ Date.now() - iterationStart,
13509
+ success2
13510
+ );
13511
+ const overbake = detector.record(success2);
13512
+ if (!overbake.shouldWarn) {
13513
+ continue;
13514
+ }
13515
+ options.onOverbakeWarning?.(
13516
+ overbake.consecutiveFailures,
13517
+ threshold
13518
+ );
13519
+ const action = options.promptOverbake ? await options.promptOverbake({
13520
+ consecutiveFailures: overbake.consecutiveFailures,
13521
+ threshold
13522
+ }) : "abort";
13523
+ if (action === "abort") {
13524
+ return {
13525
+ stopReason: "overbake_abort",
13526
+ docPath: options.docPath,
13527
+ iterationsCompleted,
13528
+ totalDurationMs: Date.now() - startTime
13529
+ };
13530
+ }
13531
+ }
13532
+ } catch (error2) {
13533
+ if (isAbortError2(error2)) {
13534
+ return {
13535
+ stopReason: "cancelled",
13536
+ docPath: options.docPath,
13537
+ iterationsCompleted,
13538
+ totalDurationMs: Date.now() - startTime
13539
+ };
13540
+ }
13541
+ throw error2;
13542
+ }
13543
+ return {
13544
+ stopReason: "max_iterations",
13545
+ docPath: options.docPath,
13546
+ iterationsCompleted,
13547
+ totalDurationMs: Date.now() - startTime
13548
+ };
13549
+ }
13550
+ function createDefaultFs5() {
13551
+ return {
13552
+ readFile: fsPromises7.readFile,
13553
+ readdir: fsPromises7.readdir,
13554
+ stat: async (filePath) => {
13555
+ const stat8 = await fsPromises7.stat(filePath);
13556
+ return {
13557
+ isFile: () => stat8.isFile(),
13558
+ mtimeMs: stat8.mtimeMs
13559
+ };
13560
+ }
13561
+ };
13562
+ }
13563
+ function resolveAbsoluteDocPath(docPath, cwd, homeDir) {
13564
+ if (docPath.startsWith("~/")) {
13565
+ return path18.join(homeDir, docPath.slice(2));
13566
+ }
13567
+ return path18.isAbsolute(docPath) ? docPath : path18.resolve(cwd, docPath);
13568
+ }
13569
+ function assertNotAborted5(signal) {
13570
+ if (!signal?.aborted) {
13571
+ return;
13572
+ }
13573
+ throw createAbortError4();
13574
+ }
13575
+ function createAbortError4() {
13576
+ const error2 = new Error("Ralph run cancelled");
13577
+ error2.name = "AbortError";
13578
+ return error2;
13579
+ }
13580
+ function isAbortError2(error2) {
13581
+ return error2 instanceof Error && error2.name === "AbortError";
13582
+ }
13583
+ var init_ralph = __esm({
13584
+ "packages/ralph/src/run/ralph.ts"() {
13585
+ "use strict";
13586
+ init_detector();
13587
+ }
13588
+ });
13589
+
13590
+ // packages/ralph/src/index.ts
13591
+ var init_src12 = __esm({
13592
+ "packages/ralph/src/index.ts"() {
13593
+ "use strict";
13594
+ init_discovery2();
13595
+ init_detector();
13596
+ init_ralph();
13597
+ }
13598
+ });
13599
+
13600
+ // src/sdk/ralph.ts
13601
+ async function runRalph2(options) {
13602
+ return runRalph({
13603
+ ...options,
13604
+ runAgent: async (input) => {
13605
+ const { events, result } = spawn5(input.agent, {
13606
+ prompt: input.prompt,
13607
+ cwd: input.cwd,
13608
+ model: input.model,
13609
+ mode: "yolo",
13610
+ ...input.signal ? { signal: input.signal } : {}
13611
+ });
13612
+ await renderAcpStream(events);
13613
+ return result;
13614
+ }
13615
+ });
13616
+ }
13617
+ var init_ralph2 = __esm({
13618
+ async "src/sdk/ralph.ts"() {
13619
+ "use strict";
13620
+ init_src12();
13011
13621
  init_src5();
13012
13622
  await init_spawn3();
13013
13623
  }
@@ -13077,13 +13687,13 @@ async function readErrorBody(response) {
13077
13687
  }
13078
13688
  }
13079
13689
  function extractTextContent(data) {
13080
- if (!isRecord3(data)) return void 0;
13690
+ if (!isRecord4(data)) return void 0;
13081
13691
  const choices = data.choices;
13082
13692
  if (!Array.isArray(choices) || choices.length === 0) return void 0;
13083
13693
  const first = choices[0];
13084
- if (!isRecord3(first)) return void 0;
13694
+ if (!isRecord4(first)) return void 0;
13085
13695
  const message = first.message;
13086
- if (!isRecord3(message)) return void 0;
13696
+ if (!isRecord4(message)) return void 0;
13087
13697
  return typeof message.content === "string" ? message.content : void 0;
13088
13698
  }
13089
13699
  function extractMediaFromCompletion(data) {
@@ -13091,14 +13701,14 @@ function extractMediaFromCompletion(data) {
13091
13701
  if (!content) return {};
13092
13702
  try {
13093
13703
  const parsed = JSON.parse(content);
13094
- if (isRecord3(parsed) && typeof parsed.url === "string") {
13704
+ if (isRecord4(parsed) && typeof parsed.url === "string") {
13095
13705
  return {
13096
13706
  url: parsed.url,
13097
13707
  mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0,
13098
13708
  data: typeof parsed.data === "string" ? parsed.data : void 0
13099
13709
  };
13100
13710
  }
13101
- if (isRecord3(parsed) && typeof parsed.data === "string") {
13711
+ if (isRecord4(parsed) && typeof parsed.data === "string") {
13102
13712
  return {
13103
13713
  data: parsed.data,
13104
13714
  mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0
@@ -13132,7 +13742,7 @@ function isValidUrl(value) {
13132
13742
  return false;
13133
13743
  }
13134
13744
  }
13135
- function isRecord3(value) {
13745
+ function isRecord4(value) {
13136
13746
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
13137
13747
  }
13138
13748
  var init_llm_client = __esm({
@@ -13172,218 +13782,6 @@ var init_client_instance = __esm({
13172
13782
  }
13173
13783
  });
13174
13784
 
13175
- // packages/poe-oauth/src/check-auth.ts
13176
- var init_check_auth = __esm({
13177
- "packages/poe-oauth/src/check-auth.ts"() {
13178
- "use strict";
13179
- }
13180
- });
13181
-
13182
- // packages/poe-oauth/src/api-key-validation.ts
13183
- var init_api_key_validation = __esm({
13184
- "packages/poe-oauth/src/api-key-validation.ts"() {
13185
- "use strict";
13186
- }
13187
- });
13188
-
13189
- // packages/poe-oauth/src/oauth-client.ts
13190
- import http from "node:http";
13191
- import crypto from "node:crypto";
13192
- function createOAuthClient(config2) {
13193
- const fetchFn = config2.fetch ?? globalThis.fetch;
13194
- return {
13195
- authorize: () => startAuthorization(config2, fetchFn)
13196
- };
13197
- }
13198
- function generateCodeVerifier() {
13199
- return crypto.randomBytes(32).toString("base64url");
13200
- }
13201
- function generateCodeChallenge(verifier) {
13202
- return crypto.createHash("sha256").update(verifier).digest("base64url");
13203
- }
13204
- async function startAuthorization(config2, fetchFn) {
13205
- const authorizationEndpoint = config2.authorizationEndpoint ?? DEFAULT_AUTHORIZATION_ENDPOINT;
13206
- const tokenEndpoint = config2.tokenEndpoint ?? DEFAULT_TOKEN_ENDPOINT;
13207
- const codeVerifier = generateCodeVerifier();
13208
- const codeChallenge = generateCodeChallenge(codeVerifier);
13209
- const server = config2.createServer ? config2.createServer() : http.createServer();
13210
- const port = await startServer(server);
13211
- const redirectUri = `http://127.0.0.1:${port}/callback`;
13212
- const authorizationUrl = buildAuthorizationUrl({
13213
- endpoint: authorizationEndpoint,
13214
- clientId: config2.clientId,
13215
- redirectUri,
13216
- codeChallenge
13217
- });
13218
- const waitForResult = async () => {
13219
- try {
13220
- const code = await waitForAuthorizationCode(server, config2, authorizationUrl);
13221
- return await exchangeCodeForApiKey({
13222
- tokenEndpoint,
13223
- code,
13224
- codeVerifier,
13225
- clientId: config2.clientId,
13226
- redirectUri,
13227
- fetchFn
13228
- });
13229
- } finally {
13230
- server.closeAllConnections?.();
13231
- server.close();
13232
- }
13233
- };
13234
- return { authorizationUrl, waitForResult };
13235
- }
13236
- function startServer(server) {
13237
- return new Promise((resolve) => {
13238
- server.listen(0, "127.0.0.1", () => {
13239
- const address = server.address();
13240
- resolve(address.port);
13241
- });
13242
- });
13243
- }
13244
- function buildAuthorizationUrl(params) {
13245
- const url2 = new URL(params.endpoint);
13246
- url2.searchParams.set("response_type", "code");
13247
- url2.searchParams.set("client_id", params.clientId);
13248
- url2.searchParams.set("scope", "apikey:create");
13249
- url2.searchParams.set("code_challenge", params.codeChallenge);
13250
- url2.searchParams.set("code_challenge_method", "S256");
13251
- url2.searchParams.set("redirect_uri", params.redirectUri);
13252
- return url2.toString();
13253
- }
13254
- function waitForAuthorizationCode(server, config2, authorizationUrl) {
13255
- return new Promise((resolve, reject) => {
13256
- let settled = false;
13257
- const settle = (fn) => {
13258
- if (!settled) {
13259
- settled = true;
13260
- fn();
13261
- }
13262
- };
13263
- server.on("request", (req, res) => {
13264
- const url2 = new URL(req.url, `http://127.0.0.1`);
13265
- if (url2.pathname !== "/callback") {
13266
- res.writeHead(404);
13267
- res.end("Not found");
13268
- return;
13269
- }
13270
- const error2 = url2.searchParams.get("error");
13271
- if (error2) {
13272
- const description = url2.searchParams.get("error_description") ?? error2;
13273
- res.writeHead(400);
13274
- res.end(`Authorization failed: ${description}`);
13275
- settle(() => reject(new Error(`OAuth authorization failed: ${error2} \u2014 ${description}`)));
13276
- return;
13277
- }
13278
- const code = url2.searchParams.get("code");
13279
- if (!code) {
13280
- res.writeHead(400);
13281
- res.end("Missing authorization code");
13282
- settle(() => reject(new Error("OAuth callback missing authorization code")));
13283
- return;
13284
- }
13285
- res.writeHead(200, { "Content-Type": "text/html" });
13286
- res.end(buildSuccessPage());
13287
- settle(() => resolve(code));
13288
- });
13289
- if (config2.readLine) {
13290
- config2.readLine().then((input) => {
13291
- const code = extractCodeFromInput(input);
13292
- if (code) {
13293
- settle(() => resolve(code));
13294
- }
13295
- }).catch(() => {
13296
- });
13297
- }
13298
- if (config2.openBrowser) {
13299
- config2.openBrowser(authorizationUrl).catch(
13300
- (err) => settle(() => reject(err))
13301
- );
13302
- }
13303
- });
13304
- }
13305
- function extractCodeFromInput(input) {
13306
- const trimmed = input.replace(/[\r\n]/g, "").trim();
13307
- if (trimmed.length === 0) {
13308
- return null;
13309
- }
13310
- try {
13311
- const url2 = new URL(trimmed);
13312
- return url2.searchParams.get("code");
13313
- } catch {
13314
- return trimmed;
13315
- }
13316
- }
13317
- async function exchangeCodeForApiKey(params) {
13318
- const body = new URLSearchParams({
13319
- grant_type: "authorization_code",
13320
- code: params.code,
13321
- code_verifier: params.codeVerifier,
13322
- client_id: params.clientId,
13323
- redirect_uri: params.redirectUri
13324
- });
13325
- const response = await params.fetchFn(params.tokenEndpoint, {
13326
- method: "POST",
13327
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
13328
- body: body.toString()
13329
- });
13330
- if (!response.ok) {
13331
- const text4 = await response.text();
13332
- const description = parseErrorDescription(text4);
13333
- throw new Error(description ?? `Token exchange failed (${response.status}): ${text4}`);
13334
- }
13335
- const data = await response.json();
13336
- if (typeof data.api_key !== "string" || data.api_key.length === 0) {
13337
- throw new Error("Token response missing api_key field");
13338
- }
13339
- return {
13340
- apiKey: data.api_key,
13341
- expiresIn: typeof data.api_key_expires_in === "number" ? data.api_key_expires_in : null
13342
- };
13343
- }
13344
- function parseErrorDescription(text4) {
13345
- try {
13346
- const data = JSON.parse(text4);
13347
- if (typeof data.error_description === "string") {
13348
- return data.error_description;
13349
- }
13350
- if (typeof data.error === "string") {
13351
- return data.error;
13352
- }
13353
- } catch {
13354
- }
13355
- return null;
13356
- }
13357
- function buildSuccessPage() {
13358
- return [
13359
- "<!DOCTYPE html>",
13360
- "<html><head><meta charset=utf-8><title>Connected to Poe</title></head>",
13361
- '<body style="font-family:system-ui,sans-serif;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0">',
13362
- '<div style="text-align:center">',
13363
- "<h1>Connected to Poe</h1>",
13364
- '<p style="color:#666">You can close this tab and return to your terminal.</p>',
13365
- "</div></body></html>"
13366
- ].join("");
13367
- }
13368
- var DEFAULT_AUTHORIZATION_ENDPOINT, DEFAULT_TOKEN_ENDPOINT;
13369
- var init_oauth_client = __esm({
13370
- "packages/poe-oauth/src/oauth-client.ts"() {
13371
- "use strict";
13372
- DEFAULT_AUTHORIZATION_ENDPOINT = "https://poe.com/oauth/authorize";
13373
- DEFAULT_TOKEN_ENDPOINT = "https://api.poe.com/token";
13374
- }
13375
- });
13376
-
13377
- // packages/poe-oauth/src/index.ts
13378
- var init_src10 = __esm({
13379
- "packages/poe-oauth/src/index.ts"() {
13380
- "use strict";
13381
- init_check_auth();
13382
- init_api_key_validation();
13383
- init_oauth_client();
13384
- }
13385
- });
13386
-
13387
13785
  // src/cli/oauth-login.ts
13388
13786
  import { exec as exec2 } from "node:child_process";
13389
13787
  import readline from "node:readline";
@@ -13426,7 +13824,7 @@ function openInBrowser(url2) {
13426
13824
  var init_oauth_login = __esm({
13427
13825
  "src/cli/oauth-login.ts"() {
13428
13826
  "use strict";
13429
- init_src10();
13827
+ init_src7();
13430
13828
  init_src4();
13431
13829
  }
13432
13830
  });
@@ -13496,6 +13894,7 @@ function createCliContainer(dependencies) {
13496
13894
  read: readApiKey,
13497
13895
  write: writeApiKey
13498
13896
  },
13897
+ checkAuth: async (apiKey) => await checkAuth({ apiKey }) !== null,
13499
13898
  confirm: async (message) => {
13500
13899
  const result = await confirm2({ message });
13501
13900
  if (isCancel2(result)) {
@@ -13544,6 +13943,7 @@ var init_container2 = __esm({
13544
13943
  init_service_registry();
13545
13944
  init_context();
13546
13945
  init_prompts2();
13946
+ init_src7();
13547
13947
  init_options();
13548
13948
  init_logger2();
13549
13949
  init_error_logger();
@@ -13557,7 +13957,7 @@ var init_container2 = __esm({
13557
13957
  });
13558
13958
 
13559
13959
  // src/services/config.ts
13560
- import path17 from "node:path";
13960
+ import path20 from "node:path";
13561
13961
  async function deleteConfig(options) {
13562
13962
  const { fs: fs3, filePath } = options;
13563
13963
  try {
@@ -13572,31 +13972,32 @@ async function deleteConfig(options) {
13572
13972
  }
13573
13973
  async function loadConfiguredServices(options) {
13574
13974
  const { fs: fs3, filePath } = options;
13575
- const document = await readConfigDocument(fs3, filePath);
13576
- return { ...document.configured_services ?? {} };
13975
+ await migrateLegacyCredentialsIfNeeded(fs3, filePath);
13976
+ const document = await readDocument(fs3, filePath);
13977
+ return normalizeConfiguredServices(document[configuredServicesScope]);
13577
13978
  }
13578
13979
  async function saveConfiguredService(options) {
13579
13980
  const { fs: fs3, filePath, service, metadata } = options;
13580
- const document = await readConfigDocument(fs3, filePath);
13581
- const normalized = normalizeConfiguredServiceMetadata(metadata);
13582
- document.configured_services = {
13583
- ...document.configured_services ?? {},
13584
- [service]: normalized
13585
- };
13586
- await writeConfigDocument(fs3, filePath, document);
13981
+ await migrateLegacyConfigIfNeeded(fs3, filePath);
13982
+ const document = await readDocument(fs3, filePath);
13983
+ const services = normalizeConfiguredServices(
13984
+ document[configuredServicesScope]
13985
+ );
13986
+ services[service] = normalizeConfiguredServiceMetadata(metadata);
13987
+ await writeScope(fs3, filePath, configuredServicesScope, services);
13587
13988
  }
13588
13989
  async function unconfigureService(options) {
13589
13990
  const { fs: fs3, filePath, service } = options;
13590
- const document = await readConfigDocument(fs3, filePath);
13591
- const services = document.configured_services;
13592
- if (!services || !(service in services)) {
13991
+ await migrateLegacyConfigIfNeeded(fs3, filePath);
13992
+ const document = await readDocument(fs3, filePath);
13993
+ const services = normalizeConfiguredServices(
13994
+ document[configuredServicesScope]
13995
+ );
13996
+ if (!(service in services)) {
13593
13997
  return false;
13594
13998
  }
13595
13999
  delete services[service];
13596
- if (Object.keys(services).length === 0) {
13597
- delete document.configured_services;
13598
- }
13599
- await writeConfigDocument(fs3, filePath, document);
14000
+ await writeScope(fs3, filePath, configuredServicesScope, services);
13600
14001
  return true;
13601
14002
  }
13602
14003
  function normalizeConfiguredServiceMetadata(metadata) {
@@ -13611,47 +14012,78 @@ function normalizeConfiguredServiceMetadata(metadata) {
13611
14012
  seen.add(entry);
13612
14013
  }
13613
14014
  }
13614
- return {
13615
- files
13616
- };
14015
+ return { files };
13617
14016
  }
13618
- async function readConfigDocument(fs3, filePath) {
13619
- try {
13620
- const raw = await fs3.readFile(filePath, "utf8");
13621
- return await parseConfigDocument2(fs3, filePath, raw);
13622
- } catch (error2) {
13623
- if (isNotFound(error2)) {
13624
- return migrateLegacyCredentialsFile(fs3, filePath);
13625
- }
13626
- throw error2;
14017
+ async function migrateLegacyConfigIfNeeded(fs3, filePath) {
14018
+ await migrateLegacyCredentialsIfNeeded(fs3, filePath);
14019
+ const currentRaw = await readFileIfExists(fs3, filePath);
14020
+ if (currentRaw === null) {
14021
+ return;
14022
+ }
14023
+ const legacyDocument = normalizeLegacyConfigDocument(
14024
+ parseLegacyConfigDocument(currentRaw)
14025
+ );
14026
+ if (!legacyDocument.apiKey) {
14027
+ return;
13627
14028
  }
14029
+ const document = await readDocument(fs3, filePath);
14030
+ const existingCore = document[CORE_SCOPE] ?? {};
14031
+ if (typeof existingCore.apiKey === "string" && existingCore.apiKey.length > 0) {
14032
+ return;
14033
+ }
14034
+ await writeScope(fs3, filePath, CORE_SCOPE, {
14035
+ ...existingCore,
14036
+ apiKey: legacyDocument.apiKey
14037
+ });
13628
14038
  }
13629
- async function migrateLegacyCredentialsFile(fs3, configPath) {
13630
- const legacyPath = path17.join(path17.dirname(configPath), "credentials.json");
13631
- try {
13632
- const raw = await fs3.readFile(legacyPath, "utf8");
13633
- const document = await parseConfigDocument2(fs3, legacyPath, raw);
13634
- await writeConfigDocument(fs3, configPath, document);
13635
- await fs3.unlink(legacyPath);
13636
- return document;
13637
- } catch {
13638
- return {};
14039
+ async function migrateLegacyCredentialsIfNeeded(fs3, filePath) {
14040
+ const currentRaw = await readFileIfExists(fs3, filePath);
14041
+ if (currentRaw !== null) {
14042
+ return;
13639
14043
  }
14044
+ await migrateLegacyCredentialsFile(fs3, filePath);
13640
14045
  }
13641
- async function parseConfigDocument2(fs3, filePath, raw) {
14046
+ async function migrateLegacyCredentialsFile(fs3, configPath) {
14047
+ const legacyPath = path20.join(path20.dirname(configPath), "credentials.json");
14048
+ const raw = await readFileIfExists(fs3, legacyPath);
14049
+ if (raw === null) {
14050
+ return;
14051
+ }
14052
+ let legacyDocument;
13642
14053
  try {
13643
- const parsed = JSON.parse(raw);
13644
- return normalizeConfigDocument(parsed);
14054
+ legacyDocument = normalizeLegacyConfigDocument(JSON.parse(raw));
13645
14055
  } catch (error2) {
13646
14056
  if (error2 instanceof SyntaxError) {
13647
- await recoverInvalidConfig(fs3, filePath, raw);
13648
- return {};
14057
+ await recoverInvalidConfig(fs3, legacyPath, raw);
14058
+ await fs3.unlink(legacyPath);
14059
+ return;
13649
14060
  }
13650
14061
  throw error2;
13651
14062
  }
14063
+ if (legacyDocument.configured_services) {
14064
+ await writeScope(
14065
+ fs3,
14066
+ configPath,
14067
+ configuredServicesScope,
14068
+ legacyDocument.configured_services
14069
+ );
14070
+ }
14071
+ if (legacyDocument.apiKey) {
14072
+ await writeScope(fs3, configPath, CORE_SCOPE, {
14073
+ apiKey: legacyDocument.apiKey
14074
+ });
14075
+ }
14076
+ await fs3.unlink(legacyPath);
13652
14077
  }
13653
- function normalizeConfigDocument(value) {
13654
- if (!isRecord4(value)) {
14078
+ function parseLegacyConfigDocument(raw) {
14079
+ try {
14080
+ return JSON.parse(raw);
14081
+ } catch {
14082
+ return null;
14083
+ }
14084
+ }
14085
+ function normalizeLegacyConfigDocument(value) {
14086
+ if (!isRecord5(value)) {
13655
14087
  return {};
13656
14088
  }
13657
14089
  const document = {};
@@ -13665,55 +14097,42 @@ function normalizeConfigDocument(value) {
13665
14097
  return document;
13666
14098
  }
13667
14099
  function normalizeConfiguredServices(value) {
13668
- if (!isRecord4(value)) {
14100
+ if (!isRecord5(value)) {
13669
14101
  return {};
13670
14102
  }
13671
14103
  const entries = {};
13672
14104
  for (const [key, entry] of Object.entries(value)) {
13673
- if (!isRecord4(entry)) {
14105
+ if (!isRecord5(entry)) {
13674
14106
  continue;
13675
14107
  }
13676
- const normalized = normalizeConfiguredServiceMetadata({
14108
+ entries[key] = normalizeConfiguredServiceMetadata({
13677
14109
  files: Array.isArray(entry.files) ? entry.files : []
13678
14110
  });
13679
- entries[key] = normalized;
13680
14111
  }
13681
14112
  return entries;
13682
14113
  }
13683
- async function writeConfigDocument(fs3, filePath, document) {
13684
- await fs3.mkdir(path17.dirname(filePath), { recursive: true });
13685
- const payload = {};
13686
- if (document.apiKey) {
13687
- payload.apiKey = document.apiKey;
13688
- }
13689
- if (document.configured_services) {
13690
- payload.configured_services = document.configured_services;
13691
- }
13692
- await fs3.writeFile(filePath, `${JSON.stringify(payload, null, 2)}
13693
- `, {
13694
- encoding: "utf8"
13695
- });
13696
- }
13697
14114
  async function recoverInvalidConfig(fs3, filePath, content) {
13698
- const backupPath = createInvalidBackupPath(filePath);
14115
+ const backupPath = createInvalidBackupPath2(filePath);
13699
14116
  await fs3.writeFile(backupPath, content, { encoding: "utf8" });
13700
- await fs3.writeFile(filePath, EMPTY_DOCUMENT, { encoding: "utf8" });
14117
+ await fs3.writeFile(filePath, EMPTY_DOCUMENT2, { encoding: "utf8" });
13701
14118
  }
13702
- function createInvalidBackupPath(filePath) {
13703
- const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
13704
- const dir = path17.dirname(filePath);
13705
- const base = path17.basename(filePath);
13706
- return path17.join(dir, `${base}.invalid-${timestamp}.json`);
14119
+ function createInvalidBackupPath2(filePath) {
14120
+ const directory = path20.dirname(filePath);
14121
+ const baseName = path20.basename(filePath);
14122
+ return path20.join(directory, `${baseName}.invalid-${createTimestamp()}.json`);
13707
14123
  }
13708
- function isRecord4(value) {
14124
+ function isRecord5(value) {
13709
14125
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
13710
14126
  }
13711
- var EMPTY_DOCUMENT;
13712
- var init_config2 = __esm({
14127
+ var CORE_SCOPE, configuredServicesScope, EMPTY_DOCUMENT2;
14128
+ var init_config3 = __esm({
13713
14129
  "src/services/config.ts"() {
13714
14130
  "use strict";
13715
14131
  init_src2();
13716
- EMPTY_DOCUMENT = `${JSON.stringify({}, null, 2)}
14132
+ init_src6();
14133
+ CORE_SCOPE = "core";
14134
+ configuredServicesScope = "configured_services";
14135
+ EMPTY_DOCUMENT2 = `${JSON.stringify({}, null, 2)}
13717
14136
  `;
13718
14137
  }
13719
14138
  });
@@ -13882,7 +14301,7 @@ var init_configure = __esm({
13882
14301
  "use strict";
13883
14302
  init_shared();
13884
14303
  init_errors();
13885
- init_config2();
14304
+ init_config3();
13886
14305
  init_mutation_events();
13887
14306
  init_configure_payload();
13888
14307
  serviceSelectionPrompt = (action) => `Pick an agent to ${action}:`;
@@ -13906,7 +14325,7 @@ function registerAgentCommand(program, container) {
13906
14325
  }
13907
14326
  let session;
13908
14327
  try {
13909
- const { createAgentSession: createAgentSession2 } = await Promise.resolve().then(() => (init_src8(), src_exports));
14328
+ const { createAgentSession: createAgentSession2 } = await Promise.resolve().then(() => (init_src10(), src_exports));
13910
14329
  session = await createAgentSession2({
13911
14330
  model: options.model,
13912
14331
  apiKey: options.apiKey,
@@ -13965,7 +14384,7 @@ var init_agent2 = __esm({
13965
14384
  });
13966
14385
 
13967
14386
  // src/cli/commands/spawn.ts
13968
- import path18 from "node:path";
14387
+ import path21 from "node:path";
13969
14388
  function registerSpawnCommand(program, container, options = {}) {
13970
14389
  const spawnServices = container.registry.list().filter((service) => typeof service.spawn === "function" || getSpawnConfig(service.name)).map((service) => service.name);
13971
14390
  const extraServices = options.extraServices ?? [];
@@ -14176,10 +14595,10 @@ function resolveSpawnWorkingDirectory2(baseDir, candidate) {
14176
14595
  if (!candidate || candidate.trim().length === 0) {
14177
14596
  return void 0;
14178
14597
  }
14179
- if (path18.isAbsolute(candidate)) {
14598
+ if (path21.isAbsolute(candidate)) {
14180
14599
  return candidate;
14181
14600
  }
14182
- return path18.resolve(baseDir, candidate);
14601
+ return path21.resolve(baseDir, candidate);
14183
14602
  }
14184
14603
  function parseMcpSpawnConfig2(input) {
14185
14604
  if (!input) {
@@ -14290,7 +14709,7 @@ var init_spawn4 = __esm({
14290
14709
  init_src5();
14291
14710
  init_src3();
14292
14711
  init_src4();
14293
- init_config2();
14712
+ init_config3();
14294
14713
  init_shared();
14295
14714
  init_spawn_core();
14296
14715
  await init_spawn3();
@@ -14299,7 +14718,7 @@ var init_spawn4 = __esm({
14299
14718
  });
14300
14719
 
14301
14720
  // src/sdk/research.ts
14302
- import path19 from "node:path";
14721
+ import path22 from "node:path";
14303
14722
  async function research(container, options) {
14304
14723
  const logger2 = options.logger;
14305
14724
  const source = await resolveSource({
@@ -14334,7 +14753,7 @@ async function research(container, options) {
14334
14753
  markdown: markdownOutput
14335
14754
  });
14336
14755
  outputPath = buildOutputPath(container.env.homeDir, options.prompt);
14337
- await ensureDirectory2(container.fs, path19.dirname(outputPath));
14756
+ await ensureDirectory2(container.fs, path22.dirname(outputPath));
14338
14757
  await container.fs.writeFile(outputPath, document, {
14339
14758
  encoding: "utf8"
14340
14759
  });
@@ -14409,7 +14828,7 @@ function buildResearchDocument(input) {
14409
14828
  }
14410
14829
  function buildClonePath(homeDir, github) {
14411
14830
  const slug = extractRepoSlug(github);
14412
- return path19.join(homeDir, ".poe-code", "repos", slug);
14831
+ return path22.join(homeDir, ".poe-code", "repos", slug);
14413
14832
  }
14414
14833
  function extractRepoSlug(value) {
14415
14834
  const trimmed = value.trim();
@@ -14447,7 +14866,7 @@ function extractRepoSlug(value) {
14447
14866
  function buildOutputPath(homeDir, prompt, now = /* @__PURE__ */ new Date()) {
14448
14867
  const timestamp = formatTimestamp2(now);
14449
14868
  const slug = buildSlug(prompt);
14450
- return path19.join(
14869
+ return path22.join(
14451
14870
  homeDir,
14452
14871
  ".poe-code",
14453
14872
  "research",
@@ -14468,7 +14887,7 @@ async function resolveSource(input) {
14468
14887
  if (options.github) {
14469
14888
  const cloneUrl = resolveGithubCloneUrl(options.github);
14470
14889
  const clonePath = buildClonePath(container.env.homeDir, options.github);
14471
- await ensureDirectory2(container.fs, path19.dirname(clonePath));
14890
+ await ensureDirectory2(container.fs, path22.dirname(clonePath));
14472
14891
  const exists = await pathExists2(container.fs, clonePath);
14473
14892
  if (!exists) {
14474
14893
  const cloneResult = await container.commandRunner(
@@ -14566,10 +14985,10 @@ function formatYamlString(value) {
14566
14985
  return JSON.stringify(value);
14567
14986
  }
14568
14987
  function resolvePath2(baseDir, candidate) {
14569
- if (path19.isAbsolute(candidate)) {
14988
+ if (path22.isAbsolute(candidate)) {
14570
14989
  return candidate;
14571
14990
  }
14572
- return path19.resolve(baseDir, candidate);
14991
+ return path22.resolve(baseDir, candidate);
14573
14992
  }
14574
14993
  function teeAcpStream(events) {
14575
14994
  const chunks = [];
@@ -14629,7 +15048,7 @@ async function removePathFallback(fs3, target) {
14629
15048
  if (stats && typeof stats.isDirectory === "function" && stats.isDirectory()) {
14630
15049
  const entries = await fs3.readdir(target);
14631
15050
  for (const entry of entries) {
14632
- await removePathFallback(fs3, path19.join(target, entry));
15051
+ await removePathFallback(fs3, path22.join(target, entry));
14633
15052
  }
14634
15053
  }
14635
15054
  try {
@@ -14796,7 +15215,7 @@ var init_research2 = __esm({
14796
15215
  async "src/cli/commands/research.ts"() {
14797
15216
  "use strict";
14798
15217
  init_src5();
14799
- init_config2();
15218
+ init_config3();
14800
15219
  await init_research();
14801
15220
  init_errors();
14802
15221
  init_shared();
@@ -15026,7 +15445,7 @@ var init_login = __esm({
15026
15445
  "use strict";
15027
15446
  init_shared();
15028
15447
  init_errors();
15029
- init_config2();
15448
+ init_config3();
15030
15449
  init_mutation_events();
15031
15450
  }
15032
15451
  });
@@ -15151,7 +15570,7 @@ function formatUnconfigureMessages(service, label, unconfigured, _payload) {
15151
15570
  var init_unconfigure = __esm({
15152
15571
  "src/cli/commands/unconfigure.ts"() {
15153
15572
  "use strict";
15154
- init_config2();
15573
+ init_config3();
15155
15574
  init_mutation_events();
15156
15575
  init_isolated_env();
15157
15576
  init_shared();
@@ -15205,7 +15624,7 @@ async function executeLogout(program, container) {
15205
15624
  var init_logout = __esm({
15206
15625
  "src/cli/commands/logout.ts"() {
15207
15626
  "use strict";
15208
- init_config2();
15627
+ init_config3();
15209
15628
  init_shared();
15210
15629
  init_unconfigure();
15211
15630
  }
@@ -15305,7 +15724,7 @@ var init_auth = __esm({
15305
15724
  "src/cli/commands/auth.ts"() {
15306
15725
  "use strict";
15307
15726
  init_errors();
15308
- init_config2();
15727
+ init_config3();
15309
15728
  init_shared();
15310
15729
  init_login();
15311
15730
  init_logout();
@@ -15508,7 +15927,7 @@ var init_media_download = __esm({
15508
15927
  });
15509
15928
 
15510
15929
  // src/cli/commands/generate.ts
15511
- import path20 from "node:path";
15930
+ import path23 from "node:path";
15512
15931
  function registerGenerateCommand(program, container) {
15513
15932
  const generate2 = program.command("generate").description("Generate content via Poe API").option("--model <model>", `Model identifier (default: ${DEFAULT_TEXT_MODEL})`).option(
15514
15933
  "--param <key=value>",
@@ -15774,11 +16193,11 @@ function getDefaultMimeType(type) {
15774
16193
  return defaults[type];
15775
16194
  }
15776
16195
  function resolveOutputPath(filename, cwd) {
15777
- if (path20.isAbsolute(filename)) {
16196
+ if (path23.isAbsolute(filename)) {
15778
16197
  return { path: filename, label: filename };
15779
16198
  }
15780
16199
  return {
15781
- path: path20.join(cwd, filename),
16200
+ path: path23.join(cwd, filename),
15782
16201
  label: `./${filename}`
15783
16202
  };
15784
16203
  }
@@ -16471,7 +16890,7 @@ function defineSchema(definition) {
16471
16890
  required: required2
16472
16891
  };
16473
16892
  }
16474
- var init_schema = __esm({
16893
+ var init_schema2 = __esm({
16475
16894
  "packages/tiny-stdio-mcp-server/src/schema.ts"() {
16476
16895
  "use strict";
16477
16896
  }
@@ -16882,8 +17301,8 @@ var init_parseUtil = __esm({
16882
17301
  init_errors3();
16883
17302
  init_en();
16884
17303
  makeIssue = (params) => {
16885
- const { data, path: path24, errorMaps, issueData } = params;
16886
- const fullPath = [...path24, ...issueData.path || []];
17304
+ const { data, path: path27, errorMaps, issueData } = params;
17305
+ const fullPath = [...path27, ...issueData.path || []];
16887
17306
  const fullIssue = {
16888
17307
  ...issueData,
16889
17308
  path: fullPath
@@ -17163,11 +17582,11 @@ var init_types4 = __esm({
17163
17582
  init_parseUtil();
17164
17583
  init_util();
17165
17584
  ParseInputLazyPath = class {
17166
- constructor(parent, value, path24, key) {
17585
+ constructor(parent, value, path27, key) {
17167
17586
  this._cachedPath = [];
17168
17587
  this.parent = parent;
17169
17588
  this.data = value;
17170
- this._path = path24;
17589
+ this._path = path27;
17171
17590
  this._key = key;
17172
17591
  }
17173
17592
  get path() {
@@ -20671,10 +21090,10 @@ function mergeDefs(...defs) {
20671
21090
  function cloneDef(schema) {
20672
21091
  return mergeDefs(schema._zod.def);
20673
21092
  }
20674
- function getElementAtPath(obj, path24) {
20675
- if (!path24)
21093
+ function getElementAtPath(obj, path27) {
21094
+ if (!path27)
20676
21095
  return obj;
20677
- return path24.reduce((acc, key) => acc?.[key], obj);
21096
+ return path27.reduce((acc, key) => acc?.[key], obj);
20678
21097
  }
20679
21098
  function promiseAllObject(promisesObj) {
20680
21099
  const keys = Object.keys(promisesObj);
@@ -20986,11 +21405,11 @@ function aborted(x, startIndex = 0) {
20986
21405
  }
20987
21406
  return false;
20988
21407
  }
20989
- function prefixIssues(path24, issues) {
21408
+ function prefixIssues(path27, issues) {
20990
21409
  return issues.map((iss) => {
20991
21410
  var _a2;
20992
21411
  (_a2 = iss).path ?? (_a2.path = []);
20993
- iss.path.unshift(path24);
21412
+ iss.path.unshift(path27);
20994
21413
  return iss;
20995
21414
  });
20996
21415
  }
@@ -33151,8 +33570,8 @@ var require_utils = __commonJS({
33151
33570
  }
33152
33571
  return ind;
33153
33572
  }
33154
- function removeDotSegments(path24) {
33155
- let input = path24;
33573
+ function removeDotSegments(path27) {
33574
+ let input = path27;
33156
33575
  const output = [];
33157
33576
  let nextSlash = -1;
33158
33577
  let len = 0;
@@ -33351,8 +33770,8 @@ var require_schemes = __commonJS({
33351
33770
  wsComponent.secure = void 0;
33352
33771
  }
33353
33772
  if (wsComponent.resourceName) {
33354
- const [path24, query] = wsComponent.resourceName.split("?");
33355
- wsComponent.path = path24 && path24 !== "/" ? path24 : void 0;
33773
+ const [path27, query] = wsComponent.resourceName.split("?");
33774
+ wsComponent.path = path27 && path27 !== "/" ? path27 : void 0;
33356
33775
  wsComponent.query = query;
33357
33776
  wsComponent.resourceName = void 0;
33358
33777
  }
@@ -36585,11 +37004,11 @@ var init_content = __esm({
36585
37004
  });
36586
37005
 
36587
37006
  // packages/tiny-stdio-mcp-server/src/index.ts
36588
- var init_src11 = __esm({
37007
+ var init_src13 = __esm({
36589
37008
  "packages/tiny-stdio-mcp-server/src/index.ts"() {
36590
37009
  "use strict";
36591
37010
  init_server();
36592
- init_schema();
37011
+ init_schema2();
36593
37012
  init_testing();
36594
37013
  init_content();
36595
37014
  init_types3();
@@ -36889,7 +37308,7 @@ var generateTextSchema, generateImageSchema, generateVideoSchema, generateAudioS
36889
37308
  var init_mcp_server = __esm({
36890
37309
  "src/cli/mcp-server.ts"() {
36891
37310
  "use strict";
36892
- init_src11();
37311
+ init_src13();
36893
37312
  init_client_instance();
36894
37313
  init_constants();
36895
37314
  generateTextSchema = defineSchema({
@@ -37295,9 +37714,9 @@ var init_shapes = __esm({
37295
37714
  });
37296
37715
 
37297
37716
  // packages/agent-mcp-config/src/apply.ts
37298
- import path21 from "node:path";
37717
+ import path24 from "node:path";
37299
37718
  function getConfigDirectory(configPath) {
37300
- return path21.dirname(configPath);
37719
+ return path24.dirname(configPath);
37301
37720
  }
37302
37721
  function isConfigObject5(value) {
37303
37722
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
@@ -37399,7 +37818,7 @@ var init_apply = __esm({
37399
37818
  });
37400
37819
 
37401
37820
  // packages/agent-mcp-config/src/index.ts
37402
- var init_src12 = __esm({
37821
+ var init_src14 = __esm({
37403
37822
  "packages/agent-mcp-config/src/index.ts"() {
37404
37823
  "use strict";
37405
37824
  init_configs2();
@@ -37579,7 +37998,7 @@ var init_mcp2 = __esm({
37579
37998
  init_shared();
37580
37999
  init_mcp_output_format();
37581
38000
  init_command_not_found();
37582
- init_src12();
38001
+ init_src14();
37583
38002
  init_execution_context();
37584
38003
  DEFAULT_MCP_AGENT = "claude-code";
37585
38004
  }
@@ -37587,7 +38006,7 @@ var init_mcp2 = __esm({
37587
38006
 
37588
38007
  // packages/agent-skill-config/src/configs.ts
37589
38008
  import os2 from "node:os";
37590
- import path22 from "node:path";
38009
+ import path25 from "node:path";
37591
38010
  function resolveAgentSupport2(input, registry2 = agentSkillConfigs) {
37592
38011
  const resolvedId = resolveAgentId(input);
37593
38012
  if (!resolvedId) {
@@ -37623,7 +38042,7 @@ var init_configs3 = __esm({
37623
38042
  });
37624
38043
 
37625
38044
  // packages/agent-skill-config/src/templates.ts
37626
- import { readFile as readFile5 } from "node:fs/promises";
38045
+ import { readFile as readFile7 } from "node:fs/promises";
37627
38046
  async function getTemplates() {
37628
38047
  if (templatesCache) {
37629
38048
  return templatesCache;
@@ -37632,7 +38051,7 @@ async function getTemplates() {
37632
38051
  "./templates/poe-generate.md",
37633
38052
  import.meta.url
37634
38053
  );
37635
- const poeGenerateTemplate = await readFile5(poeGenerateTemplateUrl, "utf8");
38054
+ const poeGenerateTemplate = await readFile7(poeGenerateTemplateUrl, "utf8");
37636
38055
  templatesCache = {
37637
38056
  "poe-generate.md": poeGenerateTemplate
37638
38057
  };
@@ -37779,7 +38198,7 @@ var init_apply2 = __esm({
37779
38198
  });
37780
38199
 
37781
38200
  // packages/agent-skill-config/src/index.ts
37782
- var init_src13 = __esm({
38201
+ var init_src15 = __esm({
37783
38202
  "packages/agent-skill-config/src/index.ts"() {
37784
38203
  "use strict";
37785
38204
  init_configs3();
@@ -38004,7 +38423,7 @@ var init_skill = __esm({
38004
38423
  "src/cli/commands/skill.ts"() {
38005
38424
  "use strict";
38006
38425
  init_src4();
38007
- init_src13();
38426
+ init_src15();
38008
38427
  init_shared();
38009
38428
  init_command_not_found();
38010
38429
  DEFAULT_SKILL_AGENT = "claude-code";
@@ -38598,8 +39017,8 @@ var init_models = __esm({
38598
39017
  });
38599
39018
 
38600
39019
  // src/cli/commands/pipeline.ts
38601
- import path23 from "node:path";
38602
- import { readFile as readFile6, stat as stat5 } from "node:fs/promises";
39020
+ import path26 from "node:path";
39021
+ import { readFile as readFile8, stat as stat7 } from "node:fs/promises";
38603
39022
  import { fileURLToPath as fileURLToPath4 } from "node:url";
38604
39023
  function formatDuration(ms) {
38605
39024
  const totalSeconds = Math.round(ms / 1e3);
@@ -38630,11 +39049,11 @@ function resolveMaxRuns(value) {
38630
39049
  return parsed;
38631
39050
  }
38632
39051
  function resolvePipelinePaths(scope, cwd, homeDir) {
38633
- const rootPath = scope === "global" ? path23.join(homeDir, ".poe-code", "pipeline") : path23.join(cwd, ".poe-code", "pipeline");
39052
+ const rootPath = scope === "global" ? path26.join(homeDir, ".poe-code", "pipeline") : path26.join(cwd, ".poe-code", "pipeline");
38634
39053
  const displayRoot = scope === "global" ? "~/.poe-code/pipeline" : ".poe-code/pipeline";
38635
39054
  return {
38636
- plansPath: path23.join(rootPath, "plans"),
38637
- stepsPath: path23.join(rootPath, "steps.yaml"),
39055
+ plansPath: path26.join(rootPath, "plans"),
39056
+ stepsPath: path26.join(rootPath, "steps.yaml"),
38638
39057
  displayPlansPath: `${displayRoot}/plans`,
38639
39058
  displayStepsPath: `${displayRoot}/steps.yaml`
38640
39059
  };
@@ -38645,16 +39064,16 @@ async function loadPipelineTemplates() {
38645
39064
  }
38646
39065
  const packageRoot = await findPackageRoot(fileURLToPath4(import.meta.url));
38647
39066
  const templateRoots = [
38648
- path23.join(packageRoot, "src", "templates", "pipeline"),
38649
- path23.join(packageRoot, "dist", "templates", "pipeline")
39067
+ path26.join(packageRoot, "src", "templates", "pipeline"),
39068
+ path26.join(packageRoot, "dist", "templates", "pipeline")
38650
39069
  ];
38651
39070
  for (const templateRoot of templateRoots) {
38652
39071
  if (!await pathExistsOnDisk(templateRoot)) {
38653
39072
  continue;
38654
39073
  }
38655
39074
  const [skillPlan, steps] = await Promise.all([
38656
- readFile6(path23.join(templateRoot, "SKILL_plan.md"), "utf8"),
38657
- readFile6(path23.join(templateRoot, "steps.yaml.hbs"), "utf8")
39075
+ readFile8(path26.join(templateRoot, "SKILL_plan.md"), "utf8"),
39076
+ readFile8(path26.join(templateRoot, "steps.yaml.hbs"), "utf8")
38658
39077
  ]);
38659
39078
  pipelineTemplatesCache = { skillPlan, steps };
38660
39079
  return pipelineTemplatesCache;
@@ -38663,7 +39082,7 @@ async function loadPipelineTemplates() {
38663
39082
  }
38664
39083
  async function pathExistsOnDisk(targetPath) {
38665
39084
  try {
38666
- await stat5(targetPath);
39085
+ await stat7(targetPath);
38667
39086
  return true;
38668
39087
  } catch (error2) {
38669
39088
  if (error2 && typeof error2 === "object" && "code" in error2 && error2.code === "ENOENT") {
@@ -38673,12 +39092,12 @@ async function pathExistsOnDisk(targetPath) {
38673
39092
  }
38674
39093
  }
38675
39094
  async function findPackageRoot(entryFilePath) {
38676
- let currentPath = path23.dirname(entryFilePath);
39095
+ let currentPath = path26.dirname(entryFilePath);
38677
39096
  while (true) {
38678
- if (await pathExistsOnDisk(path23.join(currentPath, "package.json"))) {
39097
+ if (await pathExistsOnDisk(path26.join(currentPath, "package.json"))) {
38679
39098
  return currentPath;
38680
39099
  }
38681
- const parentPath = path23.dirname(currentPath);
39100
+ const parentPath = path26.dirname(currentPath);
38682
39101
  if (parentPath === currentPath) {
38683
39102
  throw new Error("Unable to locate package root for Pipeline templates.");
38684
39103
  }
@@ -38956,7 +39375,7 @@ function registerPipelineCommand(program, container) {
38956
39375
  `Would ${stepsExists ? "overwrite" : "create"}: ${pipelinePaths.displayStepsPath}`
38957
39376
  );
38958
39377
  } else {
38959
- await container.fs.mkdir(path23.dirname(pipelinePaths.stepsPath), {
39378
+ await container.fs.mkdir(path26.dirname(pipelinePaths.stepsPath), {
38960
39379
  recursive: true
38961
39380
  });
38962
39381
  await container.fs.writeFile(pipelinePaths.stepsPath, templates.steps, {
@@ -38981,24 +39400,244 @@ var init_pipeline4 = __esm({
38981
39400
  "use strict";
38982
39401
  init_src4();
38983
39402
  init_src3();
38984
- init_src13();
39403
+ init_src15();
38985
39404
  init_errors();
38986
39405
  init_shared();
38987
39406
  await init_pipeline2();
38988
- init_src9();
39407
+ init_src11();
38989
39408
  DEFAULT_PIPELINE_AGENT = "claude-code";
38990
39409
  DEFAULT_PIPELINE_SCOPE = "local";
38991
39410
  pipelineTemplatesCache = null;
38992
39411
  }
38993
39412
  });
38994
39413
 
39414
+ // src/cli/commands/ralph.ts
39415
+ function formatDuration2(ms) {
39416
+ const totalSeconds = Math.round(ms / 1e3);
39417
+ const minutes = Math.floor(totalSeconds / 60);
39418
+ const seconds = totalSeconds % 60;
39419
+ return minutes > 0 ? `${minutes}m ${seconds}s` : `${seconds}s`;
39420
+ }
39421
+ function resolveRalphAgent(value) {
39422
+ if (!value || value.trim().length === 0) {
39423
+ return DEFAULT_RALPH_AGENT;
39424
+ }
39425
+ const resolved = resolveAgentId(value.trim());
39426
+ if (!resolved) {
39427
+ throw new ValidationError(`Unsupported agent: ${value}`);
39428
+ }
39429
+ return resolved;
39430
+ }
39431
+ function parsePositiveInt(value, fieldName) {
39432
+ if (value == null) {
39433
+ return void 0;
39434
+ }
39435
+ const parsed = Number.parseInt(value, 10);
39436
+ if (!Number.isFinite(parsed) || parsed < 1) {
39437
+ throw new ValidationError(
39438
+ `Invalid ${fieldName} "${value}". Expected a positive integer.`
39439
+ );
39440
+ }
39441
+ return parsed;
39442
+ }
39443
+ async function resolveAgent(options) {
39444
+ if (options.providedAgent) {
39445
+ return resolveRalphAgent(options.providedAgent);
39446
+ }
39447
+ const flags = resolveCommandFlags(options.program);
39448
+ if (flags.assumeYes) {
39449
+ return DEFAULT_RALPH_AGENT;
39450
+ }
39451
+ const selected = await select2({
39452
+ message: "Select agent to run Ralph with:",
39453
+ options: allSpawnConfigs.map((config2) => ({
39454
+ label: config2.agentId,
39455
+ value: config2.agentId
39456
+ }))
39457
+ });
39458
+ if (isCancel2(selected)) {
39459
+ cancel2("Ralph run cancelled.");
39460
+ return null;
39461
+ }
39462
+ return resolveRalphAgent(typeof selected === "string" ? selected : void 0);
39463
+ }
39464
+ async function resolveDocPath(options) {
39465
+ if (options.providedDoc && options.providedDoc.trim().length > 0) {
39466
+ return options.providedDoc.trim();
39467
+ }
39468
+ const docs = await discoverDocs({
39469
+ cwd: options.container.env.cwd,
39470
+ homeDir: options.container.env.homeDir,
39471
+ fs: options.container.fs
39472
+ });
39473
+ if (docs.length === 0) {
39474
+ throw new ValidationError(
39475
+ "No markdown doc found under .poe-code/ralph/plans/ or ~/.poe-code/ralph/plans/. Provide a doc path."
39476
+ );
39477
+ }
39478
+ const flags = resolveCommandFlags(options.program);
39479
+ if (flags.assumeYes) {
39480
+ return docs[0].path;
39481
+ }
39482
+ const selected = await select2({
39483
+ message: "Select the Ralph markdown doc to run:",
39484
+ options: docs.map((doc) => ({
39485
+ label: doc.displayPath,
39486
+ value: doc.path
39487
+ }))
39488
+ });
39489
+ if (isCancel2(selected)) {
39490
+ cancel2("Ralph run cancelled.");
39491
+ return null;
39492
+ }
39493
+ return typeof selected === "string" ? selected : null;
39494
+ }
39495
+ async function resolveIterations(options) {
39496
+ const explicitIterations = parsePositiveInt(
39497
+ options.providedIterations,
39498
+ "iterations"
39499
+ );
39500
+ if (explicitIterations != null) {
39501
+ return explicitIterations;
39502
+ }
39503
+ const flags = resolveCommandFlags(options.program);
39504
+ if (flags.assumeYes) {
39505
+ throw new ValidationError(
39506
+ "Iterations are required when using --yes. Provide poe-code ralph run <iterations> [doc]."
39507
+ );
39508
+ }
39509
+ const entered = await text3({
39510
+ message: "How many Ralph iterations should run?"
39511
+ });
39512
+ if (isCancel2(entered)) {
39513
+ cancel2("Ralph run cancelled.");
39514
+ return null;
39515
+ }
39516
+ return parsePositiveInt(
39517
+ typeof entered === "string" ? entered.trim() : void 0,
39518
+ "iterations"
39519
+ ) ?? null;
39520
+ }
39521
+ function registerRalphCommand(program, container) {
39522
+ const ralph = program.command("ralph").description("Run a simple iterative markdown loop.");
39523
+ ralph.command("run").description("Run the selected markdown doc through repeated agent iterations.").argument("[iterations]", "Number of Ralph iterations to run").argument("[doc]", "Markdown doc path").option("--agent <name>", "Agent to run each iteration with").option("--model <model>", "Model override passed to the agent").option(
39524
+ "--max-failures <n>",
39525
+ "Consecutive failure threshold before overbake protection prompts"
39526
+ ).action(async function(iterationsArg, docArg) {
39527
+ const flags = resolveCommandFlags(program);
39528
+ const resources = createExecutionResources(container, flags, "ralph:run");
39529
+ const options = this.opts();
39530
+ resources.logger.intro("ralph run");
39531
+ try {
39532
+ const docPath = await resolveDocPath({
39533
+ container,
39534
+ program,
39535
+ providedDoc: docArg
39536
+ });
39537
+ if (!docPath) {
39538
+ return;
39539
+ }
39540
+ const agent2 = await resolveAgent({
39541
+ program,
39542
+ providedAgent: options.agent
39543
+ });
39544
+ if (!agent2) {
39545
+ return;
39546
+ }
39547
+ const maxIterations = await resolveIterations({
39548
+ program,
39549
+ providedIterations: iterationsArg
39550
+ });
39551
+ if (maxIterations == null) {
39552
+ return;
39553
+ }
39554
+ const maxFailures = parsePositiveInt(
39555
+ options.maxFailures,
39556
+ "max-failures"
39557
+ );
39558
+ const result = await runRalph2({
39559
+ agent: agent2,
39560
+ cwd: container.env.cwd,
39561
+ homeDir: container.env.homeDir,
39562
+ docPath,
39563
+ maxIterations,
39564
+ ...options.model ? { model: options.model } : {},
39565
+ ...maxFailures != null ? { maxFailures } : {},
39566
+ promptOverbake: async (input) => {
39567
+ const selected = await select2({
39568
+ message: `Ralph hit ${input.consecutiveFailures} consecutive failures (threshold ${input.threshold}). What should happen next?`,
39569
+ options: [
39570
+ { label: "Continue", value: "continue" },
39571
+ { label: "Abort", value: "abort" }
39572
+ ]
39573
+ });
39574
+ if (isCancel2(selected)) {
39575
+ cancel2("Ralph run cancelled.");
39576
+ return "abort";
39577
+ }
39578
+ return selected === "continue" ? "continue" : "abort";
39579
+ },
39580
+ onIterationStart(iteration, total) {
39581
+ resources.logger.info(`Iteration ${iteration}/${total}`);
39582
+ },
39583
+ onIterationComplete(iteration, durationMs, success2) {
39584
+ const status = success2 ? "done" : "failed";
39585
+ resources.logger.info(
39586
+ `Iteration ${iteration} ${status} in ${formatDuration2(durationMs)}`
39587
+ );
39588
+ },
39589
+ onOverbakeWarning(consecutiveFailures, threshold) {
39590
+ resources.logger.warn(
39591
+ `Overbake protection triggered at ${consecutiveFailures} consecutive failures (threshold ${threshold}).`
39592
+ );
39593
+ }
39594
+ });
39595
+ const summary = [
39596
+ `Iterations: ${result.iterationsCompleted}/${maxIterations}`,
39597
+ `Doc: ${result.docPath}`,
39598
+ `Duration: ${formatDuration2(result.totalDurationMs)}`
39599
+ ].join("\n ");
39600
+ if (result.stopReason === "cancelled") {
39601
+ process.exitCode = 130;
39602
+ resources.logger.warn("Ralph run cancelled.");
39603
+ resources.logger.resolved("Run summary", summary);
39604
+ return;
39605
+ }
39606
+ if (result.stopReason === "overbake_abort") {
39607
+ process.exitCode = 1;
39608
+ resources.logger.warn("Ralph stopped after repeated failures.");
39609
+ resources.logger.resolved("Run summary", summary);
39610
+ return;
39611
+ }
39612
+ resources.logger.resolved("Run summary", summary);
39613
+ resources.logger.success("Ralph run finished.");
39614
+ } finally {
39615
+ resources.context.finalize();
39616
+ }
39617
+ });
39618
+ }
39619
+ var DEFAULT_RALPH_AGENT;
39620
+ var init_ralph3 = __esm({
39621
+ async "src/cli/commands/ralph.ts"() {
39622
+ "use strict";
39623
+ init_src4();
39624
+ init_src3();
39625
+ init_src5();
39626
+ init_src12();
39627
+ init_errors();
39628
+ init_shared();
39629
+ await init_ralph2();
39630
+ DEFAULT_RALPH_AGENT = "claude-code";
39631
+ }
39632
+ });
39633
+
38995
39634
  // package.json
38996
39635
  var package_default;
38997
39636
  var init_package = __esm({
38998
39637
  "package.json"() {
38999
39638
  package_default = {
39000
39639
  name: "poe-code",
39001
- version: "3.0.101",
39640
+ version: "3.0.103",
39002
39641
  description: "CLI tool to configure Poe API for developer workflows.",
39003
39642
  type: "module",
39004
39643
  main: "./dist/index.js",
@@ -39091,6 +39730,8 @@ var init_package = __esm({
39091
39730
  "@poe-code/freeze-cli": "*",
39092
39731
  "@poe-code/pipeline": "*",
39093
39732
  "@poe-code/poe-acp-client": "*",
39733
+ "@poe-code/poe-code-config": "*",
39734
+ "@poe-code/ralph": "*",
39094
39735
  "@types/mustache": "^4.2.6",
39095
39736
  "@types/node": "^25.2.2",
39096
39737
  "@types/semver": "^7.7.1",
@@ -39214,6 +39855,11 @@ function formatHelpText(input) {
39214
39855
  args: "",
39215
39856
  description: "Run a fixed-step task pipeline plan"
39216
39857
  },
39858
+ {
39859
+ name: "ralph run",
39860
+ args: "[iterations] [doc]",
39861
+ description: "Run a markdown doc through repeated agent iterations"
39862
+ },
39217
39863
  {
39218
39864
  name: "usage",
39219
39865
  args: "",
@@ -39223,11 +39869,6 @@ function formatHelpText(input) {
39223
39869
  name: "usage list",
39224
39870
  args: "",
39225
39871
  description: "Display usage history"
39226
- },
39227
- {
39228
- name: "pipeline run",
39229
- args: "",
39230
- description: "Run a fixed-step task pipeline plan"
39231
39872
  }
39232
39873
  ];
39233
39874
  const nameWidth = Math.max(0, ...commandRows.map((row) => row.name.length));
@@ -39377,6 +40018,7 @@ function bootstrapProgram(container) {
39377
40018
  registerMcpCommand(program, container);
39378
40019
  registerSkillCommand(program, container);
39379
40020
  registerPipelineCommand(program, container);
40021
+ registerRalphCommand(program, container);
39380
40022
  registerUsageCommand(program, container);
39381
40023
  registerModelsCommand(program, container);
39382
40024
  program.allowExcessArguments().action(function() {
@@ -39434,6 +40076,7 @@ var init_program = __esm({
39434
40076
  init_usage();
39435
40077
  init_models();
39436
40078
  await init_pipeline4();
40079
+ await init_ralph3();
39437
40080
  init_package();
39438
40081
  init_command_not_found();
39439
40082
  init_execution_context();
@@ -39607,6 +40250,7 @@ var init_bootstrap = __esm({
39607
40250
  // src/index.ts
39608
40251
  await init_spawn3();
39609
40252
  await init_pipeline2();
40253
+ await init_ralph2();
39610
40254
  import { realpathSync as realpathSync2 } from "node:fs";
39611
40255
  import { pathToFileURL as pathToFileURL3 } from "node:url";
39612
40256
 
@@ -39715,7 +40359,7 @@ init_src5();
39715
40359
  init_src4();
39716
40360
  init_constants();
39717
40361
  init_errors();
39718
- import path16 from "node:path";
40362
+ import path19 from "node:path";
39719
40363
  import { Command } from "commander";
39720
40364
  function parseMcpSpawnConfig(input) {
39721
40365
  if (!input) {
@@ -39786,10 +40430,10 @@ function resolveWorkingDirectory(baseDir, candidate) {
39786
40430
  if (!candidate || candidate.trim().length === 0) {
39787
40431
  return void 0;
39788
40432
  }
39789
- if (path16.isAbsolute(candidate)) {
40433
+ if (path19.isAbsolute(candidate)) {
39790
40434
  return candidate;
39791
40435
  }
39792
- return path16.resolve(baseDir, candidate);
40436
+ return path19.resolve(baseDir, candidate);
39793
40437
  }
39794
40438
  function createPoeAgentProgram() {
39795
40439
  const program = new Command();
@@ -39892,6 +40536,7 @@ export {
39892
40536
  main,
39893
40537
  poeAgentMain,
39894
40538
  runPipeline2 as runPipeline,
40539
+ runRalph2 as runRalph,
39895
40540
  spawn5 as spawn
39896
40541
  };
39897
40542
  //# sourceMappingURL=index.js.map