@jefuriiij/synthra 0.1.16 → 0.1.17
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/CHANGELOG.md +18 -0
- package/dist/cli/index.js +53 -14
- package/dist/cli/index.js.map +1 -1
- package/dist/dashboard/index.js +1 -1
- package/dist/dashboard/index.js.map +1 -1
- package/dist/server/index.js +52 -13
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
package/dist/server/index.js
CHANGED
|
@@ -1553,9 +1553,11 @@ function resolvePaths(projectRoot) {
|
|
|
1553
1553
|
|
|
1554
1554
|
// src/cli/bootstrap.ts
|
|
1555
1555
|
import { mkdir as mkdir3, readFile as readFile7, stat as stat2, writeFile as writeFile3 } from "fs/promises";
|
|
1556
|
+
import { basename as basename2 } from "path";
|
|
1556
1557
|
|
|
1557
1558
|
// src/hooks/claude-md.ts
|
|
1558
1559
|
import { readFile as readFile6, writeFile as writeFile2 } from "fs/promises";
|
|
1560
|
+
import { basename, dirname as dirname4 } from "path";
|
|
1559
1561
|
var POLICY_VERSION = 3;
|
|
1560
1562
|
var POLICY_BEGIN = `<!-- synthra-policy v${POLICY_VERSION} BEGIN -->`;
|
|
1561
1563
|
var POLICY_END = `<!-- synthra-policy v${POLICY_VERSION} END -->`;
|
|
@@ -1656,7 +1658,39 @@ function policyBlock() {
|
|
|
1656
1658
|
POLICY_END
|
|
1657
1659
|
].join("\n");
|
|
1658
1660
|
}
|
|
1659
|
-
|
|
1661
|
+
function onboardingSkeleton(projectName) {
|
|
1662
|
+
return [
|
|
1663
|
+
`# ${projectName}`,
|
|
1664
|
+
"",
|
|
1665
|
+
"> Onboarding notes for AI coding agents. Synthra's graph already knows the",
|
|
1666
|
+
"> code's *structure* (files, symbols, imports) \u2014 this file is for what the",
|
|
1667
|
+
"> graph can't infer: how to run the project, its conventions, and the",
|
|
1668
|
+
"> decisions behind them. Keep it lean and current; delete prompts you don't need.",
|
|
1669
|
+
"",
|
|
1670
|
+
"## Build & test",
|
|
1671
|
+
"",
|
|
1672
|
+
"- TODO: install deps / build",
|
|
1673
|
+
"- TODO: run tests / lint / typecheck",
|
|
1674
|
+
"- TODO: run the app locally",
|
|
1675
|
+
"",
|
|
1676
|
+
"## Conventions",
|
|
1677
|
+
"",
|
|
1678
|
+
"- TODO: code style, naming, file layout the agent should follow",
|
|
1679
|
+
"",
|
|
1680
|
+
"## Key decisions",
|
|
1681
|
+
"",
|
|
1682
|
+
'- TODO: non-obvious choices and *why* ("we use X not Y because \u2026")',
|
|
1683
|
+
"",
|
|
1684
|
+
"## Gotchas",
|
|
1685
|
+
"",
|
|
1686
|
+
`- TODO: traps, footguns, "don't touch X without Y"`,
|
|
1687
|
+
"",
|
|
1688
|
+
"_Tip: run `/init` in Claude Code to auto-draft the sections above, then trim",
|
|
1689
|
+
"to the durable bits. Synthra manages its own block below \u2014 leave it._",
|
|
1690
|
+
""
|
|
1691
|
+
].join("\n");
|
|
1692
|
+
}
|
|
1693
|
+
async function patchClaudeMd(path, projectName) {
|
|
1660
1694
|
let existing;
|
|
1661
1695
|
try {
|
|
1662
1696
|
existing = await readFile6(path, "utf8");
|
|
@@ -1665,7 +1699,8 @@ async function patchClaudeMd(path) {
|
|
|
1665
1699
|
}
|
|
1666
1700
|
const block = policyBlock();
|
|
1667
1701
|
if (existing === null) {
|
|
1668
|
-
|
|
1702
|
+
const name = projectName || basename(dirname4(path)) || "this project";
|
|
1703
|
+
await writeFile2(path, onboardingSkeleton(name) + "\n" + block + "\n", "utf8");
|
|
1669
1704
|
return { created: true, updated: false, skipped: false };
|
|
1670
1705
|
}
|
|
1671
1706
|
const stripped = existing.replace(ANY_BLOCK_RE, "");
|
|
@@ -1722,7 +1757,7 @@ async function bootstrap(paths) {
|
|
|
1722
1757
|
const contextCreated = await ensureDir(paths.contextDir);
|
|
1723
1758
|
const gitignoreUpdated = await patchGitignore(paths.gitignore);
|
|
1724
1759
|
const claudeMdExistedBefore = await exists(paths.claudeMd);
|
|
1725
|
-
const patch = await patchClaudeMd(paths.claudeMd);
|
|
1760
|
+
const patch = await patchClaudeMd(paths.claudeMd, basename2(paths.projectRoot));
|
|
1726
1761
|
return {
|
|
1727
1762
|
graphCreated,
|
|
1728
1763
|
contextCreated,
|
|
@@ -1775,8 +1810,12 @@ async function scanProject(projectRootRaw, opts = {}) {
|
|
|
1775
1810
|
if (boot.graphCreated) log.info(" created .synthra-graph/");
|
|
1776
1811
|
if (boot.contextCreated) log.info(" created .synthra/");
|
|
1777
1812
|
if (boot.gitignoreUpdated) log.info(" updated .gitignore");
|
|
1778
|
-
if (boot.claudeMdCreated)
|
|
1779
|
-
|
|
1813
|
+
if (boot.claudeMdCreated) {
|
|
1814
|
+
log.info(" created CLAUDE.md \u2014 onboarding skeleton for the agent");
|
|
1815
|
+
log.info(" \u21B3 fill in Build / Conventions / Decisions (or run /init in Claude to auto-draft)");
|
|
1816
|
+
} else if (boot.claudeMdUpdated) {
|
|
1817
|
+
log.info(" updated CLAUDE.md");
|
|
1818
|
+
}
|
|
1780
1819
|
}
|
|
1781
1820
|
const walked = [];
|
|
1782
1821
|
for await (const file of walk(projectRoot)) walked.push(file);
|
|
@@ -2073,7 +2112,7 @@ function resolveBranchPaths(contextDir, branch, isDefault) {
|
|
|
2073
2112
|
|
|
2074
2113
|
// src/memory/context-md.ts
|
|
2075
2114
|
import { mkdir as mkdir4, readFile as readFile9, writeFile as writeFile4 } from "fs/promises";
|
|
2076
|
-
import { dirname as
|
|
2115
|
+
import { dirname as dirname5 } from "path";
|
|
2077
2116
|
var MAX_BULLETS = 3;
|
|
2078
2117
|
function deriveContextMd(entries, branch) {
|
|
2079
2118
|
const tasks = entries.filter((e) => e.type === "task").reverse();
|
|
@@ -2116,13 +2155,13 @@ function formatContextMd(ctx) {
|
|
|
2116
2155
|
return lines.join("\n");
|
|
2117
2156
|
}
|
|
2118
2157
|
async function writeContextMd(path, ctx) {
|
|
2119
|
-
await mkdir4(
|
|
2158
|
+
await mkdir4(dirname5(path), { recursive: true });
|
|
2120
2159
|
await writeFile4(path, formatContextMd(ctx), "utf8");
|
|
2121
2160
|
}
|
|
2122
2161
|
|
|
2123
2162
|
// src/memory/context-store.ts
|
|
2124
2163
|
import { mkdir as mkdir5, readFile as readFile10, writeFile as writeFile5 } from "fs/promises";
|
|
2125
|
-
import { dirname as
|
|
2164
|
+
import { dirname as dirname6 } from "path";
|
|
2126
2165
|
var SCHEMA_VERSION = 1;
|
|
2127
2166
|
async function readEntries(path) {
|
|
2128
2167
|
try {
|
|
@@ -2134,7 +2173,7 @@ async function readEntries(path) {
|
|
|
2134
2173
|
}
|
|
2135
2174
|
}
|
|
2136
2175
|
async function writeEntries(path, entries) {
|
|
2137
|
-
await mkdir5(
|
|
2176
|
+
await mkdir5(dirname6(path), { recursive: true });
|
|
2138
2177
|
const store = { schema_version: SCHEMA_VERSION, entries };
|
|
2139
2178
|
await writeFile5(path, JSON.stringify(store, null, 2) + "\n", "utf8");
|
|
2140
2179
|
}
|
|
@@ -2848,7 +2887,7 @@ async function handleContextUpdate(req, ctx) {
|
|
|
2848
2887
|
|
|
2849
2888
|
// src/server/routes/gate.ts
|
|
2850
2889
|
import { appendFile as appendFile2, mkdir as mkdir6 } from "fs/promises";
|
|
2851
|
-
import { dirname as
|
|
2890
|
+
import { dirname as dirname7 } from "path";
|
|
2852
2891
|
var BLOCKABLE_TOOLS = /* @__PURE__ */ new Set(["Grep", "Glob"]);
|
|
2853
2892
|
var RECENT_ACTIVITY_WINDOW_MS = 5 * 60 * 1e3;
|
|
2854
2893
|
function extractQuery(toolName, input) {
|
|
@@ -2878,7 +2917,7 @@ function recentlyTouchedMatchesQuery(recentPaths, queryTokens) {
|
|
|
2878
2917
|
}
|
|
2879
2918
|
async function logDecision(ctx, toolName, query, decision, reason) {
|
|
2880
2919
|
try {
|
|
2881
|
-
await mkdir6(
|
|
2920
|
+
await mkdir6(dirname7(ctx.paths.gateLog), { recursive: true });
|
|
2882
2921
|
const entry = {
|
|
2883
2922
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2884
2923
|
tool: toolName,
|
|
@@ -2935,14 +2974,14 @@ async function handleGate(req, ctx) {
|
|
|
2935
2974
|
|
|
2936
2975
|
// src/server/routes/log.ts
|
|
2937
2976
|
import { appendFile as appendFile3, mkdir as mkdir7 } from "fs/promises";
|
|
2938
|
-
import { dirname as
|
|
2977
|
+
import { dirname as dirname8 } from "path";
|
|
2939
2978
|
async function handleLog(entry, ctx) {
|
|
2940
2979
|
if (!entry || typeof entry.input_tokens !== "number" || typeof entry.output_tokens !== "number") {
|
|
2941
2980
|
throw new Error("log: input_tokens and output_tokens (number) are required");
|
|
2942
2981
|
}
|
|
2943
2982
|
const written_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
2944
2983
|
const record = { ...entry, written_at };
|
|
2945
|
-
await mkdir7(
|
|
2984
|
+
await mkdir7(dirname8(ctx.paths.tokenLog), { recursive: true });
|
|
2946
2985
|
await appendFile3(ctx.paths.tokenLog, JSON.stringify(record) + "\n", "utf8");
|
|
2947
2986
|
return { ok: true, written_at };
|
|
2948
2987
|
}
|