@veilio-inc/cli 0.7.1 → 0.9.1
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/README.md +175 -14
- package/dist/client/blocks.d.ts +30 -0
- package/dist/client/blocks.d.ts.map +1 -0
- package/dist/client/blocks.js +125 -0
- package/dist/client/blocks.js.map +1 -0
- package/dist/client/maps.d.ts +8 -0
- package/dist/client/maps.d.ts.map +1 -1
- package/dist/client/maps.js +260 -16
- package/dist/client/maps.js.map +1 -1
- package/dist/client/rules-skipped.d.ts +22 -0
- package/dist/client/rules-skipped.d.ts.map +1 -0
- package/dist/client/rules-skipped.js +30 -0
- package/dist/client/rules-skipped.js.map +1 -0
- package/dist/client/wording.d.ts +2 -2
- package/dist/client/wording.d.ts.map +1 -1
- package/dist/client/wording.js +15 -0
- package/dist/client/wording.js.map +1 -1
- package/dist/cloud-commands.d.ts +5 -3
- package/dist/cloud-commands.d.ts.map +1 -1
- package/dist/cloud-commands.js +109 -28
- package/dist/cloud-commands.js.map +1 -1
- package/dist/cloud.d.ts +74 -7
- package/dist/cloud.d.ts.map +1 -1
- package/dist/cloud.js +205 -3
- package/dist/cloud.js.map +1 -1
- package/dist/commands.d.ts +10 -0
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +90 -15
- package/dist/commands.js.map +1 -1
- package/dist/credential.d.ts +12 -0
- package/dist/credential.d.ts.map +1 -1
- package/dist/credential.js +48 -0
- package/dist/credential.js.map +1 -1
- package/dist/flags.js +2 -2
- package/dist/flags.js.map +1 -1
- package/dist/guard-hint.d.ts +12 -0
- package/dist/guard-hint.d.ts.map +1 -0
- package/dist/guard-hint.js +38 -0
- package/dist/guard-hint.js.map +1 -0
- package/dist/hashed-bases.d.ts +12 -0
- package/dist/hashed-bases.d.ts.map +1 -0
- package/dist/hashed-bases.js +45 -0
- package/dist/hashed-bases.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/reservations.d.ts +145 -0
- package/dist/reservations.d.ts.map +1 -0
- package/dist/reservations.js +348 -0
- package/dist/reservations.js.map +1 -0
- package/dist/rules-open.d.ts +16 -0
- package/dist/rules-open.d.ts.map +1 -0
- package/dist/rules-open.js +87 -0
- package/dist/rules-open.js.map +1 -0
- package/dist/rules.d.ts +20 -2
- package/dist/rules.d.ts.map +1 -1
- package/dist/rules.js +86 -4
- package/dist/rules.js.map +1 -1
- package/dist/store.d.ts +3 -0
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +19 -1
- package/dist/store.js.map +1 -1
- package/dist/team-anonymize.d.ts +16 -1
- package/dist/team-anonymize.d.ts.map +1 -1
- package/dist/team-anonymize.js +39 -13
- package/dist/team-anonymize.js.map +1 -1
- package/dist/team-namespace.d.ts +59 -4
- package/dist/team-namespace.d.ts.map +1 -1
- package/dist/team-namespace.js +133 -11
- package/dist/team-namespace.js.map +1 -1
- package/package.json +8 -5
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// Opening the custom rules Cloud serves sealed (spec 065), for `veilio rules
|
|
2
|
+
// pull` and the MCP server. Apart from rules.ts because it reaches the cloud
|
|
3
|
+
// boundary's types and the team keys, and `scrub` - which reads rules.ts - must
|
|
4
|
+
// not (offline.test.ts).
|
|
5
|
+
import { openRuleFromVault, openTeamRule, parseVaultEnvelope, } from '@veilio-inc/engine';
|
|
6
|
+
import { homedir } from 'node:os';
|
|
7
|
+
import { importPersonalMapsKey, readPersonalMapsKey } from './client/personal-maps-key.js';
|
|
8
|
+
import { NO_RULES_SKIPPED } from './client/rules-skipped.js';
|
|
9
|
+
import { heldTeamKeys } from './team-namespace.js';
|
|
10
|
+
/**
|
|
11
|
+
* Open the rules Cloud served (spec 065) with the keys on this machine: the
|
|
12
|
+
* personal-maps key for personal rules, the team's unlocked keys (any held
|
|
13
|
+
* version) for each team's rules. Nothing here throws on a rule: one that
|
|
14
|
+
* cannot be opened or must not be applied is counted, and masking goes on.
|
|
15
|
+
*/
|
|
16
|
+
export async function openFetchedRules(fetched, credential, home = homedir()) {
|
|
17
|
+
const skipped = { ...NO_RULES_SKIPPED };
|
|
18
|
+
const count = (opened) => {
|
|
19
|
+
if (!opened.ok)
|
|
20
|
+
skipped[opened.reason === 'refused' ? 'refused' : 'unopenable']++;
|
|
21
|
+
};
|
|
22
|
+
// The scope is the list the row came in, never the row's own label: a
|
|
23
|
+
// team-sealed rule labelled personal is the team's (security audit).
|
|
24
|
+
const toRule = (row, opened, scope) => {
|
|
25
|
+
count(opened);
|
|
26
|
+
if (!opened.ok)
|
|
27
|
+
return null;
|
|
28
|
+
return {
|
|
29
|
+
...opened.rule,
|
|
30
|
+
id: row.id,
|
|
31
|
+
scope,
|
|
32
|
+
team_id: row.team_id,
|
|
33
|
+
sort_order: row.sort_order,
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
const personal = [];
|
|
37
|
+
const rows = fetched.rules ?? [];
|
|
38
|
+
const raw = rows.length ? readPersonalMapsKey(credential, home) : null;
|
|
39
|
+
if (rows.length && !raw)
|
|
40
|
+
skipped.vaultLocked += rows.length;
|
|
41
|
+
else if (raw) {
|
|
42
|
+
const pmk = await importPersonalMapsKey(raw);
|
|
43
|
+
for (const row of rows) {
|
|
44
|
+
const rule = toRule(row, await openPersonal(pmk, row), 'personal');
|
|
45
|
+
if (rule)
|
|
46
|
+
personal.push(rule);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const team = [];
|
|
50
|
+
const keysByTeam = new Map();
|
|
51
|
+
for (const row of fetched.teamRules ?? []) {
|
|
52
|
+
const teamId = row.team_id ?? '';
|
|
53
|
+
if (!keysByTeam.has(teamId))
|
|
54
|
+
keysByTeam.set(teamId, teamId ? await heldTeamKeys(credential, home, teamId) : []);
|
|
55
|
+
const keys = keysByTeam.get(teamId) ?? [];
|
|
56
|
+
if (keys.length === 0) {
|
|
57
|
+
skipped.teamLocked++;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const rule = toRule(row, await openTeam(keys, row), 'team');
|
|
61
|
+
if (rule)
|
|
62
|
+
team.push(rule);
|
|
63
|
+
}
|
|
64
|
+
return { personal, team, skipped };
|
|
65
|
+
}
|
|
66
|
+
const UNOPENABLE = { ok: false, reason: 'unopenable' };
|
|
67
|
+
async function openPersonal(pmk, row) {
|
|
68
|
+
try {
|
|
69
|
+
return await openRuleFromVault(pmk, parseVaultEnvelope(row.data), bindOf(row));
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return UNOPENABLE;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async function openTeam(keys, row) {
|
|
76
|
+
try {
|
|
77
|
+
return await openTeamRule(keys, JSON.parse(row.data), bindOf(row));
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return UNOPENABLE;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/** The row a body was sealed for: one moved to another row does not open. */
|
|
84
|
+
function bindOf(row) {
|
|
85
|
+
return { id: row.id, teamId: row.team_id };
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=rules-open.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules-open.js","sourceRoot":"","sources":["../src/rules-open.ts"],"names":[],"mappings":"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"}
|
package/dist/rules.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type CustomRule } from '@veilio-inc/engine';
|
|
2
|
+
import type { RulesSkipped } from './client/rules-skipped.js';
|
|
2
3
|
export declare const RULES_FILE = "rules.json";
|
|
3
4
|
export interface CachedRules {
|
|
4
5
|
/** Which account these belong to - a different sign-in does not inherit them. */
|
|
@@ -8,6 +9,9 @@ export interface CachedRules {
|
|
|
8
9
|
pulledAt: string;
|
|
9
10
|
/** Already merged into the order the engine applies them in. */
|
|
10
11
|
rules: CustomRule[];
|
|
12
|
+
/** Served but not applied here, by cause (spec 065). Absent in a cache
|
|
13
|
+
* written before it, which reads as all zeros. */
|
|
14
|
+
skipped?: RulesSkipped;
|
|
11
15
|
}
|
|
12
16
|
export declare function rulesPath(home?: string): string;
|
|
13
17
|
/**
|
|
@@ -21,11 +25,25 @@ export declare function rulesPath(home?: string): string;
|
|
|
21
25
|
* Must match `useMergedRules` in the Cloud frontend.
|
|
22
26
|
*/
|
|
23
27
|
export declare function mergeRules(personal: readonly CustomRule[], team: readonly CustomRule[]): CustomRule[];
|
|
24
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* The cached rules for this account, or null. Null for every kind of failure.
|
|
30
|
+
*
|
|
31
|
+
* Only the rules whose key is still held are returned: a rule opened while the
|
|
32
|
+
* vault or team key was unlocked must not outlive that key - a lock, an expiry,
|
|
33
|
+
* an unlock of another team. The rest are counted as vaultLocked/teamLocked.
|
|
34
|
+
*/
|
|
25
35
|
export declare function readRules(owner: {
|
|
26
36
|
instance: string;
|
|
27
37
|
account: string;
|
|
28
|
-
}, home?: string): CachedRules | null;
|
|
38
|
+
}, home?: string, now?: Date): CachedRules | null;
|
|
39
|
+
/**
|
|
40
|
+
* Remove one scope's rules from the cache when its key is locked, and count
|
|
41
|
+
* them as skipped, so the opened content does not stay readable on disk. Reads
|
|
42
|
+
* the file without the owner check: removing never needs to be ours. Returns
|
|
43
|
+
* how many were removed; a missing or damaged cache removes none. The file is
|
|
44
|
+
* rewritten 0600.
|
|
45
|
+
*/
|
|
46
|
+
export declare function purgeRules(scope: 'personal' | 'team', home?: string): number;
|
|
29
47
|
/** 0600: the patterns name what a team considers sensitive. */
|
|
30
48
|
export declare function writeRules(cached: CachedRules, home?: string): void;
|
|
31
49
|
/** Remove the cache. Missing is not an error; failing to delete is. */
|
package/dist/rules.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"AAiBA,OAAO,
|
|
1
|
+
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAyB,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAC3E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAI7D,eAAO,MAAM,UAAU,eAAe,CAAA;AAEtC,MAAM,WAAW,WAAW;IAC1B,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAA;IAChB,gEAAgE;IAChE,KAAK,EAAE,UAAU,EAAE,CAAA;IACnB;uDACmD;IACnD,OAAO,CAAC,EAAE,YAAY,CAAA;CACvB;AAED,wBAAgB,SAAS,CAAC,IAAI,GAAE,MAAkB,GAAG,MAAM,CAE1D;AAED;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CACxB,QAAQ,EAAE,SAAS,UAAU,EAAE,EAC/B,IAAI,EAAE,SAAS,UAAU,EAAE,GAC1B,UAAU,EAAE,CAUd;AAqDD;;;;;;GAMG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAC5C,IAAI,GAAE,MAAkB,EACxB,GAAG,GAAE,IAAiB,GACrB,WAAW,GAAG,IAAI,CAsBpB;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,EAAE,IAAI,GAAE,MAAkB,GAAG,MAAM,CAgBvF;AAED,+DAA+D;AAC/D,wBAAgB,UAAU,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,GAAE,MAAkB,GAAG,IAAI,CAK9E;AAED,uEAAuE;AACvE,wBAAgB,WAAW,CAAC,IAAI,GAAE,MAAkB,GAAG,OAAO,CAS7D;AAED,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,GAAE,IAAiB,GAAG,MAAM,CAQ5E"}
|
package/dist/rules.js
CHANGED
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
import { chmodSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
15
15
|
import { dirname, join } from 'node:path';
|
|
16
16
|
import { homedir } from 'node:os';
|
|
17
|
-
import { STORE_DIR } from '@veilio-inc/engine';
|
|
17
|
+
import { STORE_DIR, fromBase64 } from '@veilio-inc/engine';
|
|
18
|
+
import { readPersonalMapsKey } from './client/personal-maps-key.js';
|
|
19
|
+
import { readTeamUnlock } from './team-unlock.js';
|
|
18
20
|
export const RULES_FILE = 'rules.json';
|
|
19
21
|
export function rulesPath(home = homedir()) {
|
|
20
22
|
return join(home, STORE_DIR, RULES_FILE);
|
|
@@ -39,6 +41,16 @@ export function mergeRules(personal, team) {
|
|
|
39
41
|
...on(personal, 'replace'),
|
|
40
42
|
].map((r, i) => ({ ...r, sort_order: i }));
|
|
41
43
|
}
|
|
44
|
+
function readSkipped(value) {
|
|
45
|
+
const v = (typeof value === 'object' && value !== null ? value : {});
|
|
46
|
+
const n = (x) => (Number.isInteger(x) && x >= 0 ? x : 0);
|
|
47
|
+
return {
|
|
48
|
+
vaultLocked: n(v.vaultLocked),
|
|
49
|
+
teamLocked: n(v.teamLocked),
|
|
50
|
+
unopenable: n(v.unopenable),
|
|
51
|
+
refused: n(v.refused),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
42
54
|
function isRule(value) {
|
|
43
55
|
if (typeof value !== 'object' || value === null)
|
|
44
56
|
return false;
|
|
@@ -49,8 +61,42 @@ function isRule(value) {
|
|
|
49
61
|
return true;
|
|
50
62
|
return r.type === 'replace' && typeof r.placeholder === 'string';
|
|
51
63
|
}
|
|
52
|
-
/**
|
|
53
|
-
|
|
64
|
+
/**
|
|
65
|
+
* Which keys this machine still holds - THE definition of "held" for applying
|
|
66
|
+
* cached rules (spec 065 FR-006). The guard mirrors it in
|
|
67
|
+
* plugins/veilio-guard/lib/rules.ts; both suites run the same table
|
|
68
|
+
* (rules-lock-purge.test.ts, custom-rules.test.ts).
|
|
69
|
+
*
|
|
70
|
+
* Personal: `personal-maps-key.json` is v1, this instance and account,
|
|
71
|
+
* unexpired, and its key decodes to 32 bytes (readPersonalMapsKey).
|
|
72
|
+
* Team T: `team-keys.json` is v1, this instance and account, unexpired, its
|
|
73
|
+
* teamId is T, and at least one key decodes to 32 bytes - what heldTeamKeys
|
|
74
|
+
* keeps after importTeamKey drops a damaged one. Absent, damaged, expired or
|
|
75
|
+
* somebody else's: not held.
|
|
76
|
+
*/
|
|
77
|
+
function keysHeld(owner, home, now) {
|
|
78
|
+
const unlock = readTeamUnlock(owner, home, now);
|
|
79
|
+
const usable = (key) => {
|
|
80
|
+
try {
|
|
81
|
+
return fromBase64(key).byteLength === 32;
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
return {
|
|
88
|
+
personal: readPersonalMapsKey(owner, home, now) !== null,
|
|
89
|
+
team: unlock && unlock.keys.some((k) => usable(k.key)) ? unlock.teamId : null,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* The cached rules for this account, or null. Null for every kind of failure.
|
|
94
|
+
*
|
|
95
|
+
* Only the rules whose key is still held are returned: a rule opened while the
|
|
96
|
+
* vault or team key was unlocked must not outlive that key - a lock, an expiry,
|
|
97
|
+
* an unlock of another team. The rest are counted as vaultLocked/teamLocked.
|
|
98
|
+
*/
|
|
99
|
+
export function readRules(owner, home = homedir(), now = new Date()) {
|
|
54
100
|
let parsed;
|
|
55
101
|
try {
|
|
56
102
|
parsed = JSON.parse(readFileSync(rulesPath(home), 'utf8'));
|
|
@@ -66,7 +112,43 @@ export function readRules(owner, home = homedir()) {
|
|
|
66
112
|
if (typeof c.pulledAt !== 'string' || !Array.isArray(c.rules) || !c.rules.every(isRule)) {
|
|
67
113
|
return null;
|
|
68
114
|
}
|
|
69
|
-
|
|
115
|
+
const skipped = readSkipped(c.skipped);
|
|
116
|
+
const held = keysHeld(owner, home, now);
|
|
117
|
+
const rules = c.rules.filter((r) => {
|
|
118
|
+
// Anything not marked team is treated as personal: it needs a key either way.
|
|
119
|
+
const ok = r.scope === 'team' ? r.team_id !== null && r.team_id === held.team : held.personal;
|
|
120
|
+
if (!ok)
|
|
121
|
+
skipped[r.scope === 'team' ? 'teamLocked' : 'vaultLocked']++;
|
|
122
|
+
return ok;
|
|
123
|
+
});
|
|
124
|
+
return { ...parsed, rules, skipped };
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Remove one scope's rules from the cache when its key is locked, and count
|
|
128
|
+
* them as skipped, so the opened content does not stay readable on disk. Reads
|
|
129
|
+
* the file without the owner check: removing never needs to be ours. Returns
|
|
130
|
+
* how many were removed; a missing or damaged cache removes none. The file is
|
|
131
|
+
* rewritten 0600.
|
|
132
|
+
*/
|
|
133
|
+
export function purgeRules(scope, home = homedir()) {
|
|
134
|
+
let parsed;
|
|
135
|
+
try {
|
|
136
|
+
parsed = JSON.parse(readFileSync(rulesPath(home), 'utf8'));
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return 0;
|
|
140
|
+
}
|
|
141
|
+
if (typeof parsed !== 'object' || parsed === null || !Array.isArray(parsed.rules))
|
|
142
|
+
return 0;
|
|
143
|
+
const isScope = (r) => (r.scope === 'team') === (scope === 'team');
|
|
144
|
+
const removed = parsed.rules.filter(isScope).length;
|
|
145
|
+
if (removed === 0)
|
|
146
|
+
return 0;
|
|
147
|
+
const skipped = readSkipped(parsed.skipped);
|
|
148
|
+
skipped[scope === 'team' ? 'teamLocked' : 'vaultLocked'] += removed;
|
|
149
|
+
// Never removed outright: the count just added is something to report.
|
|
150
|
+
writeRules({ ...parsed, rules: parsed.rules.filter((r) => !isScope(r)), skipped }, home);
|
|
151
|
+
return removed;
|
|
70
152
|
}
|
|
71
153
|
/** 0600: the patterns name what a team considers sensitive. */
|
|
72
154
|
export function writeRules(cached, home = homedir()) {
|
package/dist/rules.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.js","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,EAAE;AACF,8EAA8E;AAC9E,2EAA2E;AAC3E,4EAA4E;AAC5E,2EAA2E;AAC3E,wBAAwB;AACxB,EAAE;AACF,iFAAiF;AACjF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,2BAA2B;AAE3B,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC7F,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,SAAS,EAAmB,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"rules.js","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,EAAE;AACF,8EAA8E;AAC9E,2EAA2E;AAC3E,4EAA4E;AAC5E,2EAA2E;AAC3E,wBAAwB;AACxB,EAAE;AACF,iFAAiF;AACjF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,2BAA2B;AAE3B,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC7F,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAmB,MAAM,oBAAoB,CAAA;AAE3E,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAA;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAEjD,MAAM,CAAC,MAAM,UAAU,GAAG,YAAY,CAAA;AAetC,MAAM,UAAU,SAAS,CAAC,OAAe,OAAO,EAAE;IAChD,OAAO,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,CAAC,CAAA;AAC1C,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,UAAU,CACxB,QAA+B,EAC/B,IAA2B;IAE3B,MAAM,OAAO,GAAG,CAAC,CAAa,EAAE,CAAa,EAAU,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAA;IACrF,MAAM,EAAE,GAAG,CAAC,IAA2B,EAAE,IAAwB,EAAgB,EAAE,CACjF,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAChE,OAAO;QACL,GAAG,EAAE,CAAC,IAAI,EAAE,WAAW,CAAC;QACxB,GAAG,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC;QAC5B,GAAG,EAAE,CAAC,IAAI,EAAE,SAAS,CAAC;QACtB,GAAG,EAAE,CAAC,QAAQ,EAAE,SAAS,CAAC;KAC3B,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;AAC5C,CAAC;AAED,SAAS,WAAW,CAAC,KAAc;IACjC,MAAM,CAAC,GAAG,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAA4B,CAAA;IAC/F,MAAM,CAAC,GAAG,CAAC,CAAU,EAAU,EAAE,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAK,CAAY,IAAI,CAAC,CAAC,CAAC,CAAE,CAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACjG,OAAO;QACL,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;QAC7B,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;QAC3B,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;QAC3B,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;KACtB,CAAA;AACH,CAAC;AAED,SAAS,MAAM,CAAC,KAAc;IAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAA;IAC7D,MAAM,CAAC,GAAG,KAAgC,CAAA;IAC1C,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,UAAU,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAA;IACnF,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW;QAAE,OAAO,IAAI,CAAA;IACvC,OAAO,CAAC,CAAC,IAAI,KAAK,SAAS,IAAI,OAAO,CAAC,CAAC,WAAW,KAAK,QAAQ,CAAA;AAClE,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAS,QAAQ,CACf,KAA4C,EAC5C,IAAY,EACZ,GAAS;IAET,MAAM,MAAM,GAAG,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,CAAA;IAC/C,MAAM,MAAM,GAAG,CAAC,GAAW,EAAW,EAAE;QACtC,IAAI,CAAC;YACH,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,UAAU,KAAK,EAAE,CAAA;QAC1C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAA;QACd,CAAC;IACH,CAAC,CAAA;IACD,OAAO;QACL,QAAQ,EAAE,mBAAmB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,KAAK,IAAI;QACxD,IAAI,EAAE,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;KAC9E,CAAA;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CACvB,KAA4C,EAC5C,OAAe,OAAO,EAAE,EACxB,MAAY,IAAI,IAAI,EAAE;IAEtB,IAAI,MAAe,CAAA;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,CAAA;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;IACD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAA;IAC9D,MAAM,CAAC,GAAG,MAAiC,CAAA;IAC3C,IAAI,CAAC,CAAC,QAAQ,KAAK,KAAK,CAAC,QAAQ,IAAI,CAAC,CAAC,OAAO,KAAK,KAAK,CAAC,OAAO;QAAE,OAAO,IAAI,CAAA;IAC7E,IAAI,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;QACxF,OAAO,IAAI,CAAA;IACb,CAAC;IACD,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAA;IACtC,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,CAAA;IACvC,MAAM,KAAK,GAAI,CAAC,CAAC,KAAsB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QACnD,8EAA8E;QAC9E,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,KAAK,IAAI,IAAI,CAAC,CAAC,OAAO,KAAK,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAA;QAC7F,IAAI,CAAC,EAAE;YAAE,OAAO,CAAC,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,aAAa,CAAC,EAAE,CAAA;QACrE,OAAO,EAAE,CAAA;IACX,CAAC,CAAC,CAAA;IACF,OAAO,EAAE,GAAI,MAAsB,EAAE,KAAK,EAAE,OAAO,EAAE,CAAA;AACvD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,KAA0B,EAAE,OAAe,OAAO,EAAE;IAC7E,IAAI,MAAmB,CAAA;IACvB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAgB,CAAA;IAC3E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAA;IACV,CAAC;IACD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;QAAE,OAAO,CAAC,CAAA;IAC3F,MAAM,OAAO,GAAG,CAAC,CAAa,EAAW,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,CAAC,KAAK,KAAK,MAAM,CAAC,CAAA;IACvF,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAA;IACnD,IAAI,OAAO,KAAK,CAAC;QAAE,OAAO,CAAC,CAAA;IAC3B,MAAM,OAAO,GAAG,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAC3C,OAAO,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,OAAO,CAAA;IACnE,uEAAuE;IACvE,UAAU,CAAC,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,IAAI,CAAC,CAAA;IACxF,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,UAAU,CAAC,MAAmB,EAAE,OAAe,OAAO,EAAE;IACtE,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;IAC5B,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC7C,aAAa,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;IAC5E,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;AACxB,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,WAAW,CAAC,OAAe,OAAO,EAAE;IAClD,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;IAC5B,IAAI,CAAC;QACH,QAAQ,CAAC,IAAI,CAAC,CAAA;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;IACD,MAAM,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IAC9C,OAAO,IAAI,CAAA;AACb,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,WAAW,CAAC,QAAgB,EAAE,MAAY,IAAI,IAAI,EAAE;IAClE,MAAM,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,CAAA;IACvD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QAAE,OAAO,oBAAoB,CAAA;IACrD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC,CAAA;IACpD,IAAI,OAAO,GAAG,EAAE;QAAE,OAAO,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,OAAO,cAAc,CAAA;IAC7E,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,CAAA;IACtC,IAAI,KAAK,GAAG,EAAE;QAAE,OAAO,GAAG,KAAK,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,MAAM,CAAA;IACnE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,WAAW,CAAA;AAC7C,CAAC"}
|
package/dist/store.d.ts
CHANGED
|
@@ -62,5 +62,8 @@ export declare function saveMap(path: string, map: SymbolMap, options?: {
|
|
|
62
62
|
force?: boolean;
|
|
63
63
|
remote?: StoredMap['remote'];
|
|
64
64
|
}): void;
|
|
65
|
+
/** Throws when any of `paths` is a link: the store's files are written only
|
|
66
|
+
* where they appear to be (security audit 2026-11-01). */
|
|
67
|
+
export declare function refuseLinks(what: string, ...paths: string[]): void;
|
|
65
68
|
export declare function clearMap(path: string): boolean;
|
|
66
69
|
//# sourceMappingURL=store.d.ts.map
|
package/dist/store.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAE9D,OAAO,EAAE,SAAS,EAAE,CAAA;AACpB,eAAO,MAAM,UAAU,aAAa,CAAA;AAEpC;;oCAEoC;AACpC,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQpD;AAED,4EAA4E;AAC5E,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAG3E;AAED,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,SAAS,CAAA;IACd;qCACiC;IACjC,OAAO,EAAE,CAAC,CAAA;IACV;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE;QACP,EAAE,EAAE,MAAM,CAAA;QACV,oDAAoD;QACpD,SAAS,EAAE,MAAM,CAAA;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;KAClB,CAAA;CACF;AAOD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,GAAG,SAAS,CAYxE;AAED;;qEAEqE;AACrE,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAgB/C;AAED,qBAAa,iBAAkB,SAAQ,KAAK;CAAG;AAE/C;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,OAAO,CACrB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,SAAS,EACd,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAA;CAAO,GAC9D,IAAI,CAoCN;AAED;2DAC2D;AAC3D,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAElE;AAUD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAI9C"}
|
package/dist/store.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// The map holds real identifier names, so it is written 0600 and the store
|
|
9
9
|
// directory carries a .gitignore. Committing it would undo the anonymization
|
|
10
10
|
// for anyone reading the repo.
|
|
11
|
-
import { chmodSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
11
|
+
import { chmodSync, existsSync, lstatSync, mkdirSync, readFileSync, rmSync, writeFileSync, } from 'node:fs';
|
|
12
12
|
import { dirname, join, resolve } from 'node:path';
|
|
13
13
|
import { STORE_DIR } from '@veilio-inc/engine';
|
|
14
14
|
export { STORE_DIR };
|
|
@@ -113,6 +113,9 @@ export function saveMap(path, map, options = {}) {
|
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
const dir = dirname(path);
|
|
116
|
+
// Security audit 2026-11-01: a store that is a link (one a repository
|
|
117
|
+
// committed) would put the real names in a file outside the project.
|
|
118
|
+
refuseLinks('the map', dir, path);
|
|
116
119
|
mkdirSync(dir, { recursive: true });
|
|
117
120
|
// A store directory inside a repo must never be committed — it holds the real
|
|
118
121
|
// names the anonymization exists to hide.
|
|
@@ -129,6 +132,21 @@ export function saveMap(path, map, options = {}) {
|
|
|
129
132
|
// rewrite too so a pre-existing world-readable map gets locked down.
|
|
130
133
|
chmodSync(path, 0o600);
|
|
131
134
|
}
|
|
135
|
+
/** Throws when any of `paths` is a link: the store's files are written only
|
|
136
|
+
* where they appear to be (security audit 2026-11-01). */
|
|
137
|
+
export function refuseLinks(what, ...paths) {
|
|
138
|
+
for (const p of paths)
|
|
139
|
+
if (isLink(p))
|
|
140
|
+
throw new Error(`refusing to write ${what}: ${p} is a link`);
|
|
141
|
+
}
|
|
142
|
+
function isLink(path) {
|
|
143
|
+
try {
|
|
144
|
+
return lstatSync(path).isSymbolicLink();
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
return false; // not there yet
|
|
148
|
+
}
|
|
149
|
+
}
|
|
132
150
|
export function clearMap(path) {
|
|
133
151
|
if (!existsSync(path))
|
|
134
152
|
return false;
|
package/dist/store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,0BAA0B;AAC1B,EAAE;AACF,gFAAgF;AAChF,gFAAgF;AAChF,4EAA4E;AAC5E,kEAAkE;AAClE,EAAE;AACF,2EAA2E;AAC3E,6EAA6E;AAC7E,+BAA+B;AAE/B,OAAO,
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
|
package/dist/team-anonymize.d.ts
CHANGED
|
@@ -50,7 +50,22 @@ export declare function anonymizeOverTeam(source: string, local: Record<string,
|
|
|
50
50
|
highest: Record<string, number>;
|
|
51
51
|
/** Placeholders the team's maps give different names: never emitted (spec 028). */
|
|
52
52
|
conflicts?: Record<string, number>;
|
|
53
|
-
}, options: Omit<AnonymizeOptions, 'existingMap'
|
|
53
|
+
}, options: Omit<AnonymizeOptions, 'existingMap' | 'team'>,
|
|
54
|
+
/**
|
|
55
|
+
* This checkout's blocks and local tag (spec 066 R3, from `teamNumbering`):
|
|
56
|
+
* new names go inside a usable block, else into the local family - never
|
|
57
|
+
* above the team's highest, which is where the next teammate's block starts.
|
|
58
|
+
* Absent: no team numbering applies, and new names go above the floor.
|
|
59
|
+
*/
|
|
60
|
+
numbering?: {
|
|
61
|
+
blocks: Record<string, {
|
|
62
|
+
start: number;
|
|
63
|
+
end: number;
|
|
64
|
+
}>;
|
|
65
|
+
tag: string;
|
|
66
|
+
/** Placeholders a publish retired (aliases.json): never minted again. */
|
|
67
|
+
retired?: readonly string[];
|
|
68
|
+
}): {
|
|
54
69
|
result: ReturnType<typeof anonymize>;
|
|
55
70
|
toPersist: Record<string, string>;
|
|
56
71
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"team-anonymize.d.ts","sourceRoot":"","sources":["../src/team-anonymize.ts"],"names":[],"mappings":"AAMA,OAAO,
|
|
1
|
+
{"version":3,"file":"team-anonymize.d.ts","sourceRoot":"","sources":["../src/team-anonymize.ts"],"names":[],"mappings":"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"}
|
package/dist/team-anonymize.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// 2026-09-30 walk). It lived in the MCP server, so the CLI numbered from the
|
|
4
4
|
// project's own map only and gave a member's terminal placeholders that meant
|
|
5
5
|
// something else in the team.
|
|
6
|
-
import { anonymize } from '@veilio-inc/engine';
|
|
6
|
+
import { anonymize, isSaneBlock, MAX_PLACEHOLDER_NUMBER, } from '@veilio-inc/engine';
|
|
7
7
|
/**
|
|
8
8
|
* The map handed to the engine to anonymize: this project's store and the
|
|
9
9
|
* team's namespace, reconciled so that nothing emitted can mean something else
|
|
@@ -68,8 +68,8 @@ export function floorsWith(highest, local) {
|
|
|
68
68
|
const floors = { ...highest };
|
|
69
69
|
for (const placeholder of Object.keys(local)) {
|
|
70
70
|
const m = NUMBERED.exec(placeholder);
|
|
71
|
-
if (m &&
|
|
72
|
-
floors[m[1]] =
|
|
71
|
+
if (m && counted(m[2]) > (floors[m[1]] ?? 0))
|
|
72
|
+
floors[m[1]] = counted(m[2]);
|
|
73
73
|
}
|
|
74
74
|
return floors;
|
|
75
75
|
}
|
|
@@ -77,12 +77,16 @@ export function anonymizeAbove(source, options, floors) {
|
|
|
77
77
|
const inMap = {};
|
|
78
78
|
for (const p of Object.keys(options.existingMap)) {
|
|
79
79
|
const m = NUMBERED.exec(p);
|
|
80
|
-
if (m &&
|
|
81
|
-
inMap[m[1]] =
|
|
80
|
+
if (m && counted(m[2]) > (inMap[m[1]] ?? 0))
|
|
81
|
+
inMap[m[1]] = counted(m[2]);
|
|
82
82
|
}
|
|
83
83
|
const seeded = { ...options.existingMap };
|
|
84
84
|
for (const [base, floor] of Object.entries(floors)) {
|
|
85
|
-
|
|
85
|
+
// Never above 1e8 (the engine ignores it there) and never over an entry
|
|
86
|
+
// the map holds: the marker is dropped from the result, and the entry with it.
|
|
87
|
+
if (floor > (inMap[base] ?? 0) &&
|
|
88
|
+
floor <= MAX_PLACEHOLDER_NUMBER &&
|
|
89
|
+
!(`${base}${floor}` in options.existingMap))
|
|
86
90
|
seeded[`${base}${floor}`] = `${FLOOR_MARKER}${base}`;
|
|
87
91
|
}
|
|
88
92
|
const result = anonymize(source, { ...options, existingMap: seeded });
|
|
@@ -96,13 +100,30 @@ export function anonymizeAbove(source, options, floors) {
|
|
|
96
100
|
* team's namespace (spec 005 US4: those would outlive the entitlement that
|
|
97
101
|
* fetched them).
|
|
98
102
|
*/
|
|
99
|
-
export function anonymizeOverTeam(source, local, team, options
|
|
103
|
+
export function anonymizeOverTeam(source, local, team, options,
|
|
104
|
+
/**
|
|
105
|
+
* This checkout's blocks and local tag (spec 066 R3, from `teamNumbering`):
|
|
106
|
+
* new names go inside a usable block, else into the local family - never
|
|
107
|
+
* above the team's highest, which is where the next teammate's block starts.
|
|
108
|
+
* Absent: no team numbering applies, and new names go above the floor.
|
|
109
|
+
*/
|
|
110
|
+
numbering) {
|
|
100
111
|
// A disputed placeholder keeps its first meaning in the engine's namespace
|
|
101
112
|
// (for numbering); it is never emitted - the name gets a fresh number above
|
|
102
113
|
// it (code review, spec 030: scrub emitted it, the MCP never did).
|
|
103
114
|
const settled = Object.fromEntries(Object.entries(team.namespace).filter(([p]) => !(p in (team.conflicts ?? {}))));
|
|
104
115
|
const existingMap = mergeNamespace(local, settled);
|
|
105
|
-
const result =
|
|
116
|
+
const result = numbering
|
|
117
|
+
? anonymize(source, {
|
|
118
|
+
...options,
|
|
119
|
+
existingMap,
|
|
120
|
+
team: {
|
|
121
|
+
blocks: numbering.blocks,
|
|
122
|
+
tag: numbering.tag,
|
|
123
|
+
...(numbering.retired?.length ? { retired: numbering.retired } : {}),
|
|
124
|
+
},
|
|
125
|
+
})
|
|
126
|
+
: anonymizeAbove(source, { ...options, existingMap }, floorsWith(team.highest, local));
|
|
106
127
|
return { result, toPersist: persisted(local, result, settled) };
|
|
107
128
|
}
|
|
108
129
|
// ─── reserved numbering ──────────────────────────────────────────────────────
|
|
@@ -122,13 +143,18 @@ export function anonymizeOverTeam(source, local, team, options) {
|
|
|
122
143
|
// publishes a shared map (FR-009) and so must never reach the network to
|
|
123
144
|
// reserve. An agent that reserved numbers it then discarded would consume the
|
|
124
145
|
// team's allocation on every tool call.
|
|
146
|
+
/** A placeholder's number as a floor: one above 1e8 (planted) counts as none. */
|
|
147
|
+
function counted(digits) {
|
|
148
|
+
const n = Number(digits);
|
|
149
|
+
return n <= MAX_PLACEHOLDER_NUMBER ? n : 0;
|
|
150
|
+
}
|
|
125
151
|
/** Highest number per base in a map. */
|
|
126
152
|
export function highestPerBase(map) {
|
|
127
153
|
const out = {};
|
|
128
154
|
for (const placeholder of Object.keys(map)) {
|
|
129
155
|
const m = NUMBERED.exec(placeholder);
|
|
130
|
-
if (m &&
|
|
131
|
-
out[m[1]] =
|
|
156
|
+
if (m && counted(m[2]) > (out[m[1]] ?? 0))
|
|
157
|
+
out[m[1]] = counted(m[2]);
|
|
132
158
|
}
|
|
133
159
|
return out;
|
|
134
160
|
}
|
|
@@ -145,8 +171,8 @@ const TOKEN = /(?<![A-Za-z0-9_$])(__[A-Z][A-Z0-9_]*__)(\d+)(?![A-Za-z0-9_$])/g;
|
|
|
145
171
|
export function highestInText(text) {
|
|
146
172
|
const out = {};
|
|
147
173
|
for (const m of text.matchAll(TOKEN)) {
|
|
148
|
-
if (
|
|
149
|
-
out[m[1]] =
|
|
174
|
+
if (counted(m[2]) > (out[m[1]] ?? 0))
|
|
175
|
+
out[m[1]] = counted(m[2]);
|
|
150
176
|
}
|
|
151
177
|
return out;
|
|
152
178
|
}
|
|
@@ -225,7 +251,7 @@ export async function reservedAnonymizeOverTeam(source, local, team, options, re
|
|
|
225
251
|
const floors = {};
|
|
226
252
|
for (const { base } of requests) {
|
|
227
253
|
const range = byBase.get(base);
|
|
228
|
-
if (!range)
|
|
254
|
+
if (!range || !isSaneBlock(range))
|
|
229
255
|
throw new ReservationMismatch(`${base}*`);
|
|
230
256
|
floors[base] = range.start - 1;
|
|
231
257
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"team-anonymize.js","sourceRoot":"","sources":["../src/team-anonymize.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,+EAA+E;AAC/E,6EAA6E;AAC7E,8EAA8E;AAC9E,8BAA8B;AAE9B,OAAO,
|
|
1
|
+
{"version":3,"file":"team-anonymize.js","sourceRoot":"","sources":["../src/team-anonymize.ts"],"names":[],"mappings":"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"}
|