@godmode-team/godmode 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js
CHANGED
|
@@ -4768,10 +4768,12 @@ var init_resolve_claude_bin = __esm({
|
|
|
4768
4768
|
// src/lib/agent-roster.ts
|
|
4769
4769
|
var agent_roster_exports = {};
|
|
4770
4770
|
__export(agent_roster_exports, {
|
|
4771
|
+
clearRosterCache: () => clearRosterCache,
|
|
4771
4772
|
formatHandoff: () => formatHandoff,
|
|
4772
4773
|
listRoster: () => listRoster,
|
|
4773
4774
|
loadRoster: () => loadRoster,
|
|
4774
4775
|
resolvePersona: () => resolvePersona,
|
|
4776
|
+
resolveRosterDir: () => resolveRosterDir,
|
|
4775
4777
|
resolveSwarmPersona: () => resolveSwarmPersona,
|
|
4776
4778
|
setTrustScores: () => setTrustScores
|
|
4777
4779
|
});
|
|
@@ -4783,6 +4785,10 @@ function setTrustScores(scores) {
|
|
|
4783
4785
|
_trustScores.set(slug, score);
|
|
4784
4786
|
}
|
|
4785
4787
|
}
|
|
4788
|
+
function clearRosterCache() {
|
|
4789
|
+
_cache2.clear();
|
|
4790
|
+
_cacheTs = 0;
|
|
4791
|
+
}
|
|
4786
4792
|
function resolveRosterDir() {
|
|
4787
4793
|
const vault = getVaultPath();
|
|
4788
4794
|
if (vault) {
|
|
@@ -4816,6 +4822,7 @@ function parsePersonaFile(filePath, category) {
|
|
|
4816
4822
|
const engine = ["claude", "codex", "gemini"].includes(
|
|
4817
4823
|
meta.engine?.toLowerCase()
|
|
4818
4824
|
) ? meta.engine.toLowerCase() : void 0;
|
|
4825
|
+
const mission = meta.mission || void 0;
|
|
4819
4826
|
return {
|
|
4820
4827
|
slug,
|
|
4821
4828
|
category,
|
|
@@ -4823,6 +4830,7 @@ function parsePersonaFile(filePath, category) {
|
|
|
4823
4830
|
taskTypes,
|
|
4824
4831
|
swarmStages,
|
|
4825
4832
|
engine,
|
|
4833
|
+
mission,
|
|
4826
4834
|
body: body.trim()
|
|
4827
4835
|
};
|
|
4828
4836
|
} catch {
|
|
@@ -4897,7 +4905,8 @@ function listRoster() {
|
|
|
4897
4905
|
category: p.category,
|
|
4898
4906
|
name: p.name,
|
|
4899
4907
|
taskTypes: p.taskTypes,
|
|
4900
|
-
engine: p.engine
|
|
4908
|
+
engine: p.engine,
|
|
4909
|
+
mission: p.mission
|
|
4901
4910
|
}));
|
|
4902
4911
|
}
|
|
4903
4912
|
var _cache2, _cacheTs, CACHE_TTL_MS5, _trustScores;
|
|
@@ -5490,6 +5499,35 @@ function isPidAlive(pid) {
|
|
|
5490
5499
|
return false;
|
|
5491
5500
|
}
|
|
5492
5501
|
}
|
|
5502
|
+
function extractArtifacts(content) {
|
|
5503
|
+
const artifacts = [];
|
|
5504
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5505
|
+
for (const line of content.split("\n")) {
|
|
5506
|
+
const prMatch = line.match(/https:\/\/github\.com\/[^\s)]+\/pull\/\d+/g);
|
|
5507
|
+
if (prMatch) {
|
|
5508
|
+
for (const m of prMatch) if (!seen.has(m)) {
|
|
5509
|
+
artifacts.push(m);
|
|
5510
|
+
seen.add(m);
|
|
5511
|
+
}
|
|
5512
|
+
}
|
|
5513
|
+
const urlMatch = line.match(/https?:\/\/[^\s)>]+/g);
|
|
5514
|
+
if (urlMatch) {
|
|
5515
|
+
for (const m of urlMatch) if (!seen.has(m)) {
|
|
5516
|
+
artifacts.push(m);
|
|
5517
|
+
seen.add(m);
|
|
5518
|
+
}
|
|
5519
|
+
}
|
|
5520
|
+
const pathMatch = line.match(/(?:^|\s)(\/[\w./-]+\.\w{1,10})\b/g);
|
|
5521
|
+
if (pathMatch) for (const m of pathMatch) {
|
|
5522
|
+
const cleaned = m.trim();
|
|
5523
|
+
if (!seen.has(cleaned)) {
|
|
5524
|
+
artifacts.push(cleaned);
|
|
5525
|
+
seen.add(cleaned);
|
|
5526
|
+
}
|
|
5527
|
+
}
|
|
5528
|
+
}
|
|
5529
|
+
return artifacts.slice(0, 20);
|
|
5530
|
+
}
|
|
5493
5531
|
async function expireStaleQueueItems() {
|
|
5494
5532
|
const { updateQueueState: updateQueueState2 } = await Promise.resolve().then(() => (init_queue_state(), queue_state_exports));
|
|
5495
5533
|
await updateQueueState2((state) => {
|
|
@@ -5497,7 +5535,7 @@ async function expireStaleQueueItems() {
|
|
|
5497
5535
|
const SEVEN_DAYS = 7 * 24 * 60 * 60 * 1e3;
|
|
5498
5536
|
const THREE_DAYS = 3 * 24 * 60 * 60 * 1e3;
|
|
5499
5537
|
state.items = state.items.filter((item) => {
|
|
5500
|
-
if (item.status === "review" && item.completedAt && now - item.completedAt > SEVEN_DAYS) {
|
|
5538
|
+
if ((item.status === "review" || item.status === "needs-review") && item.completedAt && now - item.completedAt > SEVEN_DAYS) {
|
|
5501
5539
|
return false;
|
|
5502
5540
|
}
|
|
5503
5541
|
if (item.status === "failed" && item.completedAt && now - item.completedAt > THREE_DAYS) {
|
|
@@ -5731,7 +5769,6 @@ var init_queue_processor = __esm({
|
|
|
5731
5769
|
}
|
|
5732
5770
|
// ── Completion handler ─────────────────────────────────────────
|
|
5733
5771
|
async handleItemCompleted(itemId, exitCode) {
|
|
5734
|
-
this.activeCount = Math.max(0, this.activeCount - 1);
|
|
5735
5772
|
if (exitCode !== 0) {
|
|
5736
5773
|
await this.handleItemFailed(
|
|
5737
5774
|
itemId,
|
|
@@ -5739,12 +5776,15 @@ var init_queue_processor = __esm({
|
|
|
5739
5776
|
);
|
|
5740
5777
|
return;
|
|
5741
5778
|
}
|
|
5779
|
+
this.activeCount = Math.max(0, this.activeCount - 1);
|
|
5742
5780
|
const outPath = outputPathForItem(itemId);
|
|
5743
5781
|
let summary = "";
|
|
5782
|
+
let artifacts = [];
|
|
5744
5783
|
try {
|
|
5745
5784
|
const content = await fs3.readFile(outPath, "utf-8");
|
|
5746
5785
|
const lines = content.split("\n").filter((l) => l.trim().length > 0).slice(0, 3);
|
|
5747
5786
|
summary = lines.join(" ").slice(0, 500);
|
|
5787
|
+
artifacts = extractArtifacts(content);
|
|
5748
5788
|
} catch {
|
|
5749
5789
|
summary = "Output file not found \u2014 agent may have completed without writing results.";
|
|
5750
5790
|
}
|
|
@@ -5754,11 +5794,48 @@ var init_queue_processor = __esm({
|
|
|
5754
5794
|
qi.status = "review";
|
|
5755
5795
|
qi.completedAt = Date.now();
|
|
5756
5796
|
qi.result = { summary, outputPath: outPath };
|
|
5797
|
+
qi.artifacts = artifacts;
|
|
5757
5798
|
}
|
|
5758
5799
|
return state;
|
|
5759
5800
|
});
|
|
5760
5801
|
const completedItem = queueState.items.find((i) => i.id === itemId);
|
|
5761
5802
|
const personaSlug = completedItem?.personaHint;
|
|
5803
|
+
if (completedItem && completedItem.type === "coding") {
|
|
5804
|
+
const hasPrLink = artifacts.some((a) => a.includes("/pull/"));
|
|
5805
|
+
const hasFilePath = artifacts.some((a) => a.startsWith("/"));
|
|
5806
|
+
if (!hasPrLink && !hasFilePath) {
|
|
5807
|
+
await updateQueueState((state) => {
|
|
5808
|
+
const qi = state.items.find((i) => i.id === itemId);
|
|
5809
|
+
if (qi) {
|
|
5810
|
+
qi.status = "needs-review";
|
|
5811
|
+
qi.result = {
|
|
5812
|
+
...qi.result,
|
|
5813
|
+
summary: summary + "\n\n\u26A0\uFE0F No artifact provided \u2014 verify manually"
|
|
5814
|
+
};
|
|
5815
|
+
}
|
|
5816
|
+
});
|
|
5817
|
+
this.logger.info(
|
|
5818
|
+
`[GodMode][Queue] Item ${itemId} (coding) has no artifacts \u2014 set to needs-review`
|
|
5819
|
+
);
|
|
5820
|
+
this.broadcast("queue:update", {
|
|
5821
|
+
itemId,
|
|
5822
|
+
status: "needs-review",
|
|
5823
|
+
personaHint: personaSlug
|
|
5824
|
+
});
|
|
5825
|
+
try {
|
|
5826
|
+
this.broadcast("ally:notification", {
|
|
5827
|
+
type: "queue-needs-review",
|
|
5828
|
+
title: completedItem.title,
|
|
5829
|
+
summary: `Agent finished "${completedItem.title}" but provided no artifact \u2014 manual verification needed.`,
|
|
5830
|
+
actions: [
|
|
5831
|
+
{ label: "Review", action: "navigate", target: "today" }
|
|
5832
|
+
]
|
|
5833
|
+
});
|
|
5834
|
+
} catch {
|
|
5835
|
+
}
|
|
5836
|
+
return;
|
|
5837
|
+
}
|
|
5838
|
+
}
|
|
5762
5839
|
if (personaSlug) {
|
|
5763
5840
|
try {
|
|
5764
5841
|
const { getAutonomyLevel: getAutonomyLevel2 } = await Promise.resolve().then(() => (init_trust_tracker(), trust_tracker_exports));
|
|
@@ -10670,7 +10747,7 @@ __export(fathom_processor_exports, {
|
|
|
10670
10747
|
stopFathomProcessor: () => stopFathomProcessor
|
|
10671
10748
|
});
|
|
10672
10749
|
import { readFile as readFile27, writeFile as writeFile22, mkdir as mkdir20 } from "fs/promises";
|
|
10673
|
-
import { existsSync as
|
|
10750
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync6 } from "fs";
|
|
10674
10751
|
import { join as join34, dirname as dirname10 } from "path";
|
|
10675
10752
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
10676
10753
|
function withQueueLock(fn) {
|
|
@@ -10935,7 +11012,7 @@ async function fileMeetingToVault(meeting, meetingDate) {
|
|
|
10935
11012
|
logger.warn(`[FathomProcessor] Daily note path not allowed: ${dailyFilePath}`);
|
|
10936
11013
|
return;
|
|
10937
11014
|
}
|
|
10938
|
-
if (!
|
|
11015
|
+
if (!existsSync17(dailyDir)) {
|
|
10939
11016
|
mkdirSync6(dailyDir, { recursive: true });
|
|
10940
11017
|
}
|
|
10941
11018
|
let dailyContent = "";
|
|
@@ -10994,7 +11071,7 @@ async function fileMeetingToVault(meeting, meetingDate) {
|
|
|
10994
11071
|
logger.warn(`[FathomProcessor] Meeting note path not allowed: ${meetingFilePath}`);
|
|
10995
11072
|
return;
|
|
10996
11073
|
}
|
|
10997
|
-
if (!
|
|
11074
|
+
if (!existsSync17(meetingsDir)) {
|
|
10998
11075
|
mkdirSync6(meetingsDir, { recursive: true });
|
|
10999
11076
|
}
|
|
11000
11077
|
const attendeeNames = meeting.attendees.map((a) => a.name || a.email || "Unknown").filter(Boolean);
|
|
@@ -11090,7 +11167,7 @@ async function draftFollowUpEmail(meeting) {
|
|
|
11090
11167
|
logger.info(`[FathomProcessor] No external attendees \u2014 skipping email draft for ${meeting.id}`);
|
|
11091
11168
|
return;
|
|
11092
11169
|
}
|
|
11093
|
-
if (!
|
|
11170
|
+
if (!existsSync17(EMAIL_DRAFTS_DIR)) {
|
|
11094
11171
|
mkdirSync6(EMAIL_DRAFTS_DIR, { recursive: true });
|
|
11095
11172
|
}
|
|
11096
11173
|
const toList = externalAttendees.map((a) => {
|
|
@@ -11151,7 +11228,7 @@ async function appendDecisionsToWorking(meeting, meetingDate) {
|
|
|
11151
11228
|
return;
|
|
11152
11229
|
}
|
|
11153
11230
|
const parentDir = dirname10(workingPath);
|
|
11154
|
-
if (!
|
|
11231
|
+
if (!existsSync17(parentDir)) {
|
|
11155
11232
|
mkdirSync6(parentDir, { recursive: true });
|
|
11156
11233
|
}
|
|
11157
11234
|
let content = "";
|
|
@@ -11896,7 +11973,7 @@ var init_team_memory_route = __esm({
|
|
|
11896
11973
|
});
|
|
11897
11974
|
|
|
11898
11975
|
// index.ts
|
|
11899
|
-
import { existsSync as
|
|
11976
|
+
import { existsSync as existsSync20, readFileSync as readFileSync16 } from "fs";
|
|
11900
11977
|
import {
|
|
11901
11978
|
request as httpRequest
|
|
11902
11979
|
} from "http";
|
|
@@ -12628,6 +12705,7 @@ var goalsHandlers = {
|
|
|
12628
12705
|
init_data_paths();
|
|
12629
12706
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
12630
12707
|
import { readFile as readFile15, writeFile as writeFile15, mkdir as mkdir12 } from "fs/promises";
|
|
12708
|
+
import { existsSync as existsSync11 } from "fs";
|
|
12631
12709
|
import { join as join22 } from "path";
|
|
12632
12710
|
import { homedir as homedir5 } from "os";
|
|
12633
12711
|
|
|
@@ -12843,6 +12921,7 @@ async function generateConfigRecommendations() {
|
|
|
12843
12921
|
const plugins = config.plugins;
|
|
12844
12922
|
const cron = config.cron;
|
|
12845
12923
|
const session = config.session;
|
|
12924
|
+
const sessions = config.sessions;
|
|
12846
12925
|
const gatewayAuth = gateway?.auth;
|
|
12847
12926
|
const hasGatewayToken = Boolean(gateway?.token) || Boolean(gatewayAuth?.token);
|
|
12848
12927
|
if (!hasGatewayToken) {
|
|
@@ -12855,6 +12934,16 @@ async function generateConfigRecommendations() {
|
|
|
12855
12934
|
priority: "critical"
|
|
12856
12935
|
});
|
|
12857
12936
|
}
|
|
12937
|
+
if (sessions?.dmScope !== "per-channel-peer") {
|
|
12938
|
+
recommendations.push({
|
|
12939
|
+
key: "sessions.dmScope",
|
|
12940
|
+
label: "DM session isolation",
|
|
12941
|
+
currentValue: sessions?.dmScope ?? "not set",
|
|
12942
|
+
recommendedValue: "per-channel-peer",
|
|
12943
|
+
reason: "Set dmScope to per-channel-peer to prevent DM data leaking between users.",
|
|
12944
|
+
priority: "critical"
|
|
12945
|
+
});
|
|
12946
|
+
}
|
|
12858
12947
|
if (gateway?.mode !== "local") {
|
|
12859
12948
|
recommendations.push({
|
|
12860
12949
|
key: "gateway.mode",
|
|
@@ -14846,8 +14935,207 @@ var onboardingHandlers = {
|
|
|
14846
14935
|
configError: configResult.error,
|
|
14847
14936
|
workspacePath: GODMODE_ROOT
|
|
14848
14937
|
});
|
|
14938
|
+
},
|
|
14939
|
+
/**
|
|
14940
|
+
* Seed the agent roster with default starter personas.
|
|
14941
|
+
* Writes persona files to ~/godmode/memory/agent-roster/ if they don't exist.
|
|
14942
|
+
* Returns the seeded roster list for the "Meet Your Team" UI.
|
|
14943
|
+
*/
|
|
14944
|
+
"onboarding.seedRoster": async ({ respond }) => {
|
|
14945
|
+
const { resolveRosterDir: resolveRosterDir2, clearRosterCache: clearRosterCache2, listRoster: listRoster2 } = await Promise.resolve().then(() => (init_agent_roster(), agent_roster_exports));
|
|
14946
|
+
const rosterDir = resolveRosterDir2() ?? join22(MEMORY_DIR, "agent-roster");
|
|
14947
|
+
let seeded = 0;
|
|
14948
|
+
for (const persona of DEFAULT_PERSONAS) {
|
|
14949
|
+
const dir = join22(rosterDir, persona.category);
|
|
14950
|
+
const filePath = join22(dir, `${persona.slug}.md`);
|
|
14951
|
+
if (existsSync11(filePath)) continue;
|
|
14952
|
+
await mkdir12(dir, { recursive: true });
|
|
14953
|
+
await writeFile15(filePath, persona.content, "utf-8");
|
|
14954
|
+
seeded++;
|
|
14955
|
+
}
|
|
14956
|
+
clearRosterCache2();
|
|
14957
|
+
const roster = listRoster2();
|
|
14958
|
+
respond(true, { seeded, roster });
|
|
14959
|
+
},
|
|
14960
|
+
/**
|
|
14961
|
+
* Return the current agent roster for the UI to display.
|
|
14962
|
+
*/
|
|
14963
|
+
"onboarding.roster": async ({ respond }) => {
|
|
14964
|
+
const { listRoster: listRoster2 } = await Promise.resolve().then(() => (init_agent_roster(), agent_roster_exports));
|
|
14965
|
+
const roster = listRoster2();
|
|
14966
|
+
respond(true, { roster });
|
|
14849
14967
|
}
|
|
14850
14968
|
};
|
|
14969
|
+
var DEFAULT_PERSONAS = [
|
|
14970
|
+
{
|
|
14971
|
+
slug: "researcher",
|
|
14972
|
+
category: "_defaults",
|
|
14973
|
+
content: `---
|
|
14974
|
+
name: Researcher
|
|
14975
|
+
taskTypes: research,url
|
|
14976
|
+
engine: claude
|
|
14977
|
+
mission: Find the truth, cite the sources, and deliver answers you can act on.
|
|
14978
|
+
---
|
|
14979
|
+
|
|
14980
|
+
## Identity
|
|
14981
|
+
Deep researcher who values accuracy over speed. Treats every question like it matters.
|
|
14982
|
+
|
|
14983
|
+
## Approach
|
|
14984
|
+
- Start with primary sources. Cross-reference everything.
|
|
14985
|
+
- Structure findings: Summary, Key Findings, Sources, Recommendations.
|
|
14986
|
+
- Flag uncertainty explicitly \u2014 "I'm 80% confident" beats false certainty.
|
|
14987
|
+
|
|
14988
|
+
## Output Standards
|
|
14989
|
+
Deliver structured reports with cited sources. Every claim links to evidence. Include confidence levels.
|
|
14990
|
+
|
|
14991
|
+
## Evidence Requirements
|
|
14992
|
+
Minimum 3 sources per finding. No unsourced claims. URLs or file paths for every reference.
|
|
14993
|
+
|
|
14994
|
+
## Handoff Protocol
|
|
14995
|
+
End with "Suggested Next Steps" and flag any unresolved questions for the human.
|
|
14996
|
+
`
|
|
14997
|
+
},
|
|
14998
|
+
{
|
|
14999
|
+
slug: "writer",
|
|
15000
|
+
category: "creative",
|
|
15001
|
+
content: `---
|
|
15002
|
+
name: Writer
|
|
15003
|
+
taskTypes: creative,review
|
|
15004
|
+
engine: claude
|
|
15005
|
+
mission: Write words that sound like you, not like a robot.
|
|
15006
|
+
---
|
|
15007
|
+
|
|
15008
|
+
## Identity
|
|
15009
|
+
Versatile writer who adapts to the owner's voice. Reads SOUL.md before every draft.
|
|
15010
|
+
|
|
15011
|
+
## Approach
|
|
15012
|
+
- Match the owner's tone and style from their profile.
|
|
15013
|
+
- Provide 2-3 variations when the format allows.
|
|
15014
|
+
- Drafts are publication-ready, not rough outlines.
|
|
15015
|
+
|
|
15016
|
+
## Output Standards
|
|
15017
|
+
Deliver polished copy with word count noted. Include tone assessment and readability level.
|
|
15018
|
+
|
|
15019
|
+
## Evidence Requirements
|
|
15020
|
+
Word count, readability score, and tone match confirmation against owner profile.
|
|
15021
|
+
|
|
15022
|
+
## Handoff Protocol
|
|
15023
|
+
Flag which version is recommended, what needs owner review, and any brand-voice questions.
|
|
15024
|
+
`
|
|
15025
|
+
},
|
|
15026
|
+
{
|
|
15027
|
+
slug: "analyst",
|
|
15028
|
+
category: "operations",
|
|
15029
|
+
content: `---
|
|
15030
|
+
name: Analyst
|
|
15031
|
+
taskTypes: analysis,research
|
|
15032
|
+
engine: claude
|
|
15033
|
+
mission: Turn messy data into clear decisions.
|
|
15034
|
+
---
|
|
15035
|
+
|
|
15036
|
+
## Identity
|
|
15037
|
+
Structured thinker who finds signal in noise. Makes complex data simple.
|
|
15038
|
+
|
|
15039
|
+
## Approach
|
|
15040
|
+
- Start with the question, not the data.
|
|
15041
|
+
- Present findings as: Data Summary, Key Insights, Comparisons, Actionable Conclusions.
|
|
15042
|
+
- State assumptions and confidence levels explicitly.
|
|
15043
|
+
|
|
15044
|
+
## Output Standards
|
|
15045
|
+
Deliver structured analysis with data sources cited. Include visual-friendly formats (tables, comparisons).
|
|
15046
|
+
|
|
15047
|
+
## Evidence Requirements
|
|
15048
|
+
Data sources cited, methodology stated, confidence levels for each conclusion.
|
|
15049
|
+
|
|
15050
|
+
## Handoff Protocol
|
|
15051
|
+
End with prioritized recommendations and flag data gaps that need human input.
|
|
15052
|
+
`
|
|
15053
|
+
},
|
|
15054
|
+
{
|
|
15055
|
+
slug: "task-runner",
|
|
15056
|
+
category: "operations",
|
|
15057
|
+
content: `---
|
|
15058
|
+
name: Task Runner
|
|
15059
|
+
taskTypes: ops,task
|
|
15060
|
+
engine: claude
|
|
15061
|
+
mission: Get it done, document what happened, flag what's next.
|
|
15062
|
+
---
|
|
15063
|
+
|
|
15064
|
+
## Identity
|
|
15065
|
+
Reliable executor who handles infrastructure, automation, maintenance, and errands.
|
|
15066
|
+
|
|
15067
|
+
## Approach
|
|
15068
|
+
- Execute the task, don't over-plan it.
|
|
15069
|
+
- Document every step taken and every decision made.
|
|
15070
|
+
- Escalate blockers immediately instead of guessing.
|
|
15071
|
+
|
|
15072
|
+
## Output Standards
|
|
15073
|
+
Deliver completion reports with before/after state. Include command output and timestamps.
|
|
15074
|
+
|
|
15075
|
+
## Evidence Requirements
|
|
15076
|
+
Command output, file paths created/modified, before/after state proof.
|
|
15077
|
+
|
|
15078
|
+
## Handoff Protocol
|
|
15079
|
+
List what was done, what's still pending, and any follow-up tasks discovered.
|
|
15080
|
+
`
|
|
15081
|
+
},
|
|
15082
|
+
{
|
|
15083
|
+
slug: "creative-director",
|
|
15084
|
+
category: "creative",
|
|
15085
|
+
content: `---
|
|
15086
|
+
name: Creative Director
|
|
15087
|
+
taskTypes: creative
|
|
15088
|
+
engine: claude
|
|
15089
|
+
mission: Make it look, feel, and land exactly right.
|
|
15090
|
+
---
|
|
15091
|
+
|
|
15092
|
+
## Identity
|
|
15093
|
+
Brand-first thinker who sees the system behind the aesthetic.
|
|
15094
|
+
|
|
15095
|
+
## Approach
|
|
15096
|
+
- Think in systems: color, typography, spacing, voice, audience.
|
|
15097
|
+
- Reference real-world examples and competitors.
|
|
15098
|
+
- Deliver briefs that a designer or developer can execute without guessing.
|
|
15099
|
+
|
|
15100
|
+
## Output Standards
|
|
15101
|
+
Deliver design briefs, mood references, campaign concepts. Include rationale for every creative choice.
|
|
15102
|
+
|
|
15103
|
+
## Evidence Requirements
|
|
15104
|
+
Reference links, mockup descriptions, brand alignment notes, audience fit assessment.
|
|
15105
|
+
|
|
15106
|
+
## Handoff Protocol
|
|
15107
|
+
Specify what's ready for execution vs. what needs owner sign-off on direction.
|
|
15108
|
+
`
|
|
15109
|
+
},
|
|
15110
|
+
{
|
|
15111
|
+
slug: "growth",
|
|
15112
|
+
category: "operations",
|
|
15113
|
+
content: `---
|
|
15114
|
+
name: Growth Strategist
|
|
15115
|
+
taskTypes: research,analysis
|
|
15116
|
+
engine: claude
|
|
15117
|
+
mission: Find the levers that move the needle and pull them.
|
|
15118
|
+
---
|
|
15119
|
+
|
|
15120
|
+
## Identity
|
|
15121
|
+
Data-driven strategist focused on funnels, competitive intel, and GTM.
|
|
15122
|
+
|
|
15123
|
+
## Approach
|
|
15124
|
+
- Start with the metric that matters. Work backward to the lever.
|
|
15125
|
+
- Benchmark against competitors and market data.
|
|
15126
|
+
- Deliver actionable recommendations with projected impact.
|
|
15127
|
+
|
|
15128
|
+
## Output Standards
|
|
15129
|
+
Deliver prioritized action lists with expected impact. Include market data and competitor analysis.
|
|
15130
|
+
|
|
15131
|
+
## Evidence Requirements
|
|
15132
|
+
Market data sources, competitor references, funnel metrics, projected ROI where applicable.
|
|
15133
|
+
|
|
15134
|
+
## Handoff Protocol
|
|
15135
|
+
Rank recommendations by effort-to-impact ratio. Flag quick wins separately from long plays.
|
|
15136
|
+
`
|
|
15137
|
+
}
|
|
15138
|
+
];
|
|
14851
15139
|
function parseWizardAnswers(params) {
|
|
14852
15140
|
return sanitizeAnswers({
|
|
14853
15141
|
name: typeof params.name === "string" ? params.name : void 0,
|
|
@@ -15786,7 +16074,7 @@ function createTeamMemoryWriteTool(ctx) {
|
|
|
15786
16074
|
init_integration_registry();
|
|
15787
16075
|
init_platform_detect();
|
|
15788
16076
|
init_vault_paths();
|
|
15789
|
-
import { existsSync as
|
|
16077
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync4 } from "fs";
|
|
15790
16078
|
var status2 = async ({ respond }) => {
|
|
15791
16079
|
try {
|
|
15792
16080
|
const integrations = getIntegrationsForPlatform();
|
|
@@ -15857,7 +16145,7 @@ var configure = async ({ params, respond }) => {
|
|
|
15857
16145
|
}
|
|
15858
16146
|
if (integrationId === "obsidian-vault" && values.OBSIDIAN_VAULT_PATH) {
|
|
15859
16147
|
const vaultPath = values.OBSIDIAN_VAULT_PATH.replace(/^~/, process.env.HOME ?? "");
|
|
15860
|
-
if (!
|
|
16148
|
+
if (!existsSync12(vaultPath)) {
|
|
15861
16149
|
mkdirSync4(vaultPath, { recursive: true });
|
|
15862
16150
|
}
|
|
15863
16151
|
ensureVaultStructure();
|
|
@@ -15995,7 +16283,7 @@ init_trust_tracker();
|
|
|
15995
16283
|
// src/methods/system-update.ts
|
|
15996
16284
|
init_data_paths();
|
|
15997
16285
|
import { exec as nodeExec } from "child_process";
|
|
15998
|
-
import { existsSync as
|
|
16286
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync5, readFileSync as readFileSync8, unlinkSync, writeFileSync as writeFileSync4 } from "fs";
|
|
15999
16287
|
import { join as join26 } from "path";
|
|
16000
16288
|
var CHECKPOINT_FILE = join26(DATA_DIR, "update-checkpoint.json");
|
|
16001
16289
|
var POST_UPDATE_STATUS_FILE = join26(DATA_DIR, "post-update-status.json");
|
|
@@ -16097,7 +16385,7 @@ var check = async ({ respond }) => {
|
|
|
16097
16385
|
var run2 = async ({ respond }) => {
|
|
16098
16386
|
try {
|
|
16099
16387
|
const openclawVersion = await getOpenclawVersion();
|
|
16100
|
-
if (!
|
|
16388
|
+
if (!existsSync13(DATA_DIR)) {
|
|
16101
16389
|
mkdirSync5(DATA_DIR, { recursive: true });
|
|
16102
16390
|
}
|
|
16103
16391
|
const checkpoint = {
|
|
@@ -16153,7 +16441,7 @@ var pluginCheck = async ({ respond }) => {
|
|
|
16153
16441
|
};
|
|
16154
16442
|
function runPostUpdateHealthCheck(currentOpenclawVersion, methodCount, logger2) {
|
|
16155
16443
|
try {
|
|
16156
|
-
if (!
|
|
16444
|
+
if (!existsSync13(CHECKPOINT_FILE)) return;
|
|
16157
16445
|
const checkpoint = JSON.parse(readFileSync8(CHECKPOINT_FILE, "utf8"));
|
|
16158
16446
|
const status3 = {
|
|
16159
16447
|
previousVersion: checkpoint.openclawVersion,
|
|
@@ -16163,7 +16451,7 @@ function runPostUpdateHealthCheck(currentOpenclawVersion, methodCount, logger2)
|
|
|
16163
16451
|
timestamp: Date.now(),
|
|
16164
16452
|
checkedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
16165
16453
|
};
|
|
16166
|
-
if (!
|
|
16454
|
+
if (!existsSync13(DATA_DIR)) {
|
|
16167
16455
|
mkdirSync5(DATA_DIR, { recursive: true });
|
|
16168
16456
|
}
|
|
16169
16457
|
writeFileSync4(POST_UPDATE_STATUS_FILE, JSON.stringify(status3, null, 2));
|
|
@@ -16677,6 +16965,7 @@ function countsByStatus(items) {
|
|
|
16677
16965
|
pending: 0,
|
|
16678
16966
|
processing: 0,
|
|
16679
16967
|
review: 0,
|
|
16968
|
+
"needs-review": 0,
|
|
16680
16969
|
done: 0,
|
|
16681
16970
|
failed: 0
|
|
16682
16971
|
};
|
|
@@ -16776,7 +17065,7 @@ var approveItem = async ({ params, respond }) => {
|
|
|
16776
17065
|
const idx = state.items.findIndex((i) => i.id === id);
|
|
16777
17066
|
if (idx === -1) return { item: null, error: "Queue item not found" };
|
|
16778
17067
|
const existing = state.items[idx];
|
|
16779
|
-
if (existing.status !== "review") {
|
|
17068
|
+
if (existing.status !== "review" && existing.status !== "needs-review") {
|
|
16780
17069
|
return { item: null, error: `Cannot approve item with status "${existing.status}". Only "review" items can be approved.` };
|
|
16781
17070
|
}
|
|
16782
17071
|
existing.status = "done";
|
|
@@ -16824,7 +17113,7 @@ var rejectItem = async ({ params, respond }) => {
|
|
|
16824
17113
|
const idx = state.items.findIndex((i) => i.id === id);
|
|
16825
17114
|
if (idx === -1) return { item: null, error: "Queue item not found" };
|
|
16826
17115
|
const existing = state.items[idx];
|
|
16827
|
-
if (existing.status !== "review") {
|
|
17116
|
+
if (existing.status !== "review" && existing.status !== "needs-review") {
|
|
16828
17117
|
return { item: null, error: `Cannot reject item with status "${existing.status}"` };
|
|
16829
17118
|
}
|
|
16830
17119
|
existing.status = "failed";
|
|
@@ -18744,7 +19033,7 @@ var imageCacheHandlers = {
|
|
|
18744
19033
|
init_data_paths();
|
|
18745
19034
|
init_vault_paths();
|
|
18746
19035
|
import {
|
|
18747
|
-
existsSync as
|
|
19036
|
+
existsSync as existsSync16,
|
|
18748
19037
|
lstatSync,
|
|
18749
19038
|
readdirSync as readdirSync7,
|
|
18750
19039
|
readFileSync as readFileSync12,
|
|
@@ -18757,7 +19046,7 @@ import { basename as basename3, extname as extname4, join as join31, relative }
|
|
|
18757
19046
|
// src/lib/vault-migrate.ts
|
|
18758
19047
|
init_data_paths();
|
|
18759
19048
|
init_vault_paths();
|
|
18760
|
-
import { existsSync as
|
|
19049
|
+
import { existsSync as existsSync15, readdirSync as readdirSync6 } from "fs";
|
|
18761
19050
|
import { copyFile as copyFile3, mkdir as mkdir16 } from "fs/promises";
|
|
18762
19051
|
import { basename as basename2, extname as extname3, join as join29 } from "path";
|
|
18763
19052
|
function getMigrationMap() {
|
|
@@ -18810,7 +19099,7 @@ async function copyDirContents(sourceDir, destDir, recursive) {
|
|
|
18810
19099
|
let copied = 0;
|
|
18811
19100
|
let skipped = 0;
|
|
18812
19101
|
const errors = [];
|
|
18813
|
-
if (!
|
|
19102
|
+
if (!existsSync15(sourceDir)) return { copied, skipped, errors };
|
|
18814
19103
|
try {
|
|
18815
19104
|
const entries = readdirSync6(sourceDir, { withFileTypes: true });
|
|
18816
19105
|
await mkdir16(destDir, { recursive: true });
|
|
@@ -18828,7 +19117,7 @@ async function copyDirContents(sourceDir, destDir, recursive) {
|
|
|
18828
19117
|
if (entry.isDirectory()) continue;
|
|
18829
19118
|
const ext = extname3(entry.name);
|
|
18830
19119
|
if (ext !== ".md" && ext !== ".txt" && ext !== ".json") continue;
|
|
18831
|
-
if (
|
|
19120
|
+
if (existsSync15(destPath)) {
|
|
18832
19121
|
skipped++;
|
|
18833
19122
|
continue;
|
|
18834
19123
|
}
|
|
@@ -18865,10 +19154,10 @@ async function migrateToVault() {
|
|
|
18865
19154
|
}
|
|
18866
19155
|
}
|
|
18867
19156
|
for (const file of getFileMigrations()) {
|
|
18868
|
-
if (!
|
|
19157
|
+
if (!existsSync15(file.source)) continue;
|
|
18869
19158
|
const destPath = join29(vault, file.destRelative);
|
|
18870
19159
|
const destDir = join29(destPath, "..");
|
|
18871
|
-
if (
|
|
19160
|
+
if (existsSync15(destPath)) {
|
|
18872
19161
|
totalSkipped++;
|
|
18873
19162
|
continue;
|
|
18874
19163
|
}
|
|
@@ -18941,7 +19230,7 @@ function extractExcerpt(content) {
|
|
|
18941
19230
|
return content.split("\n").filter((line) => line.trim() && !line.startsWith("#") && !line.startsWith("---") && !line.startsWith("*Last")).slice(0, 3).join(" ").slice(0, 200);
|
|
18942
19231
|
}
|
|
18943
19232
|
function listEntries(dirPath) {
|
|
18944
|
-
if (!
|
|
19233
|
+
if (!existsSync16(dirPath)) return [];
|
|
18945
19234
|
try {
|
|
18946
19235
|
const entries = readdirSync7(dirPath, { withFileTypes: true });
|
|
18947
19236
|
return entries.filter((e) => {
|
|
@@ -19005,7 +19294,7 @@ function resolveIdentityFilePath(spec) {
|
|
|
19005
19294
|
const vault = getVaultPath();
|
|
19006
19295
|
if (vault) {
|
|
19007
19296
|
const vaultPath = spec.key === "opinions" ? resolveOpinionsPath().path : join31(vault, VAULT_FOLDERS.identity, spec.vaultFilename);
|
|
19008
|
-
if (
|
|
19297
|
+
if (existsSync16(vaultPath)) return vaultPath;
|
|
19009
19298
|
}
|
|
19010
19299
|
return spec.localDir === "root" ? join31(GODMODE_ROOT, spec.filename) : join31(MEMORY_DIR, spec.filename);
|
|
19011
19300
|
}
|
|
@@ -19025,7 +19314,7 @@ var identity = async ({ respond }) => {
|
|
|
19025
19314
|
}
|
|
19026
19315
|
}
|
|
19027
19316
|
const identityOsDashboard = join31(MEMORY_DIR, "projects", "identity-os", "final", "dashboard", "index.html");
|
|
19028
|
-
const identityOsExists =
|
|
19317
|
+
const identityOsExists = existsSync16(identityOsDashboard);
|
|
19029
19318
|
const identityOsFinalPath = join31(MEMORY_DIR, "projects", "identity-os", "final");
|
|
19030
19319
|
const identityOsArtifacts = listEntries(identityOsFinalPath);
|
|
19031
19320
|
respond(true, {
|
|
@@ -19376,7 +19665,7 @@ function listResearchEntries(dirPath) {
|
|
|
19376
19665
|
});
|
|
19377
19666
|
}
|
|
19378
19667
|
function scanResearchDir(dirPath, rootLabel, rootKey) {
|
|
19379
|
-
if (!
|
|
19668
|
+
if (!existsSync16(dirPath)) return { categories: [], count: 0 };
|
|
19380
19669
|
const categories = [];
|
|
19381
19670
|
let count = 0;
|
|
19382
19671
|
try {
|
|
@@ -19480,7 +19769,7 @@ var addResearch = async ({ params, respond }) => {
|
|
|
19480
19769
|
let filename = `${baseSlug}.md`;
|
|
19481
19770
|
let filePath = join31(targetDir, filename);
|
|
19482
19771
|
let suffix = 2;
|
|
19483
|
-
while (
|
|
19772
|
+
while (existsSync16(filePath)) {
|
|
19484
19773
|
filename = `${baseSlug}-${suffix}.md`;
|
|
19485
19774
|
filePath = join31(targetDir, filename);
|
|
19486
19775
|
suffix++;
|
|
@@ -19504,7 +19793,7 @@ var addResearch = async ({ params, respond }) => {
|
|
|
19504
19793
|
var researchCategories = async ({ respond }) => {
|
|
19505
19794
|
const cats = /* @__PURE__ */ new Set();
|
|
19506
19795
|
for (const dir of [getResearchDir(), RESEARCH_DIR_ALT]) {
|
|
19507
|
-
if (!
|
|
19796
|
+
if (!existsSync16(dir)) continue;
|
|
19508
19797
|
try {
|
|
19509
19798
|
const entries = readdirSync7(dir, { withFileTypes: true });
|
|
19510
19799
|
for (const e of entries) {
|
|
@@ -19695,7 +19984,7 @@ var brainSearch = async ({ params, respond }) => {
|
|
|
19695
19984
|
const searchDirs = [];
|
|
19696
19985
|
if (scope === "all" || scope === "research") {
|
|
19697
19986
|
searchDirs.push({ dir: getResearchDir(), label: "research" });
|
|
19698
|
-
if (
|
|
19987
|
+
if (existsSync16(join31(GODMODE_ROOT, "research"))) {
|
|
19699
19988
|
searchDirs.push({ dir: join31(GODMODE_ROOT, "research"), label: "analysis" });
|
|
19700
19989
|
}
|
|
19701
19990
|
}
|
|
@@ -19792,7 +20081,7 @@ var consolidateResearch = async ({ params, respond }) => {
|
|
|
19792
20081
|
const dryRun = !p.execute;
|
|
19793
20082
|
const actions = [];
|
|
19794
20083
|
const altDir = join31(GODMODE_ROOT, "research");
|
|
19795
|
-
if (
|
|
20084
|
+
if (existsSync16(altDir)) {
|
|
19796
20085
|
try {
|
|
19797
20086
|
const walk = (dir, relativeBase) => {
|
|
19798
20087
|
const entries = readdirSync7(dir, { withFileTypes: true });
|
|
@@ -19804,7 +20093,7 @@ var consolidateResearch = async ({ params, respond }) => {
|
|
|
19804
20093
|
walk(srcPath, relPath);
|
|
19805
20094
|
} else {
|
|
19806
20095
|
const destPath = join31(getResearchDir(), relPath);
|
|
19807
|
-
if (!
|
|
20096
|
+
if (!existsSync16(destPath)) {
|
|
19808
20097
|
actions.push({
|
|
19809
20098
|
source: relative(GODMODE_ROOT, srcPath),
|
|
19810
20099
|
destination: relative(GODMODE_ROOT, destPath),
|
|
@@ -19824,7 +20113,7 @@ var consolidateResearch = async ({ params, respond }) => {
|
|
|
19824
20113
|
if (e.isDirectory() || !e.name.endsWith(".html") || e.name.startsWith(".")) continue;
|
|
19825
20114
|
const srcPath = join31(GODMODE_ROOT, e.name);
|
|
19826
20115
|
const destPath = join31(getResearchDir(), "proposals", e.name);
|
|
19827
|
-
if (!
|
|
20116
|
+
if (!existsSync16(destPath)) {
|
|
19828
20117
|
actions.push({
|
|
19829
20118
|
source: relative(GODMODE_ROOT, srcPath),
|
|
19830
20119
|
destination: relative(GODMODE_ROOT, destPath),
|
|
@@ -19882,7 +20171,7 @@ var vaultHealth = async ({ respond }) => {
|
|
|
19882
20171
|
];
|
|
19883
20172
|
for (const folder of foldersToScan) {
|
|
19884
20173
|
const dirPath = join31(vault, folder);
|
|
19885
|
-
if (!
|
|
20174
|
+
if (!existsSync16(dirPath)) continue;
|
|
19886
20175
|
try {
|
|
19887
20176
|
const entries = readdirSync7(dirPath, { withFileTypes: true });
|
|
19888
20177
|
for (const e of entries) {
|
|
@@ -19935,7 +20224,7 @@ var vaultHealth = async ({ respond }) => {
|
|
|
19935
20224
|
};
|
|
19936
20225
|
var inboxItems = async ({ respond }) => {
|
|
19937
20226
|
const inboxPath = resolveInboxPath();
|
|
19938
|
-
if (!inboxPath || !
|
|
20227
|
+
if (!inboxPath || !existsSync16(inboxPath)) {
|
|
19939
20228
|
respond(true, { items: [], count: 0, available: isVaultAvailable() });
|
|
19940
20229
|
return;
|
|
19941
20230
|
}
|
|
@@ -20701,7 +20990,7 @@ var fathomWebhookHandlers = {
|
|
|
20701
20990
|
};
|
|
20702
20991
|
|
|
20703
20992
|
// src/lib/auth-client.ts
|
|
20704
|
-
import { existsSync as
|
|
20993
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync7, readFileSync as readFileSync14, unlinkSync as unlinkSync2, writeFileSync as writeFileSync5 } from "fs";
|
|
20705
20994
|
import { join as join36 } from "path";
|
|
20706
20995
|
import { homedir as homedir7 } from "os";
|
|
20707
20996
|
import { createVerify } from "crypto";
|
|
@@ -20710,7 +20999,7 @@ var AUTH_FILE = join36(homedir7(), ".openclaw", "godmode-auth.json");
|
|
|
20710
20999
|
var PUBLIC_KEY = readFileSync14(new URL("./auth-public-key.pem", import.meta.url), "utf-8");
|
|
20711
21000
|
function loadAuthTokens() {
|
|
20712
21001
|
try {
|
|
20713
|
-
if (!
|
|
21002
|
+
if (!existsSync18(AUTH_FILE)) return null;
|
|
20714
21003
|
const data = JSON.parse(readFileSync14(AUTH_FILE, "utf-8"));
|
|
20715
21004
|
return data;
|
|
20716
21005
|
} catch {
|
|
@@ -20719,14 +21008,14 @@ function loadAuthTokens() {
|
|
|
20719
21008
|
}
|
|
20720
21009
|
function saveAuthTokens(tokens) {
|
|
20721
21010
|
const dir = join36(homedir7(), ".openclaw");
|
|
20722
|
-
if (!
|
|
21011
|
+
if (!existsSync18(dir)) {
|
|
20723
21012
|
mkdirSync7(dir, { recursive: true, mode: 448 });
|
|
20724
21013
|
}
|
|
20725
21014
|
writeFileSync5(AUTH_FILE, JSON.stringify(tokens, null, 2), { mode: 384 });
|
|
20726
21015
|
}
|
|
20727
21016
|
function clearAuthTokens() {
|
|
20728
21017
|
try {
|
|
20729
|
-
if (
|
|
21018
|
+
if (existsSync18(AUTH_FILE)) {
|
|
20730
21019
|
unlinkSync2(AUTH_FILE);
|
|
20731
21020
|
}
|
|
20732
21021
|
} catch {
|
|
@@ -20960,7 +21249,7 @@ var authHandlers = {
|
|
|
20960
21249
|
};
|
|
20961
21250
|
|
|
20962
21251
|
// src/static-server.ts
|
|
20963
|
-
import { readFileSync as readFileSync15, existsSync as
|
|
21252
|
+
import { readFileSync as readFileSync15, existsSync as existsSync19 } from "fs";
|
|
20964
21253
|
import { join as join37, extname as extname5 } from "path";
|
|
20965
21254
|
var MIME = {
|
|
20966
21255
|
".html": "text/html; charset=utf-8",
|
|
@@ -21017,8 +21306,8 @@ function createStaticFileHandler(root, basePath) {
|
|
|
21017
21306
|
res.end("Forbidden");
|
|
21018
21307
|
return;
|
|
21019
21308
|
}
|
|
21020
|
-
const target =
|
|
21021
|
-
if (!
|
|
21309
|
+
const target = existsSync19(filePath) && !filePath.endsWith("/") ? filePath : join37(root, "index.html");
|
|
21310
|
+
if (!existsSync19(target)) {
|
|
21022
21311
|
res.writeHead(404, { ...SECURITY_HEADERS, "Content-Type": "text/plain" });
|
|
21023
21312
|
res.end("Not Found");
|
|
21024
21313
|
return;
|
|
@@ -21210,7 +21499,7 @@ try {
|
|
|
21210
21499
|
const moduleDir = dirname13(fileURLToPath2(import.meta.url));
|
|
21211
21500
|
const packageJsonCandidates = [join41(moduleDir, "package.json"), join41(moduleDir, "..", "package.json")];
|
|
21212
21501
|
for (const candidate of packageJsonCandidates) {
|
|
21213
|
-
if (!
|
|
21502
|
+
if (!existsSync20(candidate)) {
|
|
21214
21503
|
continue;
|
|
21215
21504
|
}
|
|
21216
21505
|
const pkg = JSON.parse(readFileSync16(candidate, "utf8"));
|
|
@@ -21606,6 +21895,8 @@ var godmodePlugin = {
|
|
|
21606
21895
|
"onboarding.wizard.status",
|
|
21607
21896
|
"onboarding.wizard.preview",
|
|
21608
21897
|
"onboarding.wizard.generate",
|
|
21898
|
+
"onboarding.seedRoster",
|
|
21899
|
+
"onboarding.roster",
|
|
21609
21900
|
"integrations.status",
|
|
21610
21901
|
"integrations.test",
|
|
21611
21902
|
"integrations.configure",
|
|
@@ -21640,7 +21931,7 @@ var godmodePlugin = {
|
|
|
21640
21931
|
];
|
|
21641
21932
|
const godmodeUiRoot = godmodeUiCandidates.find((p) => {
|
|
21642
21933
|
const index = join41(p, "index.html");
|
|
21643
|
-
if (!
|
|
21934
|
+
if (!existsSync20(index)) {
|
|
21644
21935
|
return false;
|
|
21645
21936
|
}
|
|
21646
21937
|
try {
|
|
@@ -22175,7 +22466,7 @@ ${joined}
|
|
|
22175
22466
|
const configPath = process.env.OPENCLAW_CONFIG_PATH || join41(stateDir, "openclaw.json");
|
|
22176
22467
|
let config = {};
|
|
22177
22468
|
try {
|
|
22178
|
-
if (
|
|
22469
|
+
if (existsSync20(configPath)) {
|
|
22179
22470
|
config = JSON.parse(readFileSync16(configPath, "utf8"));
|
|
22180
22471
|
}
|
|
22181
22472
|
} catch {
|
|
@@ -22235,14 +22526,14 @@ ${joined}
|
|
|
22235
22526
|
const expandedRoot = workspaceRoot.replace(/^~/, process.env.HOME ?? "");
|
|
22236
22527
|
checks.push({
|
|
22237
22528
|
name: "Workspace directory exists",
|
|
22238
|
-
ok:
|
|
22239
|
-
detail:
|
|
22529
|
+
ok: existsSync20(expandedRoot),
|
|
22530
|
+
detail: existsSync20(expandedRoot) ? expandedRoot : `Missing: ${expandedRoot}`
|
|
22240
22531
|
});
|
|
22241
22532
|
const dataDir = join41(expandedRoot, "data");
|
|
22242
22533
|
checks.push({
|
|
22243
22534
|
name: "Data directory exists",
|
|
22244
|
-
ok:
|
|
22245
|
-
detail:
|
|
22535
|
+
ok: existsSync20(dataDir),
|
|
22536
|
+
detail: existsSync20(dataDir) ? dataDir : `Missing: ${dataDir}`
|
|
22246
22537
|
});
|
|
22247
22538
|
checks.push({
|
|
22248
22539
|
name: "Health endpoint registered",
|