greprag 5.80.0 → 5.82.0
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/capture-manifest.js +2 -1
- package/dist/codex-fast-hook.js +6 -0
- package/dist/codex-steering.js +1 -1
- package/dist/commands/app-model.js +0 -1
- package/dist/commands/arm-reminder.js +9 -7
- package/dist/commands/collision-check.js +7 -6
- package/dist/commands/corpus/client.js +13 -3
- package/dist/commands/delivery-reminder.js +35 -14
- package/dist/commands/deploy-gate.js +55 -0
- package/dist/commands/deploy-lock.js +100 -0
- package/dist/commands/deploy-record.js +145 -0
- package/dist/commands/deploy-verify.js +111 -0
- package/dist/commands/inbox-primer-reminder.js +5 -5
- package/dist/commands/inbox-watch.js +2 -4
- package/dist/commands/init.js +82 -0
- package/dist/commands/load.js +40 -0
- package/dist/commands/loadout-reminder.js +1 -1
- package/dist/commands/merge-guard.js +419 -0
- package/dist/commands/merge-lock.js +176 -0
- package/dist/commands/parity-reminder.js +53 -0
- package/dist/commands/persona-reminder.js +11 -0
- package/dist/commands/persona.js +50 -0
- package/dist/commands/procedure.js +77 -6
- package/dist/commands/reminder-registry.js +21 -5
- package/dist/commands/repodoc.js +433 -0
- package/dist/commands/search.js +149 -0
- package/dist/commands/skillgain.js +33 -25
- package/dist/delivery-lifecycle.js +16 -1
- package/dist/deploy-gate.js +355 -0
- package/dist/deploy-locks.js +339 -0
- package/dist/deploy-verify.js +209 -0
- package/dist/env-redaction.js +157 -0
- package/dist/harness-limits.js +17 -0
- package/dist/hook-runtime.js +11 -1
- package/dist/hook.js +170 -88
- package/dist/index.js +593 -567
- package/dist/inline-atom-episode.js +15 -7
- package/dist/inline-atom.js +8 -2
- package/dist/native-skill-adoption.js +11 -0
- package/dist/native-skill-mirror.js +8 -1
- package/dist/node-identity.bundle.js +1166 -0
- package/dist/opencode-plugin.bundle.js +307 -119
- package/dist/procedure-enabled.js +55 -0
- package/dist/procedure-runtime.js +6 -0
- package/dist/procedure-scope.js +190 -0
- package/dist/procedure-watch.js +29 -16
- package/dist/procedure.js +111 -5
- package/dist/project-anchor.js +1 -14
- package/dist/reminder-injector.js +11 -10
- package/dist/repodoc-client.js +296 -0
- package/dist/session-id.js +7 -8
- package/dist/skill-landing.js +57 -2
- package/dist/skill-mirror-client.js +14 -0
- package/dist/skill-mirror-files.js +18 -0
- package/package.json +2 -2
- package/scripts/bundle-node-identity.mjs +47 -0
- package/skill/templates/chip-spawn.md +7 -1
- package/skill/templates/delivery.md +105 -0
- package/skill/templates/prompt-audit.md +196 -0
- package/skill/templates/skill-change.md +25 -2
- package/dist/assistant-doctrine.js +0 -85
- package/dist/commands/assistant-reminder.js +0 -19
- package/dist/commands/assistant.js +0 -95
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// adr: adr/secret-scrubber.md
|
|
3
|
+
/** Env-var redaction map — the CLIENT-ONLY `.env` / `process.env` walker.
|
|
4
|
+
*
|
|
5
|
+
* Builds the value → `[REDACTED:VAR_NAME]` map the Stop hook hands to
|
|
6
|
+
* scrubString as pass 1. Lives beside the hook (never in the filesystem-free
|
|
7
|
+
* detector module): it reads the user's `.env` files and the process
|
|
8
|
+
* environment, which the API worker must never touch.
|
|
9
|
+
*
|
|
10
|
+
* Classification — WHICH environment values are secrets — is the whole point
|
|
11
|
+
* of this file. The environment is not a secret store: on any machine it is
|
|
12
|
+
* mostly paths (CLAUDE_PROJECT_DIR, PWD, PATH, TEMP, APPDATA, USERPROFILE…)
|
|
13
|
+
* and harness bookkeeping. Redacting those corrupts stored text — a learned
|
|
14
|
+
* procedure whose steps read `cd "[REDACTED:CLAUDE_PROJECT_DIR]/game"` cannot
|
|
15
|
+
* be replayed. So:
|
|
16
|
+
*
|
|
17
|
+
* 1. a PATH-SHAPED value is never a secret, whatever its source or name;
|
|
18
|
+
* 2. a `.env` value is a declared secret — redact it (minus rule 1);
|
|
19
|
+
* 3. a `process.env` value is redacted only when its NAME is secret-shaped
|
|
20
|
+
* (KEY / TOKEN / SECRET / PASSWORD / …) or its VALUE trips the pattern +
|
|
21
|
+
* entropy detector — i.e. the same judgement the scrubber already makes.
|
|
22
|
+
*
|
|
23
|
+
* Pure classification (isPathLikeValue / isSecretShapedKey /
|
|
24
|
+
* isRedactableEnvEntry / collectRedactionEntries) is split from the file I/O
|
|
25
|
+
* (buildRedactionMap) so the boundary is unit-testable without a hook.
|
|
26
|
+
*/
|
|
27
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
28
|
+
if (k2 === undefined) k2 = k;
|
|
29
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
30
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
31
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
32
|
+
}
|
|
33
|
+
Object.defineProperty(o, k2, desc);
|
|
34
|
+
}) : (function(o, m, k, k2) {
|
|
35
|
+
if (k2 === undefined) k2 = k;
|
|
36
|
+
o[k2] = m[k];
|
|
37
|
+
}));
|
|
38
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
39
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
40
|
+
}) : function(o, v) {
|
|
41
|
+
o["default"] = v;
|
|
42
|
+
});
|
|
43
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
44
|
+
var ownKeys = function(o) {
|
|
45
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
46
|
+
var ar = [];
|
|
47
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
48
|
+
return ar;
|
|
49
|
+
};
|
|
50
|
+
return ownKeys(o);
|
|
51
|
+
};
|
|
52
|
+
return function (mod) {
|
|
53
|
+
if (mod && mod.__esModule) return mod;
|
|
54
|
+
var result = {};
|
|
55
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
56
|
+
__setModuleDefault(result, mod);
|
|
57
|
+
return result;
|
|
58
|
+
};
|
|
59
|
+
})();
|
|
60
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
61
|
+
exports.MIN_REDACTABLE_LENGTH = void 0;
|
|
62
|
+
exports.isPathLikeValue = isPathLikeValue;
|
|
63
|
+
exports.isSecretShapedKey = isSecretShapedKey;
|
|
64
|
+
exports.isRedactableEnvEntry = isRedactableEnvEntry;
|
|
65
|
+
exports.parseDotenv = parseDotenv;
|
|
66
|
+
exports.collectRedactionEntries = collectRedactionEntries;
|
|
67
|
+
exports.buildRedactionMap = buildRedactionMap;
|
|
68
|
+
const path = __importStar(require("path"));
|
|
69
|
+
const fs = __importStar(require("fs"));
|
|
70
|
+
const secret_scrubber_1 = require("./secret-scrubber");
|
|
71
|
+
/** Values shorter than this are never mapped (too short to be a credential,
|
|
72
|
+
* too common as a substring). Pre-existing threshold. */
|
|
73
|
+
exports.MIN_REDACTABLE_LENGTH = 16;
|
|
74
|
+
/** A value that starts like a filesystem path — absolute (drive letter, UNC,
|
|
75
|
+
* leading slash), home-relative, or dot-relative. A PATH-style list starts with
|
|
76
|
+
* its first entry, so it qualifies too. */
|
|
77
|
+
const PATH_LIKE_RE = /^(?:[A-Za-z]:[\\/]|\\\\|[\\/]|~(?:[\\/]|$)|\.{1,2}[\\/])/;
|
|
78
|
+
/** Variable names that declare a credential. Anchored on `_`/`-`/start/end so
|
|
79
|
+
* KEYBOARD_LAYOUT, PATHEXT and friends do not match. */
|
|
80
|
+
const SECRET_KEY_RE = /(?:^|[_-])(?:KEYS?|TOKENS?|SECRETS?|PASS|PASSWORD|PASSWD|PWD|CREDENTIALS?|AUTH|PRIVATE|DSN|SIGNING|SIGNATURE|SALT|CERT|COOKIE|BEARER|LICENSE)(?:[_-]|$)/i;
|
|
81
|
+
function isPathLikeValue(value) {
|
|
82
|
+
return PATH_LIKE_RE.test(value);
|
|
83
|
+
}
|
|
84
|
+
function isSecretShapedKey(key) {
|
|
85
|
+
return SECRET_KEY_RE.test(key);
|
|
86
|
+
}
|
|
87
|
+
/** Should this environment entry go into the redaction map? PURE. */
|
|
88
|
+
function isRedactableEnvEntry(key, value, source) {
|
|
89
|
+
if (!value || value.length < exports.MIN_REDACTABLE_LENGTH)
|
|
90
|
+
return false;
|
|
91
|
+
if (isPathLikeValue(value))
|
|
92
|
+
return false; // rule 1: a path is never a secret
|
|
93
|
+
if (source === 'dotenv')
|
|
94
|
+
return true; // rule 2: .env is a declared secret store
|
|
95
|
+
if (isSecretShapedKey(key))
|
|
96
|
+
return true; // rule 3a: the name says credential
|
|
97
|
+
return (0, secret_scrubber_1.scrubString)(value) !== value; // rule 3b: the value looks like one
|
|
98
|
+
}
|
|
99
|
+
/** Parse `.env` text into [key, value] pairs (quotes stripped). PURE. */
|
|
100
|
+
function parseDotenv(raw) {
|
|
101
|
+
const out = [];
|
|
102
|
+
for (const line of raw.split('\n')) {
|
|
103
|
+
const m = line.match(/^\s*([A-Z_][A-Z0-9_]*)\s*=\s*(.+?)\s*$/);
|
|
104
|
+
if (!m)
|
|
105
|
+
continue;
|
|
106
|
+
let value = m[2].trim();
|
|
107
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
108
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
109
|
+
value = value.slice(1, -1);
|
|
110
|
+
}
|
|
111
|
+
out.push([m[1], value]);
|
|
112
|
+
}
|
|
113
|
+
return out;
|
|
114
|
+
}
|
|
115
|
+
/** Fold `.env` entries + a process environment into the longest-first redaction
|
|
116
|
+
* map. PURE — the caller supplies both. */
|
|
117
|
+
function collectRedactionEntries(dotenv, env) {
|
|
118
|
+
const entries = [];
|
|
119
|
+
const seenValues = new Set();
|
|
120
|
+
const add = (key, value, source) => {
|
|
121
|
+
if (seenValues.has(value))
|
|
122
|
+
return;
|
|
123
|
+
if (!isRedactableEnvEntry(key, value, source))
|
|
124
|
+
return;
|
|
125
|
+
seenValues.add(value);
|
|
126
|
+
entries.push([value, `[REDACTED:${key}]`]);
|
|
127
|
+
};
|
|
128
|
+
for (const [key, value] of dotenv)
|
|
129
|
+
add(key, value, 'dotenv');
|
|
130
|
+
for (const [key, value] of Object.entries(env)) {
|
|
131
|
+
if (typeof value === 'string')
|
|
132
|
+
add(key, value, 'process');
|
|
133
|
+
}
|
|
134
|
+
// Longest first so a longer secret wins before any substring of it.
|
|
135
|
+
entries.sort((a, b) => b[0].length - a[0].length);
|
|
136
|
+
return entries;
|
|
137
|
+
}
|
|
138
|
+
/** Build the redaction map from the `.env` files above `cwd` (8 levels) and
|
|
139
|
+
* the process environment. The one I/O entry point. */
|
|
140
|
+
function buildRedactionMap(cwd, env = process.env) {
|
|
141
|
+
const dotenv = [];
|
|
142
|
+
let dir = path.resolve(cwd);
|
|
143
|
+
for (let depth = 0; depth < 8; depth++) {
|
|
144
|
+
const envPath = path.join(dir, '.env');
|
|
145
|
+
if (fs.existsSync(envPath)) {
|
|
146
|
+
try {
|
|
147
|
+
dotenv.push(...parseDotenv(fs.readFileSync(envPath, 'utf-8')));
|
|
148
|
+
}
|
|
149
|
+
catch { /* skip */ }
|
|
150
|
+
}
|
|
151
|
+
const parent = path.dirname(dir);
|
|
152
|
+
if (parent === dir)
|
|
153
|
+
break;
|
|
154
|
+
dir = parent;
|
|
155
|
+
}
|
|
156
|
+
return collectRedactionEntries(dotenv, env);
|
|
157
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/** MIRROR of `packages/core/src/harness-limits.ts`; KEEP IN SYNC.
|
|
3
|
+
*
|
|
4
|
+
* Core is the canonical owner — the server derives the Persona content limit
|
|
5
|
+
* from it. The CLI ships as a zero-dependency `tsc` artifact and cannot import
|
|
6
|
+
* `@greprag/core` at runtime, the same constraint that mirrors
|
|
7
|
+
* `turn-provenance.ts` and `secret-scrubber.ts`.
|
|
8
|
+
* adr: adr/announce-inline-budget.md
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.ANNOUNCE_HARNESS_CAP = void 0;
|
|
12
|
+
/** Bytes of hook output Claude Code will inline. Past this the harness swaps the
|
|
13
|
+
* payload for a `<persisted-output>` stub plus a 2KB preview and tells nobody.
|
|
14
|
+
* MEASURED 2026-09-03 with an 80-marker ruler, not guessed, and true of both raw
|
|
15
|
+
* stdout and the `additionalContext` envelope. The cap is PER HOOK INVOCATION,
|
|
16
|
+
* which is why Persona rides its own SessionStart hook and gets the full 2048. */
|
|
17
|
+
exports.ANNOUNCE_HARNESS_CAP = 2048;
|
package/dist/hook-runtime.js
CHANGED
|
@@ -140,10 +140,20 @@ async function apiCall(url, apiKey, body) {
|
|
|
140
140
|
}
|
|
141
141
|
return res.json();
|
|
142
142
|
}
|
|
143
|
+
/** Hook REGISTRATION points that are not legal `hookSpecificOutput.hookEventName`
|
|
144
|
+
* values. The harness validates that field against a fixed enum and rejects the
|
|
145
|
+
* WHOLE payload on a miss — silently, from the emitting hook's point of view, so
|
|
146
|
+
* the failure looks like "the context never arrived" rather than a schema error.
|
|
147
|
+
* A hook that echoes its own event name back is therefore a live trap: correct for
|
|
148
|
+
* SessionStart, fatal for PostCompact. Map them here, once, instead of relying on
|
|
149
|
+
* every call site to remember. */
|
|
150
|
+
const EVENT_NAME_ALIASES = {
|
|
151
|
+
PostCompact: 'SessionStart',
|
|
152
|
+
};
|
|
143
153
|
function writeAdditionalContext(hookEventName, additionalContext) {
|
|
144
154
|
process.stdout.write(JSON.stringify({
|
|
145
155
|
hookSpecificOutput: {
|
|
146
|
-
hookEventName,
|
|
156
|
+
hookEventName: EVENT_NAME_ALIASES[hookEventName] || hookEventName,
|
|
147
157
|
additionalContext,
|
|
148
158
|
},
|
|
149
159
|
}) + '\n');
|