@miller-tech/uap 1.187.8 → 1.188.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.
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Warn when a mission's instruction names files it cannot reach.
3
+ *
4
+ * THE FAILURE THIS CATCHES
5
+ * `safePath` refuses any edit that resolves outside the project root, which is
6
+ * correct and stays. But refusing one path does not stop the model wanting that
7
+ * file — and its next move is the damaging one. Observed live on 2026-08-09 in
8
+ * `cognition-engine`:
9
+ *
10
+ * projectRoot: <repo>/src/rust-pg-ext (the crate)
11
+ * instruction: "... **src/sql/setup.sql** lines 22-29: replace SQL md5 hash
12
+ * functions with Rust XXH64 versions ..."
13
+ *
14
+ * That file is `<repo>/src/sql/setup.sql` — 62KB, outside the crate. The model
15
+ * tried `../sql/setup.sql`, was refused, and then CREATED a 1.5KB stub at
16
+ * `<crate>/src/sql/setup.sql`, which safePath allows because it is inside the
17
+ * root. The guard deflected the model into writing a plausible file in the
18
+ * wrong place: untracked, unreferenced, and easy to mistake for the real edit.
19
+ *
20
+ * The mission was mis-scoped — it should have run at the repo root — and that
21
+ * was knowable before the first turn, from the instruction and the filesystem
22
+ * alone. Saying so up front turns a silent wrong-place write into a fact the
23
+ * model and the operator both get for free.
24
+ *
25
+ * DELIBERATELY ADVISORY. A path in an instruction can be illustrative, a file
26
+ * yet to be created, or prose that merely looks like a path, so refusing the
27
+ * run on this signal would block legitimate work. It only ever reports paths
28
+ * that are ABSENT under the project root and PRESENT above it — the one
29
+ * combination that cannot be explained by "the model will create it".
30
+ */
31
+ /**
32
+ * The enclosing repository root ABOVE `projectRoot`, or null.
33
+ *
34
+ * Null when the project root is itself the repo root — there is nothing above
35
+ * to be out of scope of — and null when no repository encloses it at all.
36
+ * `.git` is a directory in a normal clone and a FILE in a worktree, so both
37
+ * count.
38
+ */
39
+ export declare function findRepoRoot(projectRoot: string, exists?: (p: string) => boolean): string | null;
40
+ /** A path the instruction asks for that this run cannot reach. */
41
+ export interface UnreachablePath {
42
+ /** The path as written in the instruction. */
43
+ mentioned: string;
44
+ /** Where it actually is, relative to the search root. */
45
+ foundAt: string;
46
+ }
47
+ /** Candidate paths mentioned in free text, de-duplicated, in first-seen order. */
48
+ export declare function mentionedPaths(instruction: string): string[];
49
+ /**
50
+ * Paths the instruction names that are missing under `projectRoot` but present
51
+ * under `searchRoot` (normally the repo root above it).
52
+ *
53
+ * Returns [] when searchRoot is not an ancestor of projectRoot — there is no
54
+ * "above" to look in, so there is nothing this can be confident about.
55
+ */
56
+ export declare function unreachablePaths(instruction: string, projectRoot: string, searchRoot: string, exists?: (p: string) => boolean): UnreachablePath[];
57
+ /**
58
+ * The prompt/console notice, or null when there is nothing to report.
59
+ *
60
+ * Names the substitute-file failure explicitly. Telling a model only "you
61
+ * cannot reach it" leaves creating a same-named file inside the root as the
62
+ * obvious next move — which is the exact damage observed.
63
+ */
64
+ export declare function formatScopeNotice(unreachable: readonly UnreachablePath[], projectRoot: string, searchRoot: string): string | null;
65
+ //# sourceMappingURL=scope-notice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope-notice.d.ts","sourceRoot":"","sources":["../../src/delivery/scope-notice.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAKH;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,EACnB,MAAM,GAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAoB,GAC1C,MAAM,GAAG,IAAI,CASf;AAED,kEAAkE;AAClE,MAAM,WAAW,eAAe;IAC9B,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,OAAO,EAAE,MAAM,CAAC;CACjB;AAqBD,kFAAkF;AAClF,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAc5D;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,MAAM,GAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAoB,GAC1C,eAAe,EAAE,CAYnB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,SAAS,eAAe,EAAE,EACvC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GACjB,MAAM,GAAG,IAAI,CAaf"}
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Warn when a mission's instruction names files it cannot reach.
3
+ *
4
+ * THE FAILURE THIS CATCHES
5
+ * `safePath` refuses any edit that resolves outside the project root, which is
6
+ * correct and stays. But refusing one path does not stop the model wanting that
7
+ * file — and its next move is the damaging one. Observed live on 2026-08-09 in
8
+ * `cognition-engine`:
9
+ *
10
+ * projectRoot: <repo>/src/rust-pg-ext (the crate)
11
+ * instruction: "... **src/sql/setup.sql** lines 22-29: replace SQL md5 hash
12
+ * functions with Rust XXH64 versions ..."
13
+ *
14
+ * That file is `<repo>/src/sql/setup.sql` — 62KB, outside the crate. The model
15
+ * tried `../sql/setup.sql`, was refused, and then CREATED a 1.5KB stub at
16
+ * `<crate>/src/sql/setup.sql`, which safePath allows because it is inside the
17
+ * root. The guard deflected the model into writing a plausible file in the
18
+ * wrong place: untracked, unreferenced, and easy to mistake for the real edit.
19
+ *
20
+ * The mission was mis-scoped — it should have run at the repo root — and that
21
+ * was knowable before the first turn, from the instruction and the filesystem
22
+ * alone. Saying so up front turns a silent wrong-place write into a fact the
23
+ * model and the operator both get for free.
24
+ *
25
+ * DELIBERATELY ADVISORY. A path in an instruction can be illustrative, a file
26
+ * yet to be created, or prose that merely looks like a path, so refusing the
27
+ * run on this signal would block legitimate work. It only ever reports paths
28
+ * that are ABSENT under the project root and PRESENT above it — the one
29
+ * combination that cannot be explained by "the model will create it".
30
+ */
31
+ import { existsSync } from 'fs';
32
+ import { isAbsolute, join, relative, resolve } from 'path';
33
+ /**
34
+ * The enclosing repository root ABOVE `projectRoot`, or null.
35
+ *
36
+ * Null when the project root is itself the repo root — there is nothing above
37
+ * to be out of scope of — and null when no repository encloses it at all.
38
+ * `.git` is a directory in a normal clone and a FILE in a worktree, so both
39
+ * count.
40
+ */
41
+ export function findRepoRoot(projectRoot, exists = existsSync) {
42
+ let dir = resolve(projectRoot);
43
+ for (let hops = 0; hops < 64; hops++) {
44
+ const parent = resolve(dir, '..');
45
+ if (parent === dir)
46
+ return null; // hit the filesystem root
47
+ dir = parent;
48
+ if (exists(join(dir, '.git')))
49
+ return dir;
50
+ }
51
+ return null;
52
+ }
53
+ /**
54
+ * File-like tokens: a path with a real extension. Requiring an extension is
55
+ * what keeps prose out — "src/sql" or "the setup" are not candidates, and a
56
+ * bare word never is. Markdown emphasis and surrounding punctuation are
57
+ * stripped by the caller before this matches.
58
+ */
59
+ const PATH_TOKEN = /[\w.-]+(?:\/[\w.-]+)*\.[a-z]{1,6}\b/gi;
60
+ /**
61
+ * Extensions worth checking. An open-ended match turns ordinary sentences
62
+ * ("v1.2", "e.g.", "node.js") into candidate paths; a fixed list keeps the
63
+ * signal specific to source trees.
64
+ */
65
+ const SOURCE_EXT = new Set([
66
+ 'ts', 'tsx', 'js', 'jsx', 'mjs', 'cjs', 'rs', 'py', 'go', 'rb', 'java', 'kt',
67
+ 'c', 'h', 'cc', 'cpp', 'hpp', 'cs', 'php', 'swift', 'sql', 'sh', 'bash',
68
+ 'toml', 'yaml', 'yml', 'json', 'md', 'css', 'scss', 'html', 'jinja',
69
+ ]);
70
+ /** Candidate paths mentioned in free text, de-duplicated, in first-seen order. */
71
+ export function mentionedPaths(instruction) {
72
+ const out = [];
73
+ const seen = new Set();
74
+ for (const raw of instruction.match(PATH_TOKEN) ?? []) {
75
+ // Strip markdown emphasis and trailing punctuation the token may have eaten.
76
+ const tok = raw.replace(/^[*_`]+/, '').replace(/[*_`.,;:)\]]+$/, '');
77
+ if (!tok.includes('/'))
78
+ continue; // a bare filename is too weak a signal
79
+ const ext = tok.split('.').pop()?.toLowerCase() ?? '';
80
+ if (!SOURCE_EXT.has(ext))
81
+ continue;
82
+ if (seen.has(tok))
83
+ continue;
84
+ seen.add(tok);
85
+ out.push(tok);
86
+ }
87
+ return out;
88
+ }
89
+ /**
90
+ * Paths the instruction names that are missing under `projectRoot` but present
91
+ * under `searchRoot` (normally the repo root above it).
92
+ *
93
+ * Returns [] when searchRoot is not an ancestor of projectRoot — there is no
94
+ * "above" to look in, so there is nothing this can be confident about.
95
+ */
96
+ export function unreachablePaths(instruction, projectRoot, searchRoot, exists = existsSync) {
97
+ const rel = relative(resolve(searchRoot), resolve(projectRoot));
98
+ if (rel === '' || rel.startsWith('..') || isAbsolute(rel))
99
+ return [];
100
+ const found = [];
101
+ for (const p of mentionedPaths(instruction)) {
102
+ if (isAbsolute(p))
103
+ continue; // an absolute path is not a scope mistake
104
+ if (exists(join(projectRoot, p)))
105
+ continue; // reachable — nothing to say
106
+ if (!exists(join(searchRoot, p)))
107
+ continue; // absent everywhere: to be created
108
+ found.push({ mentioned: p, foundAt: join(relative(projectRoot, searchRoot), p) });
109
+ }
110
+ return found;
111
+ }
112
+ /**
113
+ * The prompt/console notice, or null when there is nothing to report.
114
+ *
115
+ * Names the substitute-file failure explicitly. Telling a model only "you
116
+ * cannot reach it" leaves creating a same-named file inside the root as the
117
+ * obvious next move — which is the exact damage observed.
118
+ */
119
+ export function formatScopeNotice(unreachable, projectRoot, searchRoot) {
120
+ if (unreachable.length === 0)
121
+ return null;
122
+ const lines = unreachable.map((u) => ` - ${u.mentioned} (actually at ${u.foundAt})`);
123
+ return [
124
+ 'SCOPE NOTICE — this task names files that are OUTSIDE the project root you are running in.',
125
+ `Project root: ${projectRoot}`,
126
+ lines.join('\n'),
127
+ '',
128
+ 'You cannot edit them: every path is resolved inside the project root, so `../` is refused.',
129
+ 'Do NOT create a same-named file inside the project root as a substitute — it would be a new,',
130
+ 'unreferenced file, not the edit that was asked for. Complete the parts that ARE in scope, and',
131
+ `report the rest as out of scope. If they are essential, the run belongs at ${searchRoot}.`,
132
+ ].join('\n');
133
+ }
134
+ //# sourceMappingURL=scope-notice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope-notice.js","sourceRoot":"","sources":["../../src/delivery/scope-notice.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miller-tech/uap",
3
- "version": "1.187.8",
3
+ "version": "1.188.0",
4
4
  "description": "Autonomous AI agent memory system with CLAUDE.md protocol enforcement",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",