@beastmode-develeap/beastmode 0.1.12 → 0.1.14
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 +186 -14
- package/dist/index.js.map +1 -1
- package/dist/methodologies/design-thinking.json +47 -0
- package/dist/methodologies/superpowers.json +7 -0
- package/dist/web/board.html +194 -85
- package/package.json +1 -1
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;
|
|
@@ -4352,30 +4354,62 @@ ${formatted}
|
|
|
4352
4354
|
---
|
|
4353
4355
|
`;
|
|
4354
4356
|
}
|
|
4355
|
-
const
|
|
4356
|
-
|
|
4357
|
+
const boardApiUrl = getBoardUrl(session.factoryPath);
|
|
4358
|
+
const boardParam = scope !== "factory" ? `?board=${scope}` : "";
|
|
4359
|
+
const prompt = `CRITICAL CONTEXT \u2014 YOU MUST READ THIS:
|
|
4360
|
+
You are the BeastMode chat assistant running inside a BeastMode factory.
|
|
4361
|
+
|
|
4362
|
+
IMPORTANT RULES:
|
|
4363
|
+
- Monday.com does NOT exist in this system. NEVER mention Monday.com. There is NO Monday.com integration.
|
|
4364
|
+
- This factory uses a LOCAL self-hosted BeastMode Board with a REST API.
|
|
4365
|
+
- You have tools available. You can execute bash commands. Use curl to interact with the board API.
|
|
4366
|
+
- NEVER ask for permissions. You have full access. Just do it.
|
|
4357
4367
|
${scopeContext}
|
|
4368
|
+
${session.sessionTypePrompt ? "\nSESSION ROLE:\n" + session.sessionTypePrompt + "\n" : ""}
|
|
4369
|
+
BOARD API (use curl to manage tasks):
|
|
4370
|
+
- Base URL: ${boardApiUrl}
|
|
4371
|
+
- List items: curl -s '${boardApiUrl}/api/items${boardParam}'
|
|
4372
|
+
- Create item: curl -s -X POST '${boardApiUrl}/api/items${boardParam}' -H 'Content-Type: application/json' -d '{"name":"Task title","status":"","priority":"Medium","task_type":"deep-planning"}'
|
|
4373
|
+
(status="" means Draft/New. Valid statuses: "", "New", "Ready", "Working on it", "Done", etc.)
|
|
4374
|
+
- Update item: curl -s -X PATCH '${boardApiUrl}/api/items/ITEM_ID${boardParam}' -H 'Content-Type: application/json' -d '{"status":"Ready"}'
|
|
4358
4375
|
|
|
4359
|
-
|
|
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
|
+
|
|
4381
|
+
Current board items:
|
|
4360
4382
|
${boardContext}
|
|
4361
4383
|
|
|
4362
4384
|
Factory path: ${session.factoryPath}
|
|
4363
4385
|
${historyBlock}
|
|
4364
4386
|
USER MESSAGE: ${content}
|
|
4365
4387
|
|
|
4366
|
-
Respond concisely. Continue the conversation naturally
|
|
4367
|
-
const
|
|
4388
|
+
Respond concisely. Continue the conversation naturally.`;
|
|
4389
|
+
const isRoot = process.getuid?.() === 0;
|
|
4390
|
+
const claudeArgs = [
|
|
4368
4391
|
"-p",
|
|
4369
4392
|
prompt,
|
|
4370
4393
|
"--output-format",
|
|
4371
4394
|
"stream-json",
|
|
4372
|
-
"--verbose"
|
|
4395
|
+
"--verbose",
|
|
4396
|
+
"--dangerously-skip-permissions"
|
|
4373
4397
|
];
|
|
4374
|
-
|
|
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, {
|
|
4375
4408
|
cwd: session.factoryPath,
|
|
4376
4409
|
env: {
|
|
4377
4410
|
...process.env,
|
|
4378
|
-
BEASTMODE_FACTORY_PATH: session.factoryPath
|
|
4411
|
+
BEASTMODE_FACTORY_PATH: session.factoryPath,
|
|
4412
|
+
...isRoot ? { HOME: "/home/node" } : {}
|
|
4379
4413
|
},
|
|
4380
4414
|
stdio: ["ignore", "pipe", "pipe"]
|
|
4381
4415
|
});
|
|
@@ -4406,9 +4440,6 @@ Respond concisely. Continue the conversation naturally \u2014 you have full cont
|
|
|
4406
4440
|
const transformed = transformCliEvent(parsed);
|
|
4407
4441
|
if (transformed) sendToClient(session, transformed);
|
|
4408
4442
|
} catch {
|
|
4409
|
-
if (line.trim() && !line.startsWith("\u256D") && !line.startsWith("\u2570") && !line.startsWith("\u2502") && line.length > 2) {
|
|
4410
|
-
sendToClient(session, { type: "text", content: line });
|
|
4411
|
-
}
|
|
4412
4443
|
}
|
|
4413
4444
|
}
|
|
4414
4445
|
});
|
|
@@ -5861,7 +5892,7 @@ Path: ${projConfig.path}
|
|
|
5861
5892
|
method: "POST",
|
|
5862
5893
|
pattern: "/api/strategy/:project/sessions",
|
|
5863
5894
|
handler: async (body, params) => {
|
|
5864
|
-
const { name, idea, methodology, interactionMode, buildOnSession } = body;
|
|
5895
|
+
const { name, idea, methodology, interactionMode, buildOnSession, sessionType, approach } = body;
|
|
5865
5896
|
if (!name || !idea || !methodology) throw new Error("Missing: name, idea, methodology");
|
|
5866
5897
|
const { createStrategySession: createStrategySession2 } = await Promise.resolve().then(() => (init_strategy(), strategy_exports));
|
|
5867
5898
|
return createStrategySession2(factoryDir, params.project, {
|
|
@@ -5869,7 +5900,9 @@ Path: ${projConfig.path}
|
|
|
5869
5900
|
idea,
|
|
5870
5901
|
methodology,
|
|
5871
5902
|
interactionMode: interactionMode || "interactive",
|
|
5872
|
-
buildOnSession
|
|
5903
|
+
buildOnSession,
|
|
5904
|
+
sessionType: sessionType || "free-form",
|
|
5905
|
+
approach: approach || "auto"
|
|
5873
5906
|
});
|
|
5874
5907
|
}
|
|
5875
5908
|
},
|
|
@@ -5890,6 +5923,145 @@ Path: ${projConfig.path}
|
|
|
5890
5923
|
if (!content) throw new Error(`Artifact not found: ${params.artifact}`);
|
|
5891
5924
|
return { content };
|
|
5892
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
|
+
}
|
|
5893
6065
|
}
|
|
5894
6066
|
];
|
|
5895
6067
|
}
|