@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 existsSync16, mkdirSync as mkdirSync6 } from "fs";
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 (!existsSync16(dailyDir)) {
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 (!existsSync16(meetingsDir)) {
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 (!existsSync16(EMAIL_DRAFTS_DIR)) {
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 (!existsSync16(parentDir)) {
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 existsSync19, readFileSync as readFileSync16 } from "fs";
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 existsSync11, mkdirSync as mkdirSync4 } from "fs";
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 (!existsSync11(vaultPath)) {
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 existsSync12, mkdirSync as mkdirSync5, readFileSync as readFileSync8, unlinkSync, writeFileSync as writeFileSync4 } from "fs";
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 (!existsSync12(DATA_DIR)) {
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 (!existsSync12(CHECKPOINT_FILE)) return;
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 (!existsSync12(DATA_DIR)) {
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 existsSync15,
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 existsSync14, readdirSync as readdirSync6 } from "fs";
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 (!existsSync14(sourceDir)) return { copied, skipped, errors };
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 (existsSync14(destPath)) {
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 (!existsSync14(file.source)) continue;
19157
+ if (!existsSync15(file.source)) continue;
18869
19158
  const destPath = join29(vault, file.destRelative);
18870
19159
  const destDir = join29(destPath, "..");
18871
- if (existsSync14(destPath)) {
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 (!existsSync15(dirPath)) return [];
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 (existsSync15(vaultPath)) return vaultPath;
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 = existsSync15(identityOsDashboard);
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 (!existsSync15(dirPath)) return { categories: [], count: 0 };
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 (existsSync15(filePath)) {
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 (!existsSync15(dir)) continue;
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 (existsSync15(join31(GODMODE_ROOT, "research"))) {
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 (existsSync15(altDir)) {
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 (!existsSync15(destPath)) {
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 (!existsSync15(destPath)) {
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 (!existsSync15(dirPath)) continue;
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 || !existsSync15(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 existsSync17, mkdirSync as mkdirSync7, readFileSync as readFileSync14, unlinkSync as unlinkSync2, writeFileSync as writeFileSync5 } from "fs";
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 (!existsSync17(AUTH_FILE)) return null;
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 (!existsSync17(dir)) {
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 (existsSync17(AUTH_FILE)) {
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 existsSync18 } from "fs";
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 = existsSync18(filePath) && !filePath.endsWith("/") ? filePath : join37(root, "index.html");
21021
- if (!existsSync18(target)) {
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 (!existsSync19(candidate)) {
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 (!existsSync19(index)) {
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 (existsSync19(configPath)) {
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: existsSync19(expandedRoot),
22239
- detail: existsSync19(expandedRoot) ? expandedRoot : `Missing: ${expandedRoot}`
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: existsSync19(dataDir),
22245
- detail: existsSync19(dataDir) ? dataDir : `Missing: ${dataDir}`
22535
+ ok: existsSync20(dataDir),
22536
+ detail: existsSync20(dataDir) ? dataDir : `Missing: ${dataDir}`
22246
22537
  });
22247
22538
  checks.push({
22248
22539
  name: "Health endpoint registered",