@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.
Files changed (3) hide show
  1. package/README.md +5 -0
  2. package/dist/bin.js +55 -4
  3. 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 { resolve } from "node:path";
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(dirname(absPath), { recursive: true });
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
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.5",
4
4
  "description": "prom.codes Saver — cut token cost without cutting quality, as an MCP installer.",
5
5
  "type": "module",
6
6
  "bin": {