majlis 0.6.1 → 0.6.2
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/cli.js +368 -203
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -435,6 +435,10 @@ var init_format = __esm({
|
|
|
435
435
|
// src/commands/init.ts
|
|
436
436
|
var init_exports = {};
|
|
437
437
|
__export(init_exports, {
|
|
438
|
+
AGENT_DEFINITIONS: () => AGENT_DEFINITIONS,
|
|
439
|
+
CLAUDE_MD_SECTION: () => CLAUDE_MD_SECTION,
|
|
440
|
+
HOOKS_CONFIG: () => HOOKS_CONFIG,
|
|
441
|
+
SLASH_COMMANDS: () => SLASH_COMMANDS,
|
|
438
442
|
init: () => init
|
|
439
443
|
});
|
|
440
444
|
async function init(_args) {
|
|
@@ -1435,6 +1439,193 @@ Run \`majlis status\` for live experiment state and cycle position.
|
|
|
1435
1439
|
}
|
|
1436
1440
|
});
|
|
1437
1441
|
|
|
1442
|
+
// src/git.ts
|
|
1443
|
+
function autoCommit(root, message) {
|
|
1444
|
+
try {
|
|
1445
|
+
(0, import_node_child_process.execSync)("git add docs/ .majlis/scripts/ 2>/dev/null; true", {
|
|
1446
|
+
cwd: root,
|
|
1447
|
+
encoding: "utf-8",
|
|
1448
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
1449
|
+
});
|
|
1450
|
+
const diff = (0, import_node_child_process.execSync)("git diff --cached --stat", {
|
|
1451
|
+
cwd: root,
|
|
1452
|
+
encoding: "utf-8",
|
|
1453
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
1454
|
+
}).trim();
|
|
1455
|
+
if (!diff) return;
|
|
1456
|
+
(0, import_node_child_process.execSync)(`git commit -m ${JSON.stringify(`[majlis] ${message}`)}`, {
|
|
1457
|
+
cwd: root,
|
|
1458
|
+
encoding: "utf-8",
|
|
1459
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
1460
|
+
});
|
|
1461
|
+
info(`Auto-committed: ${message}`);
|
|
1462
|
+
} catch {
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
var import_node_child_process;
|
|
1466
|
+
var init_git = __esm({
|
|
1467
|
+
"src/git.ts"() {
|
|
1468
|
+
"use strict";
|
|
1469
|
+
import_node_child_process = require("child_process");
|
|
1470
|
+
init_format();
|
|
1471
|
+
}
|
|
1472
|
+
});
|
|
1473
|
+
|
|
1474
|
+
// src/commands/upgrade.ts
|
|
1475
|
+
var upgrade_exports = {};
|
|
1476
|
+
__export(upgrade_exports, {
|
|
1477
|
+
upgrade: () => upgrade
|
|
1478
|
+
});
|
|
1479
|
+
async function upgrade(_args) {
|
|
1480
|
+
const root = findProjectRoot();
|
|
1481
|
+
if (!root) throw new Error("Not in a Majlis project. Run `majlis init` first.");
|
|
1482
|
+
header(`Upgrading to Majlis v${VERSION}`);
|
|
1483
|
+
let updated = 0;
|
|
1484
|
+
let added = 0;
|
|
1485
|
+
const majlisAgentsDir = path3.join(root, ".majlis", "agents");
|
|
1486
|
+
const claudeAgentsDir = path3.join(root, ".claude", "agents");
|
|
1487
|
+
mkdirSafe2(majlisAgentsDir);
|
|
1488
|
+
mkdirSafe2(claudeAgentsDir);
|
|
1489
|
+
for (const [name, content] of Object.entries(AGENT_DEFINITIONS)) {
|
|
1490
|
+
const majlisPath = path3.join(majlisAgentsDir, `${name}.md`);
|
|
1491
|
+
const claudePath = path3.join(claudeAgentsDir, `${name}.md`);
|
|
1492
|
+
const existed = fs3.existsSync(majlisPath);
|
|
1493
|
+
const current = existed ? fs3.readFileSync(majlisPath, "utf-8") : "";
|
|
1494
|
+
if (current !== content) {
|
|
1495
|
+
fs3.writeFileSync(majlisPath, content);
|
|
1496
|
+
fs3.writeFileSync(claudePath, content);
|
|
1497
|
+
if (existed) {
|
|
1498
|
+
info(` Updated agent: ${name}`);
|
|
1499
|
+
updated++;
|
|
1500
|
+
} else {
|
|
1501
|
+
info(` Added agent: ${name}`);
|
|
1502
|
+
added++;
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
try {
|
|
1507
|
+
for (const file of fs3.readdirSync(majlisAgentsDir)) {
|
|
1508
|
+
const name = file.replace(".md", "");
|
|
1509
|
+
if (!AGENT_DEFINITIONS[name]) {
|
|
1510
|
+
fs3.unlinkSync(path3.join(majlisAgentsDir, file));
|
|
1511
|
+
try {
|
|
1512
|
+
fs3.unlinkSync(path3.join(claudeAgentsDir, file));
|
|
1513
|
+
} catch {
|
|
1514
|
+
}
|
|
1515
|
+
info(` Removed deprecated agent: ${name}`);
|
|
1516
|
+
updated++;
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
} catch {
|
|
1520
|
+
}
|
|
1521
|
+
const commandsDir = path3.join(root, ".claude", "commands");
|
|
1522
|
+
mkdirSafe2(commandsDir);
|
|
1523
|
+
for (const [name, cmd] of Object.entries(SLASH_COMMANDS)) {
|
|
1524
|
+
const cmdPath = path3.join(commandsDir, `${name}.md`);
|
|
1525
|
+
const content = `---
|
|
1526
|
+
description: ${cmd.description}
|
|
1527
|
+
---
|
|
1528
|
+
${cmd.body}
|
|
1529
|
+
`;
|
|
1530
|
+
const existed = fs3.existsSync(cmdPath);
|
|
1531
|
+
const current = existed ? fs3.readFileSync(cmdPath, "utf-8") : "";
|
|
1532
|
+
if (current !== content) {
|
|
1533
|
+
fs3.writeFileSync(cmdPath, content);
|
|
1534
|
+
if (existed) {
|
|
1535
|
+
updated++;
|
|
1536
|
+
} else {
|
|
1537
|
+
added++;
|
|
1538
|
+
}
|
|
1539
|
+
info(` ${existed ? "Updated" : "Added"} command: /${name}`);
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
const settingsPath = path3.join(root, ".claude", "settings.json");
|
|
1543
|
+
try {
|
|
1544
|
+
if (fs3.existsSync(settingsPath)) {
|
|
1545
|
+
const existing = JSON.parse(fs3.readFileSync(settingsPath, "utf-8"));
|
|
1546
|
+
const before = JSON.stringify(existing.hooks);
|
|
1547
|
+
existing.hooks = { ...existing.hooks, ...HOOKS_CONFIG.hooks };
|
|
1548
|
+
if (JSON.stringify(existing.hooks) !== before) {
|
|
1549
|
+
fs3.writeFileSync(settingsPath, JSON.stringify(existing, null, 2));
|
|
1550
|
+
info(" Updated hooks in .claude/settings.json");
|
|
1551
|
+
updated++;
|
|
1552
|
+
}
|
|
1553
|
+
} else {
|
|
1554
|
+
fs3.writeFileSync(settingsPath, JSON.stringify(HOOKS_CONFIG, null, 2));
|
|
1555
|
+
info(" Created .claude/settings.json");
|
|
1556
|
+
added++;
|
|
1557
|
+
}
|
|
1558
|
+
} catch {
|
|
1559
|
+
warn(" Could not update .claude/settings.json");
|
|
1560
|
+
}
|
|
1561
|
+
const docDirs = [
|
|
1562
|
+
"inbox",
|
|
1563
|
+
"experiments",
|
|
1564
|
+
"decisions",
|
|
1565
|
+
"classification",
|
|
1566
|
+
"doubts",
|
|
1567
|
+
"challenges",
|
|
1568
|
+
"verification",
|
|
1569
|
+
"reframes",
|
|
1570
|
+
"rihla",
|
|
1571
|
+
"synthesis",
|
|
1572
|
+
"diagnosis"
|
|
1573
|
+
];
|
|
1574
|
+
for (const dir of docDirs) {
|
|
1575
|
+
const dirPath = path3.join(root, "docs", dir);
|
|
1576
|
+
if (!fs3.existsSync(dirPath)) {
|
|
1577
|
+
fs3.mkdirSync(dirPath, { recursive: true });
|
|
1578
|
+
info(` Added docs/${dir}/`);
|
|
1579
|
+
added++;
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
const claudeMdPath = path3.join(root, "CLAUDE.md");
|
|
1583
|
+
if (fs3.existsSync(claudeMdPath)) {
|
|
1584
|
+
const existing = fs3.readFileSync(claudeMdPath, "utf-8");
|
|
1585
|
+
if (existing.includes("## Majlis Protocol")) {
|
|
1586
|
+
const replaced = existing.replace(
|
|
1587
|
+
/## Majlis Protocol[\s\S]*?(?=\n## [^M]|\n## $|$)/,
|
|
1588
|
+
CLAUDE_MD_SECTION.trim()
|
|
1589
|
+
);
|
|
1590
|
+
if (replaced !== existing) {
|
|
1591
|
+
fs3.writeFileSync(claudeMdPath, replaced);
|
|
1592
|
+
info(" Updated Majlis Protocol in CLAUDE.md");
|
|
1593
|
+
updated++;
|
|
1594
|
+
}
|
|
1595
|
+
} else {
|
|
1596
|
+
fs3.writeFileSync(claudeMdPath, existing + "\n" + CLAUDE_MD_SECTION);
|
|
1597
|
+
info(" Appended Majlis Protocol to CLAUDE.md");
|
|
1598
|
+
added++;
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
if (updated === 0 && added === 0) {
|
|
1602
|
+
success(`Already up to date (v${VERSION}).`);
|
|
1603
|
+
} else {
|
|
1604
|
+
autoCommit(root, `upgrade to v${VERSION}`);
|
|
1605
|
+
success(`Upgraded to v${VERSION}: ${updated} updated, ${added} added.`);
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
function mkdirSafe2(dir) {
|
|
1609
|
+
if (!fs3.existsSync(dir)) {
|
|
1610
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
var fs3, path3, VERSION;
|
|
1614
|
+
var init_upgrade = __esm({
|
|
1615
|
+
"src/commands/upgrade.ts"() {
|
|
1616
|
+
"use strict";
|
|
1617
|
+
fs3 = __toESM(require("fs"));
|
|
1618
|
+
path3 = __toESM(require("path"));
|
|
1619
|
+
init_connection();
|
|
1620
|
+
init_init();
|
|
1621
|
+
init_git();
|
|
1622
|
+
init_format();
|
|
1623
|
+
VERSION = JSON.parse(
|
|
1624
|
+
fs3.readFileSync(path3.join(__dirname, "..", "package.json"), "utf-8")
|
|
1625
|
+
).version;
|
|
1626
|
+
}
|
|
1627
|
+
});
|
|
1628
|
+
|
|
1438
1629
|
// src/db/queries.ts
|
|
1439
1630
|
function createExperiment(db, slug, branch, hypothesis, subType, classificationRef) {
|
|
1440
1631
|
const stmt = db.prepare(`
|
|
@@ -1869,13 +2060,13 @@ var init_queries = __esm({
|
|
|
1869
2060
|
// src/config.ts
|
|
1870
2061
|
function loadConfig(projectRoot) {
|
|
1871
2062
|
if (_cachedConfig && _cachedRoot === projectRoot) return _cachedConfig;
|
|
1872
|
-
const configPath =
|
|
1873
|
-
if (!
|
|
2063
|
+
const configPath = path4.join(projectRoot, ".majlis", "config.json");
|
|
2064
|
+
if (!fs4.existsSync(configPath)) {
|
|
1874
2065
|
_cachedConfig = { ...DEFAULT_CONFIG2 };
|
|
1875
2066
|
_cachedRoot = projectRoot;
|
|
1876
2067
|
return _cachedConfig;
|
|
1877
2068
|
}
|
|
1878
|
-
const loaded = JSON.parse(
|
|
2069
|
+
const loaded = JSON.parse(fs4.readFileSync(configPath, "utf-8"));
|
|
1879
2070
|
_cachedConfig = {
|
|
1880
2071
|
...DEFAULT_CONFIG2,
|
|
1881
2072
|
...loaded,
|
|
@@ -1889,7 +2080,7 @@ function loadConfig(projectRoot) {
|
|
|
1889
2080
|
}
|
|
1890
2081
|
function readFileOrEmpty(filePath) {
|
|
1891
2082
|
try {
|
|
1892
|
-
return
|
|
2083
|
+
return fs4.readFileSync(filePath, "utf-8");
|
|
1893
2084
|
} catch {
|
|
1894
2085
|
return "";
|
|
1895
2086
|
}
|
|
@@ -1904,21 +2095,21 @@ function truncateContext(content, limit) {
|
|
|
1904
2095
|
return content.slice(0, limit) + "\n[TRUNCATED]";
|
|
1905
2096
|
}
|
|
1906
2097
|
function readLatestDiagnosis(projectRoot) {
|
|
1907
|
-
const dir =
|
|
2098
|
+
const dir = path4.join(projectRoot, "docs", "diagnosis");
|
|
1908
2099
|
try {
|
|
1909
|
-
const files =
|
|
2100
|
+
const files = fs4.readdirSync(dir).filter((f) => f.startsWith("diagnosis-") && f.endsWith(".md")).sort().reverse();
|
|
1910
2101
|
if (files.length === 0) return "";
|
|
1911
|
-
return
|
|
2102
|
+
return fs4.readFileSync(path4.join(dir, files[0]), "utf-8");
|
|
1912
2103
|
} catch {
|
|
1913
2104
|
return "";
|
|
1914
2105
|
}
|
|
1915
2106
|
}
|
|
1916
|
-
var
|
|
2107
|
+
var fs4, path4, DEFAULT_CONFIG2, _cachedConfig, _cachedRoot, CONTEXT_LIMITS;
|
|
1917
2108
|
var init_config = __esm({
|
|
1918
2109
|
"src/config.ts"() {
|
|
1919
2110
|
"use strict";
|
|
1920
|
-
|
|
1921
|
-
|
|
2111
|
+
fs4 = __toESM(require("fs"));
|
|
2112
|
+
path4 = __toESM(require("path"));
|
|
1922
2113
|
DEFAULT_CONFIG2 = {
|
|
1923
2114
|
project: { name: "", description: "", objective: "" },
|
|
1924
2115
|
metrics: { command: "", fixtures: [], tracked: {} },
|
|
@@ -2247,11 +2438,11 @@ var init_parse = __esm({
|
|
|
2247
2438
|
// src/agents/spawn.ts
|
|
2248
2439
|
function loadAgentDefinition(role, projectRoot) {
|
|
2249
2440
|
const root = projectRoot ?? findProjectRoot() ?? process.cwd();
|
|
2250
|
-
const filePath =
|
|
2251
|
-
if (!
|
|
2441
|
+
const filePath = path5.join(root, ".majlis", "agents", `${role}.md`);
|
|
2442
|
+
if (!fs5.existsSync(filePath)) {
|
|
2252
2443
|
throw new Error(`Agent definition not found: ${filePath}`);
|
|
2253
2444
|
}
|
|
2254
|
-
const content =
|
|
2445
|
+
const content = fs5.readFileSync(filePath, "utf-8");
|
|
2255
2446
|
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
2256
2447
|
if (!frontmatterMatch) {
|
|
2257
2448
|
throw new Error(`Invalid agent definition (missing YAML frontmatter): ${filePath}`);
|
|
@@ -2459,15 +2650,15 @@ async function spawnRecovery(role, partialOutput, context, projectRoot) {
|
|
|
2459
2650
|
const root = projectRoot ?? findProjectRoot() ?? process.cwd();
|
|
2460
2651
|
const expSlug = context.experiment?.slug ?? "unknown";
|
|
2461
2652
|
console.log(`[recovery] Cleaning up after truncated ${role} for ${expSlug}...`);
|
|
2462
|
-
const expDocPath =
|
|
2653
|
+
const expDocPath = path5.join(
|
|
2463
2654
|
root,
|
|
2464
2655
|
"docs",
|
|
2465
2656
|
"experiments",
|
|
2466
2657
|
`${String(context.experiment?.id ?? 0).padStart(3, "0")}-${expSlug}.md`
|
|
2467
2658
|
);
|
|
2468
|
-
const templatePath =
|
|
2469
|
-
const template =
|
|
2470
|
-
const currentDoc =
|
|
2659
|
+
const templatePath = path5.join(root, "docs", "experiments", "_TEMPLATE.md");
|
|
2660
|
+
const template = fs5.existsSync(templatePath) ? fs5.readFileSync(templatePath, "utf-8") : "";
|
|
2661
|
+
const currentDoc = fs5.existsSync(expDocPath) ? fs5.readFileSync(expDocPath, "utf-8") : "";
|
|
2471
2662
|
const prompt = `The ${role} agent was truncated (hit max turns) while working on experiment "${expSlug}".
|
|
2472
2663
|
|
|
2473
2664
|
Here is the partial agent output (reasoning + tool calls):
|
|
@@ -2630,23 +2821,23 @@ function writeArtifact(role, context, markdown, projectRoot) {
|
|
|
2630
2821
|
const dir = dirMap[role];
|
|
2631
2822
|
if (!dir) return null;
|
|
2632
2823
|
if (role === "builder" || role === "compressor" || role === "diagnostician") return null;
|
|
2633
|
-
const fullDir =
|
|
2634
|
-
if (!
|
|
2635
|
-
|
|
2824
|
+
const fullDir = path5.join(projectRoot, dir);
|
|
2825
|
+
if (!fs5.existsSync(fullDir)) {
|
|
2826
|
+
fs5.mkdirSync(fullDir, { recursive: true });
|
|
2636
2827
|
}
|
|
2637
2828
|
const expSlug = context.experiment?.slug ?? "general";
|
|
2638
2829
|
const nextNum = String(context.experiment?.id ?? 1).padStart(3, "0");
|
|
2639
2830
|
const filename = `${nextNum}-${role}-${expSlug}.md`;
|
|
2640
|
-
const target =
|
|
2641
|
-
|
|
2831
|
+
const target = path5.join(fullDir, filename);
|
|
2832
|
+
fs5.writeFileSync(target, markdown);
|
|
2642
2833
|
return target;
|
|
2643
2834
|
}
|
|
2644
|
-
var
|
|
2835
|
+
var fs5, path5, import_claude_agent_sdk2, ROLE_MAX_TURNS, CHECKPOINT_INTERVAL, DIM2, RESET2, CYAN2;
|
|
2645
2836
|
var init_spawn = __esm({
|
|
2646
2837
|
"src/agents/spawn.ts"() {
|
|
2647
2838
|
"use strict";
|
|
2648
|
-
|
|
2649
|
-
|
|
2839
|
+
fs5 = __toESM(require("fs"));
|
|
2840
|
+
path5 = __toESM(require("path"));
|
|
2650
2841
|
import_claude_agent_sdk2 = require("@anthropic-ai/claude-agent-sdk");
|
|
2651
2842
|
init_parse();
|
|
2652
2843
|
init_connection();
|
|
@@ -2675,38 +2866,6 @@ var init_spawn = __esm({
|
|
|
2675
2866
|
}
|
|
2676
2867
|
});
|
|
2677
2868
|
|
|
2678
|
-
// src/git.ts
|
|
2679
|
-
function autoCommit(root, message) {
|
|
2680
|
-
try {
|
|
2681
|
-
(0, import_node_child_process.execSync)("git add docs/ .majlis/scripts/ 2>/dev/null; true", {
|
|
2682
|
-
cwd: root,
|
|
2683
|
-
encoding: "utf-8",
|
|
2684
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
2685
|
-
});
|
|
2686
|
-
const diff = (0, import_node_child_process.execSync)("git diff --cached --stat", {
|
|
2687
|
-
cwd: root,
|
|
2688
|
-
encoding: "utf-8",
|
|
2689
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
2690
|
-
}).trim();
|
|
2691
|
-
if (!diff) return;
|
|
2692
|
-
(0, import_node_child_process.execSync)(`git commit -m ${JSON.stringify(`[majlis] ${message}`)}`, {
|
|
2693
|
-
cwd: root,
|
|
2694
|
-
encoding: "utf-8",
|
|
2695
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
2696
|
-
});
|
|
2697
|
-
info(`Auto-committed: ${message}`);
|
|
2698
|
-
} catch {
|
|
2699
|
-
}
|
|
2700
|
-
}
|
|
2701
|
-
var import_node_child_process;
|
|
2702
|
-
var init_git = __esm({
|
|
2703
|
-
"src/git.ts"() {
|
|
2704
|
-
"use strict";
|
|
2705
|
-
import_node_child_process = require("child_process");
|
|
2706
|
-
init_format();
|
|
2707
|
-
}
|
|
2708
|
-
});
|
|
2709
|
-
|
|
2710
2869
|
// src/metrics.ts
|
|
2711
2870
|
function compareMetrics(db, experimentId, config) {
|
|
2712
2871
|
const before = getMetricsByExperimentAndPhase(db, experimentId, "before");
|
|
@@ -2926,13 +3085,13 @@ async function newExperiment(args) {
|
|
|
2926
3085
|
const subType = getFlagValue(args, "--sub-type") ?? null;
|
|
2927
3086
|
const exp = createExperiment(db, slug, branch, hypothesis, subType, null);
|
|
2928
3087
|
success(`Created experiment #${exp.id}: ${exp.slug}`);
|
|
2929
|
-
const docsDir =
|
|
2930
|
-
const templatePath =
|
|
2931
|
-
if (
|
|
2932
|
-
const template =
|
|
3088
|
+
const docsDir = path6.join(root, "docs", "experiments");
|
|
3089
|
+
const templatePath = path6.join(docsDir, "_TEMPLATE.md");
|
|
3090
|
+
if (fs6.existsSync(templatePath)) {
|
|
3091
|
+
const template = fs6.readFileSync(templatePath, "utf-8");
|
|
2933
3092
|
const logContent = template.replace(/\{\{title\}\}/g, hypothesis).replace(/\{\{hypothesis\}\}/g, hypothesis).replace(/\{\{branch\}\}/g, branch).replace(/\{\{status\}\}/g, "classified").replace(/\{\{sub_type\}\}/g, subType ?? "unclassified").replace(/\{\{date\}\}/g, (/* @__PURE__ */ new Date()).toISOString().split("T")[0]);
|
|
2934
|
-
const logPath =
|
|
2935
|
-
|
|
3093
|
+
const logPath = path6.join(docsDir, `${paddedNum}-${slug}.md`);
|
|
3094
|
+
fs6.writeFileSync(logPath, logContent);
|
|
2936
3095
|
info(`Created experiment log: docs/experiments/${paddedNum}-${slug}.md`);
|
|
2937
3096
|
}
|
|
2938
3097
|
autoCommit(root, `new: ${slug}`);
|
|
@@ -2988,12 +3147,12 @@ async function revert(args) {
|
|
|
2988
3147
|
}
|
|
2989
3148
|
info(`Experiment ${exp.slug} reverted to dead-end. Reason: ${reason}`);
|
|
2990
3149
|
}
|
|
2991
|
-
var
|
|
3150
|
+
var fs6, path6, import_node_child_process3;
|
|
2992
3151
|
var init_experiment = __esm({
|
|
2993
3152
|
"src/commands/experiment.ts"() {
|
|
2994
3153
|
"use strict";
|
|
2995
|
-
|
|
2996
|
-
|
|
3154
|
+
fs6 = __toESM(require("fs"));
|
|
3155
|
+
path6 = __toESM(require("path"));
|
|
2997
3156
|
import_node_child_process3 = require("child_process");
|
|
2998
3157
|
init_connection();
|
|
2999
3158
|
init_queries();
|
|
@@ -3135,12 +3294,12 @@ function queryDeadEnds(db, args, isJson) {
|
|
|
3135
3294
|
console.log(table(["ID", "Sub-Type", "Approach", "Constraint"], rows));
|
|
3136
3295
|
}
|
|
3137
3296
|
function queryFragility(root, isJson) {
|
|
3138
|
-
const fragPath =
|
|
3139
|
-
if (!
|
|
3297
|
+
const fragPath = path7.join(root, "docs", "synthesis", "fragility.md");
|
|
3298
|
+
if (!fs7.existsSync(fragPath)) {
|
|
3140
3299
|
info("No fragility map found.");
|
|
3141
3300
|
return;
|
|
3142
3301
|
}
|
|
3143
|
-
const content =
|
|
3302
|
+
const content = fs7.readFileSync(fragPath, "utf-8");
|
|
3144
3303
|
if (isJson) {
|
|
3145
3304
|
console.log(JSON.stringify({ content }, null, 2));
|
|
3146
3305
|
return;
|
|
@@ -3196,7 +3355,7 @@ function queryCircuitBreakers(db, root, isJson) {
|
|
|
3196
3355
|
function checkCommit(db) {
|
|
3197
3356
|
let stdinData = "";
|
|
3198
3357
|
try {
|
|
3199
|
-
stdinData =
|
|
3358
|
+
stdinData = fs7.readFileSync(0, "utf-8");
|
|
3200
3359
|
} catch {
|
|
3201
3360
|
}
|
|
3202
3361
|
if (stdinData) {
|
|
@@ -3221,12 +3380,12 @@ function checkCommit(db) {
|
|
|
3221
3380
|
process.exit(1);
|
|
3222
3381
|
}
|
|
3223
3382
|
}
|
|
3224
|
-
var
|
|
3383
|
+
var fs7, path7;
|
|
3225
3384
|
var init_query = __esm({
|
|
3226
3385
|
"src/commands/query.ts"() {
|
|
3227
3386
|
"use strict";
|
|
3228
|
-
|
|
3229
|
-
|
|
3387
|
+
fs7 = __toESM(require("fs"));
|
|
3388
|
+
path7 = __toESM(require("path"));
|
|
3230
3389
|
init_connection();
|
|
3231
3390
|
init_queries();
|
|
3232
3391
|
init_config();
|
|
@@ -3518,23 +3677,23 @@ function gitRevert(branch, cwd) {
|
|
|
3518
3677
|
}
|
|
3519
3678
|
}
|
|
3520
3679
|
function appendToFragilityMap(projectRoot, expSlug, gaps) {
|
|
3521
|
-
const fragPath =
|
|
3680
|
+
const fragPath = path8.join(projectRoot, "docs", "synthesis", "fragility.md");
|
|
3522
3681
|
let content = "";
|
|
3523
|
-
if (
|
|
3524
|
-
content =
|
|
3682
|
+
if (fs8.existsSync(fragPath)) {
|
|
3683
|
+
content = fs8.readFileSync(fragPath, "utf-8");
|
|
3525
3684
|
}
|
|
3526
3685
|
const entry = `
|
|
3527
3686
|
## From experiment: ${expSlug}
|
|
3528
3687
|
${gaps}
|
|
3529
3688
|
`;
|
|
3530
|
-
|
|
3689
|
+
fs8.writeFileSync(fragPath, content + entry);
|
|
3531
3690
|
}
|
|
3532
|
-
var
|
|
3691
|
+
var fs8, path8, import_node_child_process4;
|
|
3533
3692
|
var init_resolve = __esm({
|
|
3534
3693
|
"src/resolve.ts"() {
|
|
3535
3694
|
"use strict";
|
|
3536
|
-
|
|
3537
|
-
|
|
3695
|
+
fs8 = __toESM(require("fs"));
|
|
3696
|
+
path8 = __toESM(require("path"));
|
|
3538
3697
|
init_types2();
|
|
3539
3698
|
init_queries();
|
|
3540
3699
|
init_spawn();
|
|
@@ -3606,8 +3765,8 @@ async function runResolve(db, exp, root) {
|
|
|
3606
3765
|
}
|
|
3607
3766
|
async function doGate(db, exp, root) {
|
|
3608
3767
|
transition(exp.status, "gated" /* GATED */);
|
|
3609
|
-
const synthesis = truncateContext(readFileOrEmpty(
|
|
3610
|
-
const fragility = truncateContext(readFileOrEmpty(
|
|
3768
|
+
const synthesis = truncateContext(readFileOrEmpty(path9.join(root, "docs", "synthesis", "current.md")), CONTEXT_LIMITS.synthesis);
|
|
3769
|
+
const fragility = truncateContext(readFileOrEmpty(path9.join(root, "docs", "synthesis", "fragility.md")), CONTEXT_LIMITS.fragility);
|
|
3611
3770
|
const structuralDeadEnds = exp.sub_type ? listStructuralDeadEndsBySubType(db, exp.sub_type) : listStructuralDeadEnds(db);
|
|
3612
3771
|
const result = await spawnAgent("gatekeeper", {
|
|
3613
3772
|
experiment: {
|
|
@@ -3651,8 +3810,8 @@ async function doBuild(db, exp, root) {
|
|
|
3651
3810
|
transition(exp.status, "building" /* BUILDING */);
|
|
3652
3811
|
const deadEnds = exp.sub_type ? listDeadEndsBySubType(db, exp.sub_type) : listAllDeadEnds(db);
|
|
3653
3812
|
const builderGuidance = getBuilderGuidance(db, exp.id);
|
|
3654
|
-
const fragility = truncateContext(readFileOrEmpty(
|
|
3655
|
-
const synthesis = truncateContext(readFileOrEmpty(
|
|
3813
|
+
const fragility = truncateContext(readFileOrEmpty(path9.join(root, "docs", "synthesis", "fragility.md")), CONTEXT_LIMITS.fragility);
|
|
3814
|
+
const synthesis = truncateContext(readFileOrEmpty(path9.join(root, "docs", "synthesis", "current.md")), CONTEXT_LIMITS.synthesis);
|
|
3656
3815
|
const confirmedDoubts = getConfirmedDoubts(db, exp.id);
|
|
3657
3816
|
const config = loadConfig(root);
|
|
3658
3817
|
const existingBaseline = getMetricsByExperimentAndPhase(db, exp.id, "before");
|
|
@@ -3747,7 +3906,7 @@ async function doChallenge(db, exp, root) {
|
|
|
3747
3906
|
} catch {
|
|
3748
3907
|
}
|
|
3749
3908
|
if (gitDiff.length > 8e3) gitDiff = gitDiff.slice(0, 8e3) + "\n[DIFF TRUNCATED]";
|
|
3750
|
-
const synthesis = truncateContext(readFileOrEmpty(
|
|
3909
|
+
const synthesis = truncateContext(readFileOrEmpty(path9.join(root, "docs", "synthesis", "current.md")), CONTEXT_LIMITS.synthesis);
|
|
3751
3910
|
let taskPrompt = `Construct adversarial test cases for experiment ${exp.slug}: ${exp.hypothesis}`;
|
|
3752
3911
|
if (gitDiff) {
|
|
3753
3912
|
taskPrompt += `
|
|
@@ -3780,9 +3939,9 @@ ${gitDiff}
|
|
|
3780
3939
|
async function doDoubt(db, exp, root) {
|
|
3781
3940
|
transition(exp.status, "doubted" /* DOUBTED */);
|
|
3782
3941
|
const paddedNum = String(exp.id).padStart(3, "0");
|
|
3783
|
-
const expDocPath =
|
|
3942
|
+
const expDocPath = path9.join(root, "docs", "experiments", `${paddedNum}-${exp.slug}.md`);
|
|
3784
3943
|
const experimentDoc = truncateContext(readFileOrEmpty(expDocPath), CONTEXT_LIMITS.experimentDoc);
|
|
3785
|
-
const synthesis = truncateContext(readFileOrEmpty(
|
|
3944
|
+
const synthesis = truncateContext(readFileOrEmpty(path9.join(root, "docs", "synthesis", "current.md")), CONTEXT_LIMITS.synthesis);
|
|
3786
3945
|
const deadEnds = exp.sub_type ? listDeadEndsBySubType(db, exp.sub_type) : listAllDeadEnds(db);
|
|
3787
3946
|
let taskPrompt = `Doubt the work in experiment ${exp.slug}: ${exp.hypothesis}. Produce a doubt document with evidence for each doubt.`;
|
|
3788
3947
|
if (experimentDoc) {
|
|
@@ -3821,8 +3980,8 @@ ${experimentDoc}
|
|
|
3821
3980
|
}
|
|
3822
3981
|
async function doScout(db, exp, root) {
|
|
3823
3982
|
transition(exp.status, "scouted" /* SCOUTED */);
|
|
3824
|
-
const synthesis = truncateContext(readFileOrEmpty(
|
|
3825
|
-
const fragility = truncateContext(readFileOrEmpty(
|
|
3983
|
+
const synthesis = truncateContext(readFileOrEmpty(path9.join(root, "docs", "synthesis", "current.md")), CONTEXT_LIMITS.synthesis);
|
|
3984
|
+
const fragility = truncateContext(readFileOrEmpty(path9.join(root, "docs", "synthesis", "fragility.md")), CONTEXT_LIMITS.fragility);
|
|
3826
3985
|
const deadEnds = exp.sub_type ? listDeadEndsBySubType(db, exp.sub_type) : listAllDeadEnds(db);
|
|
3827
3986
|
const deadEndsSummary = deadEnds.map(
|
|
3828
3987
|
(d) => `- [${d.category ?? "structural"}] ${d.approach}: ${d.why_failed}`
|
|
@@ -3869,12 +4028,12 @@ ${fragility}`;
|
|
|
3869
4028
|
async function doVerify(db, exp, root) {
|
|
3870
4029
|
transition(exp.status, "verifying" /* VERIFYING */);
|
|
3871
4030
|
const doubts = getDoubtsByExperiment(db, exp.id);
|
|
3872
|
-
const challengeDir =
|
|
4031
|
+
const challengeDir = path9.join(root, "docs", "challenges");
|
|
3873
4032
|
let challenges = "";
|
|
3874
|
-
if (
|
|
3875
|
-
const files =
|
|
4033
|
+
if (fs9.existsSync(challengeDir)) {
|
|
4034
|
+
const files = fs9.readdirSync(challengeDir).filter((f) => f.includes(exp.slug) && f.endsWith(".md"));
|
|
3876
4035
|
for (const f of files) {
|
|
3877
|
-
challenges +=
|
|
4036
|
+
challenges += fs9.readFileSync(path9.join(challengeDir, f), "utf-8") + "\n\n";
|
|
3878
4037
|
}
|
|
3879
4038
|
}
|
|
3880
4039
|
const beforeMetrics = getMetricsByExperimentAndPhase(db, exp.id, "before");
|
|
@@ -3942,14 +4101,14 @@ async function doVerify(db, exp, root) {
|
|
|
3942
4101
|
success(`Verification complete for ${exp.slug}. Run \`majlis resolve\` next.`);
|
|
3943
4102
|
}
|
|
3944
4103
|
async function doCompress(db, root) {
|
|
3945
|
-
const synthesisPath =
|
|
3946
|
-
const sizeBefore =
|
|
4104
|
+
const synthesisPath = path9.join(root, "docs", "synthesis", "current.md");
|
|
4105
|
+
const sizeBefore = fs9.existsSync(synthesisPath) ? fs9.statSync(synthesisPath).size : 0;
|
|
3947
4106
|
const sessionCount = getSessionsSinceCompression(db);
|
|
3948
4107
|
const dbExport = exportForCompressor(db);
|
|
3949
4108
|
const result = await spawnAgent("compressor", {
|
|
3950
4109
|
taskPrompt: "## Structured Data (CANONICAL \u2014 from SQLite database)\nThe database export below is the source of truth. docs/ files are agent artifacts that may contain stale or incorrect information. Cross-reference everything against this data.\n\n" + dbExport + "\n\n## Your Task\nRead ALL experiments, decisions, doubts, challenges, verification reports, reframes, and recent diffs. Cross-reference for contradictions, redundancies, and patterns. REWRITE docs/synthesis/current.md \u2014 shorter and denser. Update docs/synthesis/fragility.md with current weak areas. Update docs/synthesis/dead-ends.md with structural constraints from rejected experiments."
|
|
3951
4110
|
}, root);
|
|
3952
|
-
const sizeAfter =
|
|
4111
|
+
const sizeAfter = fs9.existsSync(synthesisPath) ? fs9.statSync(synthesisPath).size : 0;
|
|
3953
4112
|
recordCompression(db, sessionCount, sizeBefore, sizeAfter);
|
|
3954
4113
|
autoCommit(root, "compress: update synthesis");
|
|
3955
4114
|
success(`Compression complete. Synthesis: ${sizeBefore}B \u2192 ${sizeAfter}B`);
|
|
@@ -4041,12 +4200,12 @@ function ingestStructuredOutput(db, experimentId, structured) {
|
|
|
4041
4200
|
info(`Ingested ${structured.findings.length} finding(s)`);
|
|
4042
4201
|
}
|
|
4043
4202
|
}
|
|
4044
|
-
var
|
|
4203
|
+
var fs9, path9, import_node_child_process5;
|
|
4045
4204
|
var init_cycle = __esm({
|
|
4046
4205
|
"src/commands/cycle.ts"() {
|
|
4047
4206
|
"use strict";
|
|
4048
|
-
|
|
4049
|
-
|
|
4207
|
+
fs9 = __toESM(require("fs"));
|
|
4208
|
+
path9 = __toESM(require("path"));
|
|
4050
4209
|
import_node_child_process5 = require("child_process");
|
|
4051
4210
|
init_connection();
|
|
4052
4211
|
init_queries();
|
|
@@ -4074,10 +4233,10 @@ async function classify(args) {
|
|
|
4074
4233
|
if (!domain) {
|
|
4075
4234
|
throw new Error('Usage: majlis classify "domain description"');
|
|
4076
4235
|
}
|
|
4077
|
-
const synthesisPath =
|
|
4078
|
-
const synthesis =
|
|
4079
|
-
const deadEndsPath =
|
|
4080
|
-
const deadEnds =
|
|
4236
|
+
const synthesisPath = path10.join(root, "docs", "synthesis", "current.md");
|
|
4237
|
+
const synthesis = fs10.existsSync(synthesisPath) ? fs10.readFileSync(synthesisPath, "utf-8") : "";
|
|
4238
|
+
const deadEndsPath = path10.join(root, "docs", "synthesis", "dead-ends.md");
|
|
4239
|
+
const deadEnds = fs10.existsSync(deadEndsPath) ? fs10.readFileSync(deadEndsPath, "utf-8") : "";
|
|
4081
4240
|
info(`Classifying problem domain: ${domain}`);
|
|
4082
4241
|
const result = await spawnAgent("builder", {
|
|
4083
4242
|
synthesis,
|
|
@@ -4096,22 +4255,22 @@ Write the classification to docs/classification/ following the template.`
|
|
|
4096
4255
|
async function reframe(args) {
|
|
4097
4256
|
const root = findProjectRoot();
|
|
4098
4257
|
if (!root) throw new Error("Not in a Majlis project. Run `majlis init` first.");
|
|
4099
|
-
const classificationDir =
|
|
4258
|
+
const classificationDir = path10.join(root, "docs", "classification");
|
|
4100
4259
|
let classificationContent = "";
|
|
4101
|
-
if (
|
|
4102
|
-
const files =
|
|
4260
|
+
if (fs10.existsSync(classificationDir)) {
|
|
4261
|
+
const files = fs10.readdirSync(classificationDir).filter((f) => f.endsWith(".md") && !f.startsWith("_"));
|
|
4103
4262
|
for (const f of files) {
|
|
4104
|
-
classificationContent +=
|
|
4263
|
+
classificationContent += fs10.readFileSync(path10.join(classificationDir, f), "utf-8") + "\n\n";
|
|
4105
4264
|
}
|
|
4106
4265
|
}
|
|
4107
|
-
const synthesisPath =
|
|
4108
|
-
const synthesis =
|
|
4109
|
-
const deadEndsPath =
|
|
4110
|
-
const deadEnds =
|
|
4111
|
-
const configPath =
|
|
4266
|
+
const synthesisPath = path10.join(root, "docs", "synthesis", "current.md");
|
|
4267
|
+
const synthesis = fs10.existsSync(synthesisPath) ? fs10.readFileSync(synthesisPath, "utf-8") : "";
|
|
4268
|
+
const deadEndsPath = path10.join(root, "docs", "synthesis", "dead-ends.md");
|
|
4269
|
+
const deadEnds = fs10.existsSync(deadEndsPath) ? fs10.readFileSync(deadEndsPath, "utf-8") : "";
|
|
4270
|
+
const configPath = path10.join(root, ".majlis", "config.json");
|
|
4112
4271
|
let problemStatement = "";
|
|
4113
|
-
if (
|
|
4114
|
-
const config = JSON.parse(
|
|
4272
|
+
if (fs10.existsSync(configPath)) {
|
|
4273
|
+
const config = JSON.parse(fs10.readFileSync(configPath, "utf-8"));
|
|
4115
4274
|
problemStatement = `${config.project?.description ?? ""}
|
|
4116
4275
|
Objective: ${config.project?.objective ?? ""}`;
|
|
4117
4276
|
}
|
|
@@ -4136,12 +4295,12 @@ Write to docs/reframes/.`
|
|
|
4136
4295
|
autoCommit(root, `reframe: ${target.slice(0, 60)}`);
|
|
4137
4296
|
success("Reframe complete. Check docs/reframes/ for the output.");
|
|
4138
4297
|
}
|
|
4139
|
-
var
|
|
4298
|
+
var fs10, path10;
|
|
4140
4299
|
var init_classify = __esm({
|
|
4141
4300
|
"src/commands/classify.ts"() {
|
|
4142
4301
|
"use strict";
|
|
4143
|
-
|
|
4144
|
-
|
|
4302
|
+
fs10 = __toESM(require("fs"));
|
|
4303
|
+
path10 = __toESM(require("path"));
|
|
4145
4304
|
init_connection();
|
|
4146
4305
|
init_spawn();
|
|
4147
4306
|
init_git();
|
|
@@ -4163,15 +4322,15 @@ async function audit(args) {
|
|
|
4163
4322
|
const experiments = listAllExperiments(db);
|
|
4164
4323
|
const deadEnds = listAllDeadEnds(db);
|
|
4165
4324
|
const circuitBreakers = getAllCircuitBreakerStates(db, config.cycle.circuit_breaker_threshold);
|
|
4166
|
-
const classificationDir =
|
|
4325
|
+
const classificationDir = path11.join(root, "docs", "classification");
|
|
4167
4326
|
let classification = "";
|
|
4168
|
-
if (
|
|
4169
|
-
const files =
|
|
4327
|
+
if (fs11.existsSync(classificationDir)) {
|
|
4328
|
+
const files = fs11.readdirSync(classificationDir).filter((f) => f.endsWith(".md") && !f.startsWith("_"));
|
|
4170
4329
|
for (const f of files) {
|
|
4171
|
-
classification +=
|
|
4330
|
+
classification += fs11.readFileSync(path11.join(classificationDir, f), "utf-8") + "\n\n";
|
|
4172
4331
|
}
|
|
4173
4332
|
}
|
|
4174
|
-
const synthesis = readFileOrEmpty(
|
|
4333
|
+
const synthesis = readFileOrEmpty(path11.join(root, "docs", "synthesis", "current.md"));
|
|
4175
4334
|
header("Maqasid Check \u2014 Purpose Audit");
|
|
4176
4335
|
const trippedBreakers = circuitBreakers.filter((cb) => cb.tripped);
|
|
4177
4336
|
if (trippedBreakers.length > 0) {
|
|
@@ -4215,12 +4374,12 @@ Output: either "classification confirmed \u2014 continue" or "re-classify from X
|
|
|
4215
4374
|
}, root);
|
|
4216
4375
|
success("Purpose audit complete. Review the output above.");
|
|
4217
4376
|
}
|
|
4218
|
-
var
|
|
4377
|
+
var fs11, path11;
|
|
4219
4378
|
var init_audit = __esm({
|
|
4220
4379
|
"src/commands/audit.ts"() {
|
|
4221
4380
|
"use strict";
|
|
4222
|
-
|
|
4223
|
-
|
|
4381
|
+
fs11 = __toESM(require("fs"));
|
|
4382
|
+
path11 = __toESM(require("path"));
|
|
4224
4383
|
init_connection();
|
|
4225
4384
|
init_queries();
|
|
4226
4385
|
init_spawn();
|
|
@@ -4505,9 +4664,9 @@ async function run(args) {
|
|
|
4505
4664
|
info("Run `majlis status` to see final state.");
|
|
4506
4665
|
}
|
|
4507
4666
|
async function deriveNextHypothesis(goal, root, db) {
|
|
4508
|
-
const synthesis = truncateContext(readFileOrEmpty(
|
|
4509
|
-
const fragility = truncateContext(readFileOrEmpty(
|
|
4510
|
-
const deadEndsDoc = truncateContext(readFileOrEmpty(
|
|
4667
|
+
const synthesis = truncateContext(readFileOrEmpty(path12.join(root, "docs", "synthesis", "current.md")), CONTEXT_LIMITS.synthesis);
|
|
4668
|
+
const fragility = truncateContext(readFileOrEmpty(path12.join(root, "docs", "synthesis", "fragility.md")), CONTEXT_LIMITS.fragility);
|
|
4669
|
+
const deadEndsDoc = truncateContext(readFileOrEmpty(path12.join(root, "docs", "synthesis", "dead-ends.md")), CONTEXT_LIMITS.deadEnds);
|
|
4511
4670
|
const diagnosis = truncateContext(readLatestDiagnosis(root), CONTEXT_LIMITS.synthesis);
|
|
4512
4671
|
const deadEnds = listAllDeadEnds(db);
|
|
4513
4672
|
const config = loadConfig(root);
|
|
@@ -4625,23 +4784,23 @@ async function createNewExperiment(db, root, hypothesis) {
|
|
|
4625
4784
|
const exp = createExperiment(db, finalSlug, branch, hypothesis, null, null);
|
|
4626
4785
|
updateExperimentStatus(db, exp.id, "reframed");
|
|
4627
4786
|
exp.status = "reframed";
|
|
4628
|
-
const docsDir =
|
|
4629
|
-
const templatePath =
|
|
4630
|
-
if (
|
|
4631
|
-
const template =
|
|
4787
|
+
const docsDir = path12.join(root, "docs", "experiments");
|
|
4788
|
+
const templatePath = path12.join(docsDir, "_TEMPLATE.md");
|
|
4789
|
+
if (fs12.existsSync(templatePath)) {
|
|
4790
|
+
const template = fs12.readFileSync(templatePath, "utf-8");
|
|
4632
4791
|
const logContent = template.replace(/\{\{title\}\}/g, hypothesis).replace(/\{\{hypothesis\}\}/g, hypothesis).replace(/\{\{branch\}\}/g, branch).replace(/\{\{status\}\}/g, "classified").replace(/\{\{sub_type\}\}/g, "unclassified").replace(/\{\{date\}\}/g, (/* @__PURE__ */ new Date()).toISOString().split("T")[0]);
|
|
4633
|
-
const logPath =
|
|
4634
|
-
|
|
4792
|
+
const logPath = path12.join(docsDir, `${paddedNum}-${finalSlug}.md`);
|
|
4793
|
+
fs12.writeFileSync(logPath, logContent);
|
|
4635
4794
|
info(`Created experiment log: docs/experiments/${paddedNum}-${finalSlug}.md`);
|
|
4636
4795
|
}
|
|
4637
4796
|
return exp;
|
|
4638
4797
|
}
|
|
4639
|
-
var
|
|
4798
|
+
var fs12, path12, import_node_child_process6;
|
|
4640
4799
|
var init_run = __esm({
|
|
4641
4800
|
"src/commands/run.ts"() {
|
|
4642
4801
|
"use strict";
|
|
4643
|
-
|
|
4644
|
-
|
|
4802
|
+
fs12 = __toESM(require("fs"));
|
|
4803
|
+
path12 = __toESM(require("path"));
|
|
4645
4804
|
import_node_child_process6 = require("child_process");
|
|
4646
4805
|
init_connection();
|
|
4647
4806
|
init_queries();
|
|
@@ -4658,9 +4817,9 @@ var init_run = __esm({
|
|
|
4658
4817
|
|
|
4659
4818
|
// src/swarm/worktree.ts
|
|
4660
4819
|
function createWorktree(mainRoot, slug, paddedNum) {
|
|
4661
|
-
const projectName =
|
|
4820
|
+
const projectName = path13.basename(mainRoot);
|
|
4662
4821
|
const worktreeName = `${projectName}-swarm-${paddedNum}-${slug}`;
|
|
4663
|
-
const worktreePath =
|
|
4822
|
+
const worktreePath = path13.join(path13.dirname(mainRoot), worktreeName);
|
|
4664
4823
|
const branch = `swarm/${paddedNum}-${slug}`;
|
|
4665
4824
|
(0, import_node_child_process7.execSync)(`git worktree add ${JSON.stringify(worktreePath)} -b ${branch}`, {
|
|
4666
4825
|
cwd: mainRoot,
|
|
@@ -4677,36 +4836,36 @@ function createWorktree(mainRoot, slug, paddedNum) {
|
|
|
4677
4836
|
};
|
|
4678
4837
|
}
|
|
4679
4838
|
function initializeWorktree(mainRoot, worktreePath) {
|
|
4680
|
-
const majlisDir =
|
|
4681
|
-
|
|
4682
|
-
const configSrc =
|
|
4683
|
-
if (
|
|
4684
|
-
|
|
4685
|
-
}
|
|
4686
|
-
const agentsSrc =
|
|
4687
|
-
if (
|
|
4688
|
-
const agentsDst =
|
|
4689
|
-
|
|
4690
|
-
for (const file of
|
|
4691
|
-
|
|
4839
|
+
const majlisDir = path13.join(worktreePath, ".majlis");
|
|
4840
|
+
fs13.mkdirSync(majlisDir, { recursive: true });
|
|
4841
|
+
const configSrc = path13.join(mainRoot, ".majlis", "config.json");
|
|
4842
|
+
if (fs13.existsSync(configSrc)) {
|
|
4843
|
+
fs13.copyFileSync(configSrc, path13.join(majlisDir, "config.json"));
|
|
4844
|
+
}
|
|
4845
|
+
const agentsSrc = path13.join(mainRoot, ".majlis", "agents");
|
|
4846
|
+
if (fs13.existsSync(agentsSrc)) {
|
|
4847
|
+
const agentsDst = path13.join(majlisDir, "agents");
|
|
4848
|
+
fs13.mkdirSync(agentsDst, { recursive: true });
|
|
4849
|
+
for (const file of fs13.readdirSync(agentsSrc)) {
|
|
4850
|
+
fs13.copyFileSync(path13.join(agentsSrc, file), path13.join(agentsDst, file));
|
|
4692
4851
|
}
|
|
4693
4852
|
}
|
|
4694
|
-
const synthSrc =
|
|
4695
|
-
if (
|
|
4696
|
-
const synthDst =
|
|
4697
|
-
|
|
4698
|
-
for (const file of
|
|
4699
|
-
const srcFile =
|
|
4700
|
-
if (
|
|
4701
|
-
|
|
4853
|
+
const synthSrc = path13.join(mainRoot, "docs", "synthesis");
|
|
4854
|
+
if (fs13.existsSync(synthSrc)) {
|
|
4855
|
+
const synthDst = path13.join(worktreePath, "docs", "synthesis");
|
|
4856
|
+
fs13.mkdirSync(synthDst, { recursive: true });
|
|
4857
|
+
for (const file of fs13.readdirSync(synthSrc)) {
|
|
4858
|
+
const srcFile = path13.join(synthSrc, file);
|
|
4859
|
+
if (fs13.statSync(srcFile).isFile()) {
|
|
4860
|
+
fs13.copyFileSync(srcFile, path13.join(synthDst, file));
|
|
4702
4861
|
}
|
|
4703
4862
|
}
|
|
4704
4863
|
}
|
|
4705
|
-
const templateSrc =
|
|
4706
|
-
if (
|
|
4707
|
-
const expDir =
|
|
4708
|
-
|
|
4709
|
-
|
|
4864
|
+
const templateSrc = path13.join(mainRoot, "docs", "experiments", "_TEMPLATE.md");
|
|
4865
|
+
if (fs13.existsSync(templateSrc)) {
|
|
4866
|
+
const expDir = path13.join(worktreePath, "docs", "experiments");
|
|
4867
|
+
fs13.mkdirSync(expDir, { recursive: true });
|
|
4868
|
+
fs13.copyFileSync(templateSrc, path13.join(expDir, "_TEMPLATE.md"));
|
|
4710
4869
|
}
|
|
4711
4870
|
const db = openDbAt(worktreePath);
|
|
4712
4871
|
db.close();
|
|
@@ -4738,12 +4897,12 @@ function cleanupWorktree(mainRoot, wt) {
|
|
|
4738
4897
|
} catch {
|
|
4739
4898
|
}
|
|
4740
4899
|
}
|
|
4741
|
-
var
|
|
4900
|
+
var fs13, path13, import_node_child_process7;
|
|
4742
4901
|
var init_worktree = __esm({
|
|
4743
4902
|
"src/swarm/worktree.ts"() {
|
|
4744
4903
|
"use strict";
|
|
4745
|
-
|
|
4746
|
-
|
|
4904
|
+
fs13 = __toESM(require("fs"));
|
|
4905
|
+
path13 = __toESM(require("path"));
|
|
4747
4906
|
import_node_child_process7 = require("child_process");
|
|
4748
4907
|
init_connection();
|
|
4749
4908
|
init_format();
|
|
@@ -4762,12 +4921,12 @@ async function runExperimentInWorktree(wt) {
|
|
|
4762
4921
|
exp = createExperiment(db, wt.slug, wt.branch, wt.hypothesis, null, null);
|
|
4763
4922
|
updateExperimentStatus(db, exp.id, "reframed");
|
|
4764
4923
|
exp.status = "reframed";
|
|
4765
|
-
const templatePath =
|
|
4766
|
-
if (
|
|
4767
|
-
const template =
|
|
4924
|
+
const templatePath = path14.join(wt.path, "docs", "experiments", "_TEMPLATE.md");
|
|
4925
|
+
if (fs14.existsSync(templatePath)) {
|
|
4926
|
+
const template = fs14.readFileSync(templatePath, "utf-8");
|
|
4768
4927
|
const logContent = template.replace(/\{\{title\}\}/g, wt.hypothesis).replace(/\{\{hypothesis\}\}/g, wt.hypothesis).replace(/\{\{branch\}\}/g, wt.branch).replace(/\{\{status\}\}/g, "classified").replace(/\{\{sub_type\}\}/g, "unclassified").replace(/\{\{date\}\}/g, (/* @__PURE__ */ new Date()).toISOString().split("T")[0]);
|
|
4769
|
-
const logPath =
|
|
4770
|
-
|
|
4928
|
+
const logPath = path14.join(wt.path, "docs", "experiments", `${wt.paddedNum}-${wt.slug}.md`);
|
|
4929
|
+
fs14.writeFileSync(logPath, logContent);
|
|
4771
4930
|
}
|
|
4772
4931
|
info(`${label} Starting: ${wt.hypothesis}`);
|
|
4773
4932
|
while (stepCount < MAX_STEPS) {
|
|
@@ -4890,12 +5049,12 @@ function statusToStepName(status2) {
|
|
|
4890
5049
|
return null;
|
|
4891
5050
|
}
|
|
4892
5051
|
}
|
|
4893
|
-
var
|
|
5052
|
+
var fs14, path14, MAX_STEPS;
|
|
4894
5053
|
var init_runner = __esm({
|
|
4895
5054
|
"src/swarm/runner.ts"() {
|
|
4896
5055
|
"use strict";
|
|
4897
|
-
|
|
4898
|
-
|
|
5056
|
+
fs14 = __toESM(require("fs"));
|
|
5057
|
+
path14 = __toESM(require("path"));
|
|
4899
5058
|
init_connection();
|
|
4900
5059
|
init_queries();
|
|
4901
5060
|
init_machine();
|
|
@@ -5181,15 +5340,15 @@ function isMergeable(grade) {
|
|
|
5181
5340
|
}
|
|
5182
5341
|
async function deriveMultipleHypotheses(goal, root, count) {
|
|
5183
5342
|
const synthesis = truncateContext(
|
|
5184
|
-
readFileOrEmpty(
|
|
5343
|
+
readFileOrEmpty(path15.join(root, "docs", "synthesis", "current.md")),
|
|
5185
5344
|
CONTEXT_LIMITS.synthesis
|
|
5186
5345
|
);
|
|
5187
5346
|
const fragility = truncateContext(
|
|
5188
|
-
readFileOrEmpty(
|
|
5347
|
+
readFileOrEmpty(path15.join(root, "docs", "synthesis", "fragility.md")),
|
|
5189
5348
|
CONTEXT_LIMITS.fragility
|
|
5190
5349
|
);
|
|
5191
5350
|
const deadEndsDoc = truncateContext(
|
|
5192
|
-
readFileOrEmpty(
|
|
5351
|
+
readFileOrEmpty(path15.join(root, "docs", "synthesis", "dead-ends.md")),
|
|
5193
5352
|
CONTEXT_LIMITS.deadEnds
|
|
5194
5353
|
);
|
|
5195
5354
|
const diagnosis = truncateContext(readLatestDiagnosis(root), CONTEXT_LIMITS.synthesis);
|
|
@@ -5279,11 +5438,11 @@ If the goal is met:
|
|
|
5279
5438
|
warn("Planner did not return structured hypotheses. Using goal as single hypothesis.");
|
|
5280
5439
|
return [goal];
|
|
5281
5440
|
}
|
|
5282
|
-
var
|
|
5441
|
+
var path15, import_node_child_process8, MAX_PARALLEL, DEFAULT_PARALLEL;
|
|
5283
5442
|
var init_swarm = __esm({
|
|
5284
5443
|
"src/commands/swarm.ts"() {
|
|
5285
5444
|
"use strict";
|
|
5286
|
-
|
|
5445
|
+
path15 = __toESM(require("path"));
|
|
5287
5446
|
import_node_child_process8 = require("child_process");
|
|
5288
5447
|
init_connection();
|
|
5289
5448
|
init_queries();
|
|
@@ -5309,16 +5468,16 @@ async function diagnose(args) {
|
|
|
5309
5468
|
const db = getDb(root);
|
|
5310
5469
|
const focus = args.filter((a) => !a.startsWith("--")).join(" ");
|
|
5311
5470
|
const keepScripts = args.includes("--keep-scripts");
|
|
5312
|
-
const scriptsDir =
|
|
5313
|
-
if (!
|
|
5314
|
-
|
|
5471
|
+
const scriptsDir = path16.join(root, ".majlis", "scripts");
|
|
5472
|
+
if (!fs15.existsSync(scriptsDir)) {
|
|
5473
|
+
fs15.mkdirSync(scriptsDir, { recursive: true });
|
|
5315
5474
|
}
|
|
5316
5475
|
header("Deep Diagnosis");
|
|
5317
5476
|
if (focus) info(`Focus: ${focus}`);
|
|
5318
5477
|
const dbExport = exportForDiagnostician(db);
|
|
5319
|
-
const synthesis = readFileOrEmpty(
|
|
5320
|
-
const fragility = readFileOrEmpty(
|
|
5321
|
-
const deadEndsDoc = readFileOrEmpty(
|
|
5478
|
+
const synthesis = readFileOrEmpty(path16.join(root, "docs", "synthesis", "current.md"));
|
|
5479
|
+
const fragility = readFileOrEmpty(path16.join(root, "docs", "synthesis", "fragility.md"));
|
|
5480
|
+
const deadEndsDoc = readFileOrEmpty(path16.join(root, "docs", "synthesis", "dead-ends.md"));
|
|
5322
5481
|
const config = loadConfig(root);
|
|
5323
5482
|
let metricsOutput = "";
|
|
5324
5483
|
if (config.metrics?.command) {
|
|
@@ -5369,13 +5528,13 @@ Perform a deep diagnostic analysis of this project. Identify root causes, recurr
|
|
|
5369
5528
|
Remember: you may write files ONLY to .majlis/scripts/. You cannot modify project code.`;
|
|
5370
5529
|
info("Spawning diagnostician (60 turns, full DB access)...");
|
|
5371
5530
|
const result = await spawnAgent("diagnostician", { taskPrompt }, root);
|
|
5372
|
-
const diagnosisDir =
|
|
5373
|
-
if (!
|
|
5374
|
-
|
|
5531
|
+
const diagnosisDir = path16.join(root, "docs", "diagnosis");
|
|
5532
|
+
if (!fs15.existsSync(diagnosisDir)) {
|
|
5533
|
+
fs15.mkdirSync(diagnosisDir, { recursive: true });
|
|
5375
5534
|
}
|
|
5376
5535
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
5377
|
-
const artifactPath =
|
|
5378
|
-
|
|
5536
|
+
const artifactPath = path16.join(diagnosisDir, `diagnosis-${timestamp}.md`);
|
|
5537
|
+
fs15.writeFileSync(artifactPath, result.output);
|
|
5379
5538
|
info(`Diagnostic report: docs/diagnosis/diagnosis-${timestamp}.md`);
|
|
5380
5539
|
if (result.structured?.diagnosis) {
|
|
5381
5540
|
const d = result.structured.diagnosis;
|
|
@@ -5388,11 +5547,11 @@ Remember: you may write files ONLY to .majlis/scripts/. You cannot modify projec
|
|
|
5388
5547
|
}
|
|
5389
5548
|
if (!keepScripts) {
|
|
5390
5549
|
try {
|
|
5391
|
-
const files =
|
|
5550
|
+
const files = fs15.readdirSync(scriptsDir);
|
|
5392
5551
|
for (const f of files) {
|
|
5393
|
-
|
|
5552
|
+
fs15.unlinkSync(path16.join(scriptsDir, f));
|
|
5394
5553
|
}
|
|
5395
|
-
|
|
5554
|
+
fs15.rmdirSync(scriptsDir);
|
|
5396
5555
|
info("Cleaned up .majlis/scripts/");
|
|
5397
5556
|
} catch {
|
|
5398
5557
|
}
|
|
@@ -5405,12 +5564,12 @@ Remember: you may write files ONLY to .majlis/scripts/. You cannot modify projec
|
|
|
5405
5564
|
autoCommit(root, `diagnosis: ${focus || "general"}`);
|
|
5406
5565
|
success("Diagnosis complete.");
|
|
5407
5566
|
}
|
|
5408
|
-
var
|
|
5567
|
+
var fs15, path16, import_node_child_process9;
|
|
5409
5568
|
var init_diagnose = __esm({
|
|
5410
5569
|
"src/commands/diagnose.ts"() {
|
|
5411
5570
|
"use strict";
|
|
5412
|
-
|
|
5413
|
-
|
|
5571
|
+
fs15 = __toESM(require("fs"));
|
|
5572
|
+
path16 = __toESM(require("path"));
|
|
5414
5573
|
import_node_child_process9 = require("child_process");
|
|
5415
5574
|
init_connection();
|
|
5416
5575
|
init_queries();
|
|
@@ -5422,10 +5581,10 @@ var init_diagnose = __esm({
|
|
|
5422
5581
|
});
|
|
5423
5582
|
|
|
5424
5583
|
// src/cli.ts
|
|
5425
|
-
var
|
|
5426
|
-
var
|
|
5427
|
-
var
|
|
5428
|
-
|
|
5584
|
+
var fs16 = __toESM(require("fs"));
|
|
5585
|
+
var path17 = __toESM(require("path"));
|
|
5586
|
+
var VERSION2 = JSON.parse(
|
|
5587
|
+
fs16.readFileSync(path17.join(__dirname, "..", "package.json"), "utf-8")
|
|
5429
5588
|
).version;
|
|
5430
5589
|
async function main() {
|
|
5431
5590
|
let sigintCount = 0;
|
|
@@ -5438,7 +5597,7 @@ async function main() {
|
|
|
5438
5597
|
});
|
|
5439
5598
|
const args = process.argv.slice(2);
|
|
5440
5599
|
if (args.includes("--version") || args.includes("-v")) {
|
|
5441
|
-
console.log(
|
|
5600
|
+
console.log(VERSION2);
|
|
5442
5601
|
return;
|
|
5443
5602
|
}
|
|
5444
5603
|
if (args.includes("--help") || args.includes("-h") || args.length === 0) {
|
|
@@ -5455,6 +5614,11 @@ async function main() {
|
|
|
5455
5614
|
await init2(rest);
|
|
5456
5615
|
break;
|
|
5457
5616
|
}
|
|
5617
|
+
case "upgrade": {
|
|
5618
|
+
const { upgrade: upgrade2 } = await Promise.resolve().then(() => (init_upgrade(), upgrade_exports));
|
|
5619
|
+
await upgrade2(rest);
|
|
5620
|
+
break;
|
|
5621
|
+
}
|
|
5458
5622
|
case "status": {
|
|
5459
5623
|
const { status: status2 } = await Promise.resolve().then(() => (init_status(), status_exports));
|
|
5460
5624
|
await status2(isJson);
|
|
@@ -5563,12 +5727,13 @@ async function main() {
|
|
|
5563
5727
|
}
|
|
5564
5728
|
function printHelp() {
|
|
5565
5729
|
console.log(`
|
|
5566
|
-
majlis v${
|
|
5730
|
+
majlis v${VERSION2} \u2014 Structured multi-agent problem solving
|
|
5567
5731
|
|
|
5568
5732
|
Usage: majlis <command> [options]
|
|
5569
5733
|
|
|
5570
5734
|
Lifecycle:
|
|
5571
5735
|
init Initialize Majlis in current project
|
|
5736
|
+
upgrade Sync agents, commands, hooks from CLI version
|
|
5572
5737
|
status [--json] Show experiment states and cycle position
|
|
5573
5738
|
|
|
5574
5739
|
Experiments:
|