@openape/apes 1.28.13 → 1.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -2,18 +2,8 @@
2
2
  import {
3
3
  CliError,
4
4
  CliExit,
5
- RpcSessionMap,
6
- buildCreateCommand,
7
- buildIssueGet,
8
- buildPrCreate,
9
- buildPrMerge,
10
- detectForge,
11
- parseDuration,
12
- runApeShell,
13
- runLoop,
14
- taskTools,
15
- worktreePathFor
16
- } from "./chunk-ZEUSCNCH.js";
5
+ parseDuration
6
+ } from "./chunk-QMMRZPD2.js";
17
7
  import {
18
8
  loadEd25519PrivateKey,
19
9
  readPublicKeyComment
@@ -22,20 +12,15 @@ import {
22
12
  checkSudoRejection,
23
13
  isApesSelfDispatch,
24
14
  notifyGrantPending
25
- } from "./chunk-3COOEDPF.js";
15
+ } from "./chunk-RVAXRDC2.js";
26
16
  import {
27
17
  GENERIC_OPERATION_ID,
28
18
  buildGenericResolved,
29
19
  buildStructuredCliGrantRequest,
30
- createShapesGrant,
31
- extractOption,
32
20
  extractShellCommandString,
33
- extractWrappedCommand,
34
- fetchGrantToken,
35
21
  fetchRegistry,
36
22
  findAdapter,
37
23
  findConflictingAdapters,
38
- findExistingGrant,
39
24
  getInstalledDigest,
40
25
  installAdapter,
41
26
  isInstalled,
@@ -45,12 +30,19 @@ import {
45
30
  removeAdapter,
46
31
  resolveCapabilityRequest,
47
32
  resolveCommand,
48
- resolveFromGrant,
49
33
  resolveGenericOrReject,
50
- searchAdapters,
34
+ searchAdapters
35
+ } from "./chunk-JXS3KLJ5.js";
36
+ import {
37
+ createShapesGrant,
38
+ extractOption,
39
+ extractWrappedCommand,
40
+ fetchGrantToken,
41
+ findExistingGrant,
42
+ resolveFromGrant,
51
43
  verifyAndExecute,
52
44
  waitForGrantStatus
53
- } from "./chunk-PEA2RDWK.js";
45
+ } from "./chunk-BA2V3BBO.js";
54
46
  import {
55
47
  ApiError,
56
48
  apiFetch,
@@ -2994,6 +2986,7 @@ import { join as join6 } from "path";
2994
2986
  import process3 from "process";
2995
2987
  import { defineCommand as defineCommand24 } from "citty";
2996
2988
  import { consola as consola21 } from "consola";
2989
+ import { taskTools, runApeShell, runCodingTask, buildIssueGet, detectForge, createLlmReviewer, createLlmRiskAssessor, resolveMergePolicy } from "@openape/agent-runtime";
2997
2990
 
2998
2991
  // src/lib/agent-secrets-runtime.ts
2999
2992
  import { existsSync as existsSync7, readdirSync, readFileSync as readFileSync6, watch } from "fs";
@@ -3073,372 +3066,6 @@ function startSecretsWatcher(opts = {}) {
3073
3066
  };
3074
3067
  }
3075
3068
 
3076
- // src/lib/coding/issue-task.ts
3077
- var DEFAULT_TEMPLATE = "{type}/issue-{number}-{slug}";
3078
- var DEFAULT_TYPE = "fix";
3079
- var DEFAULT_SLUG_MAX = 48;
3080
- var DEFAULT_INSTRUCTIONS = [
3081
- "Work in the provided worktree. When done:",
3082
- "- ensure the verification command passes (no PR on red)",
3083
- "- open a PR that references this issue",
3084
- "- leave risk-path / agent-judged-risky changes for human approval"
3085
- ].join("\n");
3086
- var TYPE_RE = /^[a-z]{2,12}$/;
3087
- function slugify(title, max = DEFAULT_SLUG_MAX) {
3088
- return title.toLowerCase().normalize("NFKD").replace(/[^\w\s-]/g, "").trim().replace(/[\s_]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, max).replace(/-$/, "");
3089
- }
3090
- function buildBranchName(issue, naming = {}) {
3091
- const num = String(issue.number).replace(/\D/g, "");
3092
- if (!num) throw new Error("issue number required");
3093
- const type = issue.type && TYPE_RE.test(issue.type) ? issue.type : naming.defaultType ?? DEFAULT_TYPE;
3094
- const slug = slugify(issue.title, naming.slugMax ?? DEFAULT_SLUG_MAX) || "task";
3095
- return (naming.template ?? DEFAULT_TEMPLATE).replace(/\{type\}/g, type).replace(/\{number\}/g, num).replace(/\{slug\}/g, slug);
3096
- }
3097
- function buildTaskPrompt(issue, framing = {}) {
3098
- const num = String(issue.number);
3099
- const parts = [];
3100
- if (framing.persona?.trim()) parts.push(framing.persona.trim());
3101
- parts.push(`Issue #${num}: ${issue.title}`);
3102
- parts.push(issue.body?.trim() ? issue.body.trim() : "(no description provided)");
3103
- parts.push(framing.instructions?.trim() ? framing.instructions.trim() : DEFAULT_INSTRUCTIONS);
3104
- return parts.join("\n\n");
3105
- }
3106
-
3107
- // src/lib/coding/merge-policy.ts
3108
- var SECURE_DEFAULT_POLICY = {
3109
- autoMergeEnabled: false,
3110
- autoPaths: [],
3111
- riskPaths: []
3112
- };
3113
- function globToRegExp(glob) {
3114
- let re = "";
3115
- for (let i = 0; i < glob.length; i++) {
3116
- const c = glob[i];
3117
- if (c === "*") {
3118
- if (glob[i + 1] === "*") {
3119
- re += ".*";
3120
- i++;
3121
- if (glob[i + 1] === "/") i++;
3122
- } else {
3123
- re += "[^/]*";
3124
- }
3125
- } else if (c === "?") {
3126
- re += "[^/]";
3127
- } else if (".+^${}()|[]\\".includes(c)) {
3128
- re += `\\${c}`;
3129
- } else {
3130
- re += c;
3131
- }
3132
- }
3133
- return new RegExp(`^${re}$`);
3134
- }
3135
- function matchesAny(path2, globs) {
3136
- return globs.some((g) => globToRegExp(g).test(path2));
3137
- }
3138
- function classifyChange(paths, policy = SECURE_DEFAULT_POLICY) {
3139
- if (paths.length === 0) return "code";
3140
- if (paths.some((p) => matchesAny(p, policy.riskPaths))) return "risk";
3141
- if (policy.autoPaths.length > 0 && paths.every((p) => matchesAny(p, policy.autoPaths))) return "chore";
3142
- return "code";
3143
- }
3144
- function decideMerge(paths, policy = SECURE_DEFAULT_POLICY, agentRisk) {
3145
- const globClass = classifyChange(paths, policy);
3146
- const isRisk = globClass === "risk" || agentRisk?.risky === true;
3147
- const classification = isRisk ? "risk" : globClass;
3148
- if (!policy.autoMergeEnabled) {
3149
- return { classification, autoMerge: false, needsReview: false, needsHuman: true, reason: "auto-merge not enabled for this repo \u2014 human approval required (set autoMergeEnabled in .openape/coding.json to opt in)" };
3150
- }
3151
- if (isRisk) {
3152
- const why = agentRisk?.risky ? `agent judged this risky${agentRisk.reason ? `: ${agentRisk.reason}` : ""}` : "matches a repo/derived risk path";
3153
- return { classification, autoMerge: false, needsReview: false, needsHuman: true, reason: `${why} \u2014 human approval required` };
3154
- }
3155
- if (classification === "chore") {
3156
- return { classification, autoMerge: true, needsReview: false, needsHuman: false, reason: "chore/docs only \u2014 auto-merge on green CI" };
3157
- }
3158
- return { classification, autoMerge: true, needsReview: true, needsHuman: false, reason: "code change \u2014 auto-merge after reviewer-agent approval" };
3159
- }
3160
- async function loadMergePolicy(worktreeDir) {
3161
- const { readFile } = await import("fs/promises");
3162
- const { join: join21 } = await import("path");
3163
- try {
3164
- const raw = await readFile(join21(worktreeDir, ".openape", "coding.json"), "utf8");
3165
- const parsed = JSON.parse(raw);
3166
- const mp = parsed.mergePolicy;
3167
- if (!mp) return SECURE_DEFAULT_POLICY;
3168
- return {
3169
- autoMergeEnabled: mp.autoMergeEnabled === true,
3170
- autoPaths: Array.isArray(mp.autoPaths) ? mp.autoPaths.filter((g) => typeof g === "string") : [],
3171
- riskPaths: Array.isArray(mp.riskPaths) ? mp.riskPaths.filter((g) => typeof g === "string") : []
3172
- };
3173
- } catch {
3174
- return SECURE_DEFAULT_POLICY;
3175
- }
3176
- }
3177
-
3178
- // src/lib/coding/review-gate.ts
3179
- async function gateMerge(decision, req, reviewer) {
3180
- if (decision.needsHuman) {
3181
- return { armMerge: false, awaitingHuman: true, reason: "risk-path change \u2014 handed off to human reviewer" };
3182
- }
3183
- if (!decision.needsReview) {
3184
- return { armMerge: true, awaitingHuman: false, reason: "chore change \u2014 no reviewer gate" };
3185
- }
3186
- const verdict = await reviewer({ ...req, classification: decision.classification });
3187
- if (verdict.approved) {
3188
- return { armMerge: true, awaitingHuman: false, reason: `reviewer approved${verdict.reason ? `: ${verdict.reason}` : ""}` };
3189
- }
3190
- return { armMerge: false, awaitingHuman: false, reason: `reviewer blocked${verdict.reason ? `: ${verdict.reason}` : ""}` };
3191
- }
3192
-
3193
- // src/lib/coding/coding-loop.ts
3194
- var DIFF_CAP = 60 * 1024;
3195
- function taskIdFromIssue(issue) {
3196
- const num = String(issue.number).replace(/\D/g, "");
3197
- return `issue-${num || "x"}`;
3198
- }
3199
- async function runCodingTask(input, deps) {
3200
- const shell = deps.shell ?? (async (cmd, t) => {
3201
- const r = await runApeShell(cmd, t);
3202
- return { stdout: r.stdout, stderr: r.stderr, exit_code: r.exit_code };
3203
- });
3204
- const loop = deps.runLoopImpl ?? runLoop;
3205
- const log = deps.log ?? (() => {
3206
- });
3207
- const branch = buildBranchName(input.issue, deps.branchNaming);
3208
- const taskId = taskIdFromIssue(input.issue);
3209
- const worktree = worktreePathFor(taskId);
3210
- log(`[coding] creating worktree ${worktree} on ${branch}`);
3211
- const wt = await shell(buildCreateCommand(input.repo, taskId, branch));
3212
- if (wt.exit_code !== 0) {
3213
- return { branch, worktree, runStatus: "error", changedFiles: [], outcome: "run-failed", reason: `worktree create failed: ${wt.stderr.slice(0, 300)}` };
3214
- }
3215
- const policy = deps.resolvePolicy ? await deps.resolvePolicy(worktree) : deps.policy ?? SECURE_DEFAULT_POLICY;
3216
- const prompt = buildTaskPrompt(input.issue, { persona: deps.persona });
3217
- const run = await loop({
3218
- config: deps.runtimeConfig,
3219
- systemPrompt: deps.persona,
3220
- userMessage: `${prompt}
3221
-
3222
- Worktree: ${worktree}`,
3223
- tools: deps.tools,
3224
- maxSteps: deps.maxSteps,
3225
- streamAggregate: deps.streamAggregate
3226
- });
3227
- if (process.env.OPENAPE_VERBOSE_TRACE === "1") {
3228
- for (const t of run.trace) {
3229
- log(`[trace] step=${t.step} type=${t.type}${t.tool ? ` tool=${t.tool}` : ""} ${t.preview}`);
3230
- }
3231
- }
3232
- if (run.status !== "ok") {
3233
- return { branch, worktree, runStatus: "error", changedFiles: [], outcome: "run-failed", reason: `coding loop errored after ${run.stepCount} steps` };
3234
- }
3235
- const namesRes = await shell(`git -C '${worktree}' add -A && git -C '${worktree}' diff --cached --name-only`);
3236
- const changedFiles = namesRes.stdout.split("\n").map((s) => s.trim()).filter(Boolean);
3237
- if (changedFiles.length === 0) {
3238
- return { branch, worktree, runStatus: "ok", changedFiles: [], outcome: "run-failed", reason: "no changes produced \u2014 nothing to PR" };
3239
- }
3240
- const diffRes = await shell(`git -C '${worktree}' diff --cached`);
3241
- const diff = diffRes.stdout.slice(0, DIFF_CAP);
3242
- const agentRisk = await deps.riskAssessor({ paths: changedFiles, diff });
3243
- const decision = decideMerge(changedFiles, policy, agentRisk);
3244
- log(`[coding] decision=${decision.classification} (${decision.reason})`);
3245
- const authorEmail = process.env.GIT_AUTHOR_EMAIL || "coding-agent@openape.ai";
3246
- const authorName = process.env.GIT_AUTHOR_NAME || "OpenApe Coding Agent";
3247
- const ident = `-c user.email='${authorEmail.replace(/'/g, "")}' -c user.name='${authorName.replace(/'/g, "")}'`;
3248
- const commitRes = await shell(`git -C '${worktree}' ${ident} commit -m ${shqMsg(input.issue)}`);
3249
- if (commitRes.exit_code !== 0) {
3250
- return { branch, worktree, runStatus: "ok", changedFiles, decision, outcome: "run-failed", prRef: branch, reason: `commit failed: ${(commitRes.stderr || commitRes.stdout).slice(0, 300)}` };
3251
- }
3252
- const pushRes = await shell(buildPushCommand(input.forge, input.repo, worktree, branch));
3253
- if (pushRes.exit_code !== 0) {
3254
- return { branch, worktree, runStatus: "ok", changedFiles, decision, outcome: "run-failed", prRef: branch, reason: `push failed: ${(pushRes.stderr || pushRes.stdout).slice(0, 300)}` };
3255
- }
3256
- const prCmd = buildPrCreate({ forge: input.forge, title: prTitle(input.issue), body: prBody(input.issue), head: branch });
3257
- const prRes = await shell(`cd '${worktree}' && ${prCmd}`);
3258
- if (prRes.exit_code !== 0) {
3259
- return { branch, worktree, runStatus: "ok", changedFiles, decision, outcome: "run-failed", prRef: branch, reason: `pr create failed: ${(prRes.stderr || prRes.stdout).slice(0, 300)}` };
3260
- }
3261
- const prRef = prRes.stdout.match(/\/pull\/(\d+)|!(\d+)|\bpr\/(\d+)/i)?.slice(1).find(Boolean) ?? branch;
3262
- if (decision.needsHuman) {
3263
- return { branch, worktree, runStatus: "ok", changedFiles, decision, outcome: "awaiting-human", prRef, reason: decision.reason };
3264
- }
3265
- const gate = await gateMerge(decision, { prRef, diff }, deps.reviewer);
3266
- if (!gate.armMerge) {
3267
- return { branch, worktree, runStatus: "ok", changedFiles, decision, outcome: "reviewer-blocked", prRef, reason: gate.reason };
3268
- }
3269
- const mergeCmd = buildPrMerge({ forge: input.forge, ref: prRef, auto: true, squash: deps.squash, deleteBranch: true });
3270
- await shell(`cd '${worktree}' && ${mergeCmd}`);
3271
- return { branch, worktree, runStatus: "ok", changedFiles, decision, outcome: "auto-armed", prRef, reason: gate.reason };
3272
- }
3273
- function prTitle(issue) {
3274
- return `${issue.type ?? "fix"}: ${issue.title} (#${String(issue.number).replace(/\D/g, "")})`;
3275
- }
3276
- function prBody(issue) {
3277
- return `Resolves #${String(issue.number).replace(/\D/g, "")}.
3278
-
3279
- Automated by the OpenApe coding agent.`;
3280
- }
3281
- function shqMsg(issue) {
3282
- return `'${prTitle(issue).replace(/'/g, "'\\''")}'`;
3283
- }
3284
- function buildPushCommand(forge, repo, worktree, branch) {
3285
- const base = `GIT_TERMINAL_PROMPT=0 git -C '${worktree}' -c credential.helper=`;
3286
- if (forge === "github") {
3287
- const slug = repo.replace(/^[a-z]+:\/\/[^/]+\//i, "").replace(/\.git$/, "").replace(/['"\s]/g, "");
3288
- return `${base} push "https://x-access-token:\${GH_TOKEN}@github.com/${slug}.git" '${branch}'`;
3289
- }
3290
- return `${base} push -u origin '${branch}'`;
3291
- }
3292
-
3293
- // src/lib/coding/llm-review.ts
3294
- var DIFF_CAP2 = 48 * 1024;
3295
- async function jsonCompletion(config, system, user, fetchImpl = fetch) {
3296
- try {
3297
- const res = await fetchImpl(`${config.apiBase}/chat/completions`, {
3298
- method: "POST",
3299
- headers: { "authorization": `Bearer ${config.apiKey}`, "content-type": "application/json" },
3300
- body: JSON.stringify({
3301
- model: config.model,
3302
- messages: [{ role: "system", content: system }, { role: "user", content: user }],
3303
- response_format: { type: "json_object" }
3304
- })
3305
- });
3306
- if (!res.ok) return null;
3307
- const data = await res.json();
3308
- const content = data.choices?.[0]?.message?.content;
3309
- if (!content) return null;
3310
- return JSON.parse(content);
3311
- } catch {
3312
- return null;
3313
- }
3314
- }
3315
- var RISK_SYSTEM = [
3316
- "You are a security/risk classifier for an autonomous coding agent.",
3317
- "Given a diff + changed file paths, decide whether merging it WITHOUT a human is risky.",
3318
- "Risky = touches authentication, authorization, secrets/credentials, payment, data migrations,",
3319
- "deploy/release/CI config, cryptography, deletion of data, or anything whose failure is hard to",
3320
- "reverse in production. Routine code/tests/docs/refactors are NOT risky.",
3321
- 'Respond ONLY as JSON: {"risky": boolean, "reason": string}.'
3322
- ].join(" ");
3323
- function createLlmRiskAssessor(config, fetchImpl) {
3324
- return async ({ paths, diff }) => {
3325
- const user = `Changed files:
3326
- ${paths.join("\n")}
3327
-
3328
- Diff (truncated):
3329
- ${diff.slice(0, DIFF_CAP2)}`;
3330
- const out = await jsonCompletion(config, RISK_SYSTEM, user, fetchImpl);
3331
- if (!out || typeof out.risky !== "boolean") {
3332
- return { risky: true, reason: "risk classifier unavailable/unparseable \u2014 treating as risky (fail-safe)" };
3333
- }
3334
- return { risky: out.risky, reason: typeof out.reason === "string" ? out.reason : void 0 };
3335
- };
3336
- }
3337
- var REVIEW_SYSTEM = [
3338
- "You are a code reviewer for an autonomous coding agent.",
3339
- "Given a PR diff, decide whether it is correct, safe, and complete enough to auto-merge.",
3340
- "Approve only if you would be comfortable shipping it without further human review.",
3341
- "Block if you see bugs, missing tests, security issues, or incomplete work.",
3342
- 'Respond ONLY as JSON: {"approved": boolean, "reason": string}.'
3343
- ].join(" ");
3344
- function createLlmReviewer(config, fetchImpl) {
3345
- return async ({ prRef, diff }) => {
3346
- const user = `PR ${String(prRef)} diff (truncated):
3347
- ${diff.slice(0, DIFF_CAP2)}`;
3348
- const out = await jsonCompletion(config, REVIEW_SYSTEM, user, fetchImpl);
3349
- if (!out || typeof out.approved !== "boolean") {
3350
- return { approved: false, reason: "reviewer unavailable/unparseable \u2014 blocking (fail-safe)" };
3351
- }
3352
- return { approved: out.approved, reason: typeof out.reason === "string" ? out.reason : void 0 };
3353
- };
3354
- }
3355
-
3356
- // src/lib/coding/derive-policy.ts
3357
- function indentOf(line) {
3358
- return line.length - line.trimStart().length;
3359
- }
3360
- function unquote(s) {
3361
- return s.trim().replace(/^['"]|['"]$/g, "").trim();
3362
- }
3363
- function extractWorkflowPaths(yamlText) {
3364
- const out = [];
3365
- const lines = yamlText.split("\n");
3366
- let inBlock = false;
3367
- let keyIndent = -1;
3368
- for (const line of lines) {
3369
- if (inBlock) {
3370
- const m = /^\s*-\s*(\S.*)$/.exec(line);
3371
- if (m && indentOf(line) > keyIndent) {
3372
- out.push(unquote(m[1]));
3373
- continue;
3374
- }
3375
- if (line.trim() !== "") inBlock = false;
3376
- }
3377
- const inline = /^\s*paths:\s*\[(.+)\]\s*$/.exec(line);
3378
- if (inline) {
3379
- for (const tok of inline[1].split(",")) {
3380
- const g = unquote(tok);
3381
- if (g) out.push(g);
3382
- }
3383
- continue;
3384
- }
3385
- if (/^\s*paths:\s*$/.test(line)) {
3386
- inBlock = true;
3387
- keyIndent = indentOf(line);
3388
- }
3389
- }
3390
- return [...new Set(out)];
3391
- }
3392
- function parseCodeowners(text) {
3393
- const out = [];
3394
- for (const raw of text.split("\n")) {
3395
- const line = raw.trim();
3396
- if (!line || line.startsWith("#")) continue;
3397
- const pattern = line.split(/\s+/)[0];
3398
- if (!pattern || pattern.startsWith("@")) continue;
3399
- let g = pattern.replace(/^\//, "");
3400
- if (g.endsWith("/")) g += "**";
3401
- if (g) out.push(g);
3402
- }
3403
- return [...new Set(out)];
3404
- }
3405
- async function deriveRiskGlobs(worktreeDir) {
3406
- const { readFile, readdir } = await import("fs/promises");
3407
- const { join: join21 } = await import("path");
3408
- const globs = /* @__PURE__ */ new Set();
3409
- try {
3410
- const wfDir = join21(worktreeDir, ".github", "workflows");
3411
- const files = await readdir(wfDir);
3412
- for (const f of files) {
3413
- if (!/deploy.*\.ya?ml$/i.test(f)) continue;
3414
- try {
3415
- const text = await readFile(join21(wfDir, f), "utf8");
3416
- for (const g of extractWorkflowPaths(text)) globs.add(g);
3417
- } catch {
3418
- }
3419
- }
3420
- } catch {
3421
- }
3422
- for (const loc of [".github/CODEOWNERS", "CODEOWNERS", "docs/CODEOWNERS"]) {
3423
- try {
3424
- const text = await readFile(join21(worktreeDir, loc), "utf8");
3425
- for (const g of parseCodeowners(text)) globs.add(g);
3426
- break;
3427
- } catch {
3428
- }
3429
- }
3430
- return [...globs];
3431
- }
3432
- async function resolveMergePolicy(worktreeDir) {
3433
- const explicit = await loadMergePolicy(worktreeDir).catch(() => SECURE_DEFAULT_POLICY);
3434
- const derived = await deriveRiskGlobs(worktreeDir).catch(() => []);
3435
- return {
3436
- autoMergeEnabled: explicit.autoMergeEnabled,
3437
- autoPaths: explicit.autoPaths,
3438
- riskPaths: [.../* @__PURE__ */ new Set([...explicit.riskPaths, ...derived])]
3439
- };
3440
- }
3441
-
3442
3069
  // src/commands/agents/code.ts
3443
3070
  var CliError2 = class extends Error {
3444
3071
  };
@@ -4014,6 +3641,7 @@ import { homedir as homedir7 } from "os";
4014
3641
  import { join as join9 } from "path";
4015
3642
  import { defineCommand as defineCommand28 } from "citty";
4016
3643
  import consola25 from "consola";
3644
+ import { taskTools as taskTools2, runLoop } from "@openape/agent-runtime";
4017
3645
  var AUTH_PATH = join9(homedir7(), ".config", "apes", "auth.json");
4018
3646
  var TASK_CACHE_DIR = join9(homedir7(), ".openape", "agent", "tasks");
4019
3647
  function readAuth() {
@@ -4119,7 +3747,7 @@ var runAgentCommand = defineCommand28({
4119
3747
  const config = readLitellmConfig2(args.model);
4120
3748
  let tools;
4121
3749
  try {
4122
- tools = taskTools(spec.tools);
3750
+ tools = taskTools2(spec.tools);
4123
3751
  } catch (err) {
4124
3752
  throw new CliError(`task ${taskId}: ${err.message}`);
4125
3753
  }
@@ -4186,6 +3814,7 @@ import { homedir as homedir8 } from "os";
4186
3814
  import { join as join10 } from "path";
4187
3815
  import { createInterface } from "readline";
4188
3816
  import { defineCommand as defineCommand29 } from "citty";
3817
+ import { taskTools as taskTools3, runLoop as runLoop2, RpcSessionMap } from "@openape/agent-runtime";
4189
3818
  var AUTH_PATH2 = join10(homedir8(), ".config", "apes", "auth.json");
4190
3819
  function readLitellmConfig3(model) {
4191
3820
  const envPath = join10(homedir8(), "litellm", ".env");
@@ -4264,7 +3893,7 @@ var serveAgentCommand = defineCommand29({
4264
3893
  });
4265
3894
  async function handleInbound(msg, sessions) {
4266
3895
  const config = readLitellmConfig3(msg.model);
4267
- const tools = taskTools(msg.tools ?? []);
3896
+ const tools = taskTools3(msg.tools ?? []);
4268
3897
  const maxSteps = msg.max_steps ?? 10;
4269
3898
  let session = sessions.get(msg.session_id);
4270
3899
  if (!session) {
@@ -4277,7 +3906,7 @@ async function handleInbound(msg, sessions) {
4277
3906
  };
4278
3907
  sessions.put(msg.session_id, session);
4279
3908
  }
4280
- const result = await runLoop({
3909
+ const result = await runLoop2({
4281
3910
  config,
4282
3911
  systemPrompt: session.systemPrompt,
4283
3912
  userMessage: msg.user_msg,
@@ -7009,7 +6638,7 @@ var mcpCommand = defineCommand52({
7009
6638
  if (transport !== "stdio" && transport !== "sse") {
7010
6639
  throw new Error('Transport must be "stdio" or "sse"');
7011
6640
  }
7012
- const { startMcpServer } = await import("./server-JGX5FIDP.js");
6641
+ const { startMcpServer } = await import("./server-QN35XDYH.js");
7013
6642
  await startMcpServer(transport, port);
7014
6643
  }
7015
6644
  });
@@ -7647,7 +7276,7 @@ async function bestEffortGrantCount(idp) {
7647
7276
  }
7648
7277
  }
7649
7278
  async function runHealth(args) {
7650
- const version = true ? "1.28.13" : "0.0.0";
7279
+ const version = true ? "1.29.0" : "0.0.0";
7651
7280
  const auth = loadAuth();
7652
7281
  if (!auth) {
7653
7282
  throw new CliError("Not logged in. Run `apes login` first.", 1);
@@ -7920,10 +7549,10 @@ if (shellRewrite) {
7920
7549
  if (shellRewrite.action === "rewrite") {
7921
7550
  process.argv = shellRewrite.argv;
7922
7551
  } else if (shellRewrite.action === "version") {
7923
- console.log(`ape-shell ${"1.28.13"} (OpenApe DDISA shell wrapper)`);
7552
+ console.log(`ape-shell ${"1.29.0"} (OpenApe DDISA shell wrapper)`);
7924
7553
  process.exit(0);
7925
7554
  } else if (shellRewrite.action === "help") {
7926
- console.log(`ape-shell ${"1.28.13"} \u2014 OpenApe DDISA shell wrapper`);
7555
+ console.log(`ape-shell ${"1.29.0"} \u2014 OpenApe DDISA shell wrapper`);
7927
7556
  console.log("");
7928
7557
  console.log("Usage:");
7929
7558
  console.log(" ape-shell Start interactive grant-mediated REPL");
@@ -7938,7 +7567,7 @@ if (shellRewrite) {
7938
7567
  console.log(" --help, -h Show this help message");
7939
7568
  process.exit(0);
7940
7569
  } else if (shellRewrite.action === "interactive") {
7941
- const { runInteractiveShell } = await import("./orchestrator-REICEX3F.js");
7570
+ const { runInteractiveShell } = await import("./orchestrator-P7QFDBBK.js");
7942
7571
  await runInteractiveShell();
7943
7572
  process.exit(0);
7944
7573
  } else {
@@ -7981,7 +7610,7 @@ var configCommand = defineCommand64({
7981
7610
  var main = defineCommand64({
7982
7611
  meta: {
7983
7612
  name: "apes",
7984
- version: "1.28.13",
7613
+ version: "1.29.0",
7985
7614
  description: "Unified CLI for OpenApe"
7986
7615
  },
7987
7616
  subCommands: {
@@ -8039,7 +7668,7 @@ async function maybeRefreshAuth() {
8039
7668
  }
8040
7669
  }
8041
7670
  await maybeRefreshAuth();
8042
- await maybeWarnStaleVersion("1.28.13").catch(() => {
7671
+ await maybeWarnStaleVersion("1.29.0").catch(() => {
8043
7672
  });
8044
7673
  runMain(main).catch((err) => {
8045
7674
  if (err instanceof CliExit) {