@prom.codes/saver 0.1.4 → 0.1.5
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/README.md +5 -0
- package/dist/bin.js +55 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,6 +25,11 @@ never for code/destructive work). The rules keep code, caveats, destructive step
|
|
|
25
25
|
and anything the agent needs later **verbatim** — it shapes phrasing, never what the
|
|
26
26
|
agent does or remembers.
|
|
27
27
|
|
|
28
|
+
A second tool, `status`, reports where it would write, the key state, and which
|
|
29
|
+
runtimes already have the block installed. If a fresh window opens with no
|
|
30
|
+
project (workspace falls back to home), `setup` **refuses to write rule files
|
|
31
|
+
into your home dir** — open your project folder first.
|
|
32
|
+
|
|
28
33
|
No database and no native modules — `npx` works turnkey everywhere (Node ≥ 20.10).
|
|
29
34
|
The workspace is auto-detected (Claude Code `CLAUDE_PROJECT_DIR`); set
|
|
30
35
|
`PROMETHEUS_WORKSPACE_ROOT` only to target a different folder. An API key is
|
package/dist/bin.js
CHANGED
|
@@ -14,7 +14,18 @@ function classifyKey(raw) {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
// dist/workspace.js
|
|
17
|
-
import {
|
|
17
|
+
import { homedir } from "node:os";
|
|
18
|
+
import { dirname, resolve } from "node:path";
|
|
19
|
+
function isHomeOrFilesystemRoot(root) {
|
|
20
|
+
const abs = resolve(root);
|
|
21
|
+
if (abs === "")
|
|
22
|
+
return true;
|
|
23
|
+
if (abs === resolve(homedir()))
|
|
24
|
+
return true;
|
|
25
|
+
if (dirname(abs) === abs)
|
|
26
|
+
return true;
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
18
29
|
function resolveWorkspaceRoot(env = process.env) {
|
|
19
30
|
const explicit = (env.PROMETHEUS_WORKSPACE_ROOT ?? "").trim();
|
|
20
31
|
if (explicit !== "")
|
|
@@ -29,9 +40,9 @@ function resolveWorkspaceRoot(env = process.env) {
|
|
|
29
40
|
import { z } from "zod";
|
|
30
41
|
|
|
31
42
|
// dist/setup.js
|
|
32
|
-
import { existsSync } from "node:fs";
|
|
43
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
33
44
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
34
|
-
import { dirname, join } from "node:path";
|
|
45
|
+
import { dirname as dirname2, join } from "node:path";
|
|
35
46
|
var SAVER_LEVELS = ["lite", "balanced", "aggressive"];
|
|
36
47
|
var DEFAULT_LEVEL = "balanced";
|
|
37
48
|
var SAVER_RUNTIMES = [
|
|
@@ -94,6 +105,18 @@ function detectRuntimes(workspaceRoot) {
|
|
|
94
105
|
const found = SAVER_RUNTIMES.filter((rt) => existsSync(join(workspaceRoot, TARGETS[rt].detect)));
|
|
95
106
|
return found.length > 0 ? found : ["agents"];
|
|
96
107
|
}
|
|
108
|
+
function installedRuntimes(workspaceRoot) {
|
|
109
|
+
return SAVER_RUNTIMES.filter((rt) => {
|
|
110
|
+
const p = join(workspaceRoot, TARGETS[rt].relPath);
|
|
111
|
+
if (!existsSync(p))
|
|
112
|
+
return false;
|
|
113
|
+
try {
|
|
114
|
+
return readFileSync(p, "utf-8").includes(BLOCK_START);
|
|
115
|
+
} catch {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
97
120
|
function upsertBlock(existing, block) {
|
|
98
121
|
const marked = withMarkers(block);
|
|
99
122
|
const start = existing.indexOf(BLOCK_START);
|
|
@@ -114,7 +137,7 @@ async function installRuntime(workspaceRoot, runtime, level) {
|
|
|
114
137
|
if (exists && before === after) {
|
|
115
138
|
return { runtime, path: absPath, action: "unchanged" };
|
|
116
139
|
}
|
|
117
|
-
await mkdir(
|
|
140
|
+
await mkdir(dirname2(absPath), { recursive: true });
|
|
118
141
|
await writeFile(absPath, after, "utf-8");
|
|
119
142
|
return { runtime, path: absPath, action: exists ? "updated" : "created" };
|
|
120
143
|
}
|
|
@@ -130,14 +153,24 @@ var setupInput = {
|
|
|
130
153
|
level: levelEnum.optional(),
|
|
131
154
|
runtimes: z.array(runtimeEnum).min(1).optional()
|
|
132
155
|
};
|
|
156
|
+
var emptyInput = {};
|
|
133
157
|
function registerTools(server, deps) {
|
|
134
158
|
const { workspaceRoot, apiKey, requireKey } = deps;
|
|
135
159
|
const keyState = deps.keyState ?? (apiKey !== void 0 ? "valid" : "absent");
|
|
160
|
+
const rootIsHomeOrFsRoot = isHomeOrFilesystemRoot(workspaceRoot);
|
|
136
161
|
server.registerTool("setup", {
|
|
137
162
|
title: "Install the prom.codes Saver efficient-output rules",
|
|
138
163
|
description: "Idempotently install the prom.codes Saver efficient-output rule block into this workspace's agent runtime configs (CLAUDE.md / .cursor/rules / .augment/rules / AGENTS.md). The rules cut token cost by trimming the agent's own prose (preamble, narration, pasted tool output) while keeping code, caveats and destructive sequences verbatim. `level`: `lite` (filler only) | `balanced` (default \u2014 lean, not terse) | `aggressive` (telegraphic, opt-in, never for code/destructive). Without `runtimes` it auto-detects which are present (fallback: agents). Re-running updates the block in place. Run this once per workspace.",
|
|
139
164
|
inputSchema: setupInput
|
|
140
165
|
}, async (args) => {
|
|
166
|
+
if (rootIsHomeOrFsRoot) {
|
|
167
|
+
return textResult({
|
|
168
|
+
ok: false,
|
|
169
|
+
installed: false,
|
|
170
|
+
workspaceRoot,
|
|
171
|
+
reason: "Workspace resolved to your home directory or a filesystem root \u2014 refusing to write rule files there. Open your project folder (Claude Code passes it via CLAUDE_PROJECT_DIR) or set PROMETHEUS_WORKSPACE_ROOT, then retry."
|
|
172
|
+
});
|
|
173
|
+
}
|
|
141
174
|
if (requireKey === true && keyState !== "valid") {
|
|
142
175
|
return {
|
|
143
176
|
isError: true,
|
|
@@ -168,6 +201,24 @@ function registerTools(server, deps) {
|
|
|
168
201
|
results
|
|
169
202
|
});
|
|
170
203
|
});
|
|
204
|
+
server.registerTool("status", {
|
|
205
|
+
title: "Saver status / health check",
|
|
206
|
+
description: "Health check for the prom.codes Saver in this workspace: the resolved workspace root, whether the API key is present/valid (optional \u2014 the Saver works keyless), which agent runtimes are detected here, and which of them already have the Saver rule block installed. Call this to confirm where it would write and whether `setup` has already run.",
|
|
207
|
+
inputSchema: emptyInput
|
|
208
|
+
}, async () => {
|
|
209
|
+
const detected = detectRuntimes(workspaceRoot);
|
|
210
|
+
const installed = rootIsHomeOrFsRoot ? [] : installedRuntimes(workspaceRoot);
|
|
211
|
+
const summary = rootIsHomeOrFsRoot ? `Workspace resolved to ${workspaceRoot} (home/root) \u2014 setup is refused here. Open your project folder.` : installed.length > 0 ? `Saver installed in ${workspaceRoot} for: ${installed.join(", ")}.` : `Saver not yet installed in ${workspaceRoot}. Run setup. Detected runtimes: ${detected.join(", ")}.`;
|
|
212
|
+
return textResult({
|
|
213
|
+
installed: installed.length > 0,
|
|
214
|
+
workspaceRoot,
|
|
215
|
+
rootIsHomeOrFsRoot,
|
|
216
|
+
key: { keyed: apiKey !== void 0, keyState, requireKey: requireKey === true },
|
|
217
|
+
detectedRuntimes: detected,
|
|
218
|
+
installedRuntimes: installed,
|
|
219
|
+
summary
|
|
220
|
+
});
|
|
221
|
+
});
|
|
171
222
|
}
|
|
172
223
|
|
|
173
224
|
// dist/server.js
|