@askexenow/exe-os 0.9.85 → 0.9.87
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/bin/agentic-ontology-backfill.js +50 -14
- package/dist/bin/agentic-reflection-backfill.js +50 -14
- package/dist/bin/agentic-semantic-label.js +50 -14
- package/dist/bin/backfill-conversations.js +50 -14
- package/dist/bin/backfill-responses.js +50 -14
- package/dist/bin/backfill-vectors.js +50 -14
- package/dist/bin/bulk-sync-postgres.js +50 -14
- package/dist/bin/cleanup-stale-review-tasks.js +53 -17
- package/dist/bin/cli.js +339 -81
- package/dist/bin/exe-agent.js +18 -0
- package/dist/bin/exe-assign.js +50 -14
- package/dist/bin/exe-boot.js +75 -39
- package/dist/bin/exe-call.js +18 -0
- package/dist/bin/exe-cloud.js +40 -4
- package/dist/bin/exe-dispatch.js +61 -25
- package/dist/bin/exe-doctor.js +40 -4
- package/dist/bin/exe-export-behaviors.js +50 -14
- package/dist/bin/exe-forget.js +50 -14
- package/dist/bin/exe-gateway.js +65 -29
- package/dist/bin/exe-heartbeat.js +55 -19
- package/dist/bin/exe-kill.js +54 -18
- package/dist/bin/exe-launch-agent.js +58 -22
- package/dist/bin/exe-new-employee.js +33 -2
- package/dist/bin/exe-pending-messages.js +53 -17
- package/dist/bin/exe-pending-notifications.js +53 -17
- package/dist/bin/exe-pending-reviews.js +55 -19
- package/dist/bin/exe-rename.js +52 -16
- package/dist/bin/exe-review.js +50 -14
- package/dist/bin/exe-search.js +58 -22
- package/dist/bin/exe-session-cleanup.js +85 -44
- package/dist/bin/exe-start-codex.js +57 -21
- package/dist/bin/exe-start-opencode.js +55 -19
- package/dist/bin/exe-status.js +62 -26
- package/dist/bin/exe-team.js +50 -14
- package/dist/bin/git-sweep.js +63 -27
- package/dist/bin/graph-backfill.js +50 -14
- package/dist/bin/graph-export.js +50 -14
- package/dist/bin/install.js +9 -0
- package/dist/bin/intercom-check.js +67 -31
- package/dist/bin/scan-tasks.js +63 -27
- package/dist/bin/setup.js +53 -13
- package/dist/bin/shard-migrate.js +50 -14
- package/dist/bin/stack-update.js +59 -2
- package/dist/bin/update.js +1 -1
- package/dist/gateway/index.js +65 -29
- package/dist/hooks/bug-report-worker.js +65 -29
- package/dist/hooks/codex-stop-task-finalizer.js +59 -23
- package/dist/hooks/commit-complete.js +64 -28
- package/dist/hooks/error-recall.js +62 -26
- package/dist/hooks/ingest-worker.js +4 -4
- package/dist/hooks/ingest.js +56 -20
- package/dist/hooks/instructions-loaded.js +50 -14
- package/dist/hooks/notification.js +50 -14
- package/dist/hooks/post-compact.js +50 -14
- package/dist/hooks/post-tool-combined.js +63 -27
- package/dist/hooks/pre-compact.js +61 -25
- package/dist/hooks/pre-tool-use.js +58 -22
- package/dist/hooks/prompt-submit.js +78 -42
- package/dist/hooks/session-end.js +66 -30
- package/dist/hooks/session-start.js +68 -32
- package/dist/hooks/stop.js +53 -17
- package/dist/hooks/subagent-stop.js +50 -14
- package/dist/hooks/summary-worker.js +55 -19
- package/dist/index.js +61 -25
- package/dist/lib/cloud-sync.js +32 -14
- package/dist/lib/database.js +22 -4
- package/dist/lib/db-daemon-client.js +16 -4
- package/dist/lib/db.js +22 -4
- package/dist/lib/device-registry.js +22 -4
- package/dist/lib/embedder.js +16 -4
- package/dist/lib/employee-templates.js +18 -0
- package/dist/lib/exe-daemon-client.js +16 -4
- package/dist/lib/exe-daemon.js +874 -232
- package/dist/lib/hybrid-search.js +58 -22
- package/dist/lib/identity-templates.js +6 -2
- package/dist/lib/schedules.js +53 -17
- package/dist/lib/skill-learning.js +16 -4
- package/dist/lib/store.js +50 -14
- package/dist/lib/tasks.js +16 -4
- package/dist/lib/tmux-routing.js +18 -6
- package/dist/mcp/server.js +809 -200
- package/dist/mcp/tools/create-task.js +24 -8
- package/dist/mcp/tools/update-task.js +18 -6
- package/dist/runtime/index.js +61 -25
- package/dist/tui/App.js +91 -55
- package/package.json +1 -1
|
@@ -1045,7 +1045,7 @@ var init_daemon_auth = __esm({
|
|
|
1045
1045
|
// src/lib/exe-daemon-client.ts
|
|
1046
1046
|
import net from "net";
|
|
1047
1047
|
import os4 from "os";
|
|
1048
|
-
import { spawn } from "child_process";
|
|
1048
|
+
import { spawn, execSync as execSync2 } from "child_process";
|
|
1049
1049
|
import { randomUUID } from "crypto";
|
|
1050
1050
|
import { existsSync as existsSync5, unlinkSync as unlinkSync2, readFileSync as readFileSync4, openSync, closeSync, statSync } from "fs";
|
|
1051
1051
|
import path5 from "path";
|
|
@@ -1075,6 +1075,14 @@ function handleData(chunk) {
|
|
|
1075
1075
|
}
|
|
1076
1076
|
}
|
|
1077
1077
|
}
|
|
1078
|
+
function isZombie(pid) {
|
|
1079
|
+
try {
|
|
1080
|
+
const state = execSync2(`ps -p ${pid} -o state=`, { encoding: "utf8", timeout: 2e3 }).trim();
|
|
1081
|
+
return state.startsWith("Z");
|
|
1082
|
+
} catch {
|
|
1083
|
+
return false;
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1078
1086
|
function cleanupStaleFiles() {
|
|
1079
1087
|
if (existsSync5(PID_PATH)) {
|
|
1080
1088
|
try {
|
|
@@ -1082,7 +1090,11 @@ function cleanupStaleFiles() {
|
|
|
1082
1090
|
if (pid > 0) {
|
|
1083
1091
|
try {
|
|
1084
1092
|
process.kill(pid, 0);
|
|
1085
|
-
|
|
1093
|
+
if (!isZombie(pid)) {
|
|
1094
|
+
return;
|
|
1095
|
+
}
|
|
1096
|
+
process.stderr.write(`[exed-client] PID ${pid} is a zombie \u2014 cleaning up stale files
|
|
1097
|
+
`);
|
|
1086
1098
|
} catch {
|
|
1087
1099
|
}
|
|
1088
1100
|
}
|
|
@@ -1110,8 +1122,8 @@ function findPackageRoot() {
|
|
|
1110
1122
|
function getAvailableMemoryGB() {
|
|
1111
1123
|
if (process.platform === "darwin") {
|
|
1112
1124
|
try {
|
|
1113
|
-
const { execSync:
|
|
1114
|
-
const vmstat =
|
|
1125
|
+
const { execSync: execSync6 } = __require("child_process");
|
|
1126
|
+
const vmstat = execSync6("vm_stat", { encoding: "utf8" });
|
|
1115
1127
|
const pageSize = 16384;
|
|
1116
1128
|
const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
|
|
1117
1129
|
const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
|
|
@@ -3046,6 +3058,12 @@ async function disposeDatabase() {
|
|
|
3046
3058
|
clearInterval(_walCheckpointTimer);
|
|
3047
3059
|
_walCheckpointTimer = null;
|
|
3048
3060
|
}
|
|
3061
|
+
if (_client) {
|
|
3062
|
+
try {
|
|
3063
|
+
await _client.execute("PRAGMA wal_checkpoint(PASSIVE)");
|
|
3064
|
+
} catch {
|
|
3065
|
+
}
|
|
3066
|
+
}
|
|
3049
3067
|
if (_daemonClient) {
|
|
3050
3068
|
_daemonClient.close();
|
|
3051
3069
|
_daemonClient = null;
|
|
@@ -3082,7 +3100,7 @@ var init_database = __esm({
|
|
|
3082
3100
|
// src/lib/keychain.ts
|
|
3083
3101
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
3084
3102
|
import { existsSync as existsSync6, statSync as statSync2 } from "fs";
|
|
3085
|
-
import { execSync as
|
|
3103
|
+
import { execSync as execSync3 } from "child_process";
|
|
3086
3104
|
import path6 from "path";
|
|
3087
3105
|
import os5 from "os";
|
|
3088
3106
|
function getKeyDir() {
|
|
@@ -3099,13 +3117,13 @@ function linuxSecretAvailable() {
|
|
|
3099
3117
|
if (process.platform !== "linux") return false;
|
|
3100
3118
|
if (linuxSecretAvailability !== null) return linuxSecretAvailability;
|
|
3101
3119
|
try {
|
|
3102
|
-
|
|
3120
|
+
execSync3("command -v secret-tool >/dev/null 2>&1", { timeout: 1e3 });
|
|
3103
3121
|
} catch {
|
|
3104
3122
|
linuxSecretAvailability = false;
|
|
3105
3123
|
return false;
|
|
3106
3124
|
}
|
|
3107
3125
|
try {
|
|
3108
|
-
|
|
3126
|
+
execSync3("secret-tool search --all exe-os probe >/dev/null 2>&1", { timeout: 1e3 });
|
|
3109
3127
|
linuxSecretAvailability = true;
|
|
3110
3128
|
} catch {
|
|
3111
3129
|
linuxSecretAvailability = false;
|
|
@@ -3129,7 +3147,7 @@ function macKeychainGet(service = SERVICE) {
|
|
|
3129
3147
|
if (!nativeKeychainAllowed()) return null;
|
|
3130
3148
|
if (process.platform !== "darwin") return null;
|
|
3131
3149
|
try {
|
|
3132
|
-
return
|
|
3150
|
+
return execSync3(
|
|
3133
3151
|
`security find-generic-password -s "${service}" -a "${ACCOUNT}" -w 2>/dev/null`,
|
|
3134
3152
|
{ encoding: "utf-8", timeout: 5e3 }
|
|
3135
3153
|
).trim();
|
|
@@ -3142,13 +3160,13 @@ function macKeychainSet(value, service = SERVICE) {
|
|
|
3142
3160
|
if (process.platform !== "darwin") return false;
|
|
3143
3161
|
try {
|
|
3144
3162
|
try {
|
|
3145
|
-
|
|
3163
|
+
execSync3(
|
|
3146
3164
|
`security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
|
|
3147
3165
|
{ timeout: 5e3 }
|
|
3148
3166
|
);
|
|
3149
3167
|
} catch {
|
|
3150
3168
|
}
|
|
3151
|
-
|
|
3169
|
+
execSync3(
|
|
3152
3170
|
`security add-generic-password -s "${service}" -a "${ACCOUNT}" -w "${value}"`,
|
|
3153
3171
|
{ timeout: 5e3 }
|
|
3154
3172
|
);
|
|
@@ -3161,7 +3179,7 @@ function macKeychainDelete(service = SERVICE) {
|
|
|
3161
3179
|
if (!nativeKeychainAllowed()) return false;
|
|
3162
3180
|
if (process.platform !== "darwin") return false;
|
|
3163
3181
|
try {
|
|
3164
|
-
|
|
3182
|
+
execSync3(
|
|
3165
3183
|
`security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
|
|
3166
3184
|
{ timeout: 5e3 }
|
|
3167
3185
|
);
|
|
@@ -3173,7 +3191,7 @@ function macKeychainDelete(service = SERVICE) {
|
|
|
3173
3191
|
function linuxSecretGet(service = SERVICE) {
|
|
3174
3192
|
if (!linuxSecretAvailable()) return null;
|
|
3175
3193
|
try {
|
|
3176
|
-
return
|
|
3194
|
+
return execSync3(
|
|
3177
3195
|
`secret-tool lookup service "${service}" account "${ACCOUNT}" 2>/dev/null`,
|
|
3178
3196
|
{ encoding: "utf-8", timeout: 5e3 }
|
|
3179
3197
|
).trim();
|
|
@@ -3184,7 +3202,7 @@ function linuxSecretGet(service = SERVICE) {
|
|
|
3184
3202
|
function linuxSecretSet(value, service = SERVICE) {
|
|
3185
3203
|
if (!linuxSecretAvailable()) return false;
|
|
3186
3204
|
try {
|
|
3187
|
-
|
|
3205
|
+
execSync3(
|
|
3188
3206
|
`echo -n "${value}" | secret-tool store --label="exe-os master key" service "${service}" account "${ACCOUNT}" 2>/dev/null`,
|
|
3189
3207
|
{ timeout: 5e3 }
|
|
3190
3208
|
);
|
|
@@ -3197,7 +3215,7 @@ function linuxSecretDelete(service = SERVICE) {
|
|
|
3197
3215
|
if (!nativeKeychainAllowed()) return false;
|
|
3198
3216
|
if (process.platform !== "linux") return false;
|
|
3199
3217
|
try {
|
|
3200
|
-
|
|
3218
|
+
execSync3(
|
|
3201
3219
|
`secret-tool clear service "${service}" account "${ACCOUNT}" 2>/dev/null`,
|
|
3202
3220
|
{ timeout: 5e3 }
|
|
3203
3221
|
);
|
|
@@ -4134,6 +4152,24 @@ var init_platform_procedures = __esm({
|
|
|
4134
4152
|
priority: "p0",
|
|
4135
4153
|
content: "When an agent encounters a suspected Exe OS bug, update breakage, MCP/tool failure, installer issue, memory/orchestration defect, or customer-local patch need, it MUST use create_bug_report. Do this before or alongside any local workaround so the report reaches AskExe support directly via the customer's license. Do NOT ask the founder for permission to file a required bug report. If create_bug_report is deferred/lazy-loaded, load it and call it. If it is unavailable in the live MCP surface, report 'create_bug_report unavailable in this session' and save a local report in exe/output \u2014 never claim the tool does not exist unless the live MCP surface was checked. If upstream delivery fails, call support_test (MCP) and include its result in the local report so AskExe can distinguish customer setup, license provisioning, and server intake issues; only ask the founder to run `exe-os support test` if MCP is disconnected/unavailable. Classify first: upstream_bug = reproducible exe-os/platform defect; customer_customization = identity, behavior, procedure, config, branding, workflow preference that belongs in customer-owned layers; emergency_hotfix = temporary local patch. For upstream bugs/emergency hotfixes include version, repro steps, expected/actual, files changed, workaround, and local diff summary. Avoid permanent platform-code patches unless founder approves; if a hotfix is unavoidable, document it in the bug report and re-check after npm update."
|
|
4136
4154
|
},
|
|
4155
|
+
{
|
|
4156
|
+
title: "Bug report status check \u2014 surface available fixes on boot",
|
|
4157
|
+
domain: "support",
|
|
4158
|
+
priority: "p1",
|
|
4159
|
+
content: "Once per session (COO boot only, never repeat), call list_my_bug_reports to check if any previously filed bug reports have been fixed by AskExe. If any report has status 'fixed' with a fixed_version, surface it to the founder immediately: '\u{1F527} N bug fix(es) available \u2014 run exe-os update to get version X.Y.Z'. This is a one-time check at boot, not a recurring poll. If no reports exist or none are fixed, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
|
|
4160
|
+
},
|
|
4161
|
+
{
|
|
4162
|
+
title: "Feature request triage \u2014 upstream feature vs local customization",
|
|
4163
|
+
domain: "support",
|
|
4164
|
+
priority: "p0",
|
|
4165
|
+
content: "When an agent or founder identifies a desired capability that exe-os does not yet provide, the COO (or equivalent coordinator) must decide: is this a local customization (identity, behavior, procedure, config, branding, workflow preference that can be configured in customer-owned layers) or an upstream feature request (a platform capability that requires changes to exe-os code, shipped via npm update)? Local customizations: implement immediately using store_behavior, update_identity, company_procedure, or config changes. Upstream features: use create_feature_request to submit to AskExe. Include use case, business impact, and current workaround. Do NOT ask the founder for permission to file a feature request \u2014 file it proactively when the need is clear."
|
|
4166
|
+
},
|
|
4167
|
+
{
|
|
4168
|
+
title: "Feature request status check \u2014 surface shipped features on boot",
|
|
4169
|
+
domain: "support",
|
|
4170
|
+
priority: "p1",
|
|
4171
|
+
content: "Once per session (COO boot only, never repeat), call list_my_feature_requests to check if any previously filed feature requests have been shipped by AskExe. If any request has status 'shipped' with a shipped_version, surface it to the founder immediately: '\u{1F680} N feature(s) shipped \u2014 run exe-os update to get version X.Y.Z'. This is a one-time check at boot, not a recurring poll. If no requests exist or none are shipped, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
|
|
4172
|
+
},
|
|
4137
4173
|
// --- Operations ---
|
|
4138
4174
|
{
|
|
4139
4175
|
title: "Managers must supervise deployed workers",
|
|
@@ -5665,7 +5701,7 @@ __export(project_name_exports, {
|
|
|
5665
5701
|
_resetCache: () => _resetCache,
|
|
5666
5702
|
getProjectName: () => getProjectName
|
|
5667
5703
|
});
|
|
5668
|
-
import { execSync as
|
|
5704
|
+
import { execSync as execSync4 } from "child_process";
|
|
5669
5705
|
import path9 from "path";
|
|
5670
5706
|
function getProjectName(cwd) {
|
|
5671
5707
|
const dir = cwd ?? process.cwd();
|
|
@@ -5673,7 +5709,7 @@ function getProjectName(cwd) {
|
|
|
5673
5709
|
try {
|
|
5674
5710
|
let repoRoot;
|
|
5675
5711
|
try {
|
|
5676
|
-
const gitCommonDir =
|
|
5712
|
+
const gitCommonDir = execSync4("git rev-parse --path-format=absolute --git-common-dir", {
|
|
5677
5713
|
cwd: dir,
|
|
5678
5714
|
encoding: "utf8",
|
|
5679
5715
|
timeout: 2e3,
|
|
@@ -5681,7 +5717,7 @@ function getProjectName(cwd) {
|
|
|
5681
5717
|
}).trim();
|
|
5682
5718
|
repoRoot = path9.dirname(gitCommonDir);
|
|
5683
5719
|
} catch {
|
|
5684
|
-
repoRoot =
|
|
5720
|
+
repoRoot = execSync4("git rev-parse --show-toplevel", {
|
|
5685
5721
|
cwd: dir,
|
|
5686
5722
|
encoding: "utf8",
|
|
5687
5723
|
timeout: 2e3,
|
|
@@ -5715,14 +5751,14 @@ var file_grep_exports = {};
|
|
|
5715
5751
|
__export(file_grep_exports, {
|
|
5716
5752
|
grepProjectFiles: () => grepProjectFiles
|
|
5717
5753
|
});
|
|
5718
|
-
import { execSync as
|
|
5754
|
+
import { execSync as execSync5 } from "child_process";
|
|
5719
5755
|
import { readFileSync as readFileSync5, readdirSync as readdirSync2, statSync as statSync4, existsSync as existsSync9 } from "fs";
|
|
5720
5756
|
import path10 from "path";
|
|
5721
5757
|
import crypto2 from "crypto";
|
|
5722
5758
|
function hasRipgrep() {
|
|
5723
5759
|
if (_hasRg === null) {
|
|
5724
5760
|
try {
|
|
5725
|
-
|
|
5761
|
+
execSync5("rg --version", { stdio: "ignore", timeout: 2e3 });
|
|
5726
5762
|
_hasRg = true;
|
|
5727
5763
|
} catch {
|
|
5728
5764
|
_hasRg = false;
|
|
@@ -5788,7 +5824,7 @@ function grepWithRipgrep(pattern, projectRoot, patterns) {
|
|
|
5788
5824
|
const globs = (patterns ?? DEFAULT_PATTERNS).map((p) => `--glob '${p}'`).join(" ");
|
|
5789
5825
|
const excludes = EXCLUDE_DIRS.map((d) => `--glob '!${d}'`).join(" ");
|
|
5790
5826
|
const cmd = `rg -i -c --hidden --no-config --no-ignore '${pattern.replace(/'/g, "\\'")}' . ${globs} ${excludes} --max-filesize ${MAX_FILE_SIZE} 2>/dev/null || true`;
|
|
5791
|
-
const output =
|
|
5827
|
+
const output = execSync5(cmd, {
|
|
5792
5828
|
cwd: projectRoot,
|
|
5793
5829
|
encoding: "utf8",
|
|
5794
5830
|
timeout: 3e3,
|
|
@@ -5803,12 +5839,12 @@ function grepWithRipgrep(pattern, projectRoot, patterns) {
|
|
|
5803
5839
|
const matchCount = parseInt(line.slice(colonIdx + 1));
|
|
5804
5840
|
if (isNaN(matchCount) || matchCount === 0) continue;
|
|
5805
5841
|
try {
|
|
5806
|
-
const firstMatch =
|
|
5842
|
+
const firstMatch = execSync5(
|
|
5807
5843
|
`rg -i -n --hidden '${pattern.replace(/'/g, "\\'")}' '${filePath}' --max-count 1 2>/dev/null | head -1`,
|
|
5808
5844
|
{ cwd: projectRoot, encoding: "utf8", timeout: 1e3 }
|
|
5809
5845
|
).trim();
|
|
5810
5846
|
const lineNum = parseInt(firstMatch.split(":")[0] ?? "1");
|
|
5811
|
-
const totalLines =
|
|
5847
|
+
const totalLines = execSync5(`wc -l < '${filePath}'`, {
|
|
5812
5848
|
cwd: projectRoot,
|
|
5813
5849
|
encoding: "utf8",
|
|
5814
5850
|
timeout: 1e3
|
|
@@ -72,12 +72,14 @@ On EVERY new conversation, before doing anything else:
|
|
|
72
72
|
1. **Memory scan**: Run recall_my_memory with broad queries \u2014 "project", "client", "pipeline", "campaign", "deal", "decision", "blocker". Summarize what you find.
|
|
73
73
|
2. **Task scan**: Run list_tasks to see what's open, in progress, blocked, or needs review across all employees.
|
|
74
74
|
3. **Team check**: Run ask_team_memory for recent activity from CTO/CMO/engineers.
|
|
75
|
-
4. **
|
|
75
|
+
4. **Bug fix check** (one-time, never repeat): Call list_my_bug_reports to see if AskExe has fixed any previously filed bugs. If any have status "fixed" with a fixed_version, tell the founder: "\u{1F527} N bug fix(es) available \u2014 run \`exe-os update\` to get version X.Y.Z." Skip silently if none or if the call fails.
|
|
76
|
+
5. **Present the brief**: Give the founder a concise status report:
|
|
76
77
|
- What's active and progressing
|
|
77
78
|
- What's blocked and needs attention
|
|
78
79
|
- What decisions are pending
|
|
80
|
+
- Available bug fixes (from step 4, if any)
|
|
79
81
|
- What you recommend doing next
|
|
80
|
-
|
|
82
|
+
6. Then ask: "What's the priority?"
|
|
81
83
|
|
|
82
84
|
If this is your FIRST ever conversation (few or no prior memories):
|
|
83
85
|
- Search more broadly: "product", "SEO", "meeting", "strategy", "revenue"
|
|
@@ -97,6 +99,8 @@ Never say "I have no memories" without first searching broadly. Your memory may
|
|
|
97
99
|
- **get_identity** \u2014 read any agent's identity for coordination
|
|
98
100
|
- **set_agent_config** \u2014 view or change which tool (Claude Code, Codex, OpenCode) and model each agent uses. Call with no args to show all agents' current settings. Call with agent_id + runtime + model to change.
|
|
99
101
|
- **send_message** \u2014 direct intercom to employees
|
|
102
|
+
- **create_bug_report** \u2014 file a bug when you encounter an Exe OS platform issue
|
|
103
|
+
- **list_my_bug_reports** \u2014 check status of filed bugs (boot check: surface available fixes to founder)
|
|
100
104
|
${PLAN_MODE_COMPAT}
|
|
101
105
|
## Completion Workflow
|
|
102
106
|
|
package/dist/lib/schedules.js
CHANGED
|
@@ -980,7 +980,7 @@ var init_daemon_auth = __esm({
|
|
|
980
980
|
// src/lib/exe-daemon-client.ts
|
|
981
981
|
import net from "net";
|
|
982
982
|
import os4 from "os";
|
|
983
|
-
import { spawn } from "child_process";
|
|
983
|
+
import { spawn, execSync as execSync2 } from "child_process";
|
|
984
984
|
import { randomUUID } from "crypto";
|
|
985
985
|
import { existsSync as existsSync5, unlinkSync as unlinkSync2, readFileSync as readFileSync4, openSync, closeSync, statSync } from "fs";
|
|
986
986
|
import path5 from "path";
|
|
@@ -1010,6 +1010,14 @@ function handleData(chunk) {
|
|
|
1010
1010
|
}
|
|
1011
1011
|
}
|
|
1012
1012
|
}
|
|
1013
|
+
function isZombie(pid) {
|
|
1014
|
+
try {
|
|
1015
|
+
const state = execSync2(`ps -p ${pid} -o state=`, { encoding: "utf8", timeout: 2e3 }).trim();
|
|
1016
|
+
return state.startsWith("Z");
|
|
1017
|
+
} catch {
|
|
1018
|
+
return false;
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1013
1021
|
function cleanupStaleFiles() {
|
|
1014
1022
|
if (existsSync5(PID_PATH)) {
|
|
1015
1023
|
try {
|
|
@@ -1017,7 +1025,11 @@ function cleanupStaleFiles() {
|
|
|
1017
1025
|
if (pid > 0) {
|
|
1018
1026
|
try {
|
|
1019
1027
|
process.kill(pid, 0);
|
|
1020
|
-
|
|
1028
|
+
if (!isZombie(pid)) {
|
|
1029
|
+
return;
|
|
1030
|
+
}
|
|
1031
|
+
process.stderr.write(`[exed-client] PID ${pid} is a zombie \u2014 cleaning up stale files
|
|
1032
|
+
`);
|
|
1021
1033
|
} catch {
|
|
1022
1034
|
}
|
|
1023
1035
|
}
|
|
@@ -1045,8 +1057,8 @@ function findPackageRoot() {
|
|
|
1045
1057
|
function getAvailableMemoryGB() {
|
|
1046
1058
|
if (process.platform === "darwin") {
|
|
1047
1059
|
try {
|
|
1048
|
-
const { execSync:
|
|
1049
|
-
const vmstat =
|
|
1060
|
+
const { execSync: execSync5 } = __require("child_process");
|
|
1061
|
+
const vmstat = execSync5("vm_stat", { encoding: "utf8" });
|
|
1050
1062
|
const pageSize = 16384;
|
|
1051
1063
|
const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
|
|
1052
1064
|
const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
|
|
@@ -2832,6 +2844,12 @@ async function disposeDatabase() {
|
|
|
2832
2844
|
clearInterval(_walCheckpointTimer);
|
|
2833
2845
|
_walCheckpointTimer = null;
|
|
2834
2846
|
}
|
|
2847
|
+
if (_client) {
|
|
2848
|
+
try {
|
|
2849
|
+
await _client.execute("PRAGMA wal_checkpoint(PASSIVE)");
|
|
2850
|
+
} catch {
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2835
2853
|
if (_daemonClient) {
|
|
2836
2854
|
_daemonClient.close();
|
|
2837
2855
|
_daemonClient = null;
|
|
@@ -3363,6 +3381,24 @@ var init_platform_procedures = __esm({
|
|
|
3363
3381
|
priority: "p0",
|
|
3364
3382
|
content: "When an agent encounters a suspected Exe OS bug, update breakage, MCP/tool failure, installer issue, memory/orchestration defect, or customer-local patch need, it MUST use create_bug_report. Do this before or alongside any local workaround so the report reaches AskExe support directly via the customer's license. Do NOT ask the founder for permission to file a required bug report. If create_bug_report is deferred/lazy-loaded, load it and call it. If it is unavailable in the live MCP surface, report 'create_bug_report unavailable in this session' and save a local report in exe/output \u2014 never claim the tool does not exist unless the live MCP surface was checked. If upstream delivery fails, call support_test (MCP) and include its result in the local report so AskExe can distinguish customer setup, license provisioning, and server intake issues; only ask the founder to run `exe-os support test` if MCP is disconnected/unavailable. Classify first: upstream_bug = reproducible exe-os/platform defect; customer_customization = identity, behavior, procedure, config, branding, workflow preference that belongs in customer-owned layers; emergency_hotfix = temporary local patch. For upstream bugs/emergency hotfixes include version, repro steps, expected/actual, files changed, workaround, and local diff summary. Avoid permanent platform-code patches unless founder approves; if a hotfix is unavoidable, document it in the bug report and re-check after npm update."
|
|
3365
3383
|
},
|
|
3384
|
+
{
|
|
3385
|
+
title: "Bug report status check \u2014 surface available fixes on boot",
|
|
3386
|
+
domain: "support",
|
|
3387
|
+
priority: "p1",
|
|
3388
|
+
content: "Once per session (COO boot only, never repeat), call list_my_bug_reports to check if any previously filed bug reports have been fixed by AskExe. If any report has status 'fixed' with a fixed_version, surface it to the founder immediately: '\u{1F527} N bug fix(es) available \u2014 run exe-os update to get version X.Y.Z'. This is a one-time check at boot, not a recurring poll. If no reports exist or none are fixed, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
|
|
3389
|
+
},
|
|
3390
|
+
{
|
|
3391
|
+
title: "Feature request triage \u2014 upstream feature vs local customization",
|
|
3392
|
+
domain: "support",
|
|
3393
|
+
priority: "p0",
|
|
3394
|
+
content: "When an agent or founder identifies a desired capability that exe-os does not yet provide, the COO (or equivalent coordinator) must decide: is this a local customization (identity, behavior, procedure, config, branding, workflow preference that can be configured in customer-owned layers) or an upstream feature request (a platform capability that requires changes to exe-os code, shipped via npm update)? Local customizations: implement immediately using store_behavior, update_identity, company_procedure, or config changes. Upstream features: use create_feature_request to submit to AskExe. Include use case, business impact, and current workaround. Do NOT ask the founder for permission to file a feature request \u2014 file it proactively when the need is clear."
|
|
3395
|
+
},
|
|
3396
|
+
{
|
|
3397
|
+
title: "Feature request status check \u2014 surface shipped features on boot",
|
|
3398
|
+
domain: "support",
|
|
3399
|
+
priority: "p1",
|
|
3400
|
+
content: "Once per session (COO boot only, never repeat), call list_my_feature_requests to check if any previously filed feature requests have been shipped by AskExe. If any request has status 'shipped' with a shipped_version, surface it to the founder immediately: '\u{1F680} N feature(s) shipped \u2014 run exe-os update to get version X.Y.Z'. This is a one-time check at boot, not a recurring poll. If no requests exist or none are shipped, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
|
|
3401
|
+
},
|
|
3366
3402
|
// --- Operations ---
|
|
3367
3403
|
{
|
|
3368
3404
|
title: "Managers must supervise deployed workers",
|
|
@@ -3556,7 +3592,7 @@ ${p.content}`).join("\n\n");
|
|
|
3556
3592
|
// src/lib/schedules.ts
|
|
3557
3593
|
init_database();
|
|
3558
3594
|
import crypto2 from "crypto";
|
|
3559
|
-
import { execSync as
|
|
3595
|
+
import { execSync as execSync4 } from "child_process";
|
|
3560
3596
|
|
|
3561
3597
|
// src/lib/store.ts
|
|
3562
3598
|
init_memory();
|
|
@@ -3565,7 +3601,7 @@ init_database();
|
|
|
3565
3601
|
// src/lib/keychain.ts
|
|
3566
3602
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
3567
3603
|
import { existsSync as existsSync6, statSync as statSync2 } from "fs";
|
|
3568
|
-
import { execSync as
|
|
3604
|
+
import { execSync as execSync3 } from "child_process";
|
|
3569
3605
|
import path6 from "path";
|
|
3570
3606
|
import os5 from "os";
|
|
3571
3607
|
var SERVICE = "exe-os";
|
|
@@ -3586,13 +3622,13 @@ function linuxSecretAvailable() {
|
|
|
3586
3622
|
if (process.platform !== "linux") return false;
|
|
3587
3623
|
if (linuxSecretAvailability !== null) return linuxSecretAvailability;
|
|
3588
3624
|
try {
|
|
3589
|
-
|
|
3625
|
+
execSync3("command -v secret-tool >/dev/null 2>&1", { timeout: 1e3 });
|
|
3590
3626
|
} catch {
|
|
3591
3627
|
linuxSecretAvailability = false;
|
|
3592
3628
|
return false;
|
|
3593
3629
|
}
|
|
3594
3630
|
try {
|
|
3595
|
-
|
|
3631
|
+
execSync3("secret-tool search --all exe-os probe >/dev/null 2>&1", { timeout: 1e3 });
|
|
3596
3632
|
linuxSecretAvailability = true;
|
|
3597
3633
|
} catch {
|
|
3598
3634
|
linuxSecretAvailability = false;
|
|
@@ -3616,7 +3652,7 @@ function macKeychainGet(service = SERVICE) {
|
|
|
3616
3652
|
if (!nativeKeychainAllowed()) return null;
|
|
3617
3653
|
if (process.platform !== "darwin") return null;
|
|
3618
3654
|
try {
|
|
3619
|
-
return
|
|
3655
|
+
return execSync3(
|
|
3620
3656
|
`security find-generic-password -s "${service}" -a "${ACCOUNT}" -w 2>/dev/null`,
|
|
3621
3657
|
{ encoding: "utf-8", timeout: 5e3 }
|
|
3622
3658
|
).trim();
|
|
@@ -3629,13 +3665,13 @@ function macKeychainSet(value, service = SERVICE) {
|
|
|
3629
3665
|
if (process.platform !== "darwin") return false;
|
|
3630
3666
|
try {
|
|
3631
3667
|
try {
|
|
3632
|
-
|
|
3668
|
+
execSync3(
|
|
3633
3669
|
`security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
|
|
3634
3670
|
{ timeout: 5e3 }
|
|
3635
3671
|
);
|
|
3636
3672
|
} catch {
|
|
3637
3673
|
}
|
|
3638
|
-
|
|
3674
|
+
execSync3(
|
|
3639
3675
|
`security add-generic-password -s "${service}" -a "${ACCOUNT}" -w "${value}"`,
|
|
3640
3676
|
{ timeout: 5e3 }
|
|
3641
3677
|
);
|
|
@@ -3648,7 +3684,7 @@ function macKeychainDelete(service = SERVICE) {
|
|
|
3648
3684
|
if (!nativeKeychainAllowed()) return false;
|
|
3649
3685
|
if (process.platform !== "darwin") return false;
|
|
3650
3686
|
try {
|
|
3651
|
-
|
|
3687
|
+
execSync3(
|
|
3652
3688
|
`security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
|
|
3653
3689
|
{ timeout: 5e3 }
|
|
3654
3690
|
);
|
|
@@ -3660,7 +3696,7 @@ function macKeychainDelete(service = SERVICE) {
|
|
|
3660
3696
|
function linuxSecretGet(service = SERVICE) {
|
|
3661
3697
|
if (!linuxSecretAvailable()) return null;
|
|
3662
3698
|
try {
|
|
3663
|
-
return
|
|
3699
|
+
return execSync3(
|
|
3664
3700
|
`secret-tool lookup service "${service}" account "${ACCOUNT}" 2>/dev/null`,
|
|
3665
3701
|
{ encoding: "utf-8", timeout: 5e3 }
|
|
3666
3702
|
).trim();
|
|
@@ -3671,7 +3707,7 @@ function linuxSecretGet(service = SERVICE) {
|
|
|
3671
3707
|
function linuxSecretSet(value, service = SERVICE) {
|
|
3672
3708
|
if (!linuxSecretAvailable()) return false;
|
|
3673
3709
|
try {
|
|
3674
|
-
|
|
3710
|
+
execSync3(
|
|
3675
3711
|
`echo -n "${value}" | secret-tool store --label="exe-os master key" service "${service}" account "${ACCOUNT}" 2>/dev/null`,
|
|
3676
3712
|
{ timeout: 5e3 }
|
|
3677
3713
|
);
|
|
@@ -3684,7 +3720,7 @@ function linuxSecretDelete(service = SERVICE) {
|
|
|
3684
3720
|
if (!nativeKeychainAllowed()) return false;
|
|
3685
3721
|
if (process.platform !== "linux") return false;
|
|
3686
3722
|
try {
|
|
3687
|
-
|
|
3723
|
+
execSync3(
|
|
3688
3724
|
`secret-tool clear service "${service}" account "${ACCOUNT}" 2>/dev/null`,
|
|
3689
3725
|
{ timeout: 5e3 }
|
|
3690
3726
|
);
|
|
@@ -4166,7 +4202,7 @@ function addToCrontab(id, cron, prompt, projectDir) {
|
|
|
4166
4202
|
const cwd = projectDir ? `cd ${JSON.stringify(projectDir)} && ` : "";
|
|
4167
4203
|
const escapedPrompt = prompt.replace(/"/g, '\\"');
|
|
4168
4204
|
const entry = `${cron} ${cwd}claude -p --dangerously-skip-permissions "${escapedPrompt}" # exe-schedule:${id}`;
|
|
4169
|
-
|
|
4205
|
+
execSync4(
|
|
4170
4206
|
`(crontab -l 2>/dev/null; echo ${JSON.stringify(entry)}) | crontab -`,
|
|
4171
4207
|
{ timeout: 5e3, stdio: "ignore" }
|
|
4172
4208
|
);
|
|
@@ -4177,7 +4213,7 @@ function addToCrontab(id, cron, prompt, projectDir) {
|
|
|
4177
4213
|
function removeFromCrontab(id) {
|
|
4178
4214
|
if (!isValidScheduleId(id)) return;
|
|
4179
4215
|
try {
|
|
4180
|
-
|
|
4216
|
+
execSync4(
|
|
4181
4217
|
`crontab -l 2>/dev/null | grep -v "exe-schedule:${id}" | crontab -`,
|
|
4182
4218
|
{ timeout: 5e3, stdio: "ignore" }
|
|
4183
4219
|
);
|
|
@@ -368,7 +368,7 @@ var init_daemon_auth = __esm({
|
|
|
368
368
|
// src/lib/exe-daemon-client.ts
|
|
369
369
|
import net from "net";
|
|
370
370
|
import os4 from "os";
|
|
371
|
-
import { spawn } from "child_process";
|
|
371
|
+
import { spawn, execSync as execSync2 } from "child_process";
|
|
372
372
|
import { randomUUID } from "crypto";
|
|
373
373
|
import { existsSync as existsSync5, unlinkSync as unlinkSync2, readFileSync as readFileSync4, openSync, closeSync, statSync } from "fs";
|
|
374
374
|
import path5 from "path";
|
|
@@ -398,6 +398,14 @@ function handleData(chunk) {
|
|
|
398
398
|
}
|
|
399
399
|
}
|
|
400
400
|
}
|
|
401
|
+
function isZombie(pid) {
|
|
402
|
+
try {
|
|
403
|
+
const state = execSync2(`ps -p ${pid} -o state=`, { encoding: "utf8", timeout: 2e3 }).trim();
|
|
404
|
+
return state.startsWith("Z");
|
|
405
|
+
} catch {
|
|
406
|
+
return false;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
401
409
|
function cleanupStaleFiles() {
|
|
402
410
|
if (existsSync5(PID_PATH)) {
|
|
403
411
|
try {
|
|
@@ -405,7 +413,11 @@ function cleanupStaleFiles() {
|
|
|
405
413
|
if (pid > 0) {
|
|
406
414
|
try {
|
|
407
415
|
process.kill(pid, 0);
|
|
408
|
-
|
|
416
|
+
if (!isZombie(pid)) {
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
process.stderr.write(`[exed-client] PID ${pid} is a zombie \u2014 cleaning up stale files
|
|
420
|
+
`);
|
|
409
421
|
} catch {
|
|
410
422
|
}
|
|
411
423
|
}
|
|
@@ -433,8 +445,8 @@ function findPackageRoot() {
|
|
|
433
445
|
function getAvailableMemoryGB() {
|
|
434
446
|
if (process.platform === "darwin") {
|
|
435
447
|
try {
|
|
436
|
-
const { execSync:
|
|
437
|
-
const vmstat =
|
|
448
|
+
const { execSync: execSync3 } = __require("child_process");
|
|
449
|
+
const vmstat = execSync3("vm_stat", { encoding: "utf8" });
|
|
438
450
|
const pageSize = 16384;
|
|
439
451
|
const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
|
|
440
452
|
const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
|