@su-record/vibe 4.2.34 → 4.2.36
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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/dist/cli/common.js +4 -1
- package/dist/cli/common.js.map +1 -1
- package/dist/cli/heldout.js +10 -4
- package/dist/cli/heldout.js.map +1 -1
- package/dist/cli/human.js +8 -4
- package/dist/cli/human.js.map +1 -1
- package/dist/cli/internal.js +37 -24
- package/dist/cli/internal.js.map +1 -1
- package/dist/cli/ledger.js +67 -0
- package/dist/cli/ledger.js.map +1 -0
- package/dist/cli/map.js +5 -3
- package/dist/cli/map.js.map +1 -1
- package/dist/cli/memory.js +104 -74
- package/dist/cli/memory.js.map +1 -1
- package/dist/cli/risks.js +20 -3
- package/dist/cli/risks.js.map +1 -1
- package/dist/cli/session.js +4 -2
- package/dist/cli/session.js.map +1 -1
- package/dist/cli/setup.js +44 -13
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/verification.js +1 -1
- package/dist/cli/verification.js.map +1 -1
- package/dist/cli/work.js +75 -22
- package/dist/cli/work.js.map +1 -1
- package/dist/cli.js +18 -6
- package/dist/cli.js.map +1 -1
- package/dist/core/analyze.js +21 -7
- package/dist/core/analyze.js.map +1 -1
- package/dist/core/artifact-paths.js +14 -3
- package/dist/core/artifact-paths.js.map +1 -1
- package/dist/core/capabilities.js +69 -15
- package/dist/core/capabilities.js.map +1 -1
- package/dist/core/check-authorization.js +37 -0
- package/dist/core/check-authorization.js.map +1 -0
- package/dist/core/check-process.js +12 -4
- package/dist/core/check-process.js.map +1 -1
- package/dist/core/check-report.js +66 -0
- package/dist/core/check-report.js.map +1 -0
- package/dist/core/check-selection.js +4 -2
- package/dist/core/check-selection.js.map +1 -1
- package/dist/core/check.js +66 -130
- package/dist/core/check.js.map +1 -1
- package/dist/core/checks/changed.js +20 -6
- package/dist/core/checks/changed.js.map +1 -1
- package/dist/core/checks/eval.js +35 -10
- package/dist/core/checks/eval.js.map +1 -1
- package/dist/core/checks/file.js +26 -23
- package/dist/core/checks/file.js.map +1 -1
- package/dist/core/checks/fileRules.js +42 -16
- package/dist/core/checks/fileRules.js.map +1 -1
- package/dist/core/checks/http.js +35 -34
- package/dist/core/checks/http.js.map +1 -1
- package/dist/core/checks/packs.js +1 -1
- package/dist/core/checks/packs.js.map +1 -1
- package/dist/core/checks/review.js +75 -40
- package/dist/core/checks/review.js.map +1 -1
- package/dist/core/checks/run.js +5 -2
- package/dist/core/checks/run.js.map +1 -1
- package/dist/core/checks/schema.js +25 -0
- package/dist/core/checks/schema.js.map +1 -0
- package/dist/core/checks/source.js +11 -6
- package/dist/core/checks/source.js.map +1 -1
- package/dist/core/config.js +9 -2
- package/dist/core/config.js.map +1 -1
- package/dist/core/consent.js +24 -16
- package/dist/core/consent.js.map +1 -1
- package/dist/core/context-notes.js +15 -7
- package/dist/core/context-notes.js.map +1 -1
- package/dist/core/context.js +24 -12
- package/dist/core/context.js.map +1 -1
- package/dist/core/conventions.js +22 -9
- package/dist/core/conventions.js.map +1 -1
- package/dist/core/docs/cfb.js +81 -45
- package/dist/core/docs/cfb.js.map +1 -1
- package/dist/core/docs/html.js +14 -3
- package/dist/core/docs/html.js.map +1 -1
- package/dist/core/docs/hwp.js +44 -22
- package/dist/core/docs/hwp.js.map +1 -1
- package/dist/core/docs/office.js +20 -10
- package/dist/core/docs/office.js.map +1 -1
- package/dist/core/docs/pdf.js +10 -4
- package/dist/core/docs/pdf.js.map +1 -1
- package/dist/core/docs/read.js +32 -24
- package/dist/core/docs/read.js.map +1 -1
- package/dist/core/docs/zip.js +32 -15
- package/dist/core/docs/zip.js.map +1 -1
- package/dist/core/evidence.js +17 -7
- package/dist/core/evidence.js.map +1 -1
- package/dist/core/failure-message.js +35 -13
- package/dist/core/failure-message.js.map +1 -1
- package/dist/core/failure.js +49 -14
- package/dist/core/failure.js.map +1 -1
- package/dist/core/github.js +3 -1
- package/dist/core/github.js.map +1 -1
- package/dist/core/handoff.js +20 -7
- package/dist/core/handoff.js.map +1 -1
- package/dist/core/heldout-run.js +6 -3
- package/dist/core/heldout-run.js.map +1 -1
- package/dist/core/heldout.js +24 -13
- package/dist/core/heldout.js.map +1 -1
- package/dist/core/inbox.js +3 -1
- package/dist/core/inbox.js.map +1 -1
- package/dist/core/inputs.js +76 -0
- package/dist/core/inputs.js.map +1 -0
- package/dist/core/inspect.js +61 -20
- package/dist/core/inspect.js.map +1 -1
- package/dist/core/intent.js +50 -12
- package/dist/core/intent.js.map +1 -1
- package/dist/core/knowledge-find.js +31 -12
- package/dist/core/knowledge-find.js.map +1 -1
- package/dist/core/knowledge.js +22 -12
- package/dist/core/knowledge.js.map +1 -1
- package/dist/core/lang.js +5 -2
- package/dist/core/lang.js.map +1 -1
- package/dist/core/ledger.js +44 -20
- package/dist/core/ledger.js.map +1 -1
- package/dist/core/locations.js +12 -0
- package/dist/core/locations.js.map +1 -0
- package/dist/core/map/imports.js +20 -9
- package/dist/core/map/imports.js.map +1 -1
- package/dist/core/map/index.js +28 -13
- package/dist/core/map/index.js.map +1 -1
- package/dist/core/map/symbols.js +27 -12
- package/dist/core/map/symbols.js.map +1 -1
- package/dist/core/output-capture.js +7 -4
- package/dist/core/output-capture.js.map +1 -1
- package/dist/core/paths.js +2 -1
- package/dist/core/paths.js.map +1 -1
- package/dist/core/performance.js +43 -17
- package/dist/core/performance.js.map +1 -1
- package/dist/core/profile.js +6 -3
- package/dist/core/profile.js.map +1 -1
- package/dist/core/reader.js +32 -16
- package/dist/core/reader.js.map +1 -1
- package/dist/core/readerSession.js +34 -14
- package/dist/core/readerSession.js.map +1 -1
- package/dist/core/recent.js +20 -6
- package/dist/core/recent.js.map +1 -1
- package/dist/core/regress.js +21 -12
- package/dist/core/regress.js.map +1 -1
- package/dist/core/repair.js +22 -4
- package/dist/core/repair.js.map +1 -1
- package/dist/core/research-queries.js +85 -0
- package/dist/core/research-queries.js.map +1 -0
- package/dist/core/research.js +89 -88
- package/dist/core/research.js.map +1 -1
- package/dist/core/results.js +89 -0
- package/dist/core/results.js.map +1 -0
- package/dist/core/risk-signals.js +55 -16
- package/dist/core/risk-signals.js.map +1 -1
- package/dist/core/run-id.js +10 -6
- package/dist/core/run-id.js.map +1 -1
- package/dist/core/scenarios.js +97 -57
- package/dist/core/scenarios.js.map +1 -1
- package/dist/core/session.js +3 -2
- package/dist/core/session.js.map +1 -1
- package/dist/core/size-gate.js +57 -0
- package/dist/core/size-gate.js.map +1 -0
- package/dist/core/size.js +32 -10
- package/dist/core/size.js.map +1 -1
- package/dist/core/skills.js +66 -28
- package/dist/core/skills.js.map +1 -1
- package/dist/core/skillsmp.js +26 -12
- package/dist/core/skillsmp.js.map +1 -1
- package/dist/core/source-basis.js +21 -9
- package/dist/core/source-basis.js.map +1 -1
- package/dist/core/status.js +26 -13
- package/dist/core/status.js.map +1 -1
- package/dist/core/table.js +8 -1
- package/dist/core/table.js.map +1 -1
- package/dist/core/tokens.js +20 -10
- package/dist/core/tokens.js.map +1 -1
- package/dist/core/tree.js +26 -16
- package/dist/core/tree.js.map +1 -1
- package/dist/core/verification-plan.js +26 -10
- package/dist/core/verification-plan.js.map +1 -1
- package/dist/core/verification.js +14 -7
- package/dist/core/verification.js.map +1 -1
- package/dist/core/view.js +93 -44
- package/dist/core/view.js.map +1 -1
- package/dist/install/global.js +37 -18
- package/dist/install/global.js.map +1 -1
- package/dist/install/hooks.js +17 -8
- package/dist/install/hooks.js.map +1 -1
- package/dist/install/manifest.js +11 -0
- package/dist/install/manifest.js.map +1 -0
- package/dist/install/mcpb.js +52 -23
- package/dist/install/mcpb.js.map +1 -1
- package/dist/install/plugin.js +73 -33
- package/dist/install/plugin.js.map +1 -1
- package/dist/install/project.js +8 -7
- package/dist/install/project.js.map +1 -1
- package/dist/install/register.js +83 -48
- package/dist/install/register.js.map +1 -1
- package/dist/install/tree.js +27 -11
- package/dist/install/tree.js.map +1 -1
- package/dist/install/update.js +46 -20
- package/dist/install/update.js.map +1 -1
- package/hooks/code-map.cjs +22 -9
- package/hooks/file-size.cjs +83 -0
- package/hooks/journal.cjs +28 -18
- package/hooks/knowledge-auto.cjs +55 -21
- package/hooks/knowledge-journal.cjs +47 -20
- package/hooks/knowledge-projects.cjs +50 -21
- package/hooks/knowledge-recall.cjs +16 -6
- package/hooks/knowledge-upkeep.cjs +22 -5
- package/hooks/locations.cjs +35 -0
- package/hooks/notify.js +52 -24
- package/hooks/obsidian.cjs +17 -7
- package/hooks/private-store.cjs +25 -10
- package/hooks/retest.cjs +39 -16
- package/hooks/session-context.cjs +30 -13
- package/hooks/session-files.cjs +44 -21
- package/hooks/session-repair.cjs +26 -11
- package/hooks/session-state.cjs +78 -38
- package/hooks/session.js +19 -8
- package/hooks/slice-command.cjs +38 -17
- package/hooks/slice-guard.cjs +20 -6
- package/hooks/slice-store.cjs +25 -12
- package/internal/guides/code.md +17 -0
- package/mcpb/server/index.js +40 -12
- package/package.json +1 -1
package/dist/core/table.js
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
+
/**
|
|
3
|
+
* Tables — the FDE's raw material. CSV / TSV / JSONL / JSON (array of objects) become rows of
|
|
4
|
+
* cells. No Excel: the harness has no zip reader and takes no dependency for it — export a CSV.
|
|
5
|
+
*/
|
|
6
|
+
const PLAIN_NUMBER = /^-?\d+(\.\d+)?$/;
|
|
7
|
+
/** A number written with thousands separators: `1,234,567.50`. */
|
|
8
|
+
const GROUPED_NUMBER = /^-?\d{1,3}(,\d{3})+(\.\d+)?$/;
|
|
2
9
|
export function formatOf(file) {
|
|
3
10
|
const ext = path.extname(file).toLowerCase();
|
|
4
11
|
if (ext === '.csv')
|
|
@@ -57,7 +64,7 @@ function cellOf(raw) {
|
|
|
57
64
|
const text = raw.trim();
|
|
58
65
|
if (text === '')
|
|
59
66
|
return null;
|
|
60
|
-
if (
|
|
67
|
+
if (PLAIN_NUMBER.test(text) || GROUPED_NUMBER.test(text))
|
|
61
68
|
return Number(text.replace(/,/g, ''));
|
|
62
69
|
if (text === 'true' || text === 'false')
|
|
63
70
|
return text === 'true';
|
package/dist/core/table.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table.js","sourceRoot":"","sources":["../../src/core/table.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"table.js","sourceRoot":"","sources":["../../src/core/table.ts"],"names":[],"mappings":"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"}
|
package/dist/core/tokens.js
CHANGED
|
@@ -3,14 +3,23 @@ import { vibePath } from './paths.js';
|
|
|
3
3
|
import { appendJsonl, nowIso, readJsonl } from './store.js';
|
|
4
4
|
export const TOKEN_TTL_MS = 10 * 60 * 1000;
|
|
5
5
|
export const TOKEN_MAX_FAILURES = 3;
|
|
6
|
+
const TOKEN_DIGITS = 6;
|
|
7
|
+
/** The token is shown as `123 456`: this many digits, a space, the rest. */
|
|
8
|
+
const TOKEN_GROUP = 3;
|
|
9
|
+
const TOKENS_FILE = 'inbox.jsonl';
|
|
10
|
+
/** Domain prefix, so a token hash cannot be reused as another kind of hash. */
|
|
11
|
+
const TOKEN_HASH_PREFIX = 'vibe-token:';
|
|
12
|
+
const TARGET_HASH_LENGTH = 16;
|
|
13
|
+
/** Random suffix range of a token id, in base 36. */
|
|
14
|
+
const TOKEN_ID_RANDOM = 4096;
|
|
6
15
|
export function tokensPath(root) {
|
|
7
|
-
return vibePath(root,
|
|
16
|
+
return vibePath(root, TOKENS_FILE);
|
|
8
17
|
}
|
|
9
18
|
export function hashToken(digits) {
|
|
10
|
-
return createHash('sha256').update(
|
|
19
|
+
return createHash('sha256').update(`${TOKEN_HASH_PREFIX}${digits}`).digest('hex');
|
|
11
20
|
}
|
|
12
21
|
export function hashTarget(value) {
|
|
13
|
-
return createHash('sha256').update(value).digest('hex').slice(0,
|
|
22
|
+
return createHash('sha256').update(value).digest('hex').slice(0, TARGET_HASH_LENGTH);
|
|
14
23
|
}
|
|
15
24
|
export function foldTokens(root) {
|
|
16
25
|
const views = new Map();
|
|
@@ -32,29 +41,30 @@ export function foldTokens(root) {
|
|
|
32
41
|
return views;
|
|
33
42
|
}
|
|
34
43
|
function formatDigits(digits) {
|
|
35
|
-
return `${digits.slice(0,
|
|
44
|
+
return `${digits.slice(0, TOKEN_GROUP)} ${digits.slice(TOKEN_GROUP)}`;
|
|
36
45
|
}
|
|
37
46
|
export function issueToken(root, kind, target) {
|
|
38
|
-
const digits = String(randomInt(0,
|
|
47
|
+
const digits = String(randomInt(0, 10 ** TOKEN_DIGITS)).padStart(TOKEN_DIGITS, '0');
|
|
39
48
|
const issuedAt = nowIso();
|
|
40
49
|
const expiresAt = new Date(Date.now() + TOKEN_TTL_MS).toISOString();
|
|
41
|
-
const id = `t-${Date.now().toString(36)}-${randomInt(0,
|
|
50
|
+
const id = `t-${Date.now().toString(36)}-${randomInt(0, TOKEN_ID_RANDOM).toString(36)}`;
|
|
42
51
|
const event = { type: 'token', id, kind, target, tokenHash: hashToken(digits), issuedAt, expiresAt };
|
|
43
52
|
appendJsonl(tokensPath(root), event);
|
|
44
53
|
return { id, token: formatDigits(digits), expiresAt };
|
|
45
54
|
}
|
|
46
|
-
/** Verify and consume once. Failures are recorded;
|
|
55
|
+
/** Verify and consume once. Failures are recorded; `TOKEN_MAX_FAILURES` failures kill the token. */
|
|
47
56
|
export function verifyAndConsume(root, kind, target, token, now = new Date()) {
|
|
48
57
|
const digits = token.replace(/\D/g, '');
|
|
49
|
-
if (digits.length !==
|
|
58
|
+
if (digits.length !== TOKEN_DIGITS)
|
|
50
59
|
return { ok: false, reason: 'a token is six digits' };
|
|
51
60
|
const wanted = hashToken(digits);
|
|
52
|
-
const
|
|
61
|
+
const unused = (view) => view.kind === kind && view.target === target && view.usedAt === null;
|
|
62
|
+
const candidates = [...foldTokens(root).values()].filter(unused);
|
|
53
63
|
if (candidates.length === 0)
|
|
54
64
|
return { ok: false, reason: `no ${kind} token was issued for this target — ask for a new one` };
|
|
55
65
|
const live = candidates.filter((view) => view.failures < TOKEN_MAX_FAILURES && new Date(view.expiresAt).getTime() > now.getTime());
|
|
56
66
|
if (live.length === 0)
|
|
57
|
-
return { ok: false, reason:
|
|
67
|
+
return { ok: false, reason: `token expired or revoked after ${TOKEN_MAX_FAILURES} failures — ask for a new one` };
|
|
58
68
|
const match = live.find((view) => view.tokenHash === wanted);
|
|
59
69
|
if (!match) {
|
|
60
70
|
for (const view of live)
|
package/dist/core/tokens.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/core/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAQ5D,MAAM,CAAC,MAAM,YAAY,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAC3C,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/core/tokens.ts"],"names":[],"mappings":"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"}
|
package/dist/core/tree.js
CHANGED
|
@@ -2,7 +2,17 @@ import { createHash } from 'node:crypto';
|
|
|
2
2
|
import { spawnSync } from 'node:child_process';
|
|
3
3
|
import fs from 'node:fs';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
-
|
|
5
|
+
import { CLAUDE_DIR, CODEX_DIR } from './locations.js';
|
|
6
|
+
import { VIBE_DIR } from './paths.js';
|
|
7
|
+
const SKIP_DIRS = new Set(['.git', 'node_modules', VIBE_DIR, 'dist', CLAUDE_DIR, CODEX_DIR]);
|
|
8
|
+
/** Hex characters of the tree hash kept as the fingerprint. */
|
|
9
|
+
const TREE_HASH_LENGTH = 16;
|
|
10
|
+
/** Changed files hashed by `changedBlobs` unless the caller asks for more. */
|
|
11
|
+
const DEFAULT_CHANGED_LIMIT = 200;
|
|
12
|
+
const DELETED = 'deleted';
|
|
13
|
+
/** `git status --porcelain` puts a two-letter status and a space before the path. */
|
|
14
|
+
const PORCELAIN_PATH_OFFSET = 3;
|
|
15
|
+
const inVibe = (file) => file.startsWith(`${VIBE_DIR}/`);
|
|
6
16
|
function git(root, args) {
|
|
7
17
|
const result = spawnSync('git', args, { cwd: root, encoding: 'utf-8' });
|
|
8
18
|
return result.status === 0 ? result.stdout : null;
|
|
@@ -24,22 +34,26 @@ function walk(dir, rel, into) {
|
|
|
24
34
|
}
|
|
25
35
|
}
|
|
26
36
|
}
|
|
37
|
+
/** Files git reports as changed or untracked, `.vibe/` excluded; null outside git. */
|
|
38
|
+
function changedFiles(root) {
|
|
39
|
+
const status = git(root, ['status', '--porcelain', '--untracked-files=all']);
|
|
40
|
+
if (status === null)
|
|
41
|
+
return null;
|
|
42
|
+
return status.split('\n').map((line) => line.slice(PORCELAIN_PATH_OFFSET).trim()).filter((file) => file && !inVibe(file));
|
|
43
|
+
}
|
|
27
44
|
/** Changed or untracked files relative to HEAD with their content ids (`deleted` when gone), `.vibe/` excluded. Empty outside git. */
|
|
28
|
-
export function changedBlobs(root, limit =
|
|
29
|
-
const changed =
|
|
45
|
+
export function changedBlobs(root, limit = DEFAULT_CHANGED_LIMIT) {
|
|
46
|
+
const changed = changedFiles(root);
|
|
30
47
|
const out = {};
|
|
31
48
|
if (changed === null)
|
|
32
49
|
return out;
|
|
33
50
|
let n = 0;
|
|
34
|
-
for (const
|
|
35
|
-
const file = line.slice(3).trim();
|
|
36
|
-
if (!file || file.startsWith('.vibe/'))
|
|
37
|
-
continue;
|
|
51
|
+
for (const file of changed) {
|
|
38
52
|
try {
|
|
39
53
|
out[file] = blobId(fs.readFileSync(path.join(root, file)));
|
|
40
54
|
}
|
|
41
55
|
catch {
|
|
42
|
-
out[file] =
|
|
56
|
+
out[file] = DELETED;
|
|
43
57
|
}
|
|
44
58
|
n += 1;
|
|
45
59
|
if (n >= limit)
|
|
@@ -68,14 +82,10 @@ export function treeHash(root) {
|
|
|
68
82
|
for (const line of tracked.split('\n')) {
|
|
69
83
|
const [meta, file] = line.split('\t');
|
|
70
84
|
const id = meta?.split(' ')[2];
|
|
71
|
-
if (file && id && !file
|
|
85
|
+
if (file && id && !inVibe(file))
|
|
72
86
|
blobs.set(file, id);
|
|
73
87
|
}
|
|
74
|
-
const
|
|
75
|
-
for (const line of changed.split('\n')) {
|
|
76
|
-
const file = line.slice(3).trim();
|
|
77
|
-
if (!file || file.startsWith('.vibe/'))
|
|
78
|
-
continue;
|
|
88
|
+
for (const file of changedFiles(root) ?? []) {
|
|
79
89
|
try {
|
|
80
90
|
blobs.set(file, blobId(fs.readFileSync(path.join(root, file))));
|
|
81
91
|
}
|
|
@@ -85,13 +95,13 @@ export function treeHash(root) {
|
|
|
85
95
|
}
|
|
86
96
|
for (const [file, id] of [...blobs.entries()].sort())
|
|
87
97
|
hash.update(`${file}:${id}\n`);
|
|
88
|
-
return hash.digest('hex').slice(0,
|
|
98
|
+
return hash.digest('hex').slice(0, TREE_HASH_LENGTH);
|
|
89
99
|
}
|
|
90
100
|
const entries = [];
|
|
91
101
|
walk(root, '', entries);
|
|
92
102
|
entries.sort();
|
|
93
103
|
for (const entry of entries)
|
|
94
104
|
hash.update(entry);
|
|
95
|
-
return hash.digest('hex').slice(0,
|
|
105
|
+
return hash.digest('hex').slice(0, TREE_HASH_LENGTH);
|
|
96
106
|
}
|
|
97
107
|
//# sourceMappingURL=tree.js.map
|
package/dist/core/tree.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tree.js","sourceRoot":"","sources":["../../src/core/tree.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"tree.js","sourceRoot":"","sources":["../../src/core/tree.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC;AAC7F,+DAA+D;AAC/D,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAC5B,8EAA8E;AAC9E,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAClC,MAAM,OAAO,GAAG,SAAS,CAAC;AAC1B,qFAAqF;AACrF,MAAM,qBAAqB,GAAG,CAAC,CAAC;AAEhC,MAAM,MAAM,GAAG,CAAC,IAAY,EAAW,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,QAAQ,GAAG,CAAC,CAAC;AAE1E,SAAS,GAAG,CAAC,IAAY,EAAE,IAAc;IACvC,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IACxE,OAAO,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACpD,CAAC;AAED,6EAA6E;AAC7E,SAAS,MAAM,CAAC,OAAe;IAC7B,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,QAAQ,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC7F,CAAC;AAED,SAAS,IAAI,CAAC,GAAW,EAAE,GAAW,EAAE,IAAc;IACpD,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QACjE,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;gBAAE,SAAS;YACxC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,GAAG,GAAG,KAAK,CAAC,IAAI,GAAG,EAAE,IAAI,CAAC,CAAC;QACjE,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YAC1B,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;YACrD,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;AACH,CAAC;AAED,sFAAsF;AACtF,SAAS,YAAY,CAAC,IAAY;IAChC,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,aAAa,EAAE,uBAAuB,CAAC,CAAC,CAAC;IAC7E,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACjC,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;AAC5H,CAAC;AAED,sIAAsI;AACtI,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,KAAK,GAAG,qBAAqB;IACtE,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,GAAG,CAAC;IACjC,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,GAAG,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QAC7D,CAAC;QAAC,MAAM,CAAC;YACP,GAAG,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;QACtB,CAAC;QACD,CAAC,IAAI,CAAC,CAAC;QACP,IAAI,CAAC,IAAI,KAAK;YAAE,MAAM;IACxB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,gGAAgG;AAChG,MAAM,UAAU,YAAY,CAAC,QAAuC,EAAE,OAA+B;IACnG,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACnD,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AACjF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IAClC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,SAAS,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IACrD,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrB,2FAA2F;QAC3F,uFAAuF;QACvF,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;QACxC,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACvC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACtC,MAAM,EAAE,GAAG,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAC/B,IAAI,IAAI,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;gBAAE,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACvD,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;YAC5C,IAAI,CAAC;gBACH,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YAClE,CAAC;YAAC,MAAM,CAAC;gBACP,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACrB,CAAC;QACH,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE;YAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,IAAI,EAAE,IAAI,CAAC,CAAC;QACrF,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC;IACvD,CAAC;IACD,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;IACxB,OAAO,CAAC,IAAI,EAAE,CAAC;IACf,KAAK,MAAM,KAAK,IAAI,OAAO;QAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAChD,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC;AACvD,CAAC"}
|
|
@@ -7,6 +7,24 @@ import { repairAwaitingInput } from './repair.js';
|
|
|
7
7
|
import { requireRiskCoverage } from './risk-signals.js';
|
|
8
8
|
import { ancestorsOf, isHuman } from './scenarios.js';
|
|
9
9
|
import { readState } from './state.js';
|
|
10
|
+
/** States in which a plan can be executed; in any other there is no approved task to run. */
|
|
11
|
+
const EXECUTABLE_STATES = ['APPROVED', 'RUNNING', 'DONE', 'STUCK'];
|
|
12
|
+
const QUALITY_GUIDE = 'vibe internal guide verification';
|
|
13
|
+
const QUALITY_NEXT = [
|
|
14
|
+
'For authored output, inspect affected code, prose or rendered UI against its guide before delivery.',
|
|
15
|
+
'Record scope, findings and limits in the existing task note or summary.',
|
|
16
|
+
].join(' ');
|
|
17
|
+
const QUALITY_LIMITS = [
|
|
18
|
+
'Machine passes and DONE do not establish antislop quality.',
|
|
19
|
+
'This preview neither performs nor reads an agent assessment; reuse requires unchanged output and criteria.',
|
|
20
|
+
].join(' ');
|
|
21
|
+
const RETRY_NEXT = 'Inspect the existing failure evidence and identify changed input or a new hypothesis before retrying.';
|
|
22
|
+
const PLAN_LIMITS = [
|
|
23
|
+
'Read-only snapshot, not DONE, permission or a promise of execution.',
|
|
24
|
+
'Check revalidates before running; per-action authority and human/handoff waits still apply.',
|
|
25
|
+
'External state, undeclared ignored inputs, host calls and host token costs are not observed.',
|
|
26
|
+
'Explicitly rerun checks whose external inputs changed.',
|
|
27
|
+
].join(' ');
|
|
10
28
|
/** A read-only view of the existing selector, not a second verdict or execution receipt. */
|
|
11
29
|
export function verificationPlan(root, options = {}) {
|
|
12
30
|
const state = readState(root);
|
|
@@ -15,10 +33,11 @@ export function verificationPlan(root, options = {}) {
|
|
|
15
33
|
const selected = new Set(selectScenarios(universe, previous, options).map(s => s.id));
|
|
16
34
|
const blockers = [];
|
|
17
35
|
const waiting = repairAwaitingInput(root, state.repair);
|
|
18
|
-
if (!
|
|
36
|
+
if (!EXECUTABLE_STATES.includes(state.state))
|
|
19
37
|
blockers.push(`task is ${state.state}; no approved execution`);
|
|
20
38
|
else {
|
|
21
|
-
|
|
39
|
+
const validations = [() => validateApproval(root, state), () => requireConsent(root), () => requireRiskCoverage(root, universe)];
|
|
40
|
+
for (const validate of validations) {
|
|
22
41
|
try {
|
|
23
42
|
validate();
|
|
24
43
|
}
|
|
@@ -33,10 +52,10 @@ export function verificationPlan(root, options = {}) {
|
|
|
33
52
|
const result = previous[s.id];
|
|
34
53
|
const last = result?.last ?? 'never';
|
|
35
54
|
const decision = blockers.length ? 'blocked' : selected.has(s.id) ? 'selected' : last === 'pass' ? 'reuse' : 'outside-selection';
|
|
36
|
-
const reason = decision === 'reuse' ? 'recorded pass is fresh
|
|
55
|
+
const reason = decision === 'reuse' ? 'recorded pass is fresh: its inputs, artifacts and handoff are unchanged'
|
|
37
56
|
: decision === 'blocked' ? 'resolve blockers before executing or treating recorded evidence as reusable'
|
|
38
57
|
: decision === 'outside-selection' ? 'not requested; still required before completion'
|
|
39
|
-
: options.
|
|
58
|
+
: options.fresh ? 'explicit full run' : options.ids?.includes(s.id) ? 'explicitly requested'
|
|
40
59
|
: isHuman(s) ? 'human judgment; no automatic verdict' : `no reusable pass (${last})`;
|
|
41
60
|
return { id: s.id, type: s.check.type, last, decision, selected: selected.has(s.id), reason,
|
|
42
61
|
evidence: result?.run ? `${result.run}#${s.id}` : null,
|
|
@@ -44,13 +63,10 @@ export function verificationPlan(root, options = {}) {
|
|
|
44
63
|
});
|
|
45
64
|
return { root, recordedState: state.state, blockers, checks,
|
|
46
65
|
qualityReview: { status: 'not-assessed', assessedBy: null,
|
|
47
|
-
guide:
|
|
48
|
-
next: 'For authored output, inspect affected code, prose or rendered UI against its guide before delivery. Record scope, findings and limits in the existing task note or summary.',
|
|
49
|
-
limits: 'Machine passes and DONE do not establish antislop quality. This preview neither performs nor reads an agent assessment; reuse requires unchanged output and criteria.' },
|
|
66
|
+
guide: QUALITY_GUIDE, next: QUALITY_NEXT, limits: QUALITY_LIMITS },
|
|
50
67
|
nextAction: blockers.length ? 'resolve-blockers' : checks.some(c => c.decision === 'selected') ? 'run-selected-checks' : 'inspect-completion-requirements',
|
|
51
68
|
remaining: universe.filter(s => !isHuman(s) && previous[s.id]?.last !== 'pass').map(s => s.id),
|
|
52
|
-
retry: state.repair ? { failures: state.failStreak, waiting,
|
|
53
|
-
|
|
54
|
-
limits: 'Read-only snapshot, not DONE, permission or a promise of execution. Check revalidates before running; per-action authority and human/handoff waits still apply. External state, undeclared ignored inputs, host calls and host token costs are not observed. Explicitly rerun checks whose external inputs changed.' };
|
|
69
|
+
retry: state.repair ? { failures: state.failStreak, waiting, next: RETRY_NEXT } : null,
|
|
70
|
+
limits: PLAN_LIMITS };
|
|
55
71
|
}
|
|
56
72
|
//# sourceMappingURL=verification-plan.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verification-plan.js","sourceRoot":"","sources":["../../src/core/verification-plan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAqB,MAAM,YAAY,CAAC;AAC9E,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,4FAA4F;AAC5F,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,UAAwB,EAAE;IACvE,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,QAAQ,GAAG,CAAC,GAAG,aAAa,CAAC,IAAI,CAAC,EAAE,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC3G,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACtF,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,OAAO,GAAG,mBAAmB,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACxD,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"verification-plan.js","sourceRoot":"","sources":["../../src/core/verification-plan.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
+
/** Fields a declared risk may carry; any other is rejected. */
|
|
2
|
+
const RISK_FIELDS = new Set(['paths', 'kind', 'impact', 'recovery', 'failureChecks', 'recoveryChecks']);
|
|
1
3
|
export const RISK_KINDS = ['data', 'access', 'interface', 'deployment', 'integration'];
|
|
4
|
+
function projectRelative(p) {
|
|
5
|
+
return typeof p === 'string' && p !== '' && !p.startsWith('/') && !p.includes('..') && !p.includes('\\') && p !== '.';
|
|
6
|
+
}
|
|
2
7
|
/** Validate declared obligations; this does not infer domain risks from arbitrary source code. */
|
|
3
8
|
export function riskReason(value) {
|
|
4
9
|
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
@@ -12,21 +17,22 @@ export function riskReason(value) {
|
|
|
12
17
|
}
|
|
13
18
|
for (const key of ['failureChecks', 'recoveryChecks']) {
|
|
14
19
|
const ids = risk[key];
|
|
15
|
-
if (!Array.isArray(ids) || !ids.length || ids.some(id => typeof id !== 'string' || !id.trim()))
|
|
20
|
+
if (!Array.isArray(ids) || !ids.length || ids.some(id => typeof id !== 'string' || !id.trim())) {
|
|
16
21
|
return `risk.${key} must name at least one scenario`;
|
|
22
|
+
}
|
|
17
23
|
}
|
|
18
|
-
if (risk['paths'] !== undefined && (!Array.isArray(risk['paths']) || risk['paths'].
|
|
24
|
+
if (risk['paths'] !== undefined && (!Array.isArray(risk['paths']) || !risk['paths'].every(projectRelative))) {
|
|
19
25
|
return 'risk.paths must contain project-relative files or directories';
|
|
20
|
-
|
|
21
|
-
if (Object.keys(risk).some(key => !
|
|
26
|
+
}
|
|
27
|
+
if (Object.keys(risk).some(key => !RISK_FIELDS.has(key)))
|
|
22
28
|
return 'unknown risk field';
|
|
23
29
|
return null;
|
|
24
30
|
}
|
|
25
31
|
function assertsContent(check) {
|
|
26
32
|
if (check.exists === false)
|
|
27
33
|
return false;
|
|
28
|
-
|
|
29
|
-
|
|
34
|
+
const rules = [check.pattern, check.contains, check.absent, check.traceable, check.schema];
|
|
35
|
+
return rules.some(value => typeof value === 'string' && value.trim().length > 0) || check.a11y === true || check.sum !== undefined;
|
|
30
36
|
}
|
|
31
37
|
/** Risk obligations use the existing dependency scheduler and verdict, not a second pipeline. */
|
|
32
38
|
export function bindRiskChecks(scenarios, rejections) {
|
|
@@ -46,8 +52,9 @@ export function bindRiskChecks(scenarios, rejections) {
|
|
|
46
52
|
if (id === scenario.id || target.check.type === 'human' || target.check.type === 'review') {
|
|
47
53
|
rejections.push({ id: scenario.id, reason: `risk check ${id} must be a separate machine check` });
|
|
48
54
|
}
|
|
49
|
-
if (target.irreversible)
|
|
55
|
+
if (target.irreversible) {
|
|
50
56
|
rejections.push({ id: scenario.id, reason: `risk check ${id} must use a local fixture or dry run, not an irreversible action` });
|
|
57
|
+
}
|
|
51
58
|
if (target.check.type === 'file' && !assertsContent(target.check)) {
|
|
52
59
|
rejections.push({ id: scenario.id, reason: `risk check ${id} must assert behavior or content, not only file existence` });
|
|
53
60
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verification.js","sourceRoot":"","sources":["../../src/core/verification.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,CAAU,CAAC;AAUhG,kGAAkG;AAClG,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,wBAAwB,CAAC;IACjG,MAAM,IAAI,GAAG,KAAgC,CAAC;IAC9C,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAiB,CAAC;QAAE,OAAO,qBAAqB,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IAC3G,KAAK,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,CAAC;QACzC,IAAI,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE;YAAE,OAAO,QAAQ,GAAG,kDAAkD,CAAC;IAC/H,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,CAAC,eAAe,EAAE,gBAAgB,CAAC,EAAE,CAAC;QACtD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,QAAQ,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"verification.js","sourceRoot":"","sources":["../../src/core/verification.ts"],"names":[],"mappings":"AAEA,+DAA+D;AAC/D,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,eAAe,EAAE,gBAAgB,CAAC,CAAC,CAAC;AAExG,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,CAAU,CAAC;AAUhG,SAAS,eAAe,CAAC,CAAU;IACjC,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC;AACxH,CAAC;AAED,kGAAkG;AAClG,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,wBAAwB,CAAC;IACjG,MAAM,IAAI,GAAG,KAAgC,CAAC;IAC9C,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAiB,CAAC;QAAE,OAAO,qBAAqB,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IAC3G,KAAK,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,CAAC;QACzC,IAAI,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE;YAAE,OAAO,QAAQ,GAAG,kDAAkD,CAAC;IAC/H,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,CAAC,eAAe,EAAE,gBAAgB,CAAC,EAAE,CAAC;QACtD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,QAAQ,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YAC/F,OAAO,QAAQ,GAAG,kCAAkC,CAAC;QACvD,CAAC;IACH,CAAC;IACD,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC;QAC5G,OAAO,+DAA+D,CAAC;IACzE,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAAE,OAAO,oBAAoB,CAAC;IACtF,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,cAAc,CAAC,KAAgB;IACtC,IAAI,KAAK,CAAC,MAAM,KAAK,KAAK;QAAE,OAAO,KAAK,CAAC;IACzC,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC3F,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS,CAAC;AACrI,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,cAAc,CAAC,SAAqB,EAAE,UAAuB;IAC3E,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACpD,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,IAAI,CAAC,QAAQ,CAAC,IAAI;YAAE,SAAS;QAC7B,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO;YAAE,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,qDAAqD,EAAE,CAAC,CAAC;QACzI,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;QACjG,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;YAC1B,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC5B,IAAI,CAAC,MAAM,EAAE,CAAC;gBAAC,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,8BAA8B,EAAE,EAAE,EAAE,CAAC,CAAC;gBAAC,SAAS;YAAC,CAAC;YAC5G,IAAI,EAAE,KAAK,QAAQ,CAAC,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC1F,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,mCAAmC,EAAE,CAAC,CAAC;YACpG,CAAC;YACD,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;gBACxB,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,kEAAkE,EAAE,CAAC,CAAC;YACnI,CAAC;YACD,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;gBAClE,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,2DAA2D,EAAE,CAAC,CAAC;YAC5H,CAAC;YACD,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC;gBAC7E,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,mCAAmC,EAAE,CAAC,CAAC;YACpG,CAAC;QACH,CAAC;QACD,QAAQ,CAAC,KAAK,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC1E,CAAC;AACH,CAAC"}
|
package/dist/core/view.js
CHANGED
|
@@ -16,9 +16,21 @@ import { readText } from './store.js';
|
|
|
16
16
|
import { sourceValidity } from './source-basis.js';
|
|
17
17
|
import path from 'node:path';
|
|
18
18
|
import { recordReadTargets } from './read-guard.js';
|
|
19
|
+
import { RUN_PREFIX } from './run-id.js';
|
|
20
|
+
/** Files shown per scenario in the brief. */
|
|
21
|
+
const FILES_PER_SCENARIO = 8;
|
|
22
|
+
/** More scenarios than this is `full` work, not `small`. */
|
|
23
|
+
const SMALL_SCENARIO_MAX = 8;
|
|
24
|
+
const UNTITLED = '(untitled)';
|
|
25
|
+
const DISCOVER_NEXT = 'discover — the vibe-discover skill: inspect accessible evidence, resolve material unknowns, stop when agreement is sufficient';
|
|
26
|
+
const SCOPE_NEXT = 'approve — the vibe-scope skill: vibe intent analyze, confirm sufficient agreement, one approval message; wait for "yes"';
|
|
27
|
+
const REPORT_TAIL = [
|
|
28
|
+
'answer the user from this output — what was built, which checks passed — reply in chat, not vibe ask;',
|
|
29
|
+
'with no skill and no further reads; HANDOFF.md only if the intent asks',
|
|
30
|
+
].join(' ');
|
|
19
31
|
function sizeOf(scenarios) {
|
|
20
32
|
const own = scenarios.filter((s) => !('regression' in s && s.regression));
|
|
21
|
-
if (own.length >
|
|
33
|
+
if (own.length > SMALL_SCENARIO_MAX)
|
|
22
34
|
return 'full';
|
|
23
35
|
if (own.some((s) => s.irreversible))
|
|
24
36
|
return 'full';
|
|
@@ -46,7 +58,10 @@ function checkTarget(check) {
|
|
|
46
58
|
}
|
|
47
59
|
/** One scenario as the brief shows it: its check, and — while it has not passed — the files it is about. */
|
|
48
60
|
function scenarioView(root, s, results) {
|
|
49
|
-
const view = {
|
|
61
|
+
const view = {
|
|
62
|
+
id: s.id, then: s.then, type: s.check.type, last: results[s.id]?.last ?? 'never', at: results[s.id]?.at ?? null,
|
|
63
|
+
check: checkTarget(s.check),
|
|
64
|
+
};
|
|
50
65
|
const failure = results[s.id]?.failure;
|
|
51
66
|
if (failure)
|
|
52
67
|
view.failure = failure;
|
|
@@ -57,7 +72,8 @@ function scenarioView(root, s, results) {
|
|
|
57
72
|
if (s.needs)
|
|
58
73
|
view.needs = s.needs;
|
|
59
74
|
if (view.last !== 'pass' && !isHuman(s)) {
|
|
60
|
-
const
|
|
75
|
+
const located = view.failure?.locations.map((location) => location.file) ?? [];
|
|
76
|
+
const files = [...new Set([...located, ...filesFor(root, s.check)])].slice(0, FILES_PER_SCENARIO);
|
|
61
77
|
if (files.length)
|
|
62
78
|
view.files = files;
|
|
63
79
|
}
|
|
@@ -66,15 +82,27 @@ function scenarioView(root, s, results) {
|
|
|
66
82
|
function scenarioTargets(scenarios) {
|
|
67
83
|
return scenarios.map((s) => `${s.id}${s.files?.length ? ` (files: ${s.files.join(', ')})` : ''}`).join(', ');
|
|
68
84
|
}
|
|
85
|
+
/** What to do once a question is answered, by stage. */
|
|
86
|
+
function resumeAfterAnswer(state, stage, remaining) {
|
|
87
|
+
if (stage === 'discover')
|
|
88
|
+
return 'continue discovery with vibe-discover; use the answer to resolve material unknowns';
|
|
89
|
+
if (stage === 'scope')
|
|
90
|
+
return 'continue scope with vibe-scope; incorporate the answer, confirm sufficient agreement and request approval';
|
|
91
|
+
if (state === 'DONE')
|
|
92
|
+
return 'reply in chat, not vibe ask';
|
|
93
|
+
return remaining.length ? `continue building ${scenarioTargets(remaining)}; then vibe check --all` : 'then vibe check --all';
|
|
94
|
+
}
|
|
69
95
|
/** Asking is a stop: an unanswered question means wait; an answered one carries its answer and lets the work continue. */
|
|
70
96
|
function inboxLine(state, stage, items, remaining) {
|
|
71
97
|
const waiting = items.filter((q) => !q.answer?.trim());
|
|
72
98
|
const answered = items.filter((q) => q.answer?.trim());
|
|
73
|
-
if (waiting.length > 0)
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
99
|
+
if (waiting.length > 0) {
|
|
100
|
+
const failures = remaining.flatMap((s) => s.failure ? [failureLine(s.failure)] : []);
|
|
101
|
+
const because = failures.length ? ` — ${failures.join(' | ')}` : '';
|
|
102
|
+
const prefix = state === 'STUCK' ? 'STUCK — ' : 'wait — ';
|
|
103
|
+
return `${prefix}${waiting.map((q) => q.id).join(', ')} asked${because}; the user answers; stop and wait — do not answer it yourself`;
|
|
104
|
+
}
|
|
105
|
+
const resume = resumeAfterAnswer(state, stage, remaining);
|
|
78
106
|
if (answered.length > 0)
|
|
79
107
|
return `answered ${answered.map((q) => `${q.id}: "${q.answer}"`).join(' · ')} — ${resume}; vibe inbox resolve <id> once used`;
|
|
80
108
|
return null;
|
|
@@ -87,13 +115,15 @@ function nextLine(state, stage, pending, inbox, size, run, repair) {
|
|
|
87
115
|
if (state === 'STUCK')
|
|
88
116
|
return repairNext(repair);
|
|
89
117
|
if (stage === 'discover')
|
|
90
|
-
return
|
|
118
|
+
return DISCOVER_NEXT;
|
|
91
119
|
if (stage === 'scope')
|
|
92
|
-
return
|
|
93
|
-
if (state === 'DONE')
|
|
94
|
-
return `report — DONE
|
|
95
|
-
|
|
120
|
+
return SCOPE_NEXT;
|
|
121
|
+
if (state === 'DONE') {
|
|
122
|
+
return `report — DONE ${RUN_PREFIX}${run}: ${REPORT_TAIL}`;
|
|
123
|
+
}
|
|
124
|
+
if (isHandoffOnly(pending)) {
|
|
96
125
|
return `handoff — required work remains unmet: ${scenarioTargets(pending)}; reopen a handed-off scenario explicitly before retrying`;
|
|
126
|
+
}
|
|
97
127
|
if (remaining.length === 0)
|
|
98
128
|
return 'check --all — nothing remaining; the verdict comes from vibe check';
|
|
99
129
|
const failed = pending.filter((s) => s.last === 'fail');
|
|
@@ -106,28 +136,15 @@ function nextLine(state, stage, pending, inbox, size, run, repair) {
|
|
|
106
136
|
function intentTitle(root) {
|
|
107
137
|
const text = readText(intentPath(root)) ?? '';
|
|
108
138
|
const heading = text.split('\n').find((line) => line.startsWith('#'));
|
|
109
|
-
return heading ? heading.replace(/^#+\s*/, '').trim() :
|
|
139
|
+
return heading ? heading.replace(/^#+\s*/, '').trim() : UNTITLED;
|
|
110
140
|
}
|
|
111
|
-
/**
|
|
112
|
-
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
notices.push(`project root is ${root} — above the current directory; records and run checks use that root`);
|
|
116
|
-
if (invalidateDoneIfEdited(root))
|
|
117
|
-
notices.push('files changed after DONE — state is RUNNING again; run `vibe check`');
|
|
118
|
-
const state = readState(root);
|
|
119
|
-
const results = readResults(root);
|
|
120
|
-
const scenarios = loadScenarios(root);
|
|
121
|
-
const regressions = listRegressions(root);
|
|
122
|
-
const views = [...scenarios, ...regressions.map((r) => ({ ...r, regression: true }))].map((s) => scenarioView(root, s, results));
|
|
123
|
-
const gated = views.filter((v) => v.type !== 'human');
|
|
124
|
-
const pending = gated.filter((v) => v.last !== 'pass');
|
|
125
|
-
const remaining = pending.map((v) => v.id);
|
|
126
|
-
const allPassedOnce = gated.length > 0 && remaining.length === 0;
|
|
127
|
-
const inbox = openQuestions(root), repairQuestion = pendingRepairQuestion(root, state.repair);
|
|
141
|
+
/** The questions as the brief lists them; a repair question the inbox does not hold yet joins it. */
|
|
142
|
+
function inboxItems(root, repair) {
|
|
143
|
+
const inbox = openQuestions(root);
|
|
144
|
+
const repairQuestion = pendingRepairQuestion(root, repair);
|
|
128
145
|
if (repairQuestion && !inbox.some(q => q.id === repairQuestion.id))
|
|
129
146
|
inbox.push(repairQuestion);
|
|
130
|
-
|
|
147
|
+
return inbox.map((q) => {
|
|
131
148
|
const item = { id: q.id, question: q.question };
|
|
132
149
|
if (q.answer)
|
|
133
150
|
item.answer = q.answer;
|
|
@@ -141,23 +158,55 @@ export function buildStateView(root, cwd = process.cwd()) {
|
|
|
141
158
|
item.needs = q.needs;
|
|
142
159
|
return item;
|
|
143
160
|
});
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
161
|
+
}
|
|
162
|
+
const READ_MIRROR_NOTICE = 'read-target mirror unavailable; state remains available, intrinsic contract protection still applies';
|
|
163
|
+
const STUCK_WAITING_NOTICE = 'STUCK — repair limit reached; relay the question and its failure summary';
|
|
164
|
+
const STUCK_DIAGNOSE_NOTICE = 'STUCK — diagnose the failure and change the approach; ordinary repair needs no permission';
|
|
165
|
+
/** What the brief warns about once the state is read: the contract's sources, regression files, mutations, a stuck repair, human items. */
|
|
166
|
+
function recordNotices(root, state, scenarios, views) {
|
|
167
|
+
const notices = [];
|
|
168
|
+
const files = views.flatMap(view => view.files ?? []);
|
|
169
|
+
if (state.intentHash && !recordReadTargets(root, { intentHash: state.intentHash, files }))
|
|
170
|
+
notices.push(READ_MIRROR_NOTICE);
|
|
148
171
|
const sources = sourceValidity(root);
|
|
149
|
-
if (sources && !sources.valid)
|
|
150
|
-
|
|
172
|
+
if (sources && !sources.valid) {
|
|
173
|
+
const named = [...sources.changed, ...sources.missing, ...sources.unreadable].join(', ');
|
|
174
|
+
notices.push(`source basis changed or missing: ${named} — re-evaluate affected findings and redraft before approval`);
|
|
175
|
+
}
|
|
151
176
|
notices.push(...regressionProblems(root));
|
|
152
|
-
for (const s of scenarios)
|
|
153
|
-
if (s.irreversible)
|
|
154
|
-
|
|
177
|
+
for (const s of scenarios) {
|
|
178
|
+
if (!s.irreversible)
|
|
179
|
+
continue;
|
|
180
|
+
const action = actionOf(s.irreversible);
|
|
181
|
+
notices.push(`${s.id} mutates (${action}) — not run by check --all without vibe authorize --action ${action}`);
|
|
182
|
+
}
|
|
155
183
|
if (state.state === 'STUCK')
|
|
156
|
-
notices.push(state.repair?.waiting ?
|
|
184
|
+
notices.push(state.repair?.waiting ? STUCK_WAITING_NOTICE : STUCK_DIAGNOSE_NOTICE);
|
|
157
185
|
if (scenarios.some(isHuman) && state.state === 'DONE')
|
|
158
186
|
notices.push('human items are not gates — a confirmation was requested in the inbox');
|
|
159
|
-
|
|
160
|
-
|
|
187
|
+
return notices;
|
|
188
|
+
}
|
|
189
|
+
/** Every skill's first call. A DONE invalidated by edits falls back to RUNNING here. */
|
|
190
|
+
export function buildStateView(root, cwd = process.cwd()) {
|
|
191
|
+
const notices = [];
|
|
192
|
+
if (path.resolve(cwd) !== path.resolve(root))
|
|
193
|
+
notices.push(`project root is ${root} — above the current directory; records and run checks use that root`);
|
|
194
|
+
if (invalidateDoneIfEdited(root))
|
|
195
|
+
notices.push('files changed after DONE — state is RUNNING again; run `vibe check`');
|
|
196
|
+
const state = readState(root);
|
|
197
|
+
const results = readResults(root);
|
|
198
|
+
const scenarios = loadScenarios(root);
|
|
199
|
+
const withRegressions = [...scenarios, ...listRegressions(root).map((r) => ({ ...r, regression: true }))];
|
|
200
|
+
const views = withRegressions.map((s) => scenarioView(root, s, results));
|
|
201
|
+
const gated = views.filter((v) => v.type !== 'human');
|
|
202
|
+
const pending = gated.filter((v) => v.last !== 'pass');
|
|
203
|
+
const remaining = pending.map((v) => v.id);
|
|
204
|
+
const questions = inboxItems(root, state.repair);
|
|
205
|
+
const lastEvent = readLedger(root).at(-1);
|
|
206
|
+
const intent = hasIntent(root) ? { title: intentTitle(root), hash: state.intentHash, approvedAt: state.approvedAt } : null;
|
|
207
|
+
notices.push(...recordNotices(root, state, scenarios, views));
|
|
208
|
+
const stage = stageOf(state, intent !== null, gated.length > 0 && remaining.length === 0);
|
|
209
|
+
const size = sizeOf(withRegressions);
|
|
161
210
|
return {
|
|
162
211
|
root,
|
|
163
212
|
state: state.state,
|