@prom.codes/saver 0.1.4 → 0.1.6

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.
Files changed (3) hide show
  1. package/README.md +8 -0
  2. package/dist/bin.js +87 -17
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -25,6 +25,14 @@ 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
+ **It installs itself.** An MCP server can't act on its own, so the rule only
29
+ saves tokens once it's in a config file. On startup the Saver **auto-installs**
30
+ the marked rule block into config files you already have (CLAUDE.md / AGENTS.md /
31
+ Cursor / Augment) — idempotent, never creates a new file, skipped for home/root,
32
+ opt out with `PROMETHEUS_SAVER_AUTO_SETUP=off`. Run `setup` to install into all
33
+ runtimes (incl. creating AGENTS.md if you have none). A `status` tool reports
34
+ where it writes, the key state, and which runtimes already have the block.
35
+
28
36
  No database and no native modules — `npx` works turnkey everywhere (Node ≥ 20.10).
29
37
  The workspace is auto-detected (Claude Code `CLAUDE_PROJECT_DIR`); set
30
38
  `PROMETHEUS_WORKSPACE_ROOT` only to target a different folder. An API key is
package/dist/bin.js CHANGED
@@ -13,23 +13,8 @@ function classifyKey(raw) {
13
13
  return KEY_PATTERN.test(key) ? "valid" : "malformed";
14
14
  }
15
15
 
16
- // dist/workspace.js
17
- import { resolve } from "node:path";
18
- function resolveWorkspaceRoot(env = process.env) {
19
- const explicit = (env.PROMETHEUS_WORKSPACE_ROOT ?? "").trim();
20
- if (explicit !== "")
21
- return resolve(explicit);
22
- const claude = (env.CLAUDE_PROJECT_DIR ?? "").trim();
23
- if (claude !== "")
24
- return resolve(claude);
25
- return resolve(process.cwd());
26
- }
27
-
28
- // dist/tools.js
29
- import { z } from "zod";
30
-
31
16
  // dist/setup.js
32
- import { existsSync } from "node:fs";
17
+ import { existsSync, readFileSync } from "node:fs";
33
18
  import { mkdir, readFile, writeFile } from "node:fs/promises";
34
19
  import { dirname, join } from "node:path";
35
20
  var SAVER_LEVELS = ["lite", "balanced", "aggressive"];
@@ -94,6 +79,28 @@ function detectRuntimes(workspaceRoot) {
94
79
  const found = SAVER_RUNTIMES.filter((rt) => existsSync(join(workspaceRoot, TARGETS[rt].detect)));
95
80
  return found.length > 0 ? found : ["agents"];
96
81
  }
82
+ function installedRuntimes(workspaceRoot) {
83
+ return SAVER_RUNTIMES.filter((rt) => {
84
+ const p = join(workspaceRoot, TARGETS[rt].relPath);
85
+ if (!existsSync(p))
86
+ return false;
87
+ try {
88
+ return readFileSync(p, "utf-8").includes(BLOCK_START);
89
+ } catch {
90
+ return false;
91
+ }
92
+ });
93
+ }
94
+ function existingRuntimes(workspaceRoot) {
95
+ return SAVER_RUNTIMES.filter((rt) => existsSync(join(workspaceRoot, TARGETS[rt].detect)));
96
+ }
97
+ async function autoInstallExisting(workspaceRoot, level) {
98
+ const results = [];
99
+ for (const rt of existingRuntimes(workspaceRoot)) {
100
+ results.push(await installRuntime(workspaceRoot, rt, level));
101
+ }
102
+ return results;
103
+ }
97
104
  function upsertBlock(existing, block) {
98
105
  const marked = withMarkers(block);
99
106
  const start = existing.indexOf(BLOCK_START);
@@ -119,7 +126,31 @@ async function installRuntime(workspaceRoot, runtime, level) {
119
126
  return { runtime, path: absPath, action: exists ? "updated" : "created" };
120
127
  }
121
128
 
129
+ // dist/workspace.js
130
+ import { homedir } from "node:os";
131
+ import { dirname as dirname2, resolve } from "node:path";
132
+ function isHomeOrFilesystemRoot(root) {
133
+ const abs = resolve(root);
134
+ if (abs === "")
135
+ return true;
136
+ if (abs === resolve(homedir()))
137
+ return true;
138
+ if (dirname2(abs) === abs)
139
+ return true;
140
+ return false;
141
+ }
142
+ function resolveWorkspaceRoot(env = process.env) {
143
+ const explicit = (env.PROMETHEUS_WORKSPACE_ROOT ?? "").trim();
144
+ if (explicit !== "")
145
+ return resolve(explicit);
146
+ const claude = (env.CLAUDE_PROJECT_DIR ?? "").trim();
147
+ if (claude !== "")
148
+ return resolve(claude);
149
+ return resolve(process.cwd());
150
+ }
151
+
122
152
  // dist/tools.js
153
+ import { z } from "zod";
123
154
  var REQUIRE_KEY_ENV = "PROMETHEUS_SAVER_REQUIRE_KEY";
124
155
  function textResult(payload) {
125
156
  return { content: [{ type: "text", text: JSON.stringify(payload, null, 2) }] };
@@ -130,14 +161,24 @@ var setupInput = {
130
161
  level: levelEnum.optional(),
131
162
  runtimes: z.array(runtimeEnum).min(1).optional()
132
163
  };
164
+ var emptyInput = {};
133
165
  function registerTools(server, deps) {
134
166
  const { workspaceRoot, apiKey, requireKey } = deps;
135
167
  const keyState = deps.keyState ?? (apiKey !== void 0 ? "valid" : "absent");
168
+ const rootIsHomeOrFsRoot = isHomeOrFilesystemRoot(workspaceRoot);
136
169
  server.registerTool("setup", {
137
170
  title: "Install the prom.codes Saver efficient-output rules",
138
171
  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
172
  inputSchema: setupInput
140
173
  }, async (args) => {
174
+ if (rootIsHomeOrFsRoot) {
175
+ return textResult({
176
+ ok: false,
177
+ installed: false,
178
+ workspaceRoot,
179
+ 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."
180
+ });
181
+ }
141
182
  if (requireKey === true && keyState !== "valid") {
142
183
  return {
143
184
  isError: true,
@@ -168,6 +209,24 @@ function registerTools(server, deps) {
168
209
  results
169
210
  });
170
211
  });
212
+ server.registerTool("status", {
213
+ title: "Saver status / health check",
214
+ 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.",
215
+ inputSchema: emptyInput
216
+ }, async () => {
217
+ const detected = detectRuntimes(workspaceRoot);
218
+ const installed = rootIsHomeOrFsRoot ? [] : installedRuntimes(workspaceRoot);
219
+ 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(", ")}.`;
220
+ return textResult({
221
+ installed: installed.length > 0,
222
+ workspaceRoot,
223
+ rootIsHomeOrFsRoot,
224
+ key: { keyed: apiKey !== void 0, keyState, requireKey: requireKey === true },
225
+ detectedRuntimes: detected,
226
+ installedRuntimes: installed,
227
+ summary
228
+ });
229
+ });
171
230
  }
172
231
 
173
232
  // dist/server.js
@@ -177,7 +236,7 @@ var SERVER_IDENTITY = {
177
236
  version: "0.1.0",
178
237
  title: "prom.codes Saver"
179
238
  };
180
- var SERVER_INSTRUCTIONS = "prom.codes Saver cuts token cost by trimming the agent's own prose \u2014 preamble, play-by-play narration and pasted tool output \u2014 while keeping code, caveats and destructive sequences verbatim. Run `setup` once per workspace to install the efficient-output protocol into the runtime rule files. Default level is `balanced` (lean, not terse): lead with the answer, summarize long output, one end-of-task summary. Never sacrifice correctness, safety or completeness to save tokens.";
239
+ var SERVER_INSTRUCTIONS = "prom.codes Saver cuts token cost by trimming the agent's own prose \u2014 preamble, play-by-play narration and pasted tool output \u2014 while keeping code, caveats and destructive sequences verbatim. The rule only works once it is installed into this workspace's runtime config: the server AUTO-INSTALLS it on startup when a config file already exists; otherwise call `setup` once to install it (it also creates AGENTS.md if you have no config yet). Call `status` to check. Default level `balanced` (lean, not terse): lead with the answer, summarize long output, one end-of-task summary. Never sacrifice correctness, safety or completeness to save tokens.";
181
240
  function createServer(deps, options = {}) {
182
241
  const identity = { ...SERVER_IDENTITY, ...options.identity ?? {} };
183
242
  const capabilities = options.capabilities ?? { tools: {} };
@@ -212,6 +271,17 @@ async function main() {
212
271
  requireKey,
213
272
  ...apiKey !== void 0 ? { apiKey } : {}
214
273
  });
274
+ const autoSetup = !/^(off|0|false|no)$/i.test(process.env.PROMETHEUS_SAVER_AUTO_SETUP ?? "");
275
+ if (autoSetup && !isHomeOrFilesystemRoot(workspaceRoot)) {
276
+ void autoInstallExisting(workspaceRoot, DEFAULT_LEVEL).then((results) => {
277
+ const wrote = results.filter((r) => r.action !== "unchanged");
278
+ if (wrote.length > 0) {
279
+ process.stderr.write(`prom-codes-saver: auto-installed the efficiency rule into ${wrote.map((r) => r.runtime).join(", ")} (set PROMETHEUS_SAVER_AUTO_SETUP=off to disable)
280
+ `);
281
+ }
282
+ }).catch(() => {
283
+ });
284
+ }
215
285
  const transport = new StdioServerTransport();
216
286
  const shutdown = async (signal) => {
217
287
  process.stderr.write(`prom-codes-saver: received ${signal}, shutting down
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prom.codes/saver",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "prom.codes Saver — cut token cost without cutting quality, as an MCP installer.",
5
5
  "type": "module",
6
6
  "bin": {