@beastmode-develeap/beastmode 0.1.13 → 0.1.15

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
@@ -3462,7 +3462,9 @@ function createStrategySession(factoryDir, projectName, opts) {
3462
3462
  })),
3463
3463
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
3464
3464
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
3465
- buildOnSession: opts.buildOnSession
3465
+ buildOnSession: opts.buildOnSession,
3466
+ sessionType: opts.sessionType || "free-form",
3467
+ approach: opts.approach || "auto"
3466
3468
  };
3467
3469
  writeFileSync10(join11(sessionDir, "inception.json"), JSON.stringify(session, null, 2) + "\n");
3468
3470
  return session;
@@ -4363,7 +4365,7 @@ IMPORTANT RULES:
4363
4365
  - You have tools available. You can execute bash commands. Use curl to interact with the board API.
4364
4366
  - NEVER ask for permissions. You have full access. Just do it.
4365
4367
  ${scopeContext}
4366
-
4368
+ ${session.sessionTypePrompt ? "\nSESSION ROLE:\n" + session.sessionTypePrompt + "\n" : ""}
4367
4369
  BOARD API (use curl to manage tasks):
4368
4370
  - Base URL: ${boardApiUrl}
4369
4371
  - List items: curl -s '${boardApiUrl}/api/items${boardParam}'
@@ -4371,6 +4373,11 @@ BOARD API (use curl to manage tasks):
4371
4373
  (status="" means Draft/New. Valid statuses: "", "New", "Ready", "Working on it", "Done", etc.)
4372
4374
  - Update item: curl -s -X PATCH '${boardApiUrl}/api/items/ITEM_ID${boardParam}' -H 'Content-Type: application/json' -d '{"status":"Ready"}'
4373
4375
 
4376
+ DECISION API (use curl to log strategic decisions):
4377
+ - List: curl -s '${boardApiUrl}/api/strategy/${scope}/decisions'
4378
+ - Create: curl -s -X POST '${boardApiUrl}/api/strategy/${scope}/decisions' -H 'Content-Type: application/json' -d '{"title":"Decision title","context":"Why this was decided"}'
4379
+ - Update: curl -s -X PATCH '${boardApiUrl}/api/strategy/${scope}/decisions/ID' -H 'Content-Type: application/json' -d '{"status":"superseded","outcome":"What happened"}'
4380
+
4374
4381
  Current board items:
4375
4382
  ${boardContext}
4376
4383
 
@@ -4379,7 +4386,8 @@ ${historyBlock}
4379
4386
  USER MESSAGE: ${content}
4380
4387
 
4381
4388
  Respond concisely. Continue the conversation naturally.`;
4382
- const args = [
4389
+ const isRoot = process.getuid?.() === 0;
4390
+ const claudeArgs = [
4383
4391
  "-p",
4384
4392
  prompt,
4385
4393
  "--output-format",
@@ -4387,11 +4395,21 @@ Respond concisely. Continue the conversation naturally.`;
4387
4395
  "--verbose",
4388
4396
  "--dangerously-skip-permissions"
4389
4397
  ];
4390
- const child = spawn("claude", args, {
4398
+ let spawnCmd;
4399
+ let spawnArgs;
4400
+ if (isRoot) {
4401
+ spawnCmd = "runuser";
4402
+ spawnArgs = ["-u", "node", "--", "claude", ...claudeArgs];
4403
+ } else {
4404
+ spawnCmd = "claude";
4405
+ spawnArgs = claudeArgs;
4406
+ }
4407
+ const child = spawn(spawnCmd, spawnArgs, {
4391
4408
  cwd: session.factoryPath,
4392
4409
  env: {
4393
4410
  ...process.env,
4394
- BEASTMODE_FACTORY_PATH: session.factoryPath
4411
+ BEASTMODE_FACTORY_PATH: session.factoryPath,
4412
+ ...isRoot ? { HOME: "/home/node" } : {}
4395
4413
  },
4396
4414
  stdio: ["ignore", "pipe", "pipe"]
4397
4415
  });
@@ -4422,9 +4440,6 @@ Respond concisely. Continue the conversation naturally.`;
4422
4440
  const transformed = transformCliEvent(parsed);
4423
4441
  if (transformed) sendToClient(session, transformed);
4424
4442
  } catch {
4425
- if (line.trim() && !line.startsWith("\u256D") && !line.startsWith("\u2570") && !line.startsWith("\u2502") && line.length > 2) {
4426
- sendToClient(session, { type: "text", content: line });
4427
- }
4428
4443
  }
4429
4444
  }
4430
4445
  });
@@ -5877,7 +5892,7 @@ Path: ${projConfig.path}
5877
5892
  method: "POST",
5878
5893
  pattern: "/api/strategy/:project/sessions",
5879
5894
  handler: async (body, params) => {
5880
- const { name, idea, methodology, interactionMode, buildOnSession } = body;
5895
+ const { name, idea, methodology, interactionMode, buildOnSession, sessionType, approach } = body;
5881
5896
  if (!name || !idea || !methodology) throw new Error("Missing: name, idea, methodology");
5882
5897
  const { createStrategySession: createStrategySession2 } = await Promise.resolve().then(() => (init_strategy(), strategy_exports));
5883
5898
  return createStrategySession2(factoryDir, params.project, {
@@ -5885,7 +5900,9 @@ Path: ${projConfig.path}
5885
5900
  idea,
5886
5901
  methodology,
5887
5902
  interactionMode: interactionMode || "interactive",
5888
- buildOnSession
5903
+ buildOnSession,
5904
+ sessionType: sessionType || "free-form",
5905
+ approach: approach || "auto"
5889
5906
  });
5890
5907
  }
5891
5908
  },
@@ -5906,6 +5923,145 @@ Path: ${projConfig.path}
5906
5923
  if (!content) throw new Error(`Artifact not found: ${params.artifact}`);
5907
5924
  return { content };
5908
5925
  }
5926
+ },
5927
+ // ── Strategy Feed (aggregated activity) ──
5928
+ {
5929
+ method: "GET",
5930
+ pattern: "/api/strategy/:project/feed",
5931
+ handler: async (_body, params, query) => {
5932
+ const project = params.project;
5933
+ const limit = Math.min(Math.max(parseInt(query?.limit || "20", 10) || 20, 1), 50);
5934
+ const cursor = query?.cursor || null;
5935
+ const allItems = [];
5936
+ try {
5937
+ const { listStrategySessions: listStrategySessions2 } = await Promise.resolve().then(() => (init_strategy(), strategy_exports));
5938
+ const sessions = listStrategySessions2(factoryDir, project);
5939
+ for (const s of sessions) {
5940
+ const phasesDone = s.phases ? s.phases.filter((p) => p.status === "done").length : 0;
5941
+ const phasesTotal = s.phases ? s.phases.length : 0;
5942
+ const typeLabel = s.sessionType || "free-form";
5943
+ const methodLabel = s.methodology || "";
5944
+ let subtitle = `${typeLabel} (${methodLabel})`;
5945
+ if (phasesTotal > 0) {
5946
+ subtitle += ` \u2014 phase ${phasesDone}/${phasesTotal}`;
5947
+ }
5948
+ allItems.push({
5949
+ type: "session",
5950
+ title: s.name,
5951
+ subtitle,
5952
+ timestamp: s.updatedAt || s.createdAt,
5953
+ link: `#/strategy-session/${s.sessionId}`,
5954
+ id: `session-${s.sessionId}`
5955
+ });
5956
+ }
5957
+ } catch {
5958
+ }
5959
+ try {
5960
+ const boardUrl = getBoardUrl2(factoryDir);
5961
+ const resp = await proxyToBoard(boardUrl, "GET", `/api/strategy/${project}/decisions`);
5962
+ const decisions = Array.isArray(resp) ? resp : resp?.decisions || [];
5963
+ for (const d of decisions) {
5964
+ allItems.push({
5965
+ type: "decision",
5966
+ title: String(d.title || "Untitled decision"),
5967
+ subtitle: `Status: ${d.status || "active"}`,
5968
+ timestamp: String(d.updated_at || d.created_at || (/* @__PURE__ */ new Date()).toISOString()),
5969
+ id: `decision-${d.id}`
5970
+ });
5971
+ }
5972
+ } catch {
5973
+ }
5974
+ try {
5975
+ const boardUrl = getBoardUrl2(factoryDir);
5976
+ const resp = await proxyToBoard(boardUrl, "GET", "/api/items", void 0, { board: project });
5977
+ const tasks = Array.isArray(resp) ? resp : resp?.items || [];
5978
+ for (const t of tasks) {
5979
+ const parts = [];
5980
+ if (t.status) parts.push(String(t.status));
5981
+ if (t.priority) parts.push(`P${t.priority}`);
5982
+ if (t.task_type) parts.push(String(t.task_type));
5983
+ allItems.push({
5984
+ type: "task",
5985
+ title: String(t.name || "Untitled task"),
5986
+ subtitle: parts.join(" / ") || void 0,
5987
+ timestamp: String(t.updated_at || t.created_at || (/* @__PURE__ */ new Date()).toISOString()),
5988
+ link: "#/board",
5989
+ id: `task-${t.id}`
5990
+ });
5991
+ }
5992
+ } catch {
5993
+ }
5994
+ try {
5995
+ const { buildArtifactIndex: buildArtifactIndex2 } = await Promise.resolve().then(() => (init_strategy(), strategy_exports));
5996
+ const index = buildArtifactIndex2(factoryDir, project);
5997
+ const learnings = index.artifacts.filter((a) => a.type === "learning");
5998
+ for (const l of learnings) {
5999
+ allItems.push({
6000
+ type: "learning",
6001
+ title: l.summary,
6002
+ timestamp: l.date,
6003
+ id: `learning-${l.path}`
6004
+ });
6005
+ }
6006
+ } catch {
6007
+ }
6008
+ try {
6009
+ const runsDir = join13(factoryDir, "runs", project);
6010
+ if (existsSync15(runsDir)) {
6011
+ const runDirs = readdirSync6(runsDir).filter((d) => d.startsWith("run-"));
6012
+ for (const runId of runDirs) {
6013
+ const ckptPath = join13(runsDir, runId, "checkpoint.json");
6014
+ let subtitle = "";
6015
+ let timestamp = "";
6016
+ try {
6017
+ const st = statSync5(join13(runsDir, runId));
6018
+ timestamp = st.mtime.toISOString();
6019
+ } catch {
6020
+ timestamp = (/* @__PURE__ */ new Date()).toISOString();
6021
+ }
6022
+ if (existsSync15(ckptPath)) {
6023
+ try {
6024
+ const ckpt = JSON.parse(readFileSync12(ckptPath, "utf-8"));
6025
+ const history = ckpt.satisfaction_history;
6026
+ if (history && history.length > 0) {
6027
+ const latest = history[history.length - 1];
6028
+ subtitle = `Satisfaction: ${Math.round(latest * 100)}%`;
6029
+ }
6030
+ } catch {
6031
+ }
6032
+ }
6033
+ allItems.push({
6034
+ type: "run",
6035
+ title: runId,
6036
+ subtitle: subtitle || void 0,
6037
+ timestamp,
6038
+ link: "#/runs",
6039
+ id: `run-${runId}`
6040
+ });
6041
+ }
6042
+ }
6043
+ } catch {
6044
+ }
6045
+ allItems.sort((a, b) => {
6046
+ const ta = new Date(a.timestamp).getTime() || 0;
6047
+ const tb = new Date(b.timestamp).getTime() || 0;
6048
+ return tb - ta;
6049
+ });
6050
+ let startIndex = 0;
6051
+ if (cursor) {
6052
+ const cursorIdx = allItems.findIndex((item) => item.id === cursor);
6053
+ if (cursorIdx >= 0) {
6054
+ startIndex = cursorIdx + 1;
6055
+ }
6056
+ }
6057
+ const page = allItems.slice(startIndex, startIndex + limit);
6058
+ const nextCursor = page.length === limit && startIndex + limit < allItems.length ? page[page.length - 1].id : null;
6059
+ return {
6060
+ items: page,
6061
+ total: allItems.length,
6062
+ nextCursor
6063
+ };
6064
+ }
5909
6065
  }
5910
6066
  ];
5911
6067
  }