agentlife 2.6.27 → 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 +832 -273
- package/openclaw.plugin.json +8 -0
- package/package.json +16 -5
- 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
|
}
|
|
@@ -1823,7 +1916,21 @@ async function provisionAgents(state, cfg, runtime, log) {
|
|
|
1823
1916
|
globalAllowWritten = true;
|
|
1824
1917
|
}
|
|
1825
1918
|
}
|
|
1826
|
-
|
|
1919
|
+
const currentHooksAccess = rawCfgForVisibility?.plugins?.entries?.agentlife?.hooks?.allowConversationAccess;
|
|
1920
|
+
let hooksAccessWritten = false;
|
|
1921
|
+
if (currentHooksAccess !== true) {
|
|
1922
|
+
if (!rawCfgForVisibility.plugins)
|
|
1923
|
+
rawCfgForVisibility.plugins = {};
|
|
1924
|
+
if (!rawCfgForVisibility.plugins.entries)
|
|
1925
|
+
rawCfgForVisibility.plugins.entries = {};
|
|
1926
|
+
if (!rawCfgForVisibility.plugins.entries.agentlife)
|
|
1927
|
+
rawCfgForVisibility.plugins.entries.agentlife = {};
|
|
1928
|
+
if (!rawCfgForVisibility.plugins.entries.agentlife.hooks)
|
|
1929
|
+
rawCfgForVisibility.plugins.entries.agentlife.hooks = {};
|
|
1930
|
+
rawCfgForVisibility.plugins.entries.agentlife.hooks.allowConversationAccess = true;
|
|
1931
|
+
hooksAccessWritten = true;
|
|
1932
|
+
}
|
|
1933
|
+
if (visibilityWritten || a2aWritten || globalAllowWritten || hooksAccessWritten) {
|
|
1827
1934
|
writeFileSync(configPath, JSON.stringify(rawCfgForVisibility, null, 2) + `
|
|
1828
1935
|
`, "utf-8");
|
|
1829
1936
|
configChanged = true;
|
|
@@ -1833,6 +1940,8 @@ async function provisionAgents(state, cfg, runtime, log) {
|
|
|
1833
1940
|
log("[agentlife] set tools.agentToAgent.enabled=true (cross-agent sends)");
|
|
1834
1941
|
if (globalAllowWritten)
|
|
1835
1942
|
log('[agentlife] added "*" to tools.allow (unblock exec/read/write for provisioned agents)');
|
|
1943
|
+
if (hooksAccessWritten)
|
|
1944
|
+
log("[agentlife] set plugins.entries.agentlife.hooks.allowConversationAccess=true (typed hooks)");
|
|
1836
1945
|
}
|
|
1837
1946
|
if (configChanged) {
|
|
1838
1947
|
const configPath2 = path4.join(os.homedir(), ".openclaw", "openclaw.json");
|
|
@@ -2069,7 +2178,6 @@ var KNOWN_BODY_KEYWORDS = new Set([
|
|
|
2069
2178
|
"button",
|
|
2070
2179
|
"image",
|
|
2071
2180
|
"icon",
|
|
2072
|
-
"textfield",
|
|
2073
2181
|
"checkbox",
|
|
2074
2182
|
"sparkline",
|
|
2075
2183
|
"progress",
|
|
@@ -2101,7 +2209,6 @@ var INPUT_SURFACE_ACTIONS = new Set([
|
|
|
2101
2209
|
var TEXT_LEVELS = new Set(["h1", "h2", "h3", "h4", "h5", "body", "caption"]);
|
|
2102
2210
|
var TEXT_HINTS = new Set(["icon", "avatar", "smallfeature", "mediumfeature", "largefeature", "header"]);
|
|
2103
2211
|
var IMG_FITS = new Set(["contain", "cover", "fill", "none", "scale-down"]);
|
|
2104
|
-
var TF_TYPES = new Set(["email", "shorttext", "number", "phone", "longtext", "date", "obscured"]);
|
|
2105
2212
|
var ALIGN_VALUES = new Set(["start", "center", "end", "stretch"]);
|
|
2106
2213
|
var DISTRIBUTE_VALUES = new Set(["start", "center", "end", "spacebetween", "spacearound", "spaceevenly"]);
|
|
2107
2214
|
var TREND_VALUES = new Set(["up", "down", "flat"]);
|
|
@@ -2156,14 +2263,6 @@ var COMPONENT_CATALOG = {
|
|
|
2156
2263
|
}
|
|
2157
2264
|
},
|
|
2158
2265
|
icon: { positionalTokens: new Set, positionalFree: true, attrs: {} },
|
|
2159
|
-
textfield: {
|
|
2160
|
-
positionalTokens: new Set,
|
|
2161
|
-
positionalFree: true,
|
|
2162
|
-
attrs: {
|
|
2163
|
-
type: { kind: "enum", values: TF_TYPES },
|
|
2164
|
-
placeholder: { kind: "free" }
|
|
2165
|
-
}
|
|
2166
|
-
},
|
|
2167
2266
|
checkbox: {
|
|
2168
2267
|
positionalTokens: new Set(["checked"]),
|
|
2169
2268
|
positionalFree: true,
|
|
@@ -3457,9 +3556,9 @@ Each turn:
|
|
|
3457
3556
|
2. Not enough → \`agentlife_push\` the SAME surfaceId \`welcome-input\` with:
|
|
3458
3557
|
- h3 question generated from what the user just said
|
|
3459
3558
|
- 2–4 multichoice buttons \`action=choice\`, options derived from the user's own words (NEVER hardcoded domain lists)
|
|
3460
|
-
- \`textfield placeholder="Something else…"\` escape hatch
|
|
3461
3559
|
- updated \`context: {"phase":"welcome","turn":N+1,"answers":[...]}\`
|
|
3462
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.
|
|
3463
3562
|
Respond \`done\`.
|
|
3464
3563
|
3. Enough → create the generalist and hand off the dashboard:
|
|
3465
3564
|
- Workspace under \`$HOME/.openclaw/workspace-{id}\` (id = slugified short name or "me")
|
|
@@ -3489,7 +3588,6 @@ function renderWelcomeWidget(state, log) {
|
|
|
3489
3588
|
` column`,
|
|
3490
3589
|
` text "What do you want to track or improve?" h3`,
|
|
3491
3590
|
` text "One line. Anything — meals, money, a project, a habit." body`,
|
|
3492
|
-
` textfield placeholder="Type anything…"`,
|
|
3493
3591
|
`goal: Onboard the user to their first agent via a guided interview`,
|
|
3494
3592
|
`followup: +30m "If unanswered, replace the question with a gentler prompt."`,
|
|
3495
3593
|
`context: {"phase":"welcome","turn":1,"answers":[]}`
|
|
@@ -3517,7 +3615,7 @@ function deleteWelcomeWidget(state, log) {
|
|
|
3517
3615
|
}
|
|
3518
3616
|
|
|
3519
3617
|
// services/surfaces-init.ts
|
|
3520
|
-
import * as
|
|
3618
|
+
import * as path6 from "node:path";
|
|
3521
3619
|
|
|
3522
3620
|
// storage/reconciler.ts
|
|
3523
3621
|
var defaultLogger = {
|
|
@@ -3765,23 +3863,45 @@ function dispatchRehydrate(state, runtime, log = console.log) {
|
|
|
3765
3863
|
log(`[agentlife:rehydrate] dispatched rehydrate to ${orphaned.length} orphaned agent(s): ${orphaned.join(", ")}`);
|
|
3766
3864
|
}
|
|
3767
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
|
+
|
|
3768
3877
|
// services/surfaces-init.ts
|
|
3769
3878
|
function registerSurfacesService(api, state) {
|
|
3770
3879
|
api.registerService({
|
|
3771
3880
|
id: "agentlife-surfaces",
|
|
3772
3881
|
start: async (ctx) => {
|
|
3773
|
-
|
|
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
|
+
}
|
|
3774
3895
|
state.agentlifeStateDir = agentlifeDir;
|
|
3775
|
-
state.registryFilePath =
|
|
3776
|
-
state.dbBaseDir =
|
|
3777
|
-
state.historyDbPath =
|
|
3896
|
+
state.registryFilePath = path6.join(agentlifeDir, "agent-registry.json");
|
|
3897
|
+
state.dbBaseDir = path6.join(agentlifeDir, "db");
|
|
3898
|
+
state.historyDbPath = nextHistoryDbPath;
|
|
3778
3899
|
const db = getOrCreateHistoryDb(state);
|
|
3779
3900
|
if (!state.surfaceIndex)
|
|
3780
3901
|
state.surfaceIndex = new SurfaceIndex(db);
|
|
3781
3902
|
if (!state.followupQueue)
|
|
3782
3903
|
state.followupQueue = new FollowupQueue(db);
|
|
3783
|
-
|
|
3784
|
-
state.fileSurfaceStorage = new FileSurfaceStorage;
|
|
3904
|
+
state.fileSurfaceStorage = new FileSurfaceStorage({ openclawRoot: ctx.stateDir });
|
|
3785
3905
|
await loadRegistryFromDisk(state);
|
|
3786
3906
|
try {
|
|
3787
3907
|
const knownAgents = collectKnownAgents(api.runtime);
|
|
@@ -3831,11 +3951,11 @@ function collectKnownAgents(runtime) {
|
|
|
3831
3951
|
|
|
3832
3952
|
// services/config-optimizer.ts
|
|
3833
3953
|
import * as fs5 from "node:fs/promises";
|
|
3834
|
-
import * as
|
|
3954
|
+
import * as path7 from "node:path";
|
|
3835
3955
|
import * as os2 from "node:os";
|
|
3836
3956
|
var TARGET_MAX_PING_PONG = 1;
|
|
3837
3957
|
var TARGET_MAX_CONCURRENT = 10;
|
|
3838
|
-
var CONFIG_PATH =
|
|
3958
|
+
var CONFIG_PATH = process.env.OPENCLAW_CONFIG_PATH || path7.join(os2.homedir(), ".openclaw", "openclaw.json");
|
|
3839
3959
|
async function readRawConfigFromDisk() {
|
|
3840
3960
|
const raw = await fs5.readFile(CONFIG_PATH, "utf-8");
|
|
3841
3961
|
return JSON.parse(raw);
|
|
@@ -3871,8 +3991,10 @@ function registerConfigOptimizer(api, _state) {
|
|
|
3871
3991
|
api.registerService({
|
|
3872
3992
|
id: "agentlife-config-optimizer",
|
|
3873
3993
|
start: async (ctx) => {
|
|
3874
|
-
|
|
3875
|
-
|
|
3994
|
+
if (!shouldStartRuntimeServices())
|
|
3995
|
+
return;
|
|
3996
|
+
const configBackupDir = path7.join(ctx.stateDir, "agentlife");
|
|
3997
|
+
const configBackupPath = path7.join(configBackupDir, "config-backup.json");
|
|
3876
3998
|
const cfg = api.runtime.config.loadConfig();
|
|
3877
3999
|
const currentPPT = cfg.session?.agentToAgent?.maxPingPongTurns;
|
|
3878
4000
|
const currentMC = cfg.agents?.defaults?.maxConcurrent;
|
|
@@ -3883,10 +4005,16 @@ function registerConfigOptimizer(api, _state) {
|
|
|
3883
4005
|
return;
|
|
3884
4006
|
}
|
|
3885
4007
|
await fs5.mkdir(configBackupDir, { recursive: true });
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
}
|
|
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
|
+
`);
|
|
3890
4018
|
const fileCfg = await readRawConfigFromDisk();
|
|
3891
4019
|
if (needsPPT) {
|
|
3892
4020
|
fileCfg.session ??= {};
|
|
@@ -3908,13 +4036,196 @@ function registerConfigOptimizer(api, _state) {
|
|
|
3908
4036
|
},
|
|
3909
4037
|
stop: async (ctx) => {
|
|
3910
4038
|
try {
|
|
3911
|
-
const backupPath =
|
|
4039
|
+
const backupPath = path7.join(ctx.stateDir, "agentlife", "config-backup.json");
|
|
3912
4040
|
await restoreConfigFromBackup(api, backupPath);
|
|
3913
4041
|
} catch {}
|
|
3914
4042
|
}
|
|
3915
4043
|
});
|
|
3916
4044
|
}
|
|
3917
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
|
+
|
|
3918
4229
|
// services/session-reconcile.ts
|
|
3919
4230
|
function modelMatches(configured, sessionProvider, sessionModel) {
|
|
3920
4231
|
if (!sessionModel)
|
|
@@ -4077,7 +4388,7 @@ async function reconcileInternalSessions(state, createdInternalSessions) {
|
|
|
4077
4388
|
}
|
|
4078
4389
|
|
|
4079
4390
|
// services/supervisor-cleanup.ts
|
|
4080
|
-
import * as
|
|
4391
|
+
import * as fs7 from "node:fs";
|
|
4081
4392
|
var STALE_SUPERVISOR_SURFACE = "supervisor-daily";
|
|
4082
4393
|
var STALE_SUPERVISOR_DIRECT_SESSION = "agent:supervisor:agentlife:direct:operator";
|
|
4083
4394
|
async function cleanupSupervisorLegacyState(state) {
|
|
@@ -4090,7 +4401,7 @@ async function cleanupSupervisorLegacyState(state) {
|
|
|
4090
4401
|
removeFollowup(state, STALE_SUPERVISOR_SURFACE);
|
|
4091
4402
|
if (view2 && !view2.isTransient && view2.path) {
|
|
4092
4403
|
try {
|
|
4093
|
-
|
|
4404
|
+
fs7.unlinkSync(view2.path);
|
|
4094
4405
|
} catch {}
|
|
4095
4406
|
}
|
|
4096
4407
|
state.surfaceIndex?.delete(STALE_SUPERVISOR_SURFACE);
|
|
@@ -4272,6 +4583,8 @@ function startObservabilityService(state) {
|
|
|
4272
4583
|
|
|
4273
4584
|
// hooks/activity-hooks.ts
|
|
4274
4585
|
import * as fsSync2 from "node:fs";
|
|
4586
|
+
import * as nodePath from "node:path";
|
|
4587
|
+
import * as nodeOs from "node:os";
|
|
4275
4588
|
|
|
4276
4589
|
// usage.ts
|
|
4277
4590
|
var MODEL_COSTS = {
|
|
@@ -4920,6 +5233,62 @@ ${parts.join(`
|
|
|
4920
5233
|
}
|
|
4921
5234
|
var QUALITY_CHECK_MAX_WAIT_MS = 5000;
|
|
4922
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
|
+
}
|
|
4923
5292
|
function processPendingQualityChecks(state) {
|
|
4924
5293
|
if (state.disabled || !state.historyDb)
|
|
4925
5294
|
return 0;
|
|
@@ -4961,6 +5330,21 @@ function processPendingQualityChecks(state) {
|
|
|
4961
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);
|
|
4962
5331
|
if ((pushed?.c ?? 0) > 0)
|
|
4963
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
|
+
}
|
|
4964
5348
|
recordActivity(state, "quality_warning", row.sessionKey, row.agentId, {
|
|
4965
5349
|
runId: row.runId,
|
|
4966
5350
|
data: JSON.stringify({ issue: "no_widget_pushed", trigger: row.trigger })
|
|
@@ -5059,7 +5443,7 @@ function rescueOrphanedSurfaces(state, agentId, error) {
|
|
|
5059
5443
|
}
|
|
5060
5444
|
|
|
5061
5445
|
// services/escalation.ts
|
|
5062
|
-
import * as
|
|
5446
|
+
import * as fs8 from "node:fs";
|
|
5063
5447
|
var PATHOLOGY2 = process.env.PATHOLOGY_TEST_MODE === "1";
|
|
5064
5448
|
var ESCALATION_REVIEW_THRESHOLD_MS = PATHOLOGY2 ? 2 * 60 * 1000 : 48 * 60 * 60 * 1000;
|
|
5065
5449
|
var TREND_WINDOW_DAYS = 7;
|
|
@@ -5125,7 +5509,7 @@ function clearEscalationSurface(state, agentId) {
|
|
|
5125
5509
|
const view2 = getSurface(state, surfaceId);
|
|
5126
5510
|
if (view2 && !view2.isTransient && view2.path) {
|
|
5127
5511
|
try {
|
|
5128
|
-
|
|
5512
|
+
fs8.unlinkSync(view2.path);
|
|
5129
5513
|
} catch {}
|
|
5130
5514
|
}
|
|
5131
5515
|
state.surfaceIndex.delete(surfaceId);
|
|
@@ -5369,31 +5753,32 @@ function startDailySweepService(state) {
|
|
|
5369
5753
|
import * as crypto4 from "node:crypto";
|
|
5370
5754
|
import * as fsSync3 from "node:fs";
|
|
5371
5755
|
import { createRequire as createRequire3 } from "node:module";
|
|
5372
|
-
import * as
|
|
5373
|
-
import * as
|
|
5756
|
+
import * as os7 from "node:os";
|
|
5757
|
+
import * as path12 from "node:path";
|
|
5374
5758
|
|
|
5375
5759
|
// gateway/web-app.ts
|
|
5376
5760
|
import * as crypto3 from "node:crypto";
|
|
5377
|
-
import * as
|
|
5378
|
-
import * as
|
|
5379
|
-
import * as
|
|
5761
|
+
import * as os6 from "node:os";
|
|
5762
|
+
import * as path11 from "node:path";
|
|
5763
|
+
import * as fs11 from "node:fs";
|
|
5380
5764
|
|
|
5381
5765
|
// services/pairing-access-token.ts
|
|
5382
5766
|
import * as crypto from "node:crypto";
|
|
5383
|
-
import * as
|
|
5384
|
-
import * as
|
|
5385
|
-
import * as
|
|
5767
|
+
import * as fs9 from "node:fs";
|
|
5768
|
+
import * as os4 from "node:os";
|
|
5769
|
+
import * as path9 from "node:path";
|
|
5386
5770
|
var cachedToken = null;
|
|
5387
5771
|
function pairingAccessPath() {
|
|
5388
|
-
|
|
5772
|
+
const stateDir = process.env.OPENCLAW_STATE_DIR || path9.join(os4.homedir(), ".openclaw");
|
|
5773
|
+
return path9.join(stateDir, "agentlife", "pairing-access.json");
|
|
5389
5774
|
}
|
|
5390
5775
|
function loadOrCreatePairingAccessToken() {
|
|
5391
5776
|
if (cachedToken)
|
|
5392
5777
|
return cachedToken;
|
|
5393
5778
|
const filePath = pairingAccessPath();
|
|
5394
5779
|
try {
|
|
5395
|
-
if (
|
|
5396
|
-
const raw =
|
|
5780
|
+
if (fs9.existsSync(filePath)) {
|
|
5781
|
+
const raw = fs9.readFileSync(filePath, "utf-8");
|
|
5397
5782
|
const obj = JSON.parse(raw);
|
|
5398
5783
|
const token2 = typeof obj?.token === "string" ? obj.token : null;
|
|
5399
5784
|
if (token2 && token2.length >= 32) {
|
|
@@ -5402,12 +5787,12 @@ function loadOrCreatePairingAccessToken() {
|
|
|
5402
5787
|
}
|
|
5403
5788
|
}
|
|
5404
5789
|
const token = crypto.randomBytes(32).toString("base64url");
|
|
5405
|
-
const dir =
|
|
5406
|
-
if (!
|
|
5407
|
-
|
|
5408
|
-
|
|
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 });
|
|
5409
5794
|
try {
|
|
5410
|
-
|
|
5795
|
+
fs9.chmodSync(filePath, 384);
|
|
5411
5796
|
} catch {}
|
|
5412
5797
|
cachedToken = token;
|
|
5413
5798
|
return token;
|
|
@@ -5420,25 +5805,28 @@ function loadOrCreatePairingAccessToken() {
|
|
|
5420
5805
|
// services/cloudflared-supervisor.ts
|
|
5421
5806
|
import { spawn, spawnSync } from "node:child_process";
|
|
5422
5807
|
import * as crypto2 from "node:crypto";
|
|
5423
|
-
import * as
|
|
5424
|
-
import * as
|
|
5425
|
-
import * as
|
|
5426
|
-
var
|
|
5427
|
-
var
|
|
5428
|
-
var
|
|
5429
|
-
var
|
|
5430
|
-
var
|
|
5431
|
-
var
|
|
5432
|
-
var
|
|
5433
|
-
var
|
|
5434
|
-
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);
|
|
5435
5823
|
var API_BASE = process.env.AGENTLIFE_API_BASE || "https://api.agentlife.app";
|
|
5436
5824
|
var RESTART_DELAY_MS = 5000;
|
|
5437
5825
|
var STABLE_RUNTIME_MS = 60000;
|
|
5438
5826
|
function createInitialState() {
|
|
5439
5827
|
let resolver;
|
|
5440
|
-
const promise = new Promise((
|
|
5441
|
-
resolver =
|
|
5828
|
+
const promise = new Promise((resolve2) => {
|
|
5829
|
+
resolver = resolve2;
|
|
5442
5830
|
});
|
|
5443
5831
|
return {
|
|
5444
5832
|
tunnelInfo: null,
|
|
@@ -5459,7 +5847,7 @@ function getTunnelInfo() {
|
|
|
5459
5847
|
function awaitTunnelReady(timeoutMs) {
|
|
5460
5848
|
return Promise.race([
|
|
5461
5849
|
state.readyPromise,
|
|
5462
|
-
new Promise((
|
|
5850
|
+
new Promise((resolve2) => setTimeout(() => resolve2(null), timeoutMs))
|
|
5463
5851
|
]);
|
|
5464
5852
|
}
|
|
5465
5853
|
function startCloudflaredSupervisor() {
|
|
@@ -5551,20 +5939,20 @@ async function doBootstrap() {
|
|
|
5551
5939
|
return tunnelInfo;
|
|
5552
5940
|
}
|
|
5553
5941
|
function isPairRequested() {
|
|
5554
|
-
return
|
|
5942
|
+
return fs10.existsSync(PAIR_REQUEST_MARKER);
|
|
5555
5943
|
}
|
|
5556
5944
|
function requestPair() {
|
|
5557
5945
|
try {
|
|
5558
|
-
if (!
|
|
5559
|
-
|
|
5560
|
-
|
|
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 });
|
|
5561
5949
|
} catch (err) {
|
|
5562
5950
|
console.warn(`[cloudflared-supervisor] failed to write pair-request marker: ${err?.message ?? err}`);
|
|
5563
5951
|
}
|
|
5564
5952
|
}
|
|
5565
5953
|
function clearPairRequest() {
|
|
5566
5954
|
try {
|
|
5567
|
-
|
|
5955
|
+
fs10.unlinkSync(PAIR_REQUEST_MARKER);
|
|
5568
5956
|
} catch {}
|
|
5569
5957
|
}
|
|
5570
5958
|
function parseRetryAfter(value) {
|
|
@@ -5588,18 +5976,18 @@ function scheduleProvisionRetry(delayMs) {
|
|
|
5588
5976
|
}, delayMs);
|
|
5589
5977
|
}
|
|
5590
5978
|
function ensureDirs() {
|
|
5591
|
-
if (!
|
|
5592
|
-
|
|
5593
|
-
if (!
|
|
5594
|
-
|
|
5595
|
-
if (!
|
|
5596
|
-
|
|
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 });
|
|
5597
5985
|
}
|
|
5598
5986
|
function readIdentityFile(filePath) {
|
|
5599
|
-
if (!
|
|
5987
|
+
if (!fs10.existsSync(filePath))
|
|
5600
5988
|
return null;
|
|
5601
5989
|
try {
|
|
5602
|
-
const raw =
|
|
5990
|
+
const raw = fs10.readFileSync(filePath, "utf-8");
|
|
5603
5991
|
const parsed = JSON.parse(raw);
|
|
5604
5992
|
if (typeof parsed.deviceId === "string" && typeof parsed.deviceSecret === "string") {
|
|
5605
5993
|
return { deviceId: parsed.deviceId, deviceSecret: parsed.deviceSecret };
|
|
@@ -5617,14 +6005,14 @@ function loadDeviceIdentity() {
|
|
|
5617
6005
|
if (!legacy)
|
|
5618
6006
|
return null;
|
|
5619
6007
|
try {
|
|
5620
|
-
if (!
|
|
5621
|
-
|
|
5622
|
-
|
|
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 });
|
|
5623
6011
|
try {
|
|
5624
|
-
|
|
6012
|
+
fs10.chmodSync(DEVICE_FILE, 384);
|
|
5625
6013
|
} catch {}
|
|
5626
6014
|
try {
|
|
5627
|
-
|
|
6015
|
+
fs10.unlinkSync(LEGACY_DEVICE_FILE);
|
|
5628
6016
|
} catch {}
|
|
5629
6017
|
console.log(`[cloudflared-supervisor] migrated device.json to ${DEVICE_FILE}`);
|
|
5630
6018
|
} catch (err) {
|
|
@@ -5636,25 +6024,25 @@ function loadOrCreateDeviceIdentity() {
|
|
|
5636
6024
|
const existing = loadDeviceIdentity();
|
|
5637
6025
|
if (existing)
|
|
5638
6026
|
return existing;
|
|
5639
|
-
if (!
|
|
5640
|
-
|
|
6027
|
+
if (!fs10.existsSync(IDENTITY_DIR))
|
|
6028
|
+
fs10.mkdirSync(IDENTITY_DIR, { recursive: true, mode: 448 });
|
|
5641
6029
|
const identity = {
|
|
5642
6030
|
deviceId: crypto2.randomUUID(),
|
|
5643
6031
|
deviceSecret: crypto2.randomBytes(32).toString("base64url")
|
|
5644
6032
|
};
|
|
5645
|
-
|
|
6033
|
+
fs10.writeFileSync(DEVICE_FILE, JSON.stringify(identity, null, 2), { mode: 384 });
|
|
5646
6034
|
try {
|
|
5647
|
-
|
|
6035
|
+
fs10.chmodSync(DEVICE_FILE, 384);
|
|
5648
6036
|
} catch {}
|
|
5649
6037
|
console.log(`[cloudflared-supervisor] generated new device identity (deviceId=${identity.deviceId})`);
|
|
5650
6038
|
return identity;
|
|
5651
6039
|
}
|
|
5652
6040
|
var AGENTLIFE_API_BASE = API_BASE;
|
|
5653
6041
|
function loadCachedTunnel() {
|
|
5654
|
-
if (!
|
|
6042
|
+
if (!fs10.existsSync(TUNNEL_FILE))
|
|
5655
6043
|
return null;
|
|
5656
6044
|
try {
|
|
5657
|
-
const raw =
|
|
6045
|
+
const raw = fs10.readFileSync(TUNNEL_FILE, "utf-8");
|
|
5658
6046
|
const parsed = JSON.parse(raw);
|
|
5659
6047
|
if (typeof parsed.subdomain === "string" && typeof parsed.hostname === "string" && typeof parsed.tunnelUrl === "string" && typeof parsed.tunnelToken === "string" && typeof parsed.provisionedAt === "number") {
|
|
5660
6048
|
return parsed;
|
|
@@ -5663,9 +6051,9 @@ function loadCachedTunnel() {
|
|
|
5663
6051
|
return null;
|
|
5664
6052
|
}
|
|
5665
6053
|
function persistTunnel(info) {
|
|
5666
|
-
|
|
6054
|
+
fs10.writeFileSync(TUNNEL_FILE, JSON.stringify(info, null, 2), { mode: 384 });
|
|
5667
6055
|
try {
|
|
5668
|
-
|
|
6056
|
+
fs10.chmodSync(TUNNEL_FILE, 384);
|
|
5669
6057
|
} catch {}
|
|
5670
6058
|
}
|
|
5671
6059
|
async function provisionTunnel(identity) {
|
|
@@ -5718,14 +6106,14 @@ async function provisionTunnel(identity) {
|
|
|
5718
6106
|
}
|
|
5719
6107
|
}
|
|
5720
6108
|
function ensureCloudflaredBinary() {
|
|
5721
|
-
if (
|
|
6109
|
+
if (fs10.existsSync(CLOUDFLARED_PATH)) {
|
|
5722
6110
|
try {
|
|
5723
|
-
|
|
6111
|
+
fs10.accessSync(CLOUDFLARED_PATH, fs10.constants.X_OK);
|
|
5724
6112
|
return CLOUDFLARED_PATH;
|
|
5725
6113
|
} catch {}
|
|
5726
6114
|
}
|
|
5727
|
-
const platform2 =
|
|
5728
|
-
const arch2 =
|
|
6115
|
+
const platform2 = os5.platform();
|
|
6116
|
+
const arch2 = os5.arch();
|
|
5729
6117
|
const release = detectCloudflaredRelease(platform2, arch2);
|
|
5730
6118
|
if (!release) {
|
|
5731
6119
|
console.warn(`[cloudflared-supervisor] unsupported platform: ${platform2}/${arch2}`);
|
|
@@ -5738,28 +6126,28 @@ function ensureCloudflaredBinary() {
|
|
|
5738
6126
|
if (release.kind === "tgz") {
|
|
5739
6127
|
const extracted = extractTgzCloudflared(release.tempPath, BIN_DIR);
|
|
5740
6128
|
try {
|
|
5741
|
-
|
|
6129
|
+
fs10.unlinkSync(release.tempPath);
|
|
5742
6130
|
} catch {}
|
|
5743
6131
|
if (!extracted)
|
|
5744
6132
|
return null;
|
|
5745
6133
|
} else {
|
|
5746
6134
|
try {
|
|
5747
|
-
|
|
6135
|
+
fs10.renameSync(release.tempPath, CLOUDFLARED_PATH);
|
|
5748
6136
|
} catch (err) {
|
|
5749
6137
|
console.warn(`[cloudflared-supervisor] rename failed: ${err?.message}`);
|
|
5750
6138
|
return null;
|
|
5751
6139
|
}
|
|
5752
6140
|
}
|
|
5753
6141
|
try {
|
|
5754
|
-
|
|
6142
|
+
fs10.chmodSync(CLOUDFLARED_PATH, 493);
|
|
5755
6143
|
} catch {}
|
|
5756
|
-
return
|
|
6144
|
+
return fs10.existsSync(CLOUDFLARED_PATH) ? CLOUDFLARED_PATH : null;
|
|
5757
6145
|
}
|
|
5758
6146
|
function detectCloudflaredRelease(platform2, arch2) {
|
|
5759
6147
|
const base = "https://github.com/cloudflare/cloudflared/releases/latest/download";
|
|
5760
6148
|
if (platform2 === "darwin") {
|
|
5761
6149
|
const asset = arch2 === "arm64" ? "cloudflared-darwin-arm64.tgz" : "cloudflared-darwin-amd64.tgz";
|
|
5762
|
-
return { url: `${base}/${asset}`, kind: "tgz", tempPath:
|
|
6150
|
+
return { url: `${base}/${asset}`, kind: "tgz", tempPath: path10.join(BIN_DIR, asset) };
|
|
5763
6151
|
}
|
|
5764
6152
|
if (platform2 === "linux") {
|
|
5765
6153
|
const asset = arch2 === "arm64" ? "cloudflared-linux-arm64" : arch2 === "arm" ? "cloudflared-linux-arm" : arch2 === "x64" ? "cloudflared-linux-amd64" : null;
|
|
@@ -5783,11 +6171,11 @@ function downloadWithCurl(url, dest) {
|
|
|
5783
6171
|
if (result.status !== 0) {
|
|
5784
6172
|
console.warn(`[cloudflared-supervisor] curl failed (exit ${result.status}): ${result.stderr?.toString().slice(0, 200)}`);
|
|
5785
6173
|
try {
|
|
5786
|
-
|
|
6174
|
+
fs10.unlinkSync(dest);
|
|
5787
6175
|
} catch {}
|
|
5788
6176
|
return false;
|
|
5789
6177
|
}
|
|
5790
|
-
return
|
|
6178
|
+
return fs10.existsSync(dest) && fs10.statSync(dest).size > 0;
|
|
5791
6179
|
}
|
|
5792
6180
|
function extractTgzCloudflared(tgzPath, destDir) {
|
|
5793
6181
|
const result = spawnSync("tar", ["-xzf", tgzPath, "-C", destDir], { stdio: "pipe" });
|
|
@@ -5795,10 +6183,10 @@ function extractTgzCloudflared(tgzPath, destDir) {
|
|
|
5795
6183
|
console.warn(`[cloudflared-supervisor] tar extract failed (exit ${result.status}): ${result.stderr?.toString().slice(0, 200)}`);
|
|
5796
6184
|
return false;
|
|
5797
6185
|
}
|
|
5798
|
-
return
|
|
6186
|
+
return fs10.existsSync(CLOUDFLARED_PATH);
|
|
5799
6187
|
}
|
|
5800
6188
|
function killOrphanedCloudflareds(binPath) {
|
|
5801
|
-
if (
|
|
6189
|
+
if (os5.platform() === "win32")
|
|
5802
6190
|
return;
|
|
5803
6191
|
const found = spawnSync("pgrep", ["-f", binPath], { stdio: "pipe" });
|
|
5804
6192
|
if (found.status !== 0)
|
|
@@ -5868,13 +6256,16 @@ var MIME_TYPES = {
|
|
|
5868
6256
|
".txt": "text/plain",
|
|
5869
6257
|
".map": "application/json"
|
|
5870
6258
|
};
|
|
6259
|
+
function resolveStateDir() {
|
|
6260
|
+
return process.env.OPENCLAW_STATE_DIR || path11.join(os6.homedir(), ".openclaw");
|
|
6261
|
+
}
|
|
5871
6262
|
function mintBootstrapToken() {
|
|
5872
6263
|
const bootstrapToken = crypto3.randomBytes(32).toString("base64url");
|
|
5873
|
-
const devicesDir =
|
|
5874
|
-
const bootstrapPath =
|
|
5875
|
-
if (!
|
|
5876
|
-
|
|
5877
|
-
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")) : {};
|
|
5878
6269
|
registry[bootstrapToken] = {
|
|
5879
6270
|
token: bootstrapToken,
|
|
5880
6271
|
profile: {
|
|
@@ -5883,15 +6274,15 @@ function mintBootstrapToken() {
|
|
|
5883
6274
|
},
|
|
5884
6275
|
issuedAtMs: Date.now()
|
|
5885
6276
|
};
|
|
5886
|
-
|
|
6277
|
+
fs11.writeFileSync(bootstrapPath, JSON.stringify(registry, null, 2));
|
|
5887
6278
|
return bootstrapToken;
|
|
5888
6279
|
}
|
|
5889
6280
|
function registerWebApp(api) {
|
|
5890
|
-
const pluginRoot =
|
|
5891
|
-
const appRoot =
|
|
5892
|
-
const hasWebBuild =
|
|
5893
|
-
const indexPath = hasWebBuild ?
|
|
5894
|
-
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));
|
|
5895
6286
|
if (!hasWebBuild) {
|
|
5896
6287
|
api.logger.info("[agentlife] web-build/ not found — /agentlife/pair will still register; static dashboard disabled");
|
|
5897
6288
|
} else if (!hasIndex) {
|
|
@@ -5899,11 +6290,13 @@ function registerWebApp(api) {
|
|
|
5899
6290
|
}
|
|
5900
6291
|
let gatewayToken = "";
|
|
5901
6292
|
try {
|
|
5902
|
-
const configPath =
|
|
5903
|
-
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"));
|
|
5904
6295
|
gatewayToken = raw?.gateway?.auth?.token || "";
|
|
5905
6296
|
} catch {}
|
|
5906
|
-
|
|
6297
|
+
if (shouldStartRuntimeServices()) {
|
|
6298
|
+
loadOrCreatePairingAccessToken();
|
|
6299
|
+
}
|
|
5907
6300
|
const approveLatest = () => {
|
|
5908
6301
|
try {
|
|
5909
6302
|
const { execSync } = __require("node:child_process");
|
|
@@ -6018,16 +6411,16 @@ function registerWebApp(api) {
|
|
|
6018
6411
|
return true;
|
|
6019
6412
|
}
|
|
6020
6413
|
const relative = urlPath.replace(/^\/agentlife\/?/, "") || "index.html";
|
|
6021
|
-
const filePath =
|
|
6414
|
+
const filePath = path11.resolve(appRoot, relative);
|
|
6022
6415
|
if (!filePath.startsWith(appRoot)) {
|
|
6023
6416
|
res.writeHead(403);
|
|
6024
6417
|
res.end();
|
|
6025
6418
|
return true;
|
|
6026
6419
|
}
|
|
6027
|
-
const target =
|
|
6028
|
-
const ext =
|
|
6420
|
+
const target = fs11.existsSync(filePath) && fs11.statSync(filePath).isFile() ? filePath : indexPath;
|
|
6421
|
+
const ext = path11.extname(target).toLowerCase();
|
|
6029
6422
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
6030
|
-
let content =
|
|
6423
|
+
let content = fs11.readFileSync(target);
|
|
6031
6424
|
if (target === indexPath) {
|
|
6032
6425
|
setTimeout(approveLatest, 2000);
|
|
6033
6426
|
setTimeout(approveLatest, 5000);
|
|
@@ -6063,62 +6456,29 @@ function registerWebApp(api) {
|
|
|
6063
6456
|
|
|
6064
6457
|
// services/pairing.ts
|
|
6065
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
|
+
}
|
|
6066
6462
|
function registerPairingServices(api) {
|
|
6067
6463
|
api.registerService({
|
|
6068
6464
|
id: "agentlife-pairing-qr",
|
|
6069
|
-
start:
|
|
6070
|
-
|
|
6071
|
-
|
|
6072
|
-
|
|
6073
|
-
const token = cfg.gateway?.auth?.token;
|
|
6074
|
-
if (!token)
|
|
6075
|
-
return;
|
|
6076
|
-
const supervisorTunnel = await awaitTunnelReady(TUNNEL_READY_TIMEOUT_MS) ?? getTunnelInfo();
|
|
6077
|
-
if (!supervisorTunnel?.tunnelUrl) {
|
|
6078
|
-
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.`);
|
|
6079
|
-
return;
|
|
6080
|
-
}
|
|
6081
|
-
const url = supervisorTunnel.tunnelUrl;
|
|
6082
|
-
const bootstrapToken = mintBootstrapToken();
|
|
6083
|
-
const payload = JSON.stringify({ url, bootstrapToken });
|
|
6084
|
-
const setupCode = Buffer.from(payload).toString("base64url");
|
|
6085
|
-
let qrTerminal = null;
|
|
6086
|
-
try {
|
|
6087
|
-
const realPath = fsSync3.realpathSync(process.argv[1] || "");
|
|
6088
|
-
const mainRequire = createRequire3(realPath);
|
|
6089
|
-
qrTerminal = mainRequire("qrcode-terminal");
|
|
6090
|
-
} catch {}
|
|
6091
|
-
console.log(`
|
|
6092
|
-
\x1B[36m[agentlife]\x1B[0m \x1B[1mPlugin installed — get the app to see your dashboard.\x1B[0m
|
|
6093
|
-
`);
|
|
6094
|
-
if (qrTerminal?.generate) {
|
|
6095
|
-
qrTerminal.generate(setupCode, { small: true }, (qr) => {
|
|
6096
|
-
console.log(qr);
|
|
6097
|
-
console.log(`
|
|
6098
|
-
Setup code: ${setupCode}
|
|
6099
|
-
`);
|
|
6100
|
-
});
|
|
6101
|
-
} else {
|
|
6102
|
-
console.log(`Setup code: ${setupCode}`);
|
|
6103
|
-
}
|
|
6104
|
-
console.log(" \x1B[32mMac:\x1B[0m https://agentlife.app/desktop");
|
|
6105
|
-
console.log(" \x1B[32miOS:\x1B[0m https://agentlife.app/ios");
|
|
6106
|
-
console.log(" \x1B[32mAndroid:\x1B[0m https://agentlife.app/android");
|
|
6107
|
-
console.log(` \x1B[2mBrowser:\x1B[0m http://localhost:${port}/agentlife/`);
|
|
6108
|
-
console.log(`
|
|
6109
|
-
Scan the QR from the mobile app to connect.
|
|
6110
|
-
`);
|
|
6111
|
-
} catch (err) {
|
|
6465
|
+
start: (ctx) => {
|
|
6466
|
+
if (!shouldStartRuntimeServices())
|
|
6467
|
+
return;
|
|
6468
|
+
emitPairingQr(api, ctx).catch((err) => {
|
|
6112
6469
|
console.warn("[agentlife] QR generation skipped:", err?.message);
|
|
6113
|
-
}
|
|
6470
|
+
});
|
|
6114
6471
|
}
|
|
6115
6472
|
});
|
|
6116
6473
|
api.registerService({
|
|
6117
6474
|
id: "agentlife-auto-pair",
|
|
6118
6475
|
start: async (ctx) => {
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
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");
|
|
6122
6482
|
const pollInterval = 3000;
|
|
6123
6483
|
const withAdmin = (arr) => {
|
|
6124
6484
|
const base = Array.isArray(arr) ? arr.filter((s) => typeof s === "string") : [];
|
|
@@ -6213,6 +6573,52 @@ Setup code: ${setupCode}
|
|
|
6213
6573
|
}
|
|
6214
6574
|
});
|
|
6215
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
|
+
}
|
|
6216
6622
|
|
|
6217
6623
|
// hooks/bootstrap.ts
|
|
6218
6624
|
var SKIP_GUIDANCE_AGENTS = new Set(["agentlife"]);
|
|
@@ -6372,15 +6778,15 @@ function registerBootstrapHookImpl(api, state2) {
|
|
|
6372
6778
|
}
|
|
6373
6779
|
|
|
6374
6780
|
// notifications.ts
|
|
6375
|
-
import * as
|
|
6376
|
-
import * as
|
|
6781
|
+
import * as fs12 from "node:fs";
|
|
6782
|
+
import * as path13 from "node:path";
|
|
6377
6783
|
var config;
|
|
6378
6784
|
function loadConfig() {
|
|
6379
6785
|
if (config !== undefined)
|
|
6380
6786
|
return config;
|
|
6381
6787
|
try {
|
|
6382
|
-
const configPath =
|
|
6383
|
-
const raw =
|
|
6788
|
+
const configPath = path13.join(process.env.HOME ?? "~", ".openclaw", "agentlife", "notification-config.json");
|
|
6789
|
+
const raw = fs12.readFileSync(configPath, "utf-8");
|
|
6384
6790
|
const parsed = JSON.parse(raw);
|
|
6385
6791
|
if (parsed.serverUrl && parsed.apiKey) {
|
|
6386
6792
|
config = { serverUrl: parsed.serverUrl, apiKey: parsed.apiKey };
|
|
@@ -6950,9 +7356,101 @@ function registerPromptStateHook(api, state2) {
|
|
|
6950
7356
|
}
|
|
6951
7357
|
|
|
6952
7358
|
// gateway/agents.ts
|
|
6953
|
-
import * as
|
|
6954
|
-
import * as
|
|
6955
|
-
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
|
+
}
|
|
6956
7454
|
function registerAgentGateway(api, state2) {
|
|
6957
7455
|
api.registerGatewayMethod("agentlife.createAgent", async ({ params, respond }) => {
|
|
6958
7456
|
const id = typeof params?.id === "string" ? params.id.trim() : "";
|
|
@@ -6972,6 +7470,18 @@ function registerAgentGateway(api, state2) {
|
|
|
6972
7470
|
return;
|
|
6973
7471
|
}
|
|
6974
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
|
+
}
|
|
6975
7485
|
const currentList = cfg.agents?.list ?? [];
|
|
6976
7486
|
const existing = currentList.find((a) => a.id === id);
|
|
6977
7487
|
if (!existing) {
|
|
@@ -7018,6 +7528,10 @@ function registerAgentGateway(api, state2) {
|
|
|
7018
7528
|
console.log("[agentlife] builder patched agent config: %s", id);
|
|
7019
7529
|
}
|
|
7020
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
|
+
}
|
|
7021
7535
|
const hasGoodDescription = description && isUsableDescription(description, id, name);
|
|
7022
7536
|
state2.agentRegistry.set(id, {
|
|
7023
7537
|
name: name || id,
|
|
@@ -7047,7 +7561,7 @@ function registerAgentGateway(api, state2) {
|
|
|
7047
7561
|
console.warn("[agentlife] deleteWelcomeWidget failed for %s: %s", id, e?.message);
|
|
7048
7562
|
}
|
|
7049
7563
|
}
|
|
7050
|
-
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 } : {} });
|
|
7051
7565
|
});
|
|
7052
7566
|
api.registerGatewayMethod("agentlife.deleteAgent", async ({ params, respond }) => {
|
|
7053
7567
|
const id = typeof params?.id === "string" ? params.id.trim() : "";
|
|
@@ -7140,10 +7654,10 @@ function registerAgentGateway(api, state2) {
|
|
|
7140
7654
|
state2.agentDbs.delete(id);
|
|
7141
7655
|
}
|
|
7142
7656
|
if (state2.dbBaseDir) {
|
|
7143
|
-
const dbPath =
|
|
7657
|
+
const dbPath = path14.join(state2.dbBaseDir, `${id}.db`);
|
|
7144
7658
|
try {
|
|
7145
|
-
if (
|
|
7146
|
-
|
|
7659
|
+
if (fs13.existsSync(dbPath)) {
|
|
7660
|
+
fs13.unlinkSync(dbPath);
|
|
7147
7661
|
cleanup.agentDbDeleted = true;
|
|
7148
7662
|
}
|
|
7149
7663
|
} catch (e) {
|
|
@@ -7155,24 +7669,24 @@ function registerAgentGateway(api, state2) {
|
|
|
7155
7669
|
const existingEntry = currentList.find((a) => a.id === id);
|
|
7156
7670
|
const filtered = currentList.filter((a) => a.id !== id);
|
|
7157
7671
|
const removedFromConfig = filtered.length < currentList.length;
|
|
7158
|
-
const openclawHome =
|
|
7159
|
-
const stateDir =
|
|
7160
|
-
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)) {
|
|
7161
7675
|
try {
|
|
7162
|
-
if (
|
|
7163
|
-
|
|
7676
|
+
if (fs13.existsSync(stateDir)) {
|
|
7677
|
+
fs13.rmSync(stateDir, { recursive: true, force: true });
|
|
7164
7678
|
cleanup.stateDeleted = true;
|
|
7165
7679
|
}
|
|
7166
7680
|
} catch (e) {
|
|
7167
7681
|
console.warn("[agentlife] deleteAgent: failed to delete state dir:", e?.message);
|
|
7168
7682
|
}
|
|
7169
7683
|
}
|
|
7170
|
-
const defaultWorkspace =
|
|
7171
|
-
const workspaceToDelete = typeof existingEntry?.workspace === "string" && existingEntry.workspace.trim() ?
|
|
7172
|
-
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) {
|
|
7173
7687
|
try {
|
|
7174
|
-
if (
|
|
7175
|
-
|
|
7688
|
+
if (fs13.existsSync(workspaceToDelete)) {
|
|
7689
|
+
fs13.rmSync(workspaceToDelete, { recursive: true, force: true });
|
|
7176
7690
|
cleanup.workspaceDeleted = true;
|
|
7177
7691
|
}
|
|
7178
7692
|
} catch (e) {
|
|
@@ -7491,7 +8005,7 @@ function registerUsageGateway(api, state2) {
|
|
|
7491
8005
|
}
|
|
7492
8006
|
|
|
7493
8007
|
// gateway/surfaces-gateway.ts
|
|
7494
|
-
import * as
|
|
8008
|
+
import * as fs14 from "node:fs";
|
|
7495
8009
|
var guidedDismissSent = new Set;
|
|
7496
8010
|
var warnedMissingOrigin = new Set;
|
|
7497
8011
|
function registerSurfacesGateway(api, state2) {
|
|
@@ -7580,7 +8094,7 @@ function registerSurfacesGateway(api, state2) {
|
|
|
7580
8094
|
guidedDismissSent.delete(surfaceId);
|
|
7581
8095
|
if (!view2.isTransient && view2.path) {
|
|
7582
8096
|
try {
|
|
7583
|
-
|
|
8097
|
+
fs14.unlinkSync(view2.path);
|
|
7584
8098
|
} catch (err) {
|
|
7585
8099
|
if (err?.code !== "ENOENT")
|
|
7586
8100
|
console.warn("[agentlife] dismiss: file unlink failed for %s: %s", surfaceId, err?.message);
|
|
@@ -7825,17 +8339,17 @@ function registerAutomationsGateway(api, state2) {
|
|
|
7825
8339
|
}
|
|
7826
8340
|
|
|
7827
8341
|
// gateway/admin.ts
|
|
7828
|
-
import * as
|
|
8342
|
+
import * as fs15 from "node:fs/promises";
|
|
7829
8343
|
import * as fsSync4 from "node:fs";
|
|
7830
|
-
import * as
|
|
7831
|
-
import * as
|
|
8344
|
+
import * as os9 from "node:os";
|
|
8345
|
+
import * as path15 from "node:path";
|
|
7832
8346
|
import { fileURLToPath } from "node:url";
|
|
7833
8347
|
var PLUGIN_VERSION = (() => {
|
|
7834
8348
|
try {
|
|
7835
|
-
const moduleDir =
|
|
8349
|
+
const moduleDir = path15.dirname(fileURLToPath(import.meta.url));
|
|
7836
8350
|
const candidates = [
|
|
7837
|
-
|
|
7838
|
-
|
|
8351
|
+
path15.join(moduleDir, "..", "package.json"),
|
|
8352
|
+
path15.join(moduleDir, "..", "..", "package.json")
|
|
7839
8353
|
];
|
|
7840
8354
|
for (const p of candidates) {
|
|
7841
8355
|
if (fsSync4.existsSync(p)) {
|
|
@@ -7884,7 +8398,7 @@ async function fetchNpmLatestVersion(force = false) {
|
|
|
7884
8398
|
return inflightFetch;
|
|
7885
8399
|
}
|
|
7886
8400
|
function pluginConfigPath() {
|
|
7887
|
-
return
|
|
8401
|
+
return path15.join(os9.homedir(), ".openclaw", "agentlife", "plugin-config.json");
|
|
7888
8402
|
}
|
|
7889
8403
|
function readPluginConfig() {
|
|
7890
8404
|
try {
|
|
@@ -7894,7 +8408,7 @@ function readPluginConfig() {
|
|
|
7894
8408
|
}
|
|
7895
8409
|
}
|
|
7896
8410
|
function writePluginConfig(config2) {
|
|
7897
|
-
const dir =
|
|
8411
|
+
const dir = path15.dirname(pluginConfigPath());
|
|
7898
8412
|
fsSync4.mkdirSync(dir, { recursive: true });
|
|
7899
8413
|
fsSync4.writeFileSync(pluginConfigPath(), JSON.stringify(config2, null, 2));
|
|
7900
8414
|
}
|
|
@@ -8022,7 +8536,7 @@ function registerAdminGateway(api, state2) {
|
|
|
8022
8536
|
api.registerGatewayMethod("agentlife.uninstall", async ({ respond }) => {
|
|
8023
8537
|
try {
|
|
8024
8538
|
const cleaned = [];
|
|
8025
|
-
const baseDir = state2.agentlifeStateDir ??
|
|
8539
|
+
const baseDir = state2.agentlifeStateDir ?? path15.join(os9.homedir(), ".openclaw", "agentlife");
|
|
8026
8540
|
const identity = loadDeviceIdentity();
|
|
8027
8541
|
if (!identity) {
|
|
8028
8542
|
cleaned.push("server deprovision skipped (no device identity)");
|
|
@@ -8087,7 +8601,7 @@ function registerAdminGateway(api, state2) {
|
|
|
8087
8601
|
} catch {
|
|
8088
8602
|
cleaned.push("agent config cleanup skipped");
|
|
8089
8603
|
}
|
|
8090
|
-
const backupPath =
|
|
8604
|
+
const backupPath = path15.join(baseDir, "config-backup.json");
|
|
8091
8605
|
try {
|
|
8092
8606
|
cleaned.push(await restoreConfigFromBackup(api, backupPath));
|
|
8093
8607
|
} catch {
|
|
@@ -8109,35 +8623,35 @@ function registerAdminGateway(api, state2) {
|
|
|
8109
8623
|
dbPath,
|
|
8110
8624
|
dbPath ? `${dbPath}-wal` : null,
|
|
8111
8625
|
dbPath ? `${dbPath}-shm` : null,
|
|
8112
|
-
|
|
8113
|
-
|
|
8114
|
-
|
|
8626
|
+
path15.join(baseDir, "config-backup.json"),
|
|
8627
|
+
path15.join(baseDir, "notification-config.json"),
|
|
8628
|
+
path15.join(baseDir, "canvas-node-identity.json")
|
|
8115
8629
|
].filter(Boolean);
|
|
8116
8630
|
for (const fp of stateFiles) {
|
|
8117
8631
|
try {
|
|
8118
|
-
await
|
|
8119
|
-
cleaned.push(`deleted ${
|
|
8632
|
+
await fs15.unlink(fp);
|
|
8633
|
+
cleaned.push(`deleted ${path15.basename(fp)}`);
|
|
8120
8634
|
} catch {}
|
|
8121
8635
|
}
|
|
8122
8636
|
if (state2.dbBaseDir) {
|
|
8123
8637
|
try {
|
|
8124
|
-
await
|
|
8638
|
+
await fs15.rm(state2.dbBaseDir, { recursive: true, force: true });
|
|
8125
8639
|
cleaned.push("deleted agent databases");
|
|
8126
8640
|
} catch {}
|
|
8127
8641
|
}
|
|
8128
8642
|
for (const agent of PROVISIONED_AGENTS) {
|
|
8129
8643
|
if (agent.existingAgent)
|
|
8130
8644
|
continue;
|
|
8131
|
-
const wsDir = agent.workspaceDir ??
|
|
8645
|
+
const wsDir = agent.workspaceDir ?? path15.join(os9.homedir(), ".openclaw", `workspace-${agent.id}`);
|
|
8132
8646
|
try {
|
|
8133
|
-
await
|
|
8647
|
+
await fs15.rm(wsDir, { recursive: true, force: true });
|
|
8134
8648
|
cleaned.push(`deleted workspace ${agent.id}`);
|
|
8135
8649
|
} catch {}
|
|
8136
8650
|
}
|
|
8137
8651
|
try {
|
|
8138
|
-
const remaining = await
|
|
8652
|
+
const remaining = await fs15.readdir(baseDir);
|
|
8139
8653
|
if (remaining.length === 0) {
|
|
8140
|
-
await
|
|
8654
|
+
await fs15.rmdir(baseDir);
|
|
8141
8655
|
cleaned.push("deleted agentlife state directory");
|
|
8142
8656
|
}
|
|
8143
8657
|
} catch {}
|
|
@@ -8177,11 +8691,11 @@ function registerAdminGateway(api, state2) {
|
|
|
8177
8691
|
|
|
8178
8692
|
// gateway/evolutions.ts
|
|
8179
8693
|
import * as fsSync5 from "node:fs";
|
|
8180
|
-
import * as
|
|
8181
|
-
import * as
|
|
8694
|
+
import * as os10 from "node:os";
|
|
8695
|
+
import * as path16 from "node:path";
|
|
8182
8696
|
var ALLOWED_FILENAMES = new Set(["AGENTS.md", "USER.md", "SOUL.md", "TOOLS.md", "IDENTITY.md"]);
|
|
8183
8697
|
function workspaceFilePath(agentId, filename) {
|
|
8184
|
-
return
|
|
8698
|
+
return path16.join(os10.homedir(), ".openclaw", `workspace-${agentId}`, filename);
|
|
8185
8699
|
}
|
|
8186
8700
|
function hasRegressionFlag(db, agentId, filename, snapshotAt) {
|
|
8187
8701
|
const horizon = snapshotAt + 7 * 24 * 60 * 60 * 1000;
|
|
@@ -8556,39 +9070,43 @@ function parseOffset(offset) {
|
|
|
8556
9070
|
// gateway/providers.ts
|
|
8557
9071
|
import {
|
|
8558
9072
|
upsertApiKeyProfile,
|
|
8559
|
-
upsertAuthProfile,
|
|
9073
|
+
upsertAuthProfile as upsertAuthProfile3,
|
|
8560
9074
|
buildApiKeyCredential,
|
|
8561
9075
|
applyAuthProfileConfig
|
|
8562
9076
|
} from "openclaw/plugin-sdk/provider-auth-api-key";
|
|
8563
9077
|
|
|
8564
9078
|
// gateway/config-utils.ts
|
|
8565
|
-
import * as
|
|
8566
|
-
import * as
|
|
8567
|
-
import * as
|
|
9079
|
+
import * as fs16 from "node:fs";
|
|
9080
|
+
import * as os11 from "node:os";
|
|
9081
|
+
import * as path17 from "node:path";
|
|
8568
9082
|
function configPath() {
|
|
8569
|
-
return
|
|
9083
|
+
return path17.join(os11.homedir(), ".openclaw", "openclaw.json");
|
|
8570
9084
|
}
|
|
8571
9085
|
function readConfig() {
|
|
8572
9086
|
try {
|
|
8573
|
-
return JSON.parse(
|
|
9087
|
+
return JSON.parse(fs16.readFileSync(configPath(), "utf-8"));
|
|
8574
9088
|
} catch {
|
|
8575
9089
|
return {};
|
|
8576
9090
|
}
|
|
8577
9091
|
}
|
|
8578
9092
|
function writeConfig(cfg) {
|
|
8579
|
-
|
|
9093
|
+
fs16.writeFileSync(configPath(), JSON.stringify(cfg, null, 2) + `
|
|
8580
9094
|
`, "utf-8");
|
|
8581
9095
|
}
|
|
8582
9096
|
|
|
8583
9097
|
// gateway/providers.ts
|
|
8584
|
-
import * as
|
|
8585
|
-
import * as
|
|
8586
|
-
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
|
+
}
|
|
8587
9105
|
function siblingAgentDirs() {
|
|
8588
|
-
const root =
|
|
9106
|
+
const root = path18.join(resolveOpenClawRoot3(), "agents");
|
|
8589
9107
|
let entries;
|
|
8590
9108
|
try {
|
|
8591
|
-
entries =
|
|
9109
|
+
entries = fs17.readdirSync(root, { withFileTypes: true });
|
|
8592
9110
|
} catch {
|
|
8593
9111
|
return [];
|
|
8594
9112
|
}
|
|
@@ -8596,9 +9114,9 @@ function siblingAgentDirs() {
|
|
|
8596
9114
|
for (const entry of entries) {
|
|
8597
9115
|
if (!entry.isDirectory() && !entry.isSymbolicLink())
|
|
8598
9116
|
continue;
|
|
8599
|
-
const dir =
|
|
9117
|
+
const dir = path18.join(root, entry.name, "agent");
|
|
8600
9118
|
try {
|
|
8601
|
-
if (
|
|
9119
|
+
if (fs17.statSync(dir).isDirectory())
|
|
8602
9120
|
out.push(dir);
|
|
8603
9121
|
} catch {}
|
|
8604
9122
|
}
|
|
@@ -8668,20 +9186,20 @@ async function ensureModels(run) {
|
|
|
8668
9186
|
}
|
|
8669
9187
|
function readOAuthExpiries() {
|
|
8670
9188
|
const result = new Map;
|
|
8671
|
-
const
|
|
8672
|
-
const
|
|
8673
|
-
const
|
|
8674
|
-
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");
|
|
8675
9193
|
let entries;
|
|
8676
9194
|
try {
|
|
8677
|
-
entries =
|
|
9195
|
+
entries = fs18.readdirSync(agentsDir);
|
|
8678
9196
|
} catch {
|
|
8679
9197
|
return result;
|
|
8680
9198
|
}
|
|
8681
9199
|
for (const name of entries) {
|
|
8682
|
-
const filePath =
|
|
9200
|
+
const filePath = path19.join(agentsDir, name, "agent", "auth-profiles.json");
|
|
8683
9201
|
try {
|
|
8684
|
-
const raw =
|
|
9202
|
+
const raw = fs18.readFileSync(filePath, "utf-8");
|
|
8685
9203
|
const data = JSON.parse(raw);
|
|
8686
9204
|
const profiles = data?.profiles ?? {};
|
|
8687
9205
|
for (const entry of Object.values(profiles)) {
|
|
@@ -8819,7 +9337,7 @@ function registerProvidersGateway(api, state2) {
|
|
|
8819
9337
|
const credential = buildApiKeyCredential(provider, apiKey);
|
|
8820
9338
|
for (const agentDir of siblingAgentDirs()) {
|
|
8821
9339
|
try {
|
|
8822
|
-
|
|
9340
|
+
upsertAuthProfile3({ profileId, credential, agentDir });
|
|
8823
9341
|
} catch {}
|
|
8824
9342
|
}
|
|
8825
9343
|
const cfg = readConfig();
|
|
@@ -8853,9 +9371,9 @@ function registerProvidersGateway(api, state2) {
|
|
|
8853
9371
|
}
|
|
8854
9372
|
writeConfig(cfg);
|
|
8855
9373
|
for (const agentDir of siblingAgentDirs()) {
|
|
8856
|
-
const file =
|
|
9374
|
+
const file = path18.join(agentDir, "auth-profiles.json");
|
|
8857
9375
|
try {
|
|
8858
|
-
const raw =
|
|
9376
|
+
const raw = fs17.readFileSync(file, "utf-8");
|
|
8859
9377
|
const data = JSON.parse(raw);
|
|
8860
9378
|
const agentProfiles = data?.profiles;
|
|
8861
9379
|
if (!agentProfiles || typeof agentProfiles !== "object")
|
|
@@ -8872,7 +9390,7 @@ function registerProvidersGateway(api, state2) {
|
|
|
8872
9390
|
changed = true;
|
|
8873
9391
|
}
|
|
8874
9392
|
if (changed)
|
|
8875
|
-
|
|
9393
|
+
fs17.writeFileSync(file, JSON.stringify(data, null, 2), "utf-8");
|
|
8876
9394
|
} catch {}
|
|
8877
9395
|
}
|
|
8878
9396
|
respond(true, { provider, configured: false });
|
|
@@ -8962,22 +9480,22 @@ ${result?.stderr ?? ""}`;
|
|
|
8962
9480
|
}
|
|
8963
9481
|
|
|
8964
9482
|
// gateway/models-config.ts
|
|
8965
|
-
import * as
|
|
8966
|
-
import * as
|
|
8967
|
-
import * as
|
|
9483
|
+
import * as fs18 from "node:fs";
|
|
9484
|
+
import * as os13 from "node:os";
|
|
9485
|
+
import * as path19 from "node:path";
|
|
8968
9486
|
function pluginConfigPath2() {
|
|
8969
|
-
return
|
|
9487
|
+
return path19.join(os13.homedir(), ".openclaw", "agentlife", "plugin-config.json");
|
|
8970
9488
|
}
|
|
8971
9489
|
function readPluginConfig2() {
|
|
8972
9490
|
try {
|
|
8973
|
-
return JSON.parse(
|
|
9491
|
+
return JSON.parse(fs18.readFileSync(pluginConfigPath2(), "utf-8"));
|
|
8974
9492
|
} catch {
|
|
8975
9493
|
return {};
|
|
8976
9494
|
}
|
|
8977
9495
|
}
|
|
8978
9496
|
function writePluginConfig2(cfg) {
|
|
8979
|
-
|
|
8980
|
-
|
|
9497
|
+
fs18.mkdirSync(path19.dirname(pluginConfigPath2()), { recursive: true });
|
|
9498
|
+
fs18.writeFileSync(pluginConfigPath2(), JSON.stringify(cfg, null, 2) + `
|
|
8981
9499
|
`, "utf-8");
|
|
8982
9500
|
}
|
|
8983
9501
|
function registerModelsConfigGateway(api) {
|
|
@@ -9121,9 +9639,12 @@ var stopObservability = null;
|
|
|
9121
9639
|
var stopDailySweep = null;
|
|
9122
9640
|
var stopQualityCheckPoller = null;
|
|
9123
9641
|
var stopCloudflared = null;
|
|
9642
|
+
function resolveOpenClawRoot4() {
|
|
9643
|
+
return process.env.OPENCLAW_STATE_DIR || path20.join(homedir17(), ".openclaw");
|
|
9644
|
+
}
|
|
9124
9645
|
function resolveInternalModel(api) {
|
|
9125
9646
|
try {
|
|
9126
|
-
const pluginCfgPath =
|
|
9647
|
+
const pluginCfgPath = path20.join(resolveOpenClawRoot4(), "agentlife", "plugin-config.json");
|
|
9127
9648
|
try {
|
|
9128
9649
|
const raw = __require("node:fs").readFileSync(pluginCfgPath, "utf-8");
|
|
9129
9650
|
const pluginCfg = JSON.parse(raw);
|
|
@@ -9149,7 +9670,24 @@ function _getState() {
|
|
|
9149
9670
|
throw new Error("plugin not registered");
|
|
9150
9671
|
return currentState;
|
|
9151
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
|
+
}
|
|
9152
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
|
+
}
|
|
9153
9691
|
if (currentState) {
|
|
9154
9692
|
registerWidgetPushTool(api, currentState);
|
|
9155
9693
|
api.registerChannel({ plugin: createAgentlifeChannel(currentState.channelState) });
|
|
@@ -9159,7 +9697,8 @@ function register(api) {
|
|
|
9159
9697
|
return;
|
|
9160
9698
|
}
|
|
9161
9699
|
registered = true;
|
|
9162
|
-
const
|
|
9700
|
+
const fallbackRoot = resolveOpenClawRoot4();
|
|
9701
|
+
const fallbackDir = path20.join(fallbackRoot, "agentlife");
|
|
9163
9702
|
const state2 = {
|
|
9164
9703
|
fileSurfaceStorage: null,
|
|
9165
9704
|
surfaceIndex: null,
|
|
@@ -9171,9 +9710,9 @@ function register(api) {
|
|
|
9171
9710
|
agentDbs: new Map,
|
|
9172
9711
|
historyDb: null,
|
|
9173
9712
|
agentlifeStateDir: fallbackDir,
|
|
9174
|
-
registryFilePath:
|
|
9175
|
-
dbBaseDir:
|
|
9176
|
-
historyDbPath:
|
|
9713
|
+
registryFilePath: path20.join(fallbackDir, "agent-registry.json"),
|
|
9714
|
+
dbBaseDir: path20.join(fallbackDir, "db"),
|
|
9715
|
+
historyDbPath: path20.join(fallbackDir, "agentlife.db"),
|
|
9177
9716
|
runCommand: api.runtime.system?.runCommandWithTimeout ?? null,
|
|
9178
9717
|
enqueueSystemEvent: null,
|
|
9179
9718
|
requestHeartbeatNow: null,
|
|
@@ -9185,12 +9724,12 @@ function register(api) {
|
|
|
9185
9724
|
currentState = state2;
|
|
9186
9725
|
api.registerChannel({ plugin: createAgentlifeChannel(state2.channelState) });
|
|
9187
9726
|
console.log("[agentlife] channel registered, session format: %s", buildAgentSessionKey("example"));
|
|
9188
|
-
if (
|
|
9727
|
+
if (shouldStartRuntimeServices() && existsSync8(fallbackDir)) {
|
|
9189
9728
|
try {
|
|
9190
9729
|
const db = getOrCreateHistoryDb(state2);
|
|
9191
9730
|
state2.surfaceIndex = new SurfaceIndex(db);
|
|
9192
9731
|
state2.followupQueue = new FollowupQueue(db);
|
|
9193
|
-
state2.fileSurfaceStorage = new FileSurfaceStorage;
|
|
9732
|
+
state2.fileSurfaceStorage = new FileSurfaceStorage({ openclawRoot: fallbackRoot });
|
|
9194
9733
|
} catch (e) {
|
|
9195
9734
|
console.warn("[agentlife] eager surface storage init failed:", e?.message);
|
|
9196
9735
|
}
|
|
@@ -9200,20 +9739,32 @@ function register(api) {
|
|
|
9200
9739
|
registerSurfacesService(api, state2);
|
|
9201
9740
|
api.registerService({
|
|
9202
9741
|
id: "agentlife-provisioning",
|
|
9203
|
-
start:
|
|
9204
|
-
|
|
9205
|
-
|
|
9206
|
-
|
|
9207
|
-
|
|
9208
|
-
|
|
9209
|
-
stopDailySweep = startDailySweepService(state2);
|
|
9210
|
-
stopQualityCheckPoller = startQualityCheckPoller(state2);
|
|
9211
|
-
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
|
+
});
|
|
9212
9748
|
}
|
|
9213
9749
|
});
|
|
9214
9750
|
registerConfigOptimizer(api, state2);
|
|
9215
9751
|
registerPairingServices(api);
|
|
9216
|
-
|
|
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
|
+
});
|
|
9217
9768
|
api.registerService({
|
|
9218
9769
|
id: "agentlife-shutdown",
|
|
9219
9770
|
start: () => {},
|
|
@@ -9238,7 +9789,15 @@ function register(api) {
|
|
|
9238
9789
|
closeAllDbs(state2);
|
|
9239
9790
|
}
|
|
9240
9791
|
});
|
|
9241
|
-
|
|
9792
|
+
api.registerService({
|
|
9793
|
+
id: "agentlife-followups",
|
|
9794
|
+
start: () => {
|
|
9795
|
+
if (!shouldStartRuntimeServices())
|
|
9796
|
+
return;
|
|
9797
|
+
initFollowupSystem(api, state2);
|
|
9798
|
+
},
|
|
9799
|
+
stop: () => stopFollowupSystem(state2)
|
|
9800
|
+
});
|
|
9242
9801
|
registerPromptStateHook(api, state2);
|
|
9243
9802
|
registerWidgetPushTool(api, state2);
|
|
9244
9803
|
registerActivityHooks(api, state2);
|
|
@@ -9254,7 +9813,7 @@ function register(api) {
|
|
|
9254
9813
|
registerProvidersGateway(api, state2);
|
|
9255
9814
|
registerModelsConfigGateway(api);
|
|
9256
9815
|
registerWebApp(api);
|
|
9257
|
-
const notifyConfigPath =
|
|
9816
|
+
const notifyConfigPath = path20.join(fallbackDir, "notification-config.json");
|
|
9258
9817
|
api.registerGatewayMethod("agentlife.notifications.register", ({ params, respond }) => {
|
|
9259
9818
|
const serverUrl = typeof params?.serverUrl === "string" ? params.serverUrl.trim() : "";
|
|
9260
9819
|
const apiKey = typeof params?.apiKey === "string" ? params.apiKey.trim() : "";
|
|
@@ -9262,9 +9821,9 @@ function register(api) {
|
|
|
9262
9821
|
return respond(false, { error: "missing serverUrl or apiKey" });
|
|
9263
9822
|
}
|
|
9264
9823
|
try {
|
|
9265
|
-
const { writeFileSync:
|
|
9266
|
-
|
|
9267
|
-
|
|
9824
|
+
const { writeFileSync: writeFileSync12, mkdirSync: mkdirSync10 } = __require("node:fs");
|
|
9825
|
+
mkdirSync10(path20.dirname(notifyConfigPath), { recursive: true });
|
|
9826
|
+
writeFileSync12(notifyConfigPath, JSON.stringify({ serverUrl, apiKey }));
|
|
9268
9827
|
} catch {}
|
|
9269
9828
|
respond(true, { registered: true });
|
|
9270
9829
|
}, { scope: "operator.write" });
|