@openape/apes 1.1.1 → 1.2.1
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
|
@@ -3050,6 +3050,37 @@ function readAuth() {
|
|
|
3050
3050
|
if (!parsed.access_token) throw new CliError("auth.json missing access_token");
|
|
3051
3051
|
return parsed;
|
|
3052
3052
|
}
|
|
3053
|
+
async function postRunResultToChat(opts) {
|
|
3054
|
+
const endpoint = (opts.endpoint ?? process.env.APE_CHAT_ENDPOINT ?? "https://chat.openape.ai").replace(/\/$/, "");
|
|
3055
|
+
try {
|
|
3056
|
+
const contactsRes = await fetch(`${endpoint}/api/contacts`, {
|
|
3057
|
+
headers: { Authorization: `Bearer ${opts.authToken}` }
|
|
3058
|
+
});
|
|
3059
|
+
if (!contactsRes.ok) return;
|
|
3060
|
+
const contacts = await contactsRes.json();
|
|
3061
|
+
const ownerLower = opts.ownerEmail.toLowerCase();
|
|
3062
|
+
const ownerRow = contacts.find((c) => c.peerEmail.toLowerCase() === ownerLower && c.connected && c.roomId);
|
|
3063
|
+
if (!ownerRow?.roomId) {
|
|
3064
|
+
consola22.info("chat DM skipped \u2014 no active room with owner (accept the contact request in chat to enable)");
|
|
3065
|
+
return;
|
|
3066
|
+
}
|
|
3067
|
+
const prefix = opts.status === "ok" ? "\u2705" : "\u274C";
|
|
3068
|
+
const msg = opts.finalMessage?.trim() || (opts.status === "ok" ? "(no output)" : "(crashed)");
|
|
3069
|
+
const body = `${prefix} *${opts.taskName}* (${opts.stepCount} steps)
|
|
3070
|
+
|
|
3071
|
+
${msg}`.slice(0, 9e3);
|
|
3072
|
+
const postRes = await fetch(`${endpoint}/api/rooms/${encodeURIComponent(ownerRow.roomId)}/messages`, {
|
|
3073
|
+
method: "POST",
|
|
3074
|
+
headers: { "Authorization": `Bearer ${opts.authToken}`, "Content-Type": "application/json" },
|
|
3075
|
+
body: JSON.stringify({ body })
|
|
3076
|
+
});
|
|
3077
|
+
if (!postRes.ok) {
|
|
3078
|
+
consola22.warn(`chat DM post failed: ${postRes.status}`);
|
|
3079
|
+
}
|
|
3080
|
+
} catch (err) {
|
|
3081
|
+
consola22.warn(`chat DM error: ${err.message}`);
|
|
3082
|
+
}
|
|
3083
|
+
}
|
|
3053
3084
|
function readTaskSpec(taskId) {
|
|
3054
3085
|
const path2 = join3(TASK_CACHE_DIR, `${taskId}.json`);
|
|
3055
3086
|
if (!existsSync5(path2)) {
|
|
@@ -3057,6 +3088,15 @@ function readTaskSpec(taskId) {
|
|
|
3057
3088
|
}
|
|
3058
3089
|
return JSON.parse(readFileSync5(path2, "utf8"));
|
|
3059
3090
|
}
|
|
3091
|
+
var AGENT_CONFIG_PATH = join3(homedir5(), ".openape", "agent", "agent.json");
|
|
3092
|
+
function readAgentConfig() {
|
|
3093
|
+
if (!existsSync5(AGENT_CONFIG_PATH)) return { systemPrompt: "" };
|
|
3094
|
+
try {
|
|
3095
|
+
return JSON.parse(readFileSync5(AGENT_CONFIG_PATH, "utf8"));
|
|
3096
|
+
} catch {
|
|
3097
|
+
return { systemPrompt: "" };
|
|
3098
|
+
}
|
|
3099
|
+
}
|
|
3060
3100
|
function readLitellmConfig(model) {
|
|
3061
3101
|
const envPath = join3(homedir5(), "litellm", ".env");
|
|
3062
3102
|
const env = {};
|
|
@@ -3100,6 +3140,7 @@ var runAgentCommand = defineCommand24({
|
|
|
3100
3140
|
const taskId = args["task-id"];
|
|
3101
3141
|
const auth = readAuth();
|
|
3102
3142
|
const spec = readTaskSpec(taskId);
|
|
3143
|
+
const agentCfg = readAgentConfig();
|
|
3103
3144
|
const config = readLitellmConfig(args.model);
|
|
3104
3145
|
let tools;
|
|
3105
3146
|
try {
|
|
@@ -3113,11 +3154,12 @@ var runAgentCommand = defineCommand24({
|
|
|
3113
3154
|
try {
|
|
3114
3155
|
const result = await runLoop({
|
|
3115
3156
|
config,
|
|
3116
|
-
|
|
3117
|
-
//
|
|
3118
|
-
//
|
|
3119
|
-
//
|
|
3120
|
-
|
|
3157
|
+
// Agent persona/behaviour ("you are Igor, …") set at agent level;
|
|
3158
|
+
// the task's userPrompt is the imperative job ("read my mail and
|
|
3159
|
+
// summarise"). The cron firing is the trigger — the message body
|
|
3160
|
+
// is the task itself.
|
|
3161
|
+
systemPrompt: agentCfg.systemPrompt,
|
|
3162
|
+
userMessage: spec.userPrompt,
|
|
3121
3163
|
tools,
|
|
3122
3164
|
maxSteps: spec.maxSteps
|
|
3123
3165
|
});
|
|
@@ -3128,6 +3170,16 @@ var runAgentCommand = defineCommand24({
|
|
|
3128
3170
|
trace: result.trace
|
|
3129
3171
|
});
|
|
3130
3172
|
consola22.success(`Run ${runId} ${result.status} (${result.stepCount} steps)`);
|
|
3173
|
+
if (auth.owner_email) {
|
|
3174
|
+
await postRunResultToChat({
|
|
3175
|
+
authToken: auth.access_token,
|
|
3176
|
+
ownerEmail: auth.owner_email,
|
|
3177
|
+
taskName: spec.name,
|
|
3178
|
+
status: result.status,
|
|
3179
|
+
stepCount: result.stepCount,
|
|
3180
|
+
finalMessage: result.finalMessage
|
|
3181
|
+
});
|
|
3182
|
+
}
|
|
3131
3183
|
if (result.status === "error") process.exit(1);
|
|
3132
3184
|
} catch (err) {
|
|
3133
3185
|
const message = err?.message ?? String(err);
|
|
@@ -3138,6 +3190,16 @@ var runAgentCommand = defineCommand24({
|
|
|
3138
3190
|
trace: []
|
|
3139
3191
|
}).catch(() => {
|
|
3140
3192
|
});
|
|
3193
|
+
if (auth.owner_email) {
|
|
3194
|
+
await postRunResultToChat({
|
|
3195
|
+
authToken: auth.access_token,
|
|
3196
|
+
ownerEmail: auth.owner_email,
|
|
3197
|
+
taskName: spec.name,
|
|
3198
|
+
status: "error",
|
|
3199
|
+
stepCount: 0,
|
|
3200
|
+
finalMessage: message
|
|
3201
|
+
});
|
|
3202
|
+
}
|
|
3141
3203
|
throw new CliError(`Run ${runId} crashed: ${message}`);
|
|
3142
3204
|
}
|
|
3143
3205
|
}
|
|
@@ -3281,16 +3343,18 @@ function escape(s) {
|
|
|
3281
3343
|
}
|
|
3282
3344
|
function buildSyncPlist(input) {
|
|
3283
3345
|
const pathLine = ` <key>PATH</key><string>${escape(input.homeDir)}/.bun/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
|
|
3346
|
+
`;
|
|
3347
|
+
const agentUserLine = ` <key>AGENT_USER</key><string>${escape(input.userName)}</string>
|
|
3284
3348
|
`;
|
|
3285
3349
|
const envBlock = input.troopUrl ? ` <key>EnvironmentVariables</key>
|
|
3286
3350
|
<dict>
|
|
3287
3351
|
<key>HOME</key><string>${escape(input.homeDir)}</string>
|
|
3288
|
-
${pathLine} <key>OPENAPE_TROOP_URL</key><string>${escape(input.troopUrl)}</string>
|
|
3352
|
+
${pathLine}${agentUserLine} <key>OPENAPE_TROOP_URL</key><string>${escape(input.troopUrl)}</string>
|
|
3289
3353
|
</dict>
|
|
3290
3354
|
` : ` <key>EnvironmentVariables</key>
|
|
3291
3355
|
<dict>
|
|
3292
3356
|
<key>HOME</key><string>${escape(input.homeDir)}</string>
|
|
3293
|
-
${pathLine} </dict>
|
|
3357
|
+
${pathLine}${agentUserLine} </dict>
|
|
3294
3358
|
`;
|
|
3295
3359
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
3296
3360
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
@@ -3298,8 +3362,6 @@ ${pathLine} </dict>
|
|
|
3298
3362
|
<dict>
|
|
3299
3363
|
<key>Label</key>
|
|
3300
3364
|
<string>${escape(syncPlistLabel(input.agentName))}</string>
|
|
3301
|
-
<key>UserName</key>
|
|
3302
|
-
<string>${escape(input.userName)}</string>
|
|
3303
3365
|
<key>ProgramArguments</key>
|
|
3304
3366
|
<array>
|
|
3305
3367
|
<string>${escape(input.apesBin)}</string>
|
|
@@ -3688,8 +3750,8 @@ async function resolveClaudeToken(opts) {
|
|
|
3688
3750
|
}
|
|
3689
3751
|
|
|
3690
3752
|
// src/commands/agents/sync.ts
|
|
3691
|
-
import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync10, writeFileSync as writeFileSync6 } from "fs";
|
|
3692
|
-
import { homedir as
|
|
3753
|
+
import { chownSync, existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync10, statSync, writeFileSync as writeFileSync6 } from "fs";
|
|
3754
|
+
import { homedir as homedir9 } from "os";
|
|
3693
3755
|
import { join as join8 } from "path";
|
|
3694
3756
|
import { defineCommand as defineCommand27 } from "citty";
|
|
3695
3757
|
import consola24 from "consola";
|
|
@@ -3697,11 +3759,11 @@ import consola24 from "consola";
|
|
|
3697
3759
|
// src/lib/launchd-reconcile.ts
|
|
3698
3760
|
import { execFileSync as execFileSync8 } from "child_process";
|
|
3699
3761
|
import { mkdirSync as mkdirSync3, readdirSync, readFileSync as readFileSync9, unlinkSync, writeFileSync as writeFileSync5 } from "fs";
|
|
3700
|
-
import {
|
|
3762
|
+
import { userInfo as userInfo2 } from "os";
|
|
3701
3763
|
import { join as join7 } from "path";
|
|
3702
3764
|
var PLIST_PREFIX = "openape.troop.";
|
|
3703
3765
|
function plistDir() {
|
|
3704
|
-
return
|
|
3766
|
+
return "/Library/LaunchDaemons";
|
|
3705
3767
|
}
|
|
3706
3768
|
function plistPath(agentName, taskId) {
|
|
3707
3769
|
return join7(plistDir(), `${PLIST_PREFIX}${agentName}.${taskId}.plist`);
|
|
@@ -3786,6 +3848,8 @@ ${calendarBlocks}
|
|
|
3786
3848
|
<dict>
|
|
3787
3849
|
<key>Label</key>
|
|
3788
3850
|
<string>${escape2(input.label)}</string>
|
|
3851
|
+
<key>UserName</key>
|
|
3852
|
+
<string>${escape2(input.userName)}</string>
|
|
3789
3853
|
<key>ProgramArguments</key>
|
|
3790
3854
|
<array>
|
|
3791
3855
|
<string>${escape2(input.apesBin)}</string>
|
|
@@ -3799,6 +3863,8 @@ ${calendarBlocks}
|
|
|
3799
3863
|
<dict>
|
|
3800
3864
|
<key>HOME</key>
|
|
3801
3865
|
<string>${escape2(input.homeDir)}</string>
|
|
3866
|
+
<key>PATH</key>
|
|
3867
|
+
<string>${escape2(input.homeDir)}/.bun/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
|
|
3802
3868
|
</dict>
|
|
3803
3869
|
${calendarKey}
|
|
3804
3870
|
<key>StandardOutPath</key>
|
|
@@ -3815,22 +3881,20 @@ function buildPlistContent(args) {
|
|
|
3815
3881
|
apesBin: args.apesBin,
|
|
3816
3882
|
taskId: args.task.taskId,
|
|
3817
3883
|
schedule: cronToSchedule(args.task.cron),
|
|
3818
|
-
homeDir: args.homeDir
|
|
3884
|
+
homeDir: args.homeDir,
|
|
3885
|
+
userName: args.userName ?? userInfo2().username
|
|
3819
3886
|
});
|
|
3820
3887
|
}
|
|
3821
|
-
function uid() {
|
|
3822
|
-
return userInfo2().uid;
|
|
3823
|
-
}
|
|
3824
3888
|
function bootstrap(label, path2) {
|
|
3825
3889
|
try {
|
|
3826
|
-
execFileSync8("/bin/launchctl", ["bootout", `
|
|
3890
|
+
execFileSync8("/bin/launchctl", ["bootout", `system/${label}`], { stdio: "ignore" });
|
|
3827
3891
|
} catch {
|
|
3828
3892
|
}
|
|
3829
|
-
execFileSync8("/bin/launchctl", ["bootstrap",
|
|
3893
|
+
execFileSync8("/bin/launchctl", ["bootstrap", "system", path2], { stdio: "ignore" });
|
|
3830
3894
|
}
|
|
3831
3895
|
function bootout(label) {
|
|
3832
3896
|
try {
|
|
3833
|
-
execFileSync8("/bin/launchctl", ["bootout", `
|
|
3897
|
+
execFileSync8("/bin/launchctl", ["bootout", `system/${label}`], { stdio: "ignore" });
|
|
3834
3898
|
} catch {
|
|
3835
3899
|
}
|
|
3836
3900
|
}
|
|
@@ -3859,7 +3923,8 @@ function reconcile(input) {
|
|
|
3859
3923
|
agentName: input.agentName,
|
|
3860
3924
|
apesBin: input.apesBin,
|
|
3861
3925
|
homeDir: input.homeDir,
|
|
3862
|
-
task
|
|
3926
|
+
task,
|
|
3927
|
+
userName: input.userName
|
|
3863
3928
|
});
|
|
3864
3929
|
let existingContent = "";
|
|
3865
3930
|
try {
|
|
@@ -3906,8 +3971,8 @@ function getHostname() {
|
|
|
3906
3971
|
}
|
|
3907
3972
|
|
|
3908
3973
|
// src/commands/agents/sync.ts
|
|
3909
|
-
var AUTH_PATH3 = join8(
|
|
3910
|
-
var TASK_CACHE_DIR2 = join8(
|
|
3974
|
+
var AUTH_PATH3 = join8(homedir9(), ".config", "apes", "auth.json");
|
|
3975
|
+
var TASK_CACHE_DIR2 = join8(homedir9(), ".openape", "agent", "tasks");
|
|
3911
3976
|
function readAuthJson() {
|
|
3912
3977
|
if (!existsSync9(AUTH_PATH3)) {
|
|
3913
3978
|
throw new CliError(
|
|
@@ -3977,20 +4042,56 @@ var syncAgentCommand = defineCommand27({
|
|
|
3977
4042
|
ownerEmail: auth.owner_email
|
|
3978
4043
|
});
|
|
3979
4044
|
consola24.info(sync.first_sync ? "\u2713 first sync \u2014 agent registered" : "\u2713 presence updated");
|
|
3980
|
-
const tasks = await client.listTasks();
|
|
4045
|
+
const { system_prompt: systemPrompt, tasks } = await client.listTasks();
|
|
3981
4046
|
consola24.info(`Pulled ${tasks.length} task${tasks.length === 1 ? "" : "s"}`);
|
|
4047
|
+
let agentUid = null;
|
|
4048
|
+
let agentGid = null;
|
|
4049
|
+
if (process.geteuid?.() === 0) {
|
|
4050
|
+
try {
|
|
4051
|
+
const homeStat = statSync(homedir9());
|
|
4052
|
+
agentUid = homeStat.uid;
|
|
4053
|
+
agentGid = homeStat.gid;
|
|
4054
|
+
} catch {
|
|
4055
|
+
}
|
|
4056
|
+
}
|
|
4057
|
+
function chownToAgent(path2) {
|
|
4058
|
+
if (agentUid !== null && agentGid !== null) {
|
|
4059
|
+
try {
|
|
4060
|
+
chownSync(path2, agentUid, agentGid);
|
|
4061
|
+
} catch {
|
|
4062
|
+
}
|
|
4063
|
+
}
|
|
4064
|
+
}
|
|
4065
|
+
const agentDir = join8(homedir9(), ".openape", "agent");
|
|
4066
|
+
mkdirSync4(agentDir, { recursive: true });
|
|
4067
|
+
chownToAgent(join8(homedir9(), ".openape"));
|
|
4068
|
+
chownToAgent(agentDir);
|
|
4069
|
+
const agentJsonPath = join8(agentDir, "agent.json");
|
|
4070
|
+
writeFileSync6(
|
|
4071
|
+
agentJsonPath,
|
|
4072
|
+
`${JSON.stringify({ systemPrompt }, null, 2)}
|
|
4073
|
+
`,
|
|
4074
|
+
{ mode: 384 }
|
|
4075
|
+
);
|
|
4076
|
+
chownToAgent(agentJsonPath);
|
|
3982
4077
|
mkdirSync4(TASK_CACHE_DIR2, { recursive: true });
|
|
4078
|
+
chownToAgent(TASK_CACHE_DIR2);
|
|
3983
4079
|
for (const task of tasks) {
|
|
3984
4080
|
const path2 = join8(TASK_CACHE_DIR2, `${task.taskId}.json`);
|
|
3985
4081
|
writeFileSync6(path2, `${JSON.stringify(task, null, 2)}
|
|
3986
4082
|
`, { mode: 384 });
|
|
4083
|
+
chownToAgent(path2);
|
|
3987
4084
|
}
|
|
3988
4085
|
const apesBin = findApesBin();
|
|
3989
4086
|
const result = reconcile({
|
|
3990
4087
|
agentName,
|
|
3991
4088
|
apesBin,
|
|
3992
|
-
homeDir:
|
|
3993
|
-
desired: tasks
|
|
4089
|
+
homeDir: homedir9(),
|
|
4090
|
+
desired: tasks,
|
|
4091
|
+
// Sync runs as root in production — pass the agent username
|
|
4092
|
+
// explicitly for the UserName plist key (launchd will then run
|
|
4093
|
+
// each task daemon AS the agent, not as root).
|
|
4094
|
+
userName: process.env.AGENT_USER || void 0
|
|
3994
4095
|
});
|
|
3995
4096
|
if (result.added.length) consola24.success(`launchd: added ${result.added.join(", ")}`);
|
|
3996
4097
|
if (result.updated.length) consola24.success(`launchd: updated ${result.updated.join(", ")}`);
|
|
@@ -5279,7 +5380,7 @@ var mcpCommand = defineCommand36({
|
|
|
5279
5380
|
if (transport !== "stdio" && transport !== "sse") {
|
|
5280
5381
|
throw new Error('Transport must be "stdio" or "sse"');
|
|
5281
5382
|
}
|
|
5282
|
-
const { startMcpServer } = await import("./server-
|
|
5383
|
+
const { startMcpServer } = await import("./server-YDC3S4PC.js");
|
|
5283
5384
|
await startMcpServer(transport, port);
|
|
5284
5385
|
}
|
|
5285
5386
|
});
|
|
@@ -5917,7 +6018,7 @@ async function bestEffortGrantCount(idp) {
|
|
|
5917
6018
|
}
|
|
5918
6019
|
}
|
|
5919
6020
|
async function runHealth(args) {
|
|
5920
|
-
const version = true ? "1.
|
|
6021
|
+
const version = true ? "1.2.1" : "0.0.0";
|
|
5921
6022
|
const auth = loadAuth();
|
|
5922
6023
|
if (!auth) {
|
|
5923
6024
|
throw new CliError("Not logged in. Run `apes login` first.", 1);
|
|
@@ -6111,12 +6212,12 @@ var workflowsCommand = defineCommand47({
|
|
|
6111
6212
|
|
|
6112
6213
|
// src/version-check.ts
|
|
6113
6214
|
import { existsSync as existsSync13, mkdirSync as mkdirSync5, readFileSync as readFileSync13, writeFileSync as writeFileSync9 } from "fs";
|
|
6114
|
-
import { homedir as
|
|
6215
|
+
import { homedir as homedir10 } from "os";
|
|
6115
6216
|
import { join as join11 } from "path";
|
|
6116
6217
|
import consola38 from "consola";
|
|
6117
6218
|
var PACKAGE_NAME = "@openape/apes";
|
|
6118
6219
|
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
6119
|
-
var CACHE_FILE = join11(
|
|
6220
|
+
var CACHE_FILE = join11(homedir10(), ".config", "apes", ".version-check.json");
|
|
6120
6221
|
function readCache() {
|
|
6121
6222
|
if (!existsSync13(CACHE_FILE)) return null;
|
|
6122
6223
|
try {
|
|
@@ -6127,7 +6228,7 @@ function readCache() {
|
|
|
6127
6228
|
}
|
|
6128
6229
|
function writeCache(entry) {
|
|
6129
6230
|
try {
|
|
6130
|
-
const dir = join11(
|
|
6231
|
+
const dir = join11(homedir10(), ".config", "apes");
|
|
6131
6232
|
if (!existsSync13(dir)) mkdirSync5(dir, { recursive: true, mode: 448 });
|
|
6132
6233
|
writeFileSync9(CACHE_FILE, JSON.stringify(entry), { mode: 384 });
|
|
6133
6234
|
} catch {
|
|
@@ -6190,10 +6291,10 @@ if (shellRewrite) {
|
|
|
6190
6291
|
if (shellRewrite.action === "rewrite") {
|
|
6191
6292
|
process.argv = shellRewrite.argv;
|
|
6192
6293
|
} else if (shellRewrite.action === "version") {
|
|
6193
|
-
console.log(`ape-shell ${"1.
|
|
6294
|
+
console.log(`ape-shell ${"1.2.1"} (OpenApe DDISA shell wrapper)`);
|
|
6194
6295
|
process.exit(0);
|
|
6195
6296
|
} else if (shellRewrite.action === "help") {
|
|
6196
|
-
console.log(`ape-shell ${"1.
|
|
6297
|
+
console.log(`ape-shell ${"1.2.1"} \u2014 OpenApe DDISA shell wrapper`);
|
|
6197
6298
|
console.log("");
|
|
6198
6299
|
console.log("Usage:");
|
|
6199
6300
|
console.log(" ape-shell Start interactive grant-mediated REPL");
|
|
@@ -6251,7 +6352,7 @@ var configCommand = defineCommand48({
|
|
|
6251
6352
|
var main = defineCommand48({
|
|
6252
6353
|
meta: {
|
|
6253
6354
|
name: "apes",
|
|
6254
|
-
version: "1.
|
|
6355
|
+
version: "1.2.1",
|
|
6255
6356
|
description: "Unified CLI for OpenApe"
|
|
6256
6357
|
},
|
|
6257
6358
|
subCommands: {
|
|
@@ -6306,7 +6407,7 @@ async function maybeRefreshAuth() {
|
|
|
6306
6407
|
}
|
|
6307
6408
|
}
|
|
6308
6409
|
await maybeRefreshAuth();
|
|
6309
|
-
await maybeWarnStaleVersion("1.
|
|
6410
|
+
await maybeWarnStaleVersion("1.2.1").catch(() => {
|
|
6310
6411
|
});
|
|
6311
6412
|
runMain(main).catch((err) => {
|
|
6312
6413
|
if (err instanceof CliExit) {
|