agentlife 2.6.28 → 2.6.31
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 +815 -272
- package/package.json +16 -6
- package/web-build/6e23e5428398b92da386.wasm +0 -0
- package/web-build/auth-callback.html +40 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_action_plan.xml +10 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_add.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_alarm.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_amazon.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_apple.xml +12 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_arrow_clockwise.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_arrow_counter_clockwise.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_arrow_down_up.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_arrow_right.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_arrow_square_out.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_arrows_out.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_audible.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_auto_send.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_back.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_barcode.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_bell.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_bell_ringing.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_binoculars.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_brain.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_bulb.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_calendar.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_calendar_blank.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_calendar_check.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_calendar_dots.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_caret_double_down.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_caret_double_up.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_caret_down.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_caret_right.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_caret_up.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_chat.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_chat_circle.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_chat_circle_text.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_chat_teardrop.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_check_simple.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_child.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_clock_counter_clockwise.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_clock_simple.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_close.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_comment.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_community.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_copy_simple.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_credit_card.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_decision_framework.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_diff.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_dots_three.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_edit.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_experiment.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_facebook.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_faders.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_file_dotted.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_file_text.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_filter.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_flask.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_floppy_disk.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_folder_open.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_folder_simple.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_git_merge.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_google.xml +35 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_google_play.xml +22 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_habit_tracker.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_heading_1.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_heading_2.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_heading_3.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_heading_4.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_hide_pass.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_info_simple.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_instagram.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_keyboard.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_lightning.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_linkedin.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_lock.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_logo.xml +12 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_map_pin_simple.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_media.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_menu.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_microphone_simple.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_more_vert.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_paint_bucket.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_paper_plane_right.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_paperclip.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_parent.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_pause_simple.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_play_simple.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_plus_circle.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_push_pin.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_push_pin_slash.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_question.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_record.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_rocket.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_scales.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_search.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_settings.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_share_network.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_show_pass.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_sign_out.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_smiley.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_sparkles.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_sparks.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_speaker_high.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_spotify.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_star.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_stop_circle.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_stop_simple.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_swap.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_tag_simple.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_thumbs_down.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_thumbs_up.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_tiktok.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_timer_complete.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_timer_simple.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_translate.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_trash_simple.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_tree_structure.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_twitch.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_upload.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_user_circle.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_warning.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_web.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_wrench.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_x.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_x_circle.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_youtube.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/ic_youtube_music.xml +9 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/drawable/tenazitas_logo.xml +27 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/font/Caveat-Medium.ttf +0 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/font/Geist-Medium.ttf +0 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/font/Geist-Regular.ttf +0 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/font/Geist-SemiBold.ttf +0 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/font/JetBrainsMono-Medium.ttf +0 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/font/JetBrainsMono-Regular.ttf +0 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/font/SourceSerif4-Italic.ttf +0 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/font/SourceSerif4-Regular.ttf +0 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/font/SourceSerif4-SemiBold.ttf +0 -0
- package/web-build/composeResources/org.acv.agentlife.composeapp.generated.resources/values/strings.commonMain.cvr +2787 -0
- package/web-build/f722462c344efeb18c2f.wasm +0 -0
- package/web-build/index.html +23 -0
- package/web-build/webApp.js +3 -0
- package/web-build/webApp.js.LICENSE.txt +35 -0
- package/web-build/webApp.js.map +1 -0
package/dist/index.js
CHANGED
|
@@ -2,9 +2,9 @@ import { createRequire } from "node:module";
|
|
|
2
2
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
3
3
|
|
|
4
4
|
// index.ts
|
|
5
|
-
import { homedir as
|
|
6
|
-
import * as
|
|
7
|
-
import { existsSync as
|
|
5
|
+
import { homedir as homedir17 } from "node:os";
|
|
6
|
+
import * as path20 from "node:path";
|
|
7
|
+
import { existsSync as existsSync8 } from "node:fs";
|
|
8
8
|
|
|
9
9
|
// db.ts
|
|
10
10
|
import * as fsSync from "node:fs";
|
|
@@ -988,7 +988,7 @@ If you produce a followup whose residue (digits and parameter values stripped) m
|
|
|
988
988
|
|
|
989
989
|
### Guided mode — input surfaces
|
|
990
990
|
|
|
991
|
-
When you need structured input, push a surface with \`input\` in the header. It renders in the input bar, not on the dashboard. Structure: \`surface <id> input\` → \`card\` → \`column\` → h3 question + 2+ buttons
|
|
991
|
+
When you need structured input, push a surface with \`input\` in the header. It renders in the input bar, not on the dashboard. Structure: \`surface <id> input\` → \`card\` → \`column\` → h3 question + 2+ buttons.
|
|
992
992
|
|
|
993
993
|
**Flow:**
|
|
994
994
|
1. User clicks a button on a widget → \`[action:*]\`.
|
|
@@ -1581,6 +1581,82 @@ ${userSection}`;
|
|
|
1581
1581
|
}
|
|
1582
1582
|
|
|
1583
1583
|
// provisioning.ts
|
|
1584
|
+
function providerFromModel(model) {
|
|
1585
|
+
const slash = model.indexOf("/");
|
|
1586
|
+
if (slash <= 0)
|
|
1587
|
+
return null;
|
|
1588
|
+
return model.slice(0, slash).trim() || null;
|
|
1589
|
+
}
|
|
1590
|
+
function configuredProvidersFromConfig(cfg) {
|
|
1591
|
+
const profiles = cfg?.auth?.profiles;
|
|
1592
|
+
if (!profiles || typeof profiles !== "object")
|
|
1593
|
+
return [];
|
|
1594
|
+
const out = [];
|
|
1595
|
+
for (const entry of Object.values(profiles)) {
|
|
1596
|
+
const provider = entry?.provider;
|
|
1597
|
+
if (typeof provider === "string" && provider.trim() && !out.includes(provider.trim())) {
|
|
1598
|
+
out.push(provider.trim());
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
return out;
|
|
1602
|
+
}
|
|
1603
|
+
function hasGatewayDefaultModel(cfg) {
|
|
1604
|
+
const modelCfg = cfg?.agents?.defaults?.model;
|
|
1605
|
+
if (!modelCfg || typeof modelCfg !== "object")
|
|
1606
|
+
return false;
|
|
1607
|
+
if (typeof modelCfg.primary === "string" && modelCfg.primary.trim())
|
|
1608
|
+
return true;
|
|
1609
|
+
return Array.isArray(modelCfg.fallbacks) && modelCfg.fallbacks.some((m) => typeof m === "string" && m.trim());
|
|
1610
|
+
}
|
|
1611
|
+
function parseJsonArrayFromStdout(stdout) {
|
|
1612
|
+
const raw = stdout.trim();
|
|
1613
|
+
const jsonStart = raw.indexOf("[");
|
|
1614
|
+
if (jsonStart < 0)
|
|
1615
|
+
return [];
|
|
1616
|
+
try {
|
|
1617
|
+
const parsed = JSON.parse(raw.slice(jsonStart));
|
|
1618
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
1619
|
+
} catch {
|
|
1620
|
+
return [];
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
async function resolveProvisionedAgentModel(cfg, currentList, runtime, log) {
|
|
1624
|
+
if (hasGatewayDefaultModel(cfg))
|
|
1625
|
+
return null;
|
|
1626
|
+
const configuredProviders = configuredProvidersFromConfig(cfg);
|
|
1627
|
+
if (configuredProviders.length === 0)
|
|
1628
|
+
return null;
|
|
1629
|
+
const configured = new Set(configuredProviders);
|
|
1630
|
+
const provisionedIds = new Set(PROVISIONED_AGENTS.map((a) => a.id));
|
|
1631
|
+
for (const agent of currentList) {
|
|
1632
|
+
if (!agent || provisionedIds.has(agent.id))
|
|
1633
|
+
continue;
|
|
1634
|
+
const model = typeof agent.model === "string" ? agent.model.trim() : "";
|
|
1635
|
+
const provider = model ? providerFromModel(model) : null;
|
|
1636
|
+
if (model && provider && configured.has(provider)) {
|
|
1637
|
+
return model;
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
const run = runtime.system?.runCommandWithTimeout;
|
|
1641
|
+
if (!run)
|
|
1642
|
+
return null;
|
|
1643
|
+
try {
|
|
1644
|
+
const result = await run(["openclaw", "infer", "model", "providers", "--json"], { timeoutMs: 60000 });
|
|
1645
|
+
if ((result?.code ?? 0) !== 0)
|
|
1646
|
+
return null;
|
|
1647
|
+
const catalog = parseJsonArrayFromStdout(result?.stdout ?? "");
|
|
1648
|
+
for (const provider of configuredProviders) {
|
|
1649
|
+
const entry = catalog.find((p) => p?.provider === provider);
|
|
1650
|
+
const defaults = Array.isArray(entry?.defaults) ? entry.defaults : [];
|
|
1651
|
+
const firstDefault = defaults.find((m) => typeof m === "string" && m.trim());
|
|
1652
|
+
if (firstDefault)
|
|
1653
|
+
return `${provider}/${firstDefault.trim()}`;
|
|
1654
|
+
}
|
|
1655
|
+
} catch (err) {
|
|
1656
|
+
log(`[agentlife] provisioned agent model discovery skipped: ${err?.message ?? err}`);
|
|
1657
|
+
}
|
|
1658
|
+
return null;
|
|
1659
|
+
}
|
|
1584
1660
|
var PROVISIONED_AGENTS = [
|
|
1585
1661
|
{
|
|
1586
1662
|
id: "agentlife",
|
|
@@ -1671,6 +1747,7 @@ function scheduleEnrichment(state, runtime, targets, log) {
|
|
|
1671
1747
|
async function provisionAgents(state, cfg, runtime, log) {
|
|
1672
1748
|
const home = os.homedir();
|
|
1673
1749
|
const currentList = [...cfg.agents?.list ?? []];
|
|
1750
|
+
const provisionedModel = await resolveProvisionedAgentModel(cfg, currentList, runtime, log);
|
|
1674
1751
|
let configChanged = false;
|
|
1675
1752
|
const newlyProvisioned = [];
|
|
1676
1753
|
for (const agent of PROVISIONED_AGENTS) {
|
|
@@ -1710,12 +1787,15 @@ async function provisionAgents(state, cfg, runtime, log) {
|
|
|
1710
1787
|
name: agent.name,
|
|
1711
1788
|
workspace: workspaceDir
|
|
1712
1789
|
};
|
|
1713
|
-
|
|
1790
|
+
const userOwnsDefault = currentList.some((a) => a?.default === true);
|
|
1791
|
+
if (agent.isDefault && !userOwnsDefault)
|
|
1714
1792
|
entry.default = true;
|
|
1715
1793
|
if (agent.subagents)
|
|
1716
1794
|
entry.subagents = agent.subagents;
|
|
1717
1795
|
if (agent.tools)
|
|
1718
1796
|
entry.tools = agent.tools;
|
|
1797
|
+
if (provisionedModel)
|
|
1798
|
+
entry.model = provisionedModel;
|
|
1719
1799
|
if (agent.isDefault) {
|
|
1720
1800
|
currentList.unshift(entry);
|
|
1721
1801
|
} else {
|
|
@@ -1741,6 +1821,19 @@ async function provisionAgents(state, cfg, runtime, log) {
|
|
|
1741
1821
|
configChanged = true;
|
|
1742
1822
|
log(`[agentlife] added subagents for ${agent.id}`);
|
|
1743
1823
|
}
|
|
1824
|
+
if (provisionedModel && !existing.model) {
|
|
1825
|
+
existing.model = provisionedModel;
|
|
1826
|
+
configChanged = true;
|
|
1827
|
+
log(`[agentlife] set model for ${agent.id}: ${provisionedModel}`);
|
|
1828
|
+
}
|
|
1829
|
+
if (agent.isDefault && existing.default === true) {
|
|
1830
|
+
const userOwnsDefault = currentList.some((a) => a?.id !== agent.id && a?.default === true);
|
|
1831
|
+
if (userOwnsDefault) {
|
|
1832
|
+
delete existing.default;
|
|
1833
|
+
configChanged = true;
|
|
1834
|
+
log(`[agentlife] surrendered default to user agent (was ${agent.id})`);
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1744
1837
|
}
|
|
1745
1838
|
}
|
|
1746
1839
|
}
|
|
@@ -2085,7 +2178,6 @@ var KNOWN_BODY_KEYWORDS = new Set([
|
|
|
2085
2178
|
"button",
|
|
2086
2179
|
"image",
|
|
2087
2180
|
"icon",
|
|
2088
|
-
"textfield",
|
|
2089
2181
|
"checkbox",
|
|
2090
2182
|
"sparkline",
|
|
2091
2183
|
"progress",
|
|
@@ -2117,7 +2209,6 @@ var INPUT_SURFACE_ACTIONS = new Set([
|
|
|
2117
2209
|
var TEXT_LEVELS = new Set(["h1", "h2", "h3", "h4", "h5", "body", "caption"]);
|
|
2118
2210
|
var TEXT_HINTS = new Set(["icon", "avatar", "smallfeature", "mediumfeature", "largefeature", "header"]);
|
|
2119
2211
|
var IMG_FITS = new Set(["contain", "cover", "fill", "none", "scale-down"]);
|
|
2120
|
-
var TF_TYPES = new Set(["email", "shorttext", "number", "phone", "longtext", "date", "obscured"]);
|
|
2121
2212
|
var ALIGN_VALUES = new Set(["start", "center", "end", "stretch"]);
|
|
2122
2213
|
var DISTRIBUTE_VALUES = new Set(["start", "center", "end", "spacebetween", "spacearound", "spaceevenly"]);
|
|
2123
2214
|
var TREND_VALUES = new Set(["up", "down", "flat"]);
|
|
@@ -2172,14 +2263,6 @@ var COMPONENT_CATALOG = {
|
|
|
2172
2263
|
}
|
|
2173
2264
|
},
|
|
2174
2265
|
icon: { positionalTokens: new Set, positionalFree: true, attrs: {} },
|
|
2175
|
-
textfield: {
|
|
2176
|
-
positionalTokens: new Set,
|
|
2177
|
-
positionalFree: true,
|
|
2178
|
-
attrs: {
|
|
2179
|
-
type: { kind: "enum", values: TF_TYPES },
|
|
2180
|
-
placeholder: { kind: "free" }
|
|
2181
|
-
}
|
|
2182
|
-
},
|
|
2183
2266
|
checkbox: {
|
|
2184
2267
|
positionalTokens: new Set(["checked"]),
|
|
2185
2268
|
positionalFree: true,
|
|
@@ -3473,9 +3556,9 @@ Each turn:
|
|
|
3473
3556
|
2. Not enough → \`agentlife_push\` the SAME surfaceId \`welcome-input\` with:
|
|
3474
3557
|
- h3 question generated from what the user just said
|
|
3475
3558
|
- 2–4 multichoice buttons \`action=choice\`, options derived from the user's own words (NEVER hardcoded domain lists)
|
|
3476
|
-
- \`textfield placeholder="Something else…"\` escape hatch
|
|
3477
3559
|
- updated \`context: {"phase":"welcome","turn":N+1,"answers":[...]}\`
|
|
3478
3560
|
- goal + followup unchanged
|
|
3561
|
+
The input bar's text field is always-on, so the user can also type free text instead of picking a button — handle either response.
|
|
3479
3562
|
Respond \`done\`.
|
|
3480
3563
|
3. Enough → create the generalist and hand off the dashboard:
|
|
3481
3564
|
- Workspace under \`$HOME/.openclaw/workspace-{id}\` (id = slugified short name or "me")
|
|
@@ -3505,7 +3588,6 @@ function renderWelcomeWidget(state, log) {
|
|
|
3505
3588
|
` column`,
|
|
3506
3589
|
` text "What do you want to track or improve?" h3`,
|
|
3507
3590
|
` text "One line. Anything — meals, money, a project, a habit." body`,
|
|
3508
|
-
` textfield placeholder="Type anything…"`,
|
|
3509
3591
|
`goal: Onboard the user to their first agent via a guided interview`,
|
|
3510
3592
|
`followup: +30m "If unanswered, replace the question with a gentler prompt."`,
|
|
3511
3593
|
`context: {"phase":"welcome","turn":1,"answers":[]}`
|
|
@@ -3533,7 +3615,7 @@ function deleteWelcomeWidget(state, log) {
|
|
|
3533
3615
|
}
|
|
3534
3616
|
|
|
3535
3617
|
// services/surfaces-init.ts
|
|
3536
|
-
import * as
|
|
3618
|
+
import * as path6 from "node:path";
|
|
3537
3619
|
|
|
3538
3620
|
// storage/reconciler.ts
|
|
3539
3621
|
var defaultLogger = {
|
|
@@ -3781,23 +3863,45 @@ function dispatchRehydrate(state, runtime, log = console.log) {
|
|
|
3781
3863
|
log(`[agentlife:rehydrate] dispatched rehydrate to ${orphaned.length} orphaned agent(s): ${orphaned.join(", ")}`);
|
|
3782
3864
|
}
|
|
3783
3865
|
|
|
3866
|
+
// runtime-mode.ts
|
|
3867
|
+
import * as path5 from "node:path";
|
|
3868
|
+
function isPluginInstallOrInspectProcess() {
|
|
3869
|
+
const argv = process.argv.join(" ");
|
|
3870
|
+
const entrypoint = path5.basename(process.argv[1] || "");
|
|
3871
|
+
return entrypoint.includes("openclaw-plugins") || argv.includes("plugins") && argv.includes("install") || argv.includes("plugins") && argv.includes("inspect");
|
|
3872
|
+
}
|
|
3873
|
+
function shouldStartRuntimeServices() {
|
|
3874
|
+
return !isPluginInstallOrInspectProcess();
|
|
3875
|
+
}
|
|
3876
|
+
|
|
3784
3877
|
// services/surfaces-init.ts
|
|
3785
3878
|
function registerSurfacesService(api, state) {
|
|
3786
3879
|
api.registerService({
|
|
3787
3880
|
id: "agentlife-surfaces",
|
|
3788
3881
|
start: async (ctx) => {
|
|
3789
|
-
|
|
3882
|
+
if (!shouldStartRuntimeServices())
|
|
3883
|
+
return;
|
|
3884
|
+
const agentlifeDir = path6.join(ctx.stateDir, "agentlife");
|
|
3885
|
+
const nextHistoryDbPath = path6.join(agentlifeDir, "agentlife.db");
|
|
3886
|
+
const previousHistoryDbPath = state.historyDbPath;
|
|
3887
|
+
if (state.historyDb && previousHistoryDbPath && previousHistoryDbPath !== nextHistoryDbPath) {
|
|
3888
|
+
try {
|
|
3889
|
+
state.historyDb.close();
|
|
3890
|
+
} catch {}
|
|
3891
|
+
state.historyDb = null;
|
|
3892
|
+
state.surfaceIndex = null;
|
|
3893
|
+
state.followupQueue = null;
|
|
3894
|
+
}
|
|
3790
3895
|
state.agentlifeStateDir = agentlifeDir;
|
|
3791
|
-
state.registryFilePath =
|
|
3792
|
-
state.dbBaseDir =
|
|
3793
|
-
state.historyDbPath =
|
|
3896
|
+
state.registryFilePath = path6.join(agentlifeDir, "agent-registry.json");
|
|
3897
|
+
state.dbBaseDir = path6.join(agentlifeDir, "db");
|
|
3898
|
+
state.historyDbPath = nextHistoryDbPath;
|
|
3794
3899
|
const db = getOrCreateHistoryDb(state);
|
|
3795
3900
|
if (!state.surfaceIndex)
|
|
3796
3901
|
state.surfaceIndex = new SurfaceIndex(db);
|
|
3797
3902
|
if (!state.followupQueue)
|
|
3798
3903
|
state.followupQueue = new FollowupQueue(db);
|
|
3799
|
-
|
|
3800
|
-
state.fileSurfaceStorage = new FileSurfaceStorage;
|
|
3904
|
+
state.fileSurfaceStorage = new FileSurfaceStorage({ openclawRoot: ctx.stateDir });
|
|
3801
3905
|
await loadRegistryFromDisk(state);
|
|
3802
3906
|
try {
|
|
3803
3907
|
const knownAgents = collectKnownAgents(api.runtime);
|
|
@@ -3847,11 +3951,11 @@ function collectKnownAgents(runtime) {
|
|
|
3847
3951
|
|
|
3848
3952
|
// services/config-optimizer.ts
|
|
3849
3953
|
import * as fs5 from "node:fs/promises";
|
|
3850
|
-
import * as
|
|
3954
|
+
import * as path7 from "node:path";
|
|
3851
3955
|
import * as os2 from "node:os";
|
|
3852
3956
|
var TARGET_MAX_PING_PONG = 1;
|
|
3853
3957
|
var TARGET_MAX_CONCURRENT = 10;
|
|
3854
|
-
var CONFIG_PATH =
|
|
3958
|
+
var CONFIG_PATH = process.env.OPENCLAW_CONFIG_PATH || path7.join(os2.homedir(), ".openclaw", "openclaw.json");
|
|
3855
3959
|
async function readRawConfigFromDisk() {
|
|
3856
3960
|
const raw = await fs5.readFile(CONFIG_PATH, "utf-8");
|
|
3857
3961
|
return JSON.parse(raw);
|
|
@@ -3887,8 +3991,10 @@ function registerConfigOptimizer(api, _state) {
|
|
|
3887
3991
|
api.registerService({
|
|
3888
3992
|
id: "agentlife-config-optimizer",
|
|
3889
3993
|
start: async (ctx) => {
|
|
3890
|
-
|
|
3891
|
-
|
|
3994
|
+
if (!shouldStartRuntimeServices())
|
|
3995
|
+
return;
|
|
3996
|
+
const configBackupDir = path7.join(ctx.stateDir, "agentlife");
|
|
3997
|
+
const configBackupPath = path7.join(configBackupDir, "config-backup.json");
|
|
3892
3998
|
const cfg = api.runtime.config.loadConfig();
|
|
3893
3999
|
const currentPPT = cfg.session?.agentToAgent?.maxPingPongTurns;
|
|
3894
4000
|
const currentMC = cfg.agents?.defaults?.maxConcurrent;
|
|
@@ -3899,10 +4005,16 @@ function registerConfigOptimizer(api, _state) {
|
|
|
3899
4005
|
return;
|
|
3900
4006
|
}
|
|
3901
4007
|
await fs5.mkdir(configBackupDir, { recursive: true });
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
}
|
|
4008
|
+
let existing = {};
|
|
4009
|
+
try {
|
|
4010
|
+
existing = JSON.parse(await fs5.readFile(configBackupPath, "utf-8"));
|
|
4011
|
+
} catch {}
|
|
4012
|
+
if (!("maxPingPongTurns" in existing))
|
|
4013
|
+
existing.maxPingPongTurns = currentPPT ?? null;
|
|
4014
|
+
if (!("maxConcurrent" in existing))
|
|
4015
|
+
existing.maxConcurrent = currentMC ?? null;
|
|
4016
|
+
await fs5.writeFile(configBackupPath, JSON.stringify(existing, null, 2) + `
|
|
4017
|
+
`);
|
|
3906
4018
|
const fileCfg = await readRawConfigFromDisk();
|
|
3907
4019
|
if (needsPPT) {
|
|
3908
4020
|
fileCfg.session ??= {};
|
|
@@ -3924,13 +4036,196 @@ function registerConfigOptimizer(api, _state) {
|
|
|
3924
4036
|
},
|
|
3925
4037
|
stop: async (ctx) => {
|
|
3926
4038
|
try {
|
|
3927
|
-
const backupPath =
|
|
4039
|
+
const backupPath = path7.join(ctx.stateDir, "agentlife", "config-backup.json");
|
|
3928
4040
|
await restoreConfigFromBackup(api, backupPath);
|
|
3929
4041
|
} catch {}
|
|
3930
4042
|
}
|
|
3931
4043
|
});
|
|
3932
4044
|
}
|
|
3933
4045
|
|
|
4046
|
+
// services/install-bootstrap.ts
|
|
4047
|
+
import * as fs6 from "node:fs";
|
|
4048
|
+
import * as path8 from "node:path";
|
|
4049
|
+
import * as os3 from "node:os";
|
|
4050
|
+
import { upsertAuthProfile } from "openclaw/plugin-sdk/provider-auth";
|
|
4051
|
+
function resolvePaths(home) {
|
|
4052
|
+
const openclawDir = home ? path8.join(home, ".openclaw") : process.env.OPENCLAW_STATE_DIR || path8.join(os3.homedir(), ".openclaw");
|
|
4053
|
+
const configPath = home ? path8.join(openclawDir, "openclaw.json") : process.env.OPENCLAW_CONFIG_PATH || path8.join(openclawDir, "openclaw.json");
|
|
4054
|
+
const agentlifeDir = path8.join(openclawDir, "agentlife");
|
|
4055
|
+
return {
|
|
4056
|
+
configPath,
|
|
4057
|
+
gatewayTokenFile: path8.join(openclawDir, "gateway-token.txt"),
|
|
4058
|
+
agentlifeDir,
|
|
4059
|
+
configBackupPath: path8.join(agentlifeDir, "config-backup.json"),
|
|
4060
|
+
pairRequestMarker: path8.join(agentlifeDir, "pair-requested")
|
|
4061
|
+
};
|
|
4062
|
+
}
|
|
4063
|
+
function readJsonSafe(p) {
|
|
4064
|
+
try {
|
|
4065
|
+
return JSON.parse(fs6.readFileSync(p, "utf-8"));
|
|
4066
|
+
} catch {
|
|
4067
|
+
return null;
|
|
4068
|
+
}
|
|
4069
|
+
}
|
|
4070
|
+
function writeJson(p, obj) {
|
|
4071
|
+
fs6.writeFileSync(p, JSON.stringify(obj, null, 2) + `
|
|
4072
|
+
`, "utf-8");
|
|
4073
|
+
}
|
|
4074
|
+
function normalizeLegacyCredential(profile) {
|
|
4075
|
+
if (!profile || typeof profile !== "object")
|
|
4076
|
+
return null;
|
|
4077
|
+
if (typeof profile.provider !== "string" || !profile.provider.trim())
|
|
4078
|
+
return null;
|
|
4079
|
+
const credential = { ...profile };
|
|
4080
|
+
if (credential.type === "api_key" && typeof credential.key !== "string" && typeof credential.apiKey === "string") {
|
|
4081
|
+
credential.key = credential.apiKey;
|
|
4082
|
+
delete credential.apiKey;
|
|
4083
|
+
}
|
|
4084
|
+
return credential;
|
|
4085
|
+
}
|
|
4086
|
+
function migrateLegacyAuthProfiles(openclawDir) {
|
|
4087
|
+
const agentsRoot = path8.join(openclawDir, "agents");
|
|
4088
|
+
let entries;
|
|
4089
|
+
try {
|
|
4090
|
+
entries = fs6.readdirSync(agentsRoot, { withFileTypes: true });
|
|
4091
|
+
} catch {
|
|
4092
|
+
return;
|
|
4093
|
+
}
|
|
4094
|
+
let migrated = 0;
|
|
4095
|
+
for (const entry of entries) {
|
|
4096
|
+
if (!entry.isDirectory() && !entry.isSymbolicLink())
|
|
4097
|
+
continue;
|
|
4098
|
+
const agentDir = path8.join(agentsRoot, entry.name, "agent");
|
|
4099
|
+
const legacyPath = path8.join(agentDir, "auth-profiles.json");
|
|
4100
|
+
const legacy = readJsonSafe(legacyPath);
|
|
4101
|
+
const profiles = legacy?.profiles;
|
|
4102
|
+
if (!profiles || typeof profiles !== "object")
|
|
4103
|
+
continue;
|
|
4104
|
+
for (const [profileId, profile] of Object.entries(profiles)) {
|
|
4105
|
+
const credential = normalizeLegacyCredential(profile);
|
|
4106
|
+
if (!credential)
|
|
4107
|
+
continue;
|
|
4108
|
+
try {
|
|
4109
|
+
upsertAuthProfile({ profileId, credential, agentDir });
|
|
4110
|
+
migrated += 1;
|
|
4111
|
+
} catch (err) {
|
|
4112
|
+
console.warn(`[agentlife] install-bootstrap: auth profile migration skipped for ${entry.name}/${profileId}: ${err?.message ?? err}`);
|
|
4113
|
+
}
|
|
4114
|
+
}
|
|
4115
|
+
}
|
|
4116
|
+
if (migrated > 0) {
|
|
4117
|
+
console.log(`[agentlife] install-bootstrap: migrated ${migrated} legacy auth profile(s) into OpenClaw auth store`);
|
|
4118
|
+
}
|
|
4119
|
+
}
|
|
4120
|
+
function runInstallBootstrap(home) {
|
|
4121
|
+
const P = resolvePaths(home);
|
|
4122
|
+
try {
|
|
4123
|
+
fs6.mkdirSync(P.agentlifeDir, { recursive: true, mode: 448 });
|
|
4124
|
+
} catch (err) {
|
|
4125
|
+
console.warn(`[agentlife] install-bootstrap: cannot create ${P.agentlifeDir}: ${err?.message ?? err}`);
|
|
4126
|
+
return;
|
|
4127
|
+
}
|
|
4128
|
+
try {
|
|
4129
|
+
fs6.writeFileSync(P.pairRequestMarker, String(Date.now()), { mode: 384 });
|
|
4130
|
+
} catch (err) {
|
|
4131
|
+
console.warn(`[agentlife] install-bootstrap: cannot write pair-requested marker: ${err?.message ?? err}`);
|
|
4132
|
+
}
|
|
4133
|
+
migrateLegacyAuthProfiles(path8.dirname(P.gatewayTokenFile));
|
|
4134
|
+
if (!fs6.existsSync(P.configPath)) {
|
|
4135
|
+
console.log("[agentlife] install-bootstrap: gateway config missing — deferring config writes");
|
|
4136
|
+
return;
|
|
4137
|
+
}
|
|
4138
|
+
const cfg = readJsonSafe(P.configPath);
|
|
4139
|
+
if (!cfg || typeof cfg !== "object") {
|
|
4140
|
+
console.warn(`[agentlife] install-bootstrap: cannot parse ${P.configPath} — skipping config writes`);
|
|
4141
|
+
return;
|
|
4142
|
+
}
|
|
4143
|
+
const existingBackup = readJsonSafe(P.configBackupPath) ?? {};
|
|
4144
|
+
const originals = [
|
|
4145
|
+
["sessionsVisibility", cfg?.tools?.sessions?.visibility ?? null],
|
|
4146
|
+
["agentToAgentEnabled", cfg?.tools?.agentToAgent?.enabled ?? null],
|
|
4147
|
+
["gatewayBind", cfg?.gateway?.bind ?? null],
|
|
4148
|
+
["hooksAllowConversationAccess", cfg?.plugins?.entries?.agentlife?.hooks?.allowConversationAccess ?? null],
|
|
4149
|
+
["maxPingPongTurns", cfg?.session?.agentToAgent?.maxPingPongTurns ?? null],
|
|
4150
|
+
["maxConcurrent", cfg?.agents?.defaults?.maxConcurrent ?? null]
|
|
4151
|
+
];
|
|
4152
|
+
let backupChanged = false;
|
|
4153
|
+
for (const [k, orig] of originals) {
|
|
4154
|
+
if (!(k in existingBackup)) {
|
|
4155
|
+
existingBackup[k] = orig;
|
|
4156
|
+
backupChanged = true;
|
|
4157
|
+
}
|
|
4158
|
+
}
|
|
4159
|
+
if (backupChanged) {
|
|
4160
|
+
try {
|
|
4161
|
+
writeJson(P.configBackupPath, existingBackup);
|
|
4162
|
+
} catch (err) {
|
|
4163
|
+
console.warn(`[agentlife] install-bootstrap: cannot write backup: ${err?.message ?? err}`);
|
|
4164
|
+
}
|
|
4165
|
+
}
|
|
4166
|
+
let changed = false;
|
|
4167
|
+
cfg.gateway ??= {};
|
|
4168
|
+
if (cfg.gateway.bind !== "lan") {
|
|
4169
|
+
cfg.gateway.bind = "lan";
|
|
4170
|
+
changed = true;
|
|
4171
|
+
}
|
|
4172
|
+
cfg.gateway.auth ??= {};
|
|
4173
|
+
if (!cfg.gateway.auth.token && fs6.existsSync(P.gatewayTokenFile)) {
|
|
4174
|
+
try {
|
|
4175
|
+
const tok = fs6.readFileSync(P.gatewayTokenFile, "utf-8").trim();
|
|
4176
|
+
if (tok) {
|
|
4177
|
+
cfg.gateway.auth.token = tok;
|
|
4178
|
+
changed = true;
|
|
4179
|
+
console.log(`[agentlife] install-bootstrap: imported gateway token from ${P.gatewayTokenFile}`);
|
|
4180
|
+
}
|
|
4181
|
+
} catch (err) {
|
|
4182
|
+
console.warn(`[agentlife] install-bootstrap: cannot read ${P.gatewayTokenFile}: ${err?.message ?? err}`);
|
|
4183
|
+
}
|
|
4184
|
+
}
|
|
4185
|
+
cfg.tools ??= {};
|
|
4186
|
+
cfg.tools.sessions ??= {};
|
|
4187
|
+
if (cfg.tools.sessions.visibility !== "all") {
|
|
4188
|
+
cfg.tools.sessions.visibility = "all";
|
|
4189
|
+
changed = true;
|
|
4190
|
+
}
|
|
4191
|
+
cfg.tools.agentToAgent ??= {};
|
|
4192
|
+
if (cfg.tools.agentToAgent.enabled !== true) {
|
|
4193
|
+
cfg.tools.agentToAgent.enabled = true;
|
|
4194
|
+
changed = true;
|
|
4195
|
+
}
|
|
4196
|
+
cfg.plugins ??= {};
|
|
4197
|
+
cfg.plugins.entries ??= {};
|
|
4198
|
+
cfg.plugins.entries.agentlife ??= {};
|
|
4199
|
+
cfg.plugins.entries.agentlife.hooks ??= {};
|
|
4200
|
+
if (cfg.plugins.entries.agentlife.hooks.allowConversationAccess !== true) {
|
|
4201
|
+
cfg.plugins.entries.agentlife.hooks.allowConversationAccess = true;
|
|
4202
|
+
changed = true;
|
|
4203
|
+
}
|
|
4204
|
+
cfg.session ??= {};
|
|
4205
|
+
cfg.session.agentToAgent ??= {};
|
|
4206
|
+
if (cfg.session.agentToAgent.maxPingPongTurns !== 1) {
|
|
4207
|
+
cfg.session.agentToAgent.maxPingPongTurns = 1;
|
|
4208
|
+
changed = true;
|
|
4209
|
+
}
|
|
4210
|
+
cfg.agents ??= {};
|
|
4211
|
+
cfg.agents.defaults ??= {};
|
|
4212
|
+
if (!cfg.agents.defaults.maxConcurrent || cfg.agents.defaults.maxConcurrent < 10) {
|
|
4213
|
+
cfg.agents.defaults.maxConcurrent = 10;
|
|
4214
|
+
changed = true;
|
|
4215
|
+
}
|
|
4216
|
+
if (!changed) {
|
|
4217
|
+
console.log("[agentlife] install-bootstrap: config already normalized");
|
|
4218
|
+
return;
|
|
4219
|
+
}
|
|
4220
|
+
try {
|
|
4221
|
+
writeJson(P.configPath, cfg);
|
|
4222
|
+
console.log("[agentlife] install-bootstrap: gateway config normalized (bind=lan, sessions.visibility=all, agentToAgent.enabled=true, hooks.allowConversationAccess=true, maxPingPongTurns=1, maxConcurrent=10)");
|
|
4223
|
+
console.log("[agentlife] install-bootstrap: changes take effect on next `openclaw daemon restart`");
|
|
4224
|
+
} catch (err) {
|
|
4225
|
+
console.warn(`[agentlife] install-bootstrap: cannot write ${P.configPath}: ${err?.message ?? err}`);
|
|
4226
|
+
}
|
|
4227
|
+
}
|
|
4228
|
+
|
|
3934
4229
|
// services/session-reconcile.ts
|
|
3935
4230
|
function modelMatches(configured, sessionProvider, sessionModel) {
|
|
3936
4231
|
if (!sessionModel)
|
|
@@ -4093,7 +4388,7 @@ async function reconcileInternalSessions(state, createdInternalSessions) {
|
|
|
4093
4388
|
}
|
|
4094
4389
|
|
|
4095
4390
|
// services/supervisor-cleanup.ts
|
|
4096
|
-
import * as
|
|
4391
|
+
import * as fs7 from "node:fs";
|
|
4097
4392
|
var STALE_SUPERVISOR_SURFACE = "supervisor-daily";
|
|
4098
4393
|
var STALE_SUPERVISOR_DIRECT_SESSION = "agent:supervisor:agentlife:direct:operator";
|
|
4099
4394
|
async function cleanupSupervisorLegacyState(state) {
|
|
@@ -4106,7 +4401,7 @@ async function cleanupSupervisorLegacyState(state) {
|
|
|
4106
4401
|
removeFollowup(state, STALE_SUPERVISOR_SURFACE);
|
|
4107
4402
|
if (view2 && !view2.isTransient && view2.path) {
|
|
4108
4403
|
try {
|
|
4109
|
-
|
|
4404
|
+
fs7.unlinkSync(view2.path);
|
|
4110
4405
|
} catch {}
|
|
4111
4406
|
}
|
|
4112
4407
|
state.surfaceIndex?.delete(STALE_SUPERVISOR_SURFACE);
|
|
@@ -4288,6 +4583,8 @@ function startObservabilityService(state) {
|
|
|
4288
4583
|
|
|
4289
4584
|
// hooks/activity-hooks.ts
|
|
4290
4585
|
import * as fsSync2 from "node:fs";
|
|
4586
|
+
import * as nodePath from "node:path";
|
|
4587
|
+
import * as nodeOs from "node:os";
|
|
4291
4588
|
|
|
4292
4589
|
// usage.ts
|
|
4293
4590
|
var MODEL_COSTS = {
|
|
@@ -4936,6 +5233,62 @@ ${parts.join(`
|
|
|
4936
5233
|
}
|
|
4937
5234
|
var QUALITY_CHECK_MAX_WAIT_MS = 5000;
|
|
4938
5235
|
var TERMINAL_MARKERS = new Set(["NO_REPLY", "ANNOUNCE_SKIP", "REPLY_SKIP", "HEARTBEAT_OK"]);
|
|
5236
|
+
function resolveOpenClawRoot() {
|
|
5237
|
+
const fromEnv = process.env.OPENCLAW_STATE_DIR?.trim();
|
|
5238
|
+
return fromEnv ? nodePath.resolve(fromEnv) : nodePath.join(nodeOs.homedir(), ".openclaw");
|
|
5239
|
+
}
|
|
5240
|
+
function findSessionModelError(agentId, sessionKey) {
|
|
5241
|
+
const sessionsDir = nodePath.join(resolveOpenClawRoot(), "agents", agentId, "sessions");
|
|
5242
|
+
const indexPath = nodePath.join(sessionsDir, "sessions.json");
|
|
5243
|
+
let sessionFile = null;
|
|
5244
|
+
try {
|
|
5245
|
+
const index = JSON.parse(fsSync2.readFileSync(indexPath, "utf-8"));
|
|
5246
|
+
const entry = index?.[sessionKey];
|
|
5247
|
+
if (typeof entry?.sessionFile === "string") {
|
|
5248
|
+
sessionFile = entry.sessionFile;
|
|
5249
|
+
} else if (typeof entry?.sessionId === "string") {
|
|
5250
|
+
sessionFile = nodePath.join(sessionsDir, `${entry.sessionId}.jsonl`);
|
|
5251
|
+
}
|
|
5252
|
+
} catch {
|
|
5253
|
+
return null;
|
|
5254
|
+
}
|
|
5255
|
+
if (!sessionFile)
|
|
5256
|
+
return null;
|
|
5257
|
+
let provider;
|
|
5258
|
+
let model;
|
|
5259
|
+
let lines;
|
|
5260
|
+
try {
|
|
5261
|
+
lines = fsSync2.readFileSync(sessionFile, "utf-8").split(`
|
|
5262
|
+
`).filter(Boolean);
|
|
5263
|
+
} catch {
|
|
5264
|
+
return null;
|
|
5265
|
+
}
|
|
5266
|
+
for (const line of lines) {
|
|
5267
|
+
try {
|
|
5268
|
+
const entry = JSON.parse(line);
|
|
5269
|
+
if (entry?.type === "model_change") {
|
|
5270
|
+
provider = typeof entry.provider === "string" ? entry.provider : provider;
|
|
5271
|
+
model = typeof entry.modelId === "string" ? entry.modelId : model;
|
|
5272
|
+
}
|
|
5273
|
+
} catch {}
|
|
5274
|
+
}
|
|
5275
|
+
for (let i = lines.length - 1;i >= 0; i--) {
|
|
5276
|
+
try {
|
|
5277
|
+
const entry = JSON.parse(lines[i]);
|
|
5278
|
+
const msg = entry?.message;
|
|
5279
|
+
if (entry?.type !== "message" || msg?.role !== "assistant")
|
|
5280
|
+
continue;
|
|
5281
|
+
if (typeof msg.provider === "string")
|
|
5282
|
+
provider = msg.provider;
|
|
5283
|
+
if (typeof msg.model === "string")
|
|
5284
|
+
model = msg.model;
|
|
5285
|
+
if (typeof msg.errorMessage === "string" && msg.errorMessage.trim()) {
|
|
5286
|
+
return { error: msg.errorMessage, provider, model };
|
|
5287
|
+
}
|
|
5288
|
+
} catch {}
|
|
5289
|
+
}
|
|
5290
|
+
return null;
|
|
5291
|
+
}
|
|
4939
5292
|
function processPendingQualityChecks(state) {
|
|
4940
5293
|
if (state.disabled || !state.historyDb)
|
|
4941
5294
|
return 0;
|
|
@@ -4977,6 +5330,21 @@ function processPendingQualityChecks(state) {
|
|
|
4977
5330
|
const pushed = db.prepare("SELECT COUNT(*) as c FROM surface_events WHERE event IN ('created','updated') AND createdAt > ? AND (agentId = ? OR agentId IS NULL)").get(row.runStart, row.agentId);
|
|
4978
5331
|
if ((pushed?.c ?? 0) > 0)
|
|
4979
5332
|
continue;
|
|
5333
|
+
const modelError = findSessionModelError(row.agentId, row.sessionKey);
|
|
5334
|
+
if (modelError) {
|
|
5335
|
+
recordActivity(state, "quality_warning", row.sessionKey, row.agentId, {
|
|
5336
|
+
runId: row.runId,
|
|
5337
|
+
data: JSON.stringify({
|
|
5338
|
+
issue: "model_error_no_widget",
|
|
5339
|
+
trigger: row.trigger,
|
|
5340
|
+
error: modelError.error,
|
|
5341
|
+
provider: modelError.provider,
|
|
5342
|
+
model: modelError.model
|
|
5343
|
+
})
|
|
5344
|
+
});
|
|
5345
|
+
console.warn("[agentlife:quality] %s model error before widget push: %s", row.agentId, modelError.error);
|
|
5346
|
+
continue;
|
|
5347
|
+
}
|
|
4980
5348
|
recordActivity(state, "quality_warning", row.sessionKey, row.agentId, {
|
|
4981
5349
|
runId: row.runId,
|
|
4982
5350
|
data: JSON.stringify({ issue: "no_widget_pushed", trigger: row.trigger })
|
|
@@ -5075,7 +5443,7 @@ function rescueOrphanedSurfaces(state, agentId, error) {
|
|
|
5075
5443
|
}
|
|
5076
5444
|
|
|
5077
5445
|
// services/escalation.ts
|
|
5078
|
-
import * as
|
|
5446
|
+
import * as fs8 from "node:fs";
|
|
5079
5447
|
var PATHOLOGY2 = process.env.PATHOLOGY_TEST_MODE === "1";
|
|
5080
5448
|
var ESCALATION_REVIEW_THRESHOLD_MS = PATHOLOGY2 ? 2 * 60 * 1000 : 48 * 60 * 60 * 1000;
|
|
5081
5449
|
var TREND_WINDOW_DAYS = 7;
|
|
@@ -5141,7 +5509,7 @@ function clearEscalationSurface(state, agentId) {
|
|
|
5141
5509
|
const view2 = getSurface(state, surfaceId);
|
|
5142
5510
|
if (view2 && !view2.isTransient && view2.path) {
|
|
5143
5511
|
try {
|
|
5144
|
-
|
|
5512
|
+
fs8.unlinkSync(view2.path);
|
|
5145
5513
|
} catch {}
|
|
5146
5514
|
}
|
|
5147
5515
|
state.surfaceIndex.delete(surfaceId);
|
|
@@ -5385,31 +5753,32 @@ function startDailySweepService(state) {
|
|
|
5385
5753
|
import * as crypto4 from "node:crypto";
|
|
5386
5754
|
import * as fsSync3 from "node:fs";
|
|
5387
5755
|
import { createRequire as createRequire3 } from "node:module";
|
|
5388
|
-
import * as
|
|
5389
|
-
import * as
|
|
5756
|
+
import * as os7 from "node:os";
|
|
5757
|
+
import * as path12 from "node:path";
|
|
5390
5758
|
|
|
5391
5759
|
// gateway/web-app.ts
|
|
5392
5760
|
import * as crypto3 from "node:crypto";
|
|
5393
|
-
import * as
|
|
5394
|
-
import * as
|
|
5395
|
-
import * as
|
|
5761
|
+
import * as os6 from "node:os";
|
|
5762
|
+
import * as path11 from "node:path";
|
|
5763
|
+
import * as fs11 from "node:fs";
|
|
5396
5764
|
|
|
5397
5765
|
// services/pairing-access-token.ts
|
|
5398
5766
|
import * as crypto from "node:crypto";
|
|
5399
|
-
import * as
|
|
5400
|
-
import * as
|
|
5401
|
-
import * as
|
|
5767
|
+
import * as fs9 from "node:fs";
|
|
5768
|
+
import * as os4 from "node:os";
|
|
5769
|
+
import * as path9 from "node:path";
|
|
5402
5770
|
var cachedToken = null;
|
|
5403
5771
|
function pairingAccessPath() {
|
|
5404
|
-
|
|
5772
|
+
const stateDir = process.env.OPENCLAW_STATE_DIR || path9.join(os4.homedir(), ".openclaw");
|
|
5773
|
+
return path9.join(stateDir, "agentlife", "pairing-access.json");
|
|
5405
5774
|
}
|
|
5406
5775
|
function loadOrCreatePairingAccessToken() {
|
|
5407
5776
|
if (cachedToken)
|
|
5408
5777
|
return cachedToken;
|
|
5409
5778
|
const filePath = pairingAccessPath();
|
|
5410
5779
|
try {
|
|
5411
|
-
if (
|
|
5412
|
-
const raw =
|
|
5780
|
+
if (fs9.existsSync(filePath)) {
|
|
5781
|
+
const raw = fs9.readFileSync(filePath, "utf-8");
|
|
5413
5782
|
const obj = JSON.parse(raw);
|
|
5414
5783
|
const token2 = typeof obj?.token === "string" ? obj.token : null;
|
|
5415
5784
|
if (token2 && token2.length >= 32) {
|
|
@@ -5418,12 +5787,12 @@ function loadOrCreatePairingAccessToken() {
|
|
|
5418
5787
|
}
|
|
5419
5788
|
}
|
|
5420
5789
|
const token = crypto.randomBytes(32).toString("base64url");
|
|
5421
|
-
const dir =
|
|
5422
|
-
if (!
|
|
5423
|
-
|
|
5424
|
-
|
|
5790
|
+
const dir = path9.dirname(filePath);
|
|
5791
|
+
if (!fs9.existsSync(dir))
|
|
5792
|
+
fs9.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
5793
|
+
fs9.writeFileSync(filePath, JSON.stringify({ token, createdAtMs: Date.now() }, null, 2), { mode: 384 });
|
|
5425
5794
|
try {
|
|
5426
|
-
|
|
5795
|
+
fs9.chmodSync(filePath, 384);
|
|
5427
5796
|
} catch {}
|
|
5428
5797
|
cachedToken = token;
|
|
5429
5798
|
return token;
|
|
@@ -5436,25 +5805,28 @@ function loadOrCreatePairingAccessToken() {
|
|
|
5436
5805
|
// services/cloudflared-supervisor.ts
|
|
5437
5806
|
import { spawn, spawnSync } from "node:child_process";
|
|
5438
5807
|
import * as crypto2 from "node:crypto";
|
|
5439
|
-
import * as
|
|
5440
|
-
import * as
|
|
5441
|
-
import * as
|
|
5442
|
-
var
|
|
5443
|
-
var
|
|
5444
|
-
var
|
|
5445
|
-
var
|
|
5446
|
-
var
|
|
5447
|
-
var
|
|
5448
|
-
var
|
|
5449
|
-
var
|
|
5450
|
-
var
|
|
5808
|
+
import * as fs10 from "node:fs";
|
|
5809
|
+
import * as os5 from "node:os";
|
|
5810
|
+
import * as path10 from "node:path";
|
|
5811
|
+
var DEFAULT_OPENCLAW_STATE_DIR = path10.join(os5.homedir(), ".openclaw");
|
|
5812
|
+
var OPENCLAW_STATE_DIR = process.env.OPENCLAW_STATE_DIR || DEFAULT_OPENCLAW_STATE_DIR;
|
|
5813
|
+
var IS_PROFILE_STATE_DIR = OPENCLAW_STATE_DIR !== DEFAULT_OPENCLAW_STATE_DIR;
|
|
5814
|
+
var AGENTLIFE_DIR = path10.join(OPENCLAW_STATE_DIR, "agentlife");
|
|
5815
|
+
var TUNNEL_FILE = path10.join(AGENTLIFE_DIR, "tunnel.json");
|
|
5816
|
+
var BIN_DIR = path10.join(AGENTLIFE_DIR, "bin");
|
|
5817
|
+
var PAIR_REQUEST_MARKER = path10.join(AGENTLIFE_DIR, "pair-requested");
|
|
5818
|
+
var IDENTITY_DIR = IS_PROFILE_STATE_DIR ? path10.join(OPENCLAW_STATE_DIR, ".agentlife") : path10.join(os5.homedir(), ".agentlife");
|
|
5819
|
+
var DEVICE_FILE = path10.join(IDENTITY_DIR, "device.json");
|
|
5820
|
+
var LEGACY_DEVICE_FILE = path10.join(AGENTLIFE_DIR, "device.json");
|
|
5821
|
+
var CLOUDFLARED_BIN = os5.platform() === "win32" ? "cloudflared.exe" : "cloudflared";
|
|
5822
|
+
var CLOUDFLARED_PATH = path10.join(BIN_DIR, CLOUDFLARED_BIN);
|
|
5451
5823
|
var API_BASE = process.env.AGENTLIFE_API_BASE || "https://api.agentlife.app";
|
|
5452
5824
|
var RESTART_DELAY_MS = 5000;
|
|
5453
5825
|
var STABLE_RUNTIME_MS = 60000;
|
|
5454
5826
|
function createInitialState() {
|
|
5455
5827
|
let resolver;
|
|
5456
|
-
const promise = new Promise((
|
|
5457
|
-
resolver =
|
|
5828
|
+
const promise = new Promise((resolve2) => {
|
|
5829
|
+
resolver = resolve2;
|
|
5458
5830
|
});
|
|
5459
5831
|
return {
|
|
5460
5832
|
tunnelInfo: null,
|
|
@@ -5475,7 +5847,7 @@ function getTunnelInfo() {
|
|
|
5475
5847
|
function awaitTunnelReady(timeoutMs) {
|
|
5476
5848
|
return Promise.race([
|
|
5477
5849
|
state.readyPromise,
|
|
5478
|
-
new Promise((
|
|
5850
|
+
new Promise((resolve2) => setTimeout(() => resolve2(null), timeoutMs))
|
|
5479
5851
|
]);
|
|
5480
5852
|
}
|
|
5481
5853
|
function startCloudflaredSupervisor() {
|
|
@@ -5567,20 +5939,20 @@ async function doBootstrap() {
|
|
|
5567
5939
|
return tunnelInfo;
|
|
5568
5940
|
}
|
|
5569
5941
|
function isPairRequested() {
|
|
5570
|
-
return
|
|
5942
|
+
return fs10.existsSync(PAIR_REQUEST_MARKER);
|
|
5571
5943
|
}
|
|
5572
5944
|
function requestPair() {
|
|
5573
5945
|
try {
|
|
5574
|
-
if (!
|
|
5575
|
-
|
|
5576
|
-
|
|
5946
|
+
if (!fs10.existsSync(AGENTLIFE_DIR))
|
|
5947
|
+
fs10.mkdirSync(AGENTLIFE_DIR, { recursive: true, mode: 448 });
|
|
5948
|
+
fs10.writeFileSync(PAIR_REQUEST_MARKER, String(Date.now()), { mode: 384 });
|
|
5577
5949
|
} catch (err) {
|
|
5578
5950
|
console.warn(`[cloudflared-supervisor] failed to write pair-request marker: ${err?.message ?? err}`);
|
|
5579
5951
|
}
|
|
5580
5952
|
}
|
|
5581
5953
|
function clearPairRequest() {
|
|
5582
5954
|
try {
|
|
5583
|
-
|
|
5955
|
+
fs10.unlinkSync(PAIR_REQUEST_MARKER);
|
|
5584
5956
|
} catch {}
|
|
5585
5957
|
}
|
|
5586
5958
|
function parseRetryAfter(value) {
|
|
@@ -5604,18 +5976,18 @@ function scheduleProvisionRetry(delayMs) {
|
|
|
5604
5976
|
}, delayMs);
|
|
5605
5977
|
}
|
|
5606
5978
|
function ensureDirs() {
|
|
5607
|
-
if (!
|
|
5608
|
-
|
|
5609
|
-
if (!
|
|
5610
|
-
|
|
5611
|
-
if (!
|
|
5612
|
-
|
|
5979
|
+
if (!fs10.existsSync(AGENTLIFE_DIR))
|
|
5980
|
+
fs10.mkdirSync(AGENTLIFE_DIR, { recursive: true, mode: 448 });
|
|
5981
|
+
if (!fs10.existsSync(BIN_DIR))
|
|
5982
|
+
fs10.mkdirSync(BIN_DIR, { recursive: true, mode: 448 });
|
|
5983
|
+
if (!fs10.existsSync(IDENTITY_DIR))
|
|
5984
|
+
fs10.mkdirSync(IDENTITY_DIR, { recursive: true, mode: 448 });
|
|
5613
5985
|
}
|
|
5614
5986
|
function readIdentityFile(filePath) {
|
|
5615
|
-
if (!
|
|
5987
|
+
if (!fs10.existsSync(filePath))
|
|
5616
5988
|
return null;
|
|
5617
5989
|
try {
|
|
5618
|
-
const raw =
|
|
5990
|
+
const raw = fs10.readFileSync(filePath, "utf-8");
|
|
5619
5991
|
const parsed = JSON.parse(raw);
|
|
5620
5992
|
if (typeof parsed.deviceId === "string" && typeof parsed.deviceSecret === "string") {
|
|
5621
5993
|
return { deviceId: parsed.deviceId, deviceSecret: parsed.deviceSecret };
|
|
@@ -5633,14 +6005,14 @@ function loadDeviceIdentity() {
|
|
|
5633
6005
|
if (!legacy)
|
|
5634
6006
|
return null;
|
|
5635
6007
|
try {
|
|
5636
|
-
if (!
|
|
5637
|
-
|
|
5638
|
-
|
|
6008
|
+
if (!fs10.existsSync(IDENTITY_DIR))
|
|
6009
|
+
fs10.mkdirSync(IDENTITY_DIR, { recursive: true, mode: 448 });
|
|
6010
|
+
fs10.writeFileSync(DEVICE_FILE, JSON.stringify(legacy, null, 2), { mode: 384 });
|
|
5639
6011
|
try {
|
|
5640
|
-
|
|
6012
|
+
fs10.chmodSync(DEVICE_FILE, 384);
|
|
5641
6013
|
} catch {}
|
|
5642
6014
|
try {
|
|
5643
|
-
|
|
6015
|
+
fs10.unlinkSync(LEGACY_DEVICE_FILE);
|
|
5644
6016
|
} catch {}
|
|
5645
6017
|
console.log(`[cloudflared-supervisor] migrated device.json to ${DEVICE_FILE}`);
|
|
5646
6018
|
} catch (err) {
|
|
@@ -5652,25 +6024,25 @@ function loadOrCreateDeviceIdentity() {
|
|
|
5652
6024
|
const existing = loadDeviceIdentity();
|
|
5653
6025
|
if (existing)
|
|
5654
6026
|
return existing;
|
|
5655
|
-
if (!
|
|
5656
|
-
|
|
6027
|
+
if (!fs10.existsSync(IDENTITY_DIR))
|
|
6028
|
+
fs10.mkdirSync(IDENTITY_DIR, { recursive: true, mode: 448 });
|
|
5657
6029
|
const identity = {
|
|
5658
6030
|
deviceId: crypto2.randomUUID(),
|
|
5659
6031
|
deviceSecret: crypto2.randomBytes(32).toString("base64url")
|
|
5660
6032
|
};
|
|
5661
|
-
|
|
6033
|
+
fs10.writeFileSync(DEVICE_FILE, JSON.stringify(identity, null, 2), { mode: 384 });
|
|
5662
6034
|
try {
|
|
5663
|
-
|
|
6035
|
+
fs10.chmodSync(DEVICE_FILE, 384);
|
|
5664
6036
|
} catch {}
|
|
5665
6037
|
console.log(`[cloudflared-supervisor] generated new device identity (deviceId=${identity.deviceId})`);
|
|
5666
6038
|
return identity;
|
|
5667
6039
|
}
|
|
5668
6040
|
var AGENTLIFE_API_BASE = API_BASE;
|
|
5669
6041
|
function loadCachedTunnel() {
|
|
5670
|
-
if (!
|
|
6042
|
+
if (!fs10.existsSync(TUNNEL_FILE))
|
|
5671
6043
|
return null;
|
|
5672
6044
|
try {
|
|
5673
|
-
const raw =
|
|
6045
|
+
const raw = fs10.readFileSync(TUNNEL_FILE, "utf-8");
|
|
5674
6046
|
const parsed = JSON.parse(raw);
|
|
5675
6047
|
if (typeof parsed.subdomain === "string" && typeof parsed.hostname === "string" && typeof parsed.tunnelUrl === "string" && typeof parsed.tunnelToken === "string" && typeof parsed.provisionedAt === "number") {
|
|
5676
6048
|
return parsed;
|
|
@@ -5679,9 +6051,9 @@ function loadCachedTunnel() {
|
|
|
5679
6051
|
return null;
|
|
5680
6052
|
}
|
|
5681
6053
|
function persistTunnel(info) {
|
|
5682
|
-
|
|
6054
|
+
fs10.writeFileSync(TUNNEL_FILE, JSON.stringify(info, null, 2), { mode: 384 });
|
|
5683
6055
|
try {
|
|
5684
|
-
|
|
6056
|
+
fs10.chmodSync(TUNNEL_FILE, 384);
|
|
5685
6057
|
} catch {}
|
|
5686
6058
|
}
|
|
5687
6059
|
async function provisionTunnel(identity) {
|
|
@@ -5734,14 +6106,14 @@ async function provisionTunnel(identity) {
|
|
|
5734
6106
|
}
|
|
5735
6107
|
}
|
|
5736
6108
|
function ensureCloudflaredBinary() {
|
|
5737
|
-
if (
|
|
6109
|
+
if (fs10.existsSync(CLOUDFLARED_PATH)) {
|
|
5738
6110
|
try {
|
|
5739
|
-
|
|
6111
|
+
fs10.accessSync(CLOUDFLARED_PATH, fs10.constants.X_OK);
|
|
5740
6112
|
return CLOUDFLARED_PATH;
|
|
5741
6113
|
} catch {}
|
|
5742
6114
|
}
|
|
5743
|
-
const platform2 =
|
|
5744
|
-
const arch2 =
|
|
6115
|
+
const platform2 = os5.platform();
|
|
6116
|
+
const arch2 = os5.arch();
|
|
5745
6117
|
const release = detectCloudflaredRelease(platform2, arch2);
|
|
5746
6118
|
if (!release) {
|
|
5747
6119
|
console.warn(`[cloudflared-supervisor] unsupported platform: ${platform2}/${arch2}`);
|
|
@@ -5754,28 +6126,28 @@ function ensureCloudflaredBinary() {
|
|
|
5754
6126
|
if (release.kind === "tgz") {
|
|
5755
6127
|
const extracted = extractTgzCloudflared(release.tempPath, BIN_DIR);
|
|
5756
6128
|
try {
|
|
5757
|
-
|
|
6129
|
+
fs10.unlinkSync(release.tempPath);
|
|
5758
6130
|
} catch {}
|
|
5759
6131
|
if (!extracted)
|
|
5760
6132
|
return null;
|
|
5761
6133
|
} else {
|
|
5762
6134
|
try {
|
|
5763
|
-
|
|
6135
|
+
fs10.renameSync(release.tempPath, CLOUDFLARED_PATH);
|
|
5764
6136
|
} catch (err) {
|
|
5765
6137
|
console.warn(`[cloudflared-supervisor] rename failed: ${err?.message}`);
|
|
5766
6138
|
return null;
|
|
5767
6139
|
}
|
|
5768
6140
|
}
|
|
5769
6141
|
try {
|
|
5770
|
-
|
|
6142
|
+
fs10.chmodSync(CLOUDFLARED_PATH, 493);
|
|
5771
6143
|
} catch {}
|
|
5772
|
-
return
|
|
6144
|
+
return fs10.existsSync(CLOUDFLARED_PATH) ? CLOUDFLARED_PATH : null;
|
|
5773
6145
|
}
|
|
5774
6146
|
function detectCloudflaredRelease(platform2, arch2) {
|
|
5775
6147
|
const base = "https://github.com/cloudflare/cloudflared/releases/latest/download";
|
|
5776
6148
|
if (platform2 === "darwin") {
|
|
5777
6149
|
const asset = arch2 === "arm64" ? "cloudflared-darwin-arm64.tgz" : "cloudflared-darwin-amd64.tgz";
|
|
5778
|
-
return { url: `${base}/${asset}`, kind: "tgz", tempPath:
|
|
6150
|
+
return { url: `${base}/${asset}`, kind: "tgz", tempPath: path10.join(BIN_DIR, asset) };
|
|
5779
6151
|
}
|
|
5780
6152
|
if (platform2 === "linux") {
|
|
5781
6153
|
const asset = arch2 === "arm64" ? "cloudflared-linux-arm64" : arch2 === "arm" ? "cloudflared-linux-arm" : arch2 === "x64" ? "cloudflared-linux-amd64" : null;
|
|
@@ -5799,11 +6171,11 @@ function downloadWithCurl(url, dest) {
|
|
|
5799
6171
|
if (result.status !== 0) {
|
|
5800
6172
|
console.warn(`[cloudflared-supervisor] curl failed (exit ${result.status}): ${result.stderr?.toString().slice(0, 200)}`);
|
|
5801
6173
|
try {
|
|
5802
|
-
|
|
6174
|
+
fs10.unlinkSync(dest);
|
|
5803
6175
|
} catch {}
|
|
5804
6176
|
return false;
|
|
5805
6177
|
}
|
|
5806
|
-
return
|
|
6178
|
+
return fs10.existsSync(dest) && fs10.statSync(dest).size > 0;
|
|
5807
6179
|
}
|
|
5808
6180
|
function extractTgzCloudflared(tgzPath, destDir) {
|
|
5809
6181
|
const result = spawnSync("tar", ["-xzf", tgzPath, "-C", destDir], { stdio: "pipe" });
|
|
@@ -5811,10 +6183,10 @@ function extractTgzCloudflared(tgzPath, destDir) {
|
|
|
5811
6183
|
console.warn(`[cloudflared-supervisor] tar extract failed (exit ${result.status}): ${result.stderr?.toString().slice(0, 200)}`);
|
|
5812
6184
|
return false;
|
|
5813
6185
|
}
|
|
5814
|
-
return
|
|
6186
|
+
return fs10.existsSync(CLOUDFLARED_PATH);
|
|
5815
6187
|
}
|
|
5816
6188
|
function killOrphanedCloudflareds(binPath) {
|
|
5817
|
-
if (
|
|
6189
|
+
if (os5.platform() === "win32")
|
|
5818
6190
|
return;
|
|
5819
6191
|
const found = spawnSync("pgrep", ["-f", binPath], { stdio: "pipe" });
|
|
5820
6192
|
if (found.status !== 0)
|
|
@@ -5884,13 +6256,16 @@ var MIME_TYPES = {
|
|
|
5884
6256
|
".txt": "text/plain",
|
|
5885
6257
|
".map": "application/json"
|
|
5886
6258
|
};
|
|
6259
|
+
function resolveStateDir() {
|
|
6260
|
+
return process.env.OPENCLAW_STATE_DIR || path11.join(os6.homedir(), ".openclaw");
|
|
6261
|
+
}
|
|
5887
6262
|
function mintBootstrapToken() {
|
|
5888
6263
|
const bootstrapToken = crypto3.randomBytes(32).toString("base64url");
|
|
5889
|
-
const devicesDir =
|
|
5890
|
-
const bootstrapPath =
|
|
5891
|
-
if (!
|
|
5892
|
-
|
|
5893
|
-
const registry =
|
|
6264
|
+
const devicesDir = path11.join(resolveStateDir(), "devices");
|
|
6265
|
+
const bootstrapPath = path11.join(devicesDir, "bootstrap.json");
|
|
6266
|
+
if (!fs11.existsSync(devicesDir))
|
|
6267
|
+
fs11.mkdirSync(devicesDir, { recursive: true });
|
|
6268
|
+
const registry = fs11.existsSync(bootstrapPath) ? JSON.parse(fs11.readFileSync(bootstrapPath, "utf-8")) : {};
|
|
5894
6269
|
registry[bootstrapToken] = {
|
|
5895
6270
|
token: bootstrapToken,
|
|
5896
6271
|
profile: {
|
|
@@ -5899,15 +6274,15 @@ function mintBootstrapToken() {
|
|
|
5899
6274
|
},
|
|
5900
6275
|
issuedAtMs: Date.now()
|
|
5901
6276
|
};
|
|
5902
|
-
|
|
6277
|
+
fs11.writeFileSync(bootstrapPath, JSON.stringify(registry, null, 2));
|
|
5903
6278
|
return bootstrapToken;
|
|
5904
6279
|
}
|
|
5905
6280
|
function registerWebApp(api) {
|
|
5906
|
-
const pluginRoot =
|
|
5907
|
-
const appRoot =
|
|
5908
|
-
const hasWebBuild =
|
|
5909
|
-
const indexPath = hasWebBuild ?
|
|
5910
|
-
const hasIndex = !!(indexPath &&
|
|
6281
|
+
const pluginRoot = path11.resolve(path11.dirname(api.source), "..");
|
|
6282
|
+
const appRoot = path11.join(pluginRoot, "web-build");
|
|
6283
|
+
const hasWebBuild = fs11.existsSync(appRoot);
|
|
6284
|
+
const indexPath = hasWebBuild ? path11.join(appRoot, "index.html") : null;
|
|
6285
|
+
const hasIndex = !!(indexPath && fs11.existsSync(indexPath));
|
|
5911
6286
|
if (!hasWebBuild) {
|
|
5912
6287
|
api.logger.info("[agentlife] web-build/ not found — /agentlife/pair will still register; static dashboard disabled");
|
|
5913
6288
|
} else if (!hasIndex) {
|
|
@@ -5915,11 +6290,13 @@ function registerWebApp(api) {
|
|
|
5915
6290
|
}
|
|
5916
6291
|
let gatewayToken = "";
|
|
5917
6292
|
try {
|
|
5918
|
-
const configPath =
|
|
5919
|
-
const raw = JSON.parse(
|
|
6293
|
+
const configPath = process.env.OPENCLAW_CONFIG_PATH || path11.join(resolveStateDir(), "openclaw.json");
|
|
6294
|
+
const raw = JSON.parse(fs11.readFileSync(configPath, "utf-8"));
|
|
5920
6295
|
gatewayToken = raw?.gateway?.auth?.token || "";
|
|
5921
6296
|
} catch {}
|
|
5922
|
-
|
|
6297
|
+
if (shouldStartRuntimeServices()) {
|
|
6298
|
+
loadOrCreatePairingAccessToken();
|
|
6299
|
+
}
|
|
5923
6300
|
const approveLatest = () => {
|
|
5924
6301
|
try {
|
|
5925
6302
|
const { execSync } = __require("node:child_process");
|
|
@@ -6034,16 +6411,16 @@ function registerWebApp(api) {
|
|
|
6034
6411
|
return true;
|
|
6035
6412
|
}
|
|
6036
6413
|
const relative = urlPath.replace(/^\/agentlife\/?/, "") || "index.html";
|
|
6037
|
-
const filePath =
|
|
6414
|
+
const filePath = path11.resolve(appRoot, relative);
|
|
6038
6415
|
if (!filePath.startsWith(appRoot)) {
|
|
6039
6416
|
res.writeHead(403);
|
|
6040
6417
|
res.end();
|
|
6041
6418
|
return true;
|
|
6042
6419
|
}
|
|
6043
|
-
const target =
|
|
6044
|
-
const ext =
|
|
6420
|
+
const target = fs11.existsSync(filePath) && fs11.statSync(filePath).isFile() ? filePath : indexPath;
|
|
6421
|
+
const ext = path11.extname(target).toLowerCase();
|
|
6045
6422
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
6046
|
-
let content =
|
|
6423
|
+
let content = fs11.readFileSync(target);
|
|
6047
6424
|
if (target === indexPath) {
|
|
6048
6425
|
setTimeout(approveLatest, 2000);
|
|
6049
6426
|
setTimeout(approveLatest, 5000);
|
|
@@ -6079,62 +6456,29 @@ function registerWebApp(api) {
|
|
|
6079
6456
|
|
|
6080
6457
|
// services/pairing.ts
|
|
6081
6458
|
var TUNNEL_READY_TIMEOUT_MS = 90000;
|
|
6459
|
+
function resolveStateDir2(ctx) {
|
|
6460
|
+
return ctx?.stateDir || process.env.OPENCLAW_STATE_DIR || path12.join(os7.homedir(), ".openclaw");
|
|
6461
|
+
}
|
|
6082
6462
|
function registerPairingServices(api) {
|
|
6083
6463
|
api.registerService({
|
|
6084
6464
|
id: "agentlife-pairing-qr",
|
|
6085
|
-
start:
|
|
6086
|
-
|
|
6087
|
-
|
|
6088
|
-
|
|
6089
|
-
const token = cfg.gateway?.auth?.token;
|
|
6090
|
-
if (!token)
|
|
6091
|
-
return;
|
|
6092
|
-
const supervisorTunnel = await awaitTunnelReady(TUNNEL_READY_TIMEOUT_MS) ?? getTunnelInfo();
|
|
6093
|
-
if (!supervisorTunnel?.tunnelUrl) {
|
|
6094
|
-
console.warn(`[agentlife] Cloudflared tunnel did not come up within ${TUNNEL_READY_TIMEOUT_MS / 1000}s — ` + `pairing QR will not be emitted. Check cloudflared-supervisor logs in the gateway output.`);
|
|
6095
|
-
return;
|
|
6096
|
-
}
|
|
6097
|
-
const url = supervisorTunnel.tunnelUrl;
|
|
6098
|
-
const bootstrapToken = mintBootstrapToken();
|
|
6099
|
-
const payload = JSON.stringify({ url, bootstrapToken });
|
|
6100
|
-
const setupCode = Buffer.from(payload).toString("base64url");
|
|
6101
|
-
let qrTerminal = null;
|
|
6102
|
-
try {
|
|
6103
|
-
const realPath = fsSync3.realpathSync(process.argv[1] || "");
|
|
6104
|
-
const mainRequire = createRequire3(realPath);
|
|
6105
|
-
qrTerminal = mainRequire("qrcode-terminal");
|
|
6106
|
-
} catch {}
|
|
6107
|
-
console.log(`
|
|
6108
|
-
\x1B[36m[agentlife]\x1B[0m \x1B[1mPlugin installed — get the app to see your dashboard.\x1B[0m
|
|
6109
|
-
`);
|
|
6110
|
-
if (qrTerminal?.generate) {
|
|
6111
|
-
qrTerminal.generate(setupCode, { small: true }, (qr) => {
|
|
6112
|
-
console.log(qr);
|
|
6113
|
-
console.log(`
|
|
6114
|
-
Setup code: ${setupCode}
|
|
6115
|
-
`);
|
|
6116
|
-
});
|
|
6117
|
-
} else {
|
|
6118
|
-
console.log(`Setup code: ${setupCode}`);
|
|
6119
|
-
}
|
|
6120
|
-
console.log(" \x1B[32mMac:\x1B[0m https://agentlife.app/desktop");
|
|
6121
|
-
console.log(" \x1B[32miOS:\x1B[0m https://agentlife.app/ios");
|
|
6122
|
-
console.log(" \x1B[32mAndroid:\x1B[0m https://agentlife.app/android");
|
|
6123
|
-
console.log(` \x1B[2mBrowser:\x1B[0m http://localhost:${port}/agentlife/`);
|
|
6124
|
-
console.log(`
|
|
6125
|
-
Scan the QR from the mobile app to connect.
|
|
6126
|
-
`);
|
|
6127
|
-
} catch (err) {
|
|
6465
|
+
start: (ctx) => {
|
|
6466
|
+
if (!shouldStartRuntimeServices())
|
|
6467
|
+
return;
|
|
6468
|
+
emitPairingQr(api, ctx).catch((err) => {
|
|
6128
6469
|
console.warn("[agentlife] QR generation skipped:", err?.message);
|
|
6129
|
-
}
|
|
6470
|
+
});
|
|
6130
6471
|
}
|
|
6131
6472
|
});
|
|
6132
6473
|
api.registerService({
|
|
6133
6474
|
id: "agentlife-auto-pair",
|
|
6134
6475
|
start: async (ctx) => {
|
|
6135
|
-
|
|
6136
|
-
|
|
6137
|
-
const
|
|
6476
|
+
if (!shouldStartRuntimeServices())
|
|
6477
|
+
return;
|
|
6478
|
+
const stateDir = resolveStateDir2(ctx);
|
|
6479
|
+
const devicesDir = path12.join(stateDir, "devices");
|
|
6480
|
+
const pendingPath = path12.join(devicesDir, "pending.json");
|
|
6481
|
+
const pairedPath = path12.join(devicesDir, "paired.json");
|
|
6138
6482
|
const pollInterval = 3000;
|
|
6139
6483
|
const withAdmin = (arr) => {
|
|
6140
6484
|
const base = Array.isArray(arr) ? arr.filter((s) => typeof s === "string") : [];
|
|
@@ -6229,6 +6573,52 @@ Setup code: ${setupCode}
|
|
|
6229
6573
|
}
|
|
6230
6574
|
});
|
|
6231
6575
|
}
|
|
6576
|
+
async function emitPairingQr(api, _ctx) {
|
|
6577
|
+
try {
|
|
6578
|
+
const cfg = api.runtime.config.loadConfig();
|
|
6579
|
+
const port = cfg.gateway?.port ?? 18789;
|
|
6580
|
+
const token = cfg.gateway?.auth?.token;
|
|
6581
|
+
if (!token)
|
|
6582
|
+
return;
|
|
6583
|
+
const supervisorTunnel = await awaitTunnelReady(TUNNEL_READY_TIMEOUT_MS) ?? getTunnelInfo();
|
|
6584
|
+
if (!supervisorTunnel?.tunnelUrl) {
|
|
6585
|
+
console.warn(`[agentlife] Cloudflared tunnel did not come up within ${TUNNEL_READY_TIMEOUT_MS / 1000}s — ` + `pairing QR will not be emitted. Check cloudflared-supervisor logs in the gateway output.`);
|
|
6586
|
+
return;
|
|
6587
|
+
}
|
|
6588
|
+
const url = supervisorTunnel.tunnelUrl;
|
|
6589
|
+
const bootstrapToken = mintBootstrapToken();
|
|
6590
|
+
const payload = JSON.stringify({ url, bootstrapToken });
|
|
6591
|
+
const setupCode = Buffer.from(payload).toString("base64url");
|
|
6592
|
+
let qrTerminal = null;
|
|
6593
|
+
try {
|
|
6594
|
+
const realPath = fsSync3.realpathSync(process.argv[1] || "");
|
|
6595
|
+
const mainRequire = createRequire3(realPath);
|
|
6596
|
+
qrTerminal = mainRequire("qrcode-terminal");
|
|
6597
|
+
} catch {}
|
|
6598
|
+
console.log(`
|
|
6599
|
+
\x1B[36m[agentlife]\x1B[0m \x1B[1mPlugin installed — get the app to see your dashboard.\x1B[0m
|
|
6600
|
+
`);
|
|
6601
|
+
if (qrTerminal?.generate) {
|
|
6602
|
+
qrTerminal.generate(setupCode, { small: true }, (qr) => {
|
|
6603
|
+
console.log(qr);
|
|
6604
|
+
console.log(`
|
|
6605
|
+
Setup code: ${setupCode}
|
|
6606
|
+
`);
|
|
6607
|
+
});
|
|
6608
|
+
} else {
|
|
6609
|
+
console.log(`Setup code: ${setupCode}`);
|
|
6610
|
+
}
|
|
6611
|
+
console.log(" \x1B[32mMac:\x1B[0m https://agentlife.app/desktop");
|
|
6612
|
+
console.log(" \x1B[32miOS:\x1B[0m https://agentlife.app/ios");
|
|
6613
|
+
console.log(" \x1B[32mAndroid:\x1B[0m https://agentlife.app/android");
|
|
6614
|
+
console.log(` \x1B[2mBrowser:\x1B[0m http://localhost:${port}/agentlife/`);
|
|
6615
|
+
console.log(`
|
|
6616
|
+
Scan the QR from the mobile app to connect.
|
|
6617
|
+
`);
|
|
6618
|
+
} catch (err) {
|
|
6619
|
+
console.warn("[agentlife] QR generation skipped:", err?.message);
|
|
6620
|
+
}
|
|
6621
|
+
}
|
|
6232
6622
|
|
|
6233
6623
|
// hooks/bootstrap.ts
|
|
6234
6624
|
var SKIP_GUIDANCE_AGENTS = new Set(["agentlife"]);
|
|
@@ -6388,15 +6778,15 @@ function registerBootstrapHookImpl(api, state2) {
|
|
|
6388
6778
|
}
|
|
6389
6779
|
|
|
6390
6780
|
// notifications.ts
|
|
6391
|
-
import * as
|
|
6392
|
-
import * as
|
|
6781
|
+
import * as fs12 from "node:fs";
|
|
6782
|
+
import * as path13 from "node:path";
|
|
6393
6783
|
var config;
|
|
6394
6784
|
function loadConfig() {
|
|
6395
6785
|
if (config !== undefined)
|
|
6396
6786
|
return config;
|
|
6397
6787
|
try {
|
|
6398
|
-
const configPath =
|
|
6399
|
-
const raw =
|
|
6788
|
+
const configPath = path13.join(process.env.HOME ?? "~", ".openclaw", "agentlife", "notification-config.json");
|
|
6789
|
+
const raw = fs12.readFileSync(configPath, "utf-8");
|
|
6400
6790
|
const parsed = JSON.parse(raw);
|
|
6401
6791
|
if (parsed.serverUrl && parsed.apiKey) {
|
|
6402
6792
|
config = { serverUrl: parsed.serverUrl, apiKey: parsed.apiKey };
|
|
@@ -6966,9 +7356,101 @@ function registerPromptStateHook(api, state2) {
|
|
|
6966
7356
|
}
|
|
6967
7357
|
|
|
6968
7358
|
// gateway/agents.ts
|
|
6969
|
-
import * as
|
|
6970
|
-
import * as
|
|
6971
|
-
import * as
|
|
7359
|
+
import * as fs13 from "node:fs";
|
|
7360
|
+
import * as os8 from "node:os";
|
|
7361
|
+
import * as path14 from "node:path";
|
|
7362
|
+
import { ensureAuthProfileStore, upsertAuthProfile as upsertAuthProfile2 } from "openclaw/plugin-sdk/provider-auth";
|
|
7363
|
+
function resolveOpenClawRoot2() {
|
|
7364
|
+
const fromEnv = process.env.OPENCLAW_STATE_DIR?.trim();
|
|
7365
|
+
return fromEnv ? path14.resolve(fromEnv) : path14.join(os8.homedir(), ".openclaw");
|
|
7366
|
+
}
|
|
7367
|
+
function providerFromModel2(model) {
|
|
7368
|
+
const slash = model.indexOf("/");
|
|
7369
|
+
if (slash <= 0)
|
|
7370
|
+
return null;
|
|
7371
|
+
return model.slice(0, slash).trim() || null;
|
|
7372
|
+
}
|
|
7373
|
+
function authenticatedProvidersFromConfig(cfg) {
|
|
7374
|
+
const out = new Set;
|
|
7375
|
+
const profiles = cfg?.auth?.profiles;
|
|
7376
|
+
if (!profiles || typeof profiles !== "object")
|
|
7377
|
+
return out;
|
|
7378
|
+
for (const entry of Object.values(profiles)) {
|
|
7379
|
+
const provider = entry?.provider;
|
|
7380
|
+
if (typeof provider === "string" && provider.trim()) {
|
|
7381
|
+
out.add(provider.trim());
|
|
7382
|
+
}
|
|
7383
|
+
}
|
|
7384
|
+
return out;
|
|
7385
|
+
}
|
|
7386
|
+
function findSiblingAuthProfile(provider, targetAgentId) {
|
|
7387
|
+
const agentsRoot = path14.join(resolveOpenClawRoot2(), "agents");
|
|
7388
|
+
let entries;
|
|
7389
|
+
try {
|
|
7390
|
+
entries = fs13.readdirSync(agentsRoot, { withFileTypes: true });
|
|
7391
|
+
} catch {
|
|
7392
|
+
return null;
|
|
7393
|
+
}
|
|
7394
|
+
for (const entry of entries) {
|
|
7395
|
+
if (!entry.isDirectory() && !entry.isSymbolicLink())
|
|
7396
|
+
continue;
|
|
7397
|
+
if (entry.name === targetAgentId)
|
|
7398
|
+
continue;
|
|
7399
|
+
const agentDir = path14.join(agentsRoot, entry.name, "agent");
|
|
7400
|
+
try {
|
|
7401
|
+
const store = ensureAuthProfileStore(agentDir, { allowKeychainPrompt: false, syncExternalCli: false });
|
|
7402
|
+
for (const [profileId, profile] of Object.entries(store?.profiles ?? {})) {
|
|
7403
|
+
if (profile?.provider !== provider)
|
|
7404
|
+
continue;
|
|
7405
|
+
const type = profile?.type;
|
|
7406
|
+
const mode = profile?.mode;
|
|
7407
|
+
if (type === "oauth")
|
|
7408
|
+
continue;
|
|
7409
|
+
if (mode === "oauth")
|
|
7410
|
+
continue;
|
|
7411
|
+
return { profileId, profile };
|
|
7412
|
+
}
|
|
7413
|
+
} catch {}
|
|
7414
|
+
const file = path14.join(agentDir, "auth-profiles.json");
|
|
7415
|
+
let data;
|
|
7416
|
+
try {
|
|
7417
|
+
data = JSON.parse(fs13.readFileSync(file, "utf-8"));
|
|
7418
|
+
} catch {
|
|
7419
|
+
continue;
|
|
7420
|
+
}
|
|
7421
|
+
const profiles = data?.profiles;
|
|
7422
|
+
if (!profiles || typeof profiles !== "object")
|
|
7423
|
+
continue;
|
|
7424
|
+
for (const [profileId, profile] of Object.entries(profiles)) {
|
|
7425
|
+
if (profile?.provider !== provider)
|
|
7426
|
+
continue;
|
|
7427
|
+
const type = profile?.type;
|
|
7428
|
+
const mode = profile?.mode;
|
|
7429
|
+
if (type === "oauth")
|
|
7430
|
+
continue;
|
|
7431
|
+
if (mode === "oauth")
|
|
7432
|
+
continue;
|
|
7433
|
+
return {
|
|
7434
|
+
profileId,
|
|
7435
|
+
profile
|
|
7436
|
+
};
|
|
7437
|
+
}
|
|
7438
|
+
}
|
|
7439
|
+
return null;
|
|
7440
|
+
}
|
|
7441
|
+
function writeAgentAuthProfile(agentId, provider, match) {
|
|
7442
|
+
if (!match)
|
|
7443
|
+
return false;
|
|
7444
|
+
const agentDir = path14.join(resolveOpenClawRoot2(), "agents", agentId, "agent");
|
|
7445
|
+
fs13.mkdirSync(agentDir, { recursive: true });
|
|
7446
|
+
const credential = { ...match.profile };
|
|
7447
|
+
if (credential.type === "api_key" && typeof credential.key !== "string" && typeof credential.apiKey === "string") {
|
|
7448
|
+
credential.key = credential.apiKey;
|
|
7449
|
+
delete credential.apiKey;
|
|
7450
|
+
}
|
|
7451
|
+
upsertAuthProfile2({ profileId: match.profileId, credential, agentDir });
|
|
7452
|
+
return true;
|
|
7453
|
+
}
|
|
6972
7454
|
function registerAgentGateway(api, state2) {
|
|
6973
7455
|
api.registerGatewayMethod("agentlife.createAgent", async ({ params, respond }) => {
|
|
6974
7456
|
const id = typeof params?.id === "string" ? params.id.trim() : "";
|
|
@@ -6988,6 +7470,18 @@ function registerAgentGateway(api, state2) {
|
|
|
6988
7470
|
return;
|
|
6989
7471
|
}
|
|
6990
7472
|
const cfg = api.runtime.config.loadConfig();
|
|
7473
|
+
const provider = model ? providerFromModel2(model) : null;
|
|
7474
|
+
const providerInConfig = provider ? authenticatedProvidersFromConfig(cfg).has(provider) : false;
|
|
7475
|
+
const siblingAuth = provider ? findSiblingAuthProfile(provider, id) : null;
|
|
7476
|
+
if (provider && !providerInConfig && !siblingAuth) {
|
|
7477
|
+
respond(false, {
|
|
7478
|
+
error: `missing provider credentials for ${provider}; configure ${provider} before creating an agent with ${model}`,
|
|
7479
|
+
code: "missing_provider_auth",
|
|
7480
|
+
provider,
|
|
7481
|
+
model
|
|
7482
|
+
});
|
|
7483
|
+
return;
|
|
7484
|
+
}
|
|
6991
7485
|
const currentList = cfg.agents?.list ?? [];
|
|
6992
7486
|
const existing = currentList.find((a) => a.id === id);
|
|
6993
7487
|
if (!existing) {
|
|
@@ -7034,6 +7528,10 @@ function registerAgentGateway(api, state2) {
|
|
|
7034
7528
|
console.log("[agentlife] builder patched agent config: %s", id);
|
|
7035
7529
|
}
|
|
7036
7530
|
}
|
|
7531
|
+
const authCopied = provider ? writeAgentAuthProfile(id, provider, siblingAuth) : false;
|
|
7532
|
+
if (authCopied) {
|
|
7533
|
+
console.log("[agentlife] copied %s auth profile into agent: %s", provider, id);
|
|
7534
|
+
}
|
|
7037
7535
|
const hasGoodDescription = description && isUsableDescription(description, id, name);
|
|
7038
7536
|
state2.agentRegistry.set(id, {
|
|
7039
7537
|
name: name || id,
|
|
@@ -7063,7 +7561,7 @@ function registerAgentGateway(api, state2) {
|
|
|
7063
7561
|
console.warn("[agentlife] deleteWelcomeWidget failed for %s: %s", id, e?.message);
|
|
7064
7562
|
}
|
|
7065
7563
|
}
|
|
7066
|
-
respond(true, { status, id, name, model, workspace, description, ...configFields.length ? { configFields } : {} });
|
|
7564
|
+
respond(true, { status, id, name, model, workspace, description, ...authCopied ? { authCopied: true } : {}, ...configFields.length ? { configFields } : {} });
|
|
7067
7565
|
});
|
|
7068
7566
|
api.registerGatewayMethod("agentlife.deleteAgent", async ({ params, respond }) => {
|
|
7069
7567
|
const id = typeof params?.id === "string" ? params.id.trim() : "";
|
|
@@ -7156,10 +7654,10 @@ function registerAgentGateway(api, state2) {
|
|
|
7156
7654
|
state2.agentDbs.delete(id);
|
|
7157
7655
|
}
|
|
7158
7656
|
if (state2.dbBaseDir) {
|
|
7159
|
-
const dbPath =
|
|
7657
|
+
const dbPath = path14.join(state2.dbBaseDir, `${id}.db`);
|
|
7160
7658
|
try {
|
|
7161
|
-
if (
|
|
7162
|
-
|
|
7659
|
+
if (fs13.existsSync(dbPath)) {
|
|
7660
|
+
fs13.unlinkSync(dbPath);
|
|
7163
7661
|
cleanup.agentDbDeleted = true;
|
|
7164
7662
|
}
|
|
7165
7663
|
} catch (e) {
|
|
@@ -7171,24 +7669,24 @@ function registerAgentGateway(api, state2) {
|
|
|
7171
7669
|
const existingEntry = currentList.find((a) => a.id === id);
|
|
7172
7670
|
const filtered = currentList.filter((a) => a.id !== id);
|
|
7173
7671
|
const removedFromConfig = filtered.length < currentList.length;
|
|
7174
|
-
const openclawHome =
|
|
7175
|
-
const stateDir =
|
|
7176
|
-
if (stateDir.startsWith(
|
|
7672
|
+
const openclawHome = path14.join(os8.homedir(), ".openclaw");
|
|
7673
|
+
const stateDir = path14.join(openclawHome, "agents", id);
|
|
7674
|
+
if (stateDir.startsWith(path14.join(openclawHome, "agents") + path14.sep)) {
|
|
7177
7675
|
try {
|
|
7178
|
-
if (
|
|
7179
|
-
|
|
7676
|
+
if (fs13.existsSync(stateDir)) {
|
|
7677
|
+
fs13.rmSync(stateDir, { recursive: true, force: true });
|
|
7180
7678
|
cleanup.stateDeleted = true;
|
|
7181
7679
|
}
|
|
7182
7680
|
} catch (e) {
|
|
7183
7681
|
console.warn("[agentlife] deleteAgent: failed to delete state dir:", e?.message);
|
|
7184
7682
|
}
|
|
7185
7683
|
}
|
|
7186
|
-
const defaultWorkspace =
|
|
7187
|
-
const workspaceToDelete = typeof existingEntry?.workspace === "string" && existingEntry.workspace.trim() ?
|
|
7188
|
-
if (workspaceToDelete.startsWith(openclawHome +
|
|
7684
|
+
const defaultWorkspace = path14.join(openclawHome, `workspace-${id}`);
|
|
7685
|
+
const workspaceToDelete = typeof existingEntry?.workspace === "string" && existingEntry.workspace.trim() ? path14.resolve(existingEntry.workspace) : defaultWorkspace;
|
|
7686
|
+
if (workspaceToDelete.startsWith(openclawHome + path14.sep) && workspaceToDelete !== openclawHome) {
|
|
7189
7687
|
try {
|
|
7190
|
-
if (
|
|
7191
|
-
|
|
7688
|
+
if (fs13.existsSync(workspaceToDelete)) {
|
|
7689
|
+
fs13.rmSync(workspaceToDelete, { recursive: true, force: true });
|
|
7192
7690
|
cleanup.workspaceDeleted = true;
|
|
7193
7691
|
}
|
|
7194
7692
|
} catch (e) {
|
|
@@ -7507,7 +8005,7 @@ function registerUsageGateway(api, state2) {
|
|
|
7507
8005
|
}
|
|
7508
8006
|
|
|
7509
8007
|
// gateway/surfaces-gateway.ts
|
|
7510
|
-
import * as
|
|
8008
|
+
import * as fs14 from "node:fs";
|
|
7511
8009
|
var guidedDismissSent = new Set;
|
|
7512
8010
|
var warnedMissingOrigin = new Set;
|
|
7513
8011
|
function registerSurfacesGateway(api, state2) {
|
|
@@ -7596,7 +8094,7 @@ function registerSurfacesGateway(api, state2) {
|
|
|
7596
8094
|
guidedDismissSent.delete(surfaceId);
|
|
7597
8095
|
if (!view2.isTransient && view2.path) {
|
|
7598
8096
|
try {
|
|
7599
|
-
|
|
8097
|
+
fs14.unlinkSync(view2.path);
|
|
7600
8098
|
} catch (err) {
|
|
7601
8099
|
if (err?.code !== "ENOENT")
|
|
7602
8100
|
console.warn("[agentlife] dismiss: file unlink failed for %s: %s", surfaceId, err?.message);
|
|
@@ -7841,17 +8339,17 @@ function registerAutomationsGateway(api, state2) {
|
|
|
7841
8339
|
}
|
|
7842
8340
|
|
|
7843
8341
|
// gateway/admin.ts
|
|
7844
|
-
import * as
|
|
8342
|
+
import * as fs15 from "node:fs/promises";
|
|
7845
8343
|
import * as fsSync4 from "node:fs";
|
|
7846
|
-
import * as
|
|
7847
|
-
import * as
|
|
8344
|
+
import * as os9 from "node:os";
|
|
8345
|
+
import * as path15 from "node:path";
|
|
7848
8346
|
import { fileURLToPath } from "node:url";
|
|
7849
8347
|
var PLUGIN_VERSION = (() => {
|
|
7850
8348
|
try {
|
|
7851
|
-
const moduleDir =
|
|
8349
|
+
const moduleDir = path15.dirname(fileURLToPath(import.meta.url));
|
|
7852
8350
|
const candidates = [
|
|
7853
|
-
|
|
7854
|
-
|
|
8351
|
+
path15.join(moduleDir, "..", "package.json"),
|
|
8352
|
+
path15.join(moduleDir, "..", "..", "package.json")
|
|
7855
8353
|
];
|
|
7856
8354
|
for (const p of candidates) {
|
|
7857
8355
|
if (fsSync4.existsSync(p)) {
|
|
@@ -7900,7 +8398,7 @@ async function fetchNpmLatestVersion(force = false) {
|
|
|
7900
8398
|
return inflightFetch;
|
|
7901
8399
|
}
|
|
7902
8400
|
function pluginConfigPath() {
|
|
7903
|
-
return
|
|
8401
|
+
return path15.join(os9.homedir(), ".openclaw", "agentlife", "plugin-config.json");
|
|
7904
8402
|
}
|
|
7905
8403
|
function readPluginConfig() {
|
|
7906
8404
|
try {
|
|
@@ -7910,7 +8408,7 @@ function readPluginConfig() {
|
|
|
7910
8408
|
}
|
|
7911
8409
|
}
|
|
7912
8410
|
function writePluginConfig(config2) {
|
|
7913
|
-
const dir =
|
|
8411
|
+
const dir = path15.dirname(pluginConfigPath());
|
|
7914
8412
|
fsSync4.mkdirSync(dir, { recursive: true });
|
|
7915
8413
|
fsSync4.writeFileSync(pluginConfigPath(), JSON.stringify(config2, null, 2));
|
|
7916
8414
|
}
|
|
@@ -8038,7 +8536,7 @@ function registerAdminGateway(api, state2) {
|
|
|
8038
8536
|
api.registerGatewayMethod("agentlife.uninstall", async ({ respond }) => {
|
|
8039
8537
|
try {
|
|
8040
8538
|
const cleaned = [];
|
|
8041
|
-
const baseDir = state2.agentlifeStateDir ??
|
|
8539
|
+
const baseDir = state2.agentlifeStateDir ?? path15.join(os9.homedir(), ".openclaw", "agentlife");
|
|
8042
8540
|
const identity = loadDeviceIdentity();
|
|
8043
8541
|
if (!identity) {
|
|
8044
8542
|
cleaned.push("server deprovision skipped (no device identity)");
|
|
@@ -8103,7 +8601,7 @@ function registerAdminGateway(api, state2) {
|
|
|
8103
8601
|
} catch {
|
|
8104
8602
|
cleaned.push("agent config cleanup skipped");
|
|
8105
8603
|
}
|
|
8106
|
-
const backupPath =
|
|
8604
|
+
const backupPath = path15.join(baseDir, "config-backup.json");
|
|
8107
8605
|
try {
|
|
8108
8606
|
cleaned.push(await restoreConfigFromBackup(api, backupPath));
|
|
8109
8607
|
} catch {
|
|
@@ -8125,35 +8623,35 @@ function registerAdminGateway(api, state2) {
|
|
|
8125
8623
|
dbPath,
|
|
8126
8624
|
dbPath ? `${dbPath}-wal` : null,
|
|
8127
8625
|
dbPath ? `${dbPath}-shm` : null,
|
|
8128
|
-
|
|
8129
|
-
|
|
8130
|
-
|
|
8626
|
+
path15.join(baseDir, "config-backup.json"),
|
|
8627
|
+
path15.join(baseDir, "notification-config.json"),
|
|
8628
|
+
path15.join(baseDir, "canvas-node-identity.json")
|
|
8131
8629
|
].filter(Boolean);
|
|
8132
8630
|
for (const fp of stateFiles) {
|
|
8133
8631
|
try {
|
|
8134
|
-
await
|
|
8135
|
-
cleaned.push(`deleted ${
|
|
8632
|
+
await fs15.unlink(fp);
|
|
8633
|
+
cleaned.push(`deleted ${path15.basename(fp)}`);
|
|
8136
8634
|
} catch {}
|
|
8137
8635
|
}
|
|
8138
8636
|
if (state2.dbBaseDir) {
|
|
8139
8637
|
try {
|
|
8140
|
-
await
|
|
8638
|
+
await fs15.rm(state2.dbBaseDir, { recursive: true, force: true });
|
|
8141
8639
|
cleaned.push("deleted agent databases");
|
|
8142
8640
|
} catch {}
|
|
8143
8641
|
}
|
|
8144
8642
|
for (const agent of PROVISIONED_AGENTS) {
|
|
8145
8643
|
if (agent.existingAgent)
|
|
8146
8644
|
continue;
|
|
8147
|
-
const wsDir = agent.workspaceDir ??
|
|
8645
|
+
const wsDir = agent.workspaceDir ?? path15.join(os9.homedir(), ".openclaw", `workspace-${agent.id}`);
|
|
8148
8646
|
try {
|
|
8149
|
-
await
|
|
8647
|
+
await fs15.rm(wsDir, { recursive: true, force: true });
|
|
8150
8648
|
cleaned.push(`deleted workspace ${agent.id}`);
|
|
8151
8649
|
} catch {}
|
|
8152
8650
|
}
|
|
8153
8651
|
try {
|
|
8154
|
-
const remaining = await
|
|
8652
|
+
const remaining = await fs15.readdir(baseDir);
|
|
8155
8653
|
if (remaining.length === 0) {
|
|
8156
|
-
await
|
|
8654
|
+
await fs15.rmdir(baseDir);
|
|
8157
8655
|
cleaned.push("deleted agentlife state directory");
|
|
8158
8656
|
}
|
|
8159
8657
|
} catch {}
|
|
@@ -8193,11 +8691,11 @@ function registerAdminGateway(api, state2) {
|
|
|
8193
8691
|
|
|
8194
8692
|
// gateway/evolutions.ts
|
|
8195
8693
|
import * as fsSync5 from "node:fs";
|
|
8196
|
-
import * as
|
|
8197
|
-
import * as
|
|
8694
|
+
import * as os10 from "node:os";
|
|
8695
|
+
import * as path16 from "node:path";
|
|
8198
8696
|
var ALLOWED_FILENAMES = new Set(["AGENTS.md", "USER.md", "SOUL.md", "TOOLS.md", "IDENTITY.md"]);
|
|
8199
8697
|
function workspaceFilePath(agentId, filename) {
|
|
8200
|
-
return
|
|
8698
|
+
return path16.join(os10.homedir(), ".openclaw", `workspace-${agentId}`, filename);
|
|
8201
8699
|
}
|
|
8202
8700
|
function hasRegressionFlag(db, agentId, filename, snapshotAt) {
|
|
8203
8701
|
const horizon = snapshotAt + 7 * 24 * 60 * 60 * 1000;
|
|
@@ -8572,39 +9070,43 @@ function parseOffset(offset) {
|
|
|
8572
9070
|
// gateway/providers.ts
|
|
8573
9071
|
import {
|
|
8574
9072
|
upsertApiKeyProfile,
|
|
8575
|
-
upsertAuthProfile,
|
|
9073
|
+
upsertAuthProfile as upsertAuthProfile3,
|
|
8576
9074
|
buildApiKeyCredential,
|
|
8577
9075
|
applyAuthProfileConfig
|
|
8578
9076
|
} from "openclaw/plugin-sdk/provider-auth-api-key";
|
|
8579
9077
|
|
|
8580
9078
|
// gateway/config-utils.ts
|
|
8581
|
-
import * as
|
|
8582
|
-
import * as
|
|
8583
|
-
import * as
|
|
9079
|
+
import * as fs16 from "node:fs";
|
|
9080
|
+
import * as os11 from "node:os";
|
|
9081
|
+
import * as path17 from "node:path";
|
|
8584
9082
|
function configPath() {
|
|
8585
|
-
return
|
|
9083
|
+
return path17.join(os11.homedir(), ".openclaw", "openclaw.json");
|
|
8586
9084
|
}
|
|
8587
9085
|
function readConfig() {
|
|
8588
9086
|
try {
|
|
8589
|
-
return JSON.parse(
|
|
9087
|
+
return JSON.parse(fs16.readFileSync(configPath(), "utf-8"));
|
|
8590
9088
|
} catch {
|
|
8591
9089
|
return {};
|
|
8592
9090
|
}
|
|
8593
9091
|
}
|
|
8594
9092
|
function writeConfig(cfg) {
|
|
8595
|
-
|
|
9093
|
+
fs16.writeFileSync(configPath(), JSON.stringify(cfg, null, 2) + `
|
|
8596
9094
|
`, "utf-8");
|
|
8597
9095
|
}
|
|
8598
9096
|
|
|
8599
9097
|
// gateway/providers.ts
|
|
8600
|
-
import * as
|
|
8601
|
-
import * as
|
|
8602
|
-
import * as
|
|
9098
|
+
import * as fs17 from "node:fs";
|
|
9099
|
+
import * as os12 from "node:os";
|
|
9100
|
+
import * as path18 from "node:path";
|
|
9101
|
+
function resolveOpenClawRoot3() {
|
|
9102
|
+
const fromEnv = process.env.OPENCLAW_STATE_DIR?.trim();
|
|
9103
|
+
return fromEnv ? path18.resolve(fromEnv) : path18.join(os12.homedir(), ".openclaw");
|
|
9104
|
+
}
|
|
8603
9105
|
function siblingAgentDirs() {
|
|
8604
|
-
const root =
|
|
9106
|
+
const root = path18.join(resolveOpenClawRoot3(), "agents");
|
|
8605
9107
|
let entries;
|
|
8606
9108
|
try {
|
|
8607
|
-
entries =
|
|
9109
|
+
entries = fs17.readdirSync(root, { withFileTypes: true });
|
|
8608
9110
|
} catch {
|
|
8609
9111
|
return [];
|
|
8610
9112
|
}
|
|
@@ -8612,9 +9114,9 @@ function siblingAgentDirs() {
|
|
|
8612
9114
|
for (const entry of entries) {
|
|
8613
9115
|
if (!entry.isDirectory() && !entry.isSymbolicLink())
|
|
8614
9116
|
continue;
|
|
8615
|
-
const dir =
|
|
9117
|
+
const dir = path18.join(root, entry.name, "agent");
|
|
8616
9118
|
try {
|
|
8617
|
-
if (
|
|
9119
|
+
if (fs17.statSync(dir).isDirectory())
|
|
8618
9120
|
out.push(dir);
|
|
8619
9121
|
} catch {}
|
|
8620
9122
|
}
|
|
@@ -8684,20 +9186,20 @@ async function ensureModels(run) {
|
|
|
8684
9186
|
}
|
|
8685
9187
|
function readOAuthExpiries() {
|
|
8686
9188
|
const result = new Map;
|
|
8687
|
-
const
|
|
8688
|
-
const
|
|
8689
|
-
const
|
|
8690
|
-
const agentsDir =
|
|
9189
|
+
const fs18 = __require("node:fs");
|
|
9190
|
+
const path19 = __require("node:path");
|
|
9191
|
+
const os13 = __require("node:os");
|
|
9192
|
+
const agentsDir = path19.join(os13.homedir(), ".openclaw", "agents");
|
|
8691
9193
|
let entries;
|
|
8692
9194
|
try {
|
|
8693
|
-
entries =
|
|
9195
|
+
entries = fs18.readdirSync(agentsDir);
|
|
8694
9196
|
} catch {
|
|
8695
9197
|
return result;
|
|
8696
9198
|
}
|
|
8697
9199
|
for (const name of entries) {
|
|
8698
|
-
const filePath =
|
|
9200
|
+
const filePath = path19.join(agentsDir, name, "agent", "auth-profiles.json");
|
|
8699
9201
|
try {
|
|
8700
|
-
const raw =
|
|
9202
|
+
const raw = fs18.readFileSync(filePath, "utf-8");
|
|
8701
9203
|
const data = JSON.parse(raw);
|
|
8702
9204
|
const profiles = data?.profiles ?? {};
|
|
8703
9205
|
for (const entry of Object.values(profiles)) {
|
|
@@ -8835,7 +9337,7 @@ function registerProvidersGateway(api, state2) {
|
|
|
8835
9337
|
const credential = buildApiKeyCredential(provider, apiKey);
|
|
8836
9338
|
for (const agentDir of siblingAgentDirs()) {
|
|
8837
9339
|
try {
|
|
8838
|
-
|
|
9340
|
+
upsertAuthProfile3({ profileId, credential, agentDir });
|
|
8839
9341
|
} catch {}
|
|
8840
9342
|
}
|
|
8841
9343
|
const cfg = readConfig();
|
|
@@ -8869,9 +9371,9 @@ function registerProvidersGateway(api, state2) {
|
|
|
8869
9371
|
}
|
|
8870
9372
|
writeConfig(cfg);
|
|
8871
9373
|
for (const agentDir of siblingAgentDirs()) {
|
|
8872
|
-
const file =
|
|
9374
|
+
const file = path18.join(agentDir, "auth-profiles.json");
|
|
8873
9375
|
try {
|
|
8874
|
-
const raw =
|
|
9376
|
+
const raw = fs17.readFileSync(file, "utf-8");
|
|
8875
9377
|
const data = JSON.parse(raw);
|
|
8876
9378
|
const agentProfiles = data?.profiles;
|
|
8877
9379
|
if (!agentProfiles || typeof agentProfiles !== "object")
|
|
@@ -8888,7 +9390,7 @@ function registerProvidersGateway(api, state2) {
|
|
|
8888
9390
|
changed = true;
|
|
8889
9391
|
}
|
|
8890
9392
|
if (changed)
|
|
8891
|
-
|
|
9393
|
+
fs17.writeFileSync(file, JSON.stringify(data, null, 2), "utf-8");
|
|
8892
9394
|
} catch {}
|
|
8893
9395
|
}
|
|
8894
9396
|
respond(true, { provider, configured: false });
|
|
@@ -8978,22 +9480,22 @@ ${result?.stderr ?? ""}`;
|
|
|
8978
9480
|
}
|
|
8979
9481
|
|
|
8980
9482
|
// gateway/models-config.ts
|
|
8981
|
-
import * as
|
|
8982
|
-
import * as
|
|
8983
|
-
import * as
|
|
9483
|
+
import * as fs18 from "node:fs";
|
|
9484
|
+
import * as os13 from "node:os";
|
|
9485
|
+
import * as path19 from "node:path";
|
|
8984
9486
|
function pluginConfigPath2() {
|
|
8985
|
-
return
|
|
9487
|
+
return path19.join(os13.homedir(), ".openclaw", "agentlife", "plugin-config.json");
|
|
8986
9488
|
}
|
|
8987
9489
|
function readPluginConfig2() {
|
|
8988
9490
|
try {
|
|
8989
|
-
return JSON.parse(
|
|
9491
|
+
return JSON.parse(fs18.readFileSync(pluginConfigPath2(), "utf-8"));
|
|
8990
9492
|
} catch {
|
|
8991
9493
|
return {};
|
|
8992
9494
|
}
|
|
8993
9495
|
}
|
|
8994
9496
|
function writePluginConfig2(cfg) {
|
|
8995
|
-
|
|
8996
|
-
|
|
9497
|
+
fs18.mkdirSync(path19.dirname(pluginConfigPath2()), { recursive: true });
|
|
9498
|
+
fs18.writeFileSync(pluginConfigPath2(), JSON.stringify(cfg, null, 2) + `
|
|
8997
9499
|
`, "utf-8");
|
|
8998
9500
|
}
|
|
8999
9501
|
function registerModelsConfigGateway(api) {
|
|
@@ -9137,9 +9639,12 @@ var stopObservability = null;
|
|
|
9137
9639
|
var stopDailySweep = null;
|
|
9138
9640
|
var stopQualityCheckPoller = null;
|
|
9139
9641
|
var stopCloudflared = null;
|
|
9642
|
+
function resolveOpenClawRoot4() {
|
|
9643
|
+
return process.env.OPENCLAW_STATE_DIR || path20.join(homedir17(), ".openclaw");
|
|
9644
|
+
}
|
|
9140
9645
|
function resolveInternalModel(api) {
|
|
9141
9646
|
try {
|
|
9142
|
-
const pluginCfgPath =
|
|
9647
|
+
const pluginCfgPath = path20.join(resolveOpenClawRoot4(), "agentlife", "plugin-config.json");
|
|
9143
9648
|
try {
|
|
9144
9649
|
const raw = __require("node:fs").readFileSync(pluginCfgPath, "utf-8");
|
|
9145
9650
|
const pluginCfg = JSON.parse(raw);
|
|
@@ -9165,7 +9670,24 @@ function _getState() {
|
|
|
9165
9670
|
throw new Error("plugin not registered");
|
|
9166
9671
|
return currentState;
|
|
9167
9672
|
}
|
|
9673
|
+
async function startProvisioningServices(api, state2) {
|
|
9674
|
+
const cfg = api.runtime.config.loadConfig();
|
|
9675
|
+
await provisionAgents(state2, cfg, api.runtime, console.log);
|
|
9676
|
+
await reconcileInternalSessions(state2, createdInternalSessions);
|
|
9677
|
+
await cleanupSupervisorLegacyState(state2);
|
|
9678
|
+
stopObservability = startObservabilityService(state2);
|
|
9679
|
+
stopDailySweep = startDailySweepService(state2);
|
|
9680
|
+
stopQualityCheckPoller = startQualityCheckPoller(state2);
|
|
9681
|
+
renderAllAgentWidgets(state2, api.runtime, console.log);
|
|
9682
|
+
}
|
|
9168
9683
|
function register(api) {
|
|
9684
|
+
if (!shouldStartRuntimeServices()) {
|
|
9685
|
+
console.log("[agentlife] install/inspect mode — runtime registration skipped");
|
|
9686
|
+
return;
|
|
9687
|
+
}
|
|
9688
|
+
if (shouldStartRuntimeServices()) {
|
|
9689
|
+
runInstallBootstrap();
|
|
9690
|
+
}
|
|
9169
9691
|
if (currentState) {
|
|
9170
9692
|
registerWidgetPushTool(api, currentState);
|
|
9171
9693
|
api.registerChannel({ plugin: createAgentlifeChannel(currentState.channelState) });
|
|
@@ -9175,7 +9697,8 @@ function register(api) {
|
|
|
9175
9697
|
return;
|
|
9176
9698
|
}
|
|
9177
9699
|
registered = true;
|
|
9178
|
-
const
|
|
9700
|
+
const fallbackRoot = resolveOpenClawRoot4();
|
|
9701
|
+
const fallbackDir = path20.join(fallbackRoot, "agentlife");
|
|
9179
9702
|
const state2 = {
|
|
9180
9703
|
fileSurfaceStorage: null,
|
|
9181
9704
|
surfaceIndex: null,
|
|
@@ -9187,9 +9710,9 @@ function register(api) {
|
|
|
9187
9710
|
agentDbs: new Map,
|
|
9188
9711
|
historyDb: null,
|
|
9189
9712
|
agentlifeStateDir: fallbackDir,
|
|
9190
|
-
registryFilePath:
|
|
9191
|
-
dbBaseDir:
|
|
9192
|
-
historyDbPath:
|
|
9713
|
+
registryFilePath: path20.join(fallbackDir, "agent-registry.json"),
|
|
9714
|
+
dbBaseDir: path20.join(fallbackDir, "db"),
|
|
9715
|
+
historyDbPath: path20.join(fallbackDir, "agentlife.db"),
|
|
9193
9716
|
runCommand: api.runtime.system?.runCommandWithTimeout ?? null,
|
|
9194
9717
|
enqueueSystemEvent: null,
|
|
9195
9718
|
requestHeartbeatNow: null,
|
|
@@ -9201,12 +9724,12 @@ function register(api) {
|
|
|
9201
9724
|
currentState = state2;
|
|
9202
9725
|
api.registerChannel({ plugin: createAgentlifeChannel(state2.channelState) });
|
|
9203
9726
|
console.log("[agentlife] channel registered, session format: %s", buildAgentSessionKey("example"));
|
|
9204
|
-
if (
|
|
9727
|
+
if (shouldStartRuntimeServices() && existsSync8(fallbackDir)) {
|
|
9205
9728
|
try {
|
|
9206
9729
|
const db = getOrCreateHistoryDb(state2);
|
|
9207
9730
|
state2.surfaceIndex = new SurfaceIndex(db);
|
|
9208
9731
|
state2.followupQueue = new FollowupQueue(db);
|
|
9209
|
-
state2.fileSurfaceStorage = new FileSurfaceStorage;
|
|
9732
|
+
state2.fileSurfaceStorage = new FileSurfaceStorage({ openclawRoot: fallbackRoot });
|
|
9210
9733
|
} catch (e) {
|
|
9211
9734
|
console.warn("[agentlife] eager surface storage init failed:", e?.message);
|
|
9212
9735
|
}
|
|
@@ -9216,20 +9739,32 @@ function register(api) {
|
|
|
9216
9739
|
registerSurfacesService(api, state2);
|
|
9217
9740
|
api.registerService({
|
|
9218
9741
|
id: "agentlife-provisioning",
|
|
9219
|
-
start:
|
|
9220
|
-
|
|
9221
|
-
|
|
9222
|
-
|
|
9223
|
-
|
|
9224
|
-
|
|
9225
|
-
stopDailySweep = startDailySweepService(state2);
|
|
9226
|
-
stopQualityCheckPoller = startQualityCheckPoller(state2);
|
|
9227
|
-
renderAllAgentWidgets(state2, api.runtime, console.log);
|
|
9742
|
+
start: () => {
|
|
9743
|
+
if (!shouldStartRuntimeServices())
|
|
9744
|
+
return;
|
|
9745
|
+
startProvisioningServices(api, state2).catch((err) => {
|
|
9746
|
+
console.warn("[agentlife] provisioning service failed:", err?.message ?? err);
|
|
9747
|
+
});
|
|
9228
9748
|
}
|
|
9229
9749
|
});
|
|
9230
9750
|
registerConfigOptimizer(api, state2);
|
|
9231
9751
|
registerPairingServices(api);
|
|
9232
|
-
|
|
9752
|
+
api.registerService({
|
|
9753
|
+
id: "agentlife-cloudflared-supervisor",
|
|
9754
|
+
start: () => {
|
|
9755
|
+
if (!shouldStartRuntimeServices())
|
|
9756
|
+
return;
|
|
9757
|
+
if (!stopCloudflared) {
|
|
9758
|
+
stopCloudflared = startCloudflaredSupervisor();
|
|
9759
|
+
}
|
|
9760
|
+
},
|
|
9761
|
+
stop: () => {
|
|
9762
|
+
if (stopCloudflared) {
|
|
9763
|
+
stopCloudflared();
|
|
9764
|
+
stopCloudflared = null;
|
|
9765
|
+
}
|
|
9766
|
+
}
|
|
9767
|
+
});
|
|
9233
9768
|
api.registerService({
|
|
9234
9769
|
id: "agentlife-shutdown",
|
|
9235
9770
|
start: () => {},
|
|
@@ -9254,7 +9789,15 @@ function register(api) {
|
|
|
9254
9789
|
closeAllDbs(state2);
|
|
9255
9790
|
}
|
|
9256
9791
|
});
|
|
9257
|
-
|
|
9792
|
+
api.registerService({
|
|
9793
|
+
id: "agentlife-followups",
|
|
9794
|
+
start: () => {
|
|
9795
|
+
if (!shouldStartRuntimeServices())
|
|
9796
|
+
return;
|
|
9797
|
+
initFollowupSystem(api, state2);
|
|
9798
|
+
},
|
|
9799
|
+
stop: () => stopFollowupSystem(state2)
|
|
9800
|
+
});
|
|
9258
9801
|
registerPromptStateHook(api, state2);
|
|
9259
9802
|
registerWidgetPushTool(api, state2);
|
|
9260
9803
|
registerActivityHooks(api, state2);
|
|
@@ -9270,7 +9813,7 @@ function register(api) {
|
|
|
9270
9813
|
registerProvidersGateway(api, state2);
|
|
9271
9814
|
registerModelsConfigGateway(api);
|
|
9272
9815
|
registerWebApp(api);
|
|
9273
|
-
const notifyConfigPath =
|
|
9816
|
+
const notifyConfigPath = path20.join(fallbackDir, "notification-config.json");
|
|
9274
9817
|
api.registerGatewayMethod("agentlife.notifications.register", ({ params, respond }) => {
|
|
9275
9818
|
const serverUrl = typeof params?.serverUrl === "string" ? params.serverUrl.trim() : "";
|
|
9276
9819
|
const apiKey = typeof params?.apiKey === "string" ? params.apiKey.trim() : "";
|
|
@@ -9278,9 +9821,9 @@ function register(api) {
|
|
|
9278
9821
|
return respond(false, { error: "missing serverUrl or apiKey" });
|
|
9279
9822
|
}
|
|
9280
9823
|
try {
|
|
9281
|
-
const { writeFileSync:
|
|
9282
|
-
|
|
9283
|
-
|
|
9824
|
+
const { writeFileSync: writeFileSync12, mkdirSync: mkdirSync10 } = __require("node:fs");
|
|
9825
|
+
mkdirSync10(path20.dirname(notifyConfigPath), { recursive: true });
|
|
9826
|
+
writeFileSync12(notifyConfigPath, JSON.stringify({ serverUrl, apiKey }));
|
|
9284
9827
|
} catch {}
|
|
9285
9828
|
respond(true, { registered: true });
|
|
9286
9829
|
}, { scope: "operator.write" });
|