@intutic/sync-daemon 2.2.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/agentReporter.d.ts +23 -11
- package/dist/agentReporter.d.ts.map +1 -1
- package/dist/agentReporter.js +20 -13
- package/dist/agentReporter.js.map +1 -1
- package/dist/configReader.d.ts +1 -3
- package/dist/configReader.d.ts.map +1 -1
- package/dist/configReader.js +0 -2
- package/dist/configReader.js.map +1 -1
- package/dist/configWriter.d.ts +11 -12
- package/dist/configWriter.d.ts.map +1 -1
- package/dist/configWriter.js +35 -58
- package/dist/configWriter.js.map +1 -1
- package/dist/disconnect/harnesses.d.ts +0 -2
- package/dist/disconnect/harnesses.d.ts.map +1 -1
- package/dist/disconnect/harnesses.js +157 -80
- package/dist/disconnect/harnesses.js.map +1 -1
- package/dist/disconnect/index.d.ts.map +1 -1
- package/dist/disconnect/index.js +11 -1
- package/dist/disconnect/index.js.map +1 -1
- package/dist/disconnect/mcp.d.ts +21 -0
- package/dist/disconnect/mcp.d.ts.map +1 -1
- package/dist/disconnect/mcp.js +71 -0
- package/dist/disconnect/mcp.js.map +1 -1
- package/dist/disconnect/recognise.d.ts +2 -2
- package/dist/disconnect/recognise.d.ts.map +1 -1
- package/dist/disconnect/recognise.js +15 -5
- package/dist/disconnect/recognise.js.map +1 -1
- package/dist/harness/aiderConfigMerger.d.ts +28 -8
- package/dist/harness/aiderConfigMerger.d.ts.map +1 -1
- package/dist/harness/aiderConfigMerger.js +59 -11
- package/dist/harness/aiderConfigMerger.js.map +1 -1
- package/dist/harness/antigravityCliHooks.d.ts +61 -0
- package/dist/harness/antigravityCliHooks.d.ts.map +1 -0
- package/dist/harness/antigravityCliHooks.js +207 -0
- package/dist/harness/antigravityCliHooks.js.map +1 -0
- package/dist/harness/antigravityHooks.d.ts +12 -2
- package/dist/harness/antigravityHooks.d.ts.map +1 -1
- package/dist/harness/antigravityHooks.js +36 -16
- package/dist/harness/antigravityHooks.js.map +1 -1
- package/dist/harness/antigravityProducts.d.ts +40 -0
- package/dist/harness/antigravityProducts.d.ts.map +1 -0
- package/dist/harness/antigravityProducts.js +109 -0
- package/dist/harness/antigravityProducts.js.map +1 -0
- package/dist/harness/claudeAgentsMd.d.ts +29 -0
- package/dist/harness/claudeAgentsMd.d.ts.map +1 -0
- package/dist/harness/claudeAgentsMd.js +80 -0
- package/dist/harness/claudeAgentsMd.js.map +1 -0
- package/dist/harness/claudeCodeHooks.d.ts +6 -5
- package/dist/harness/claudeCodeHooks.d.ts.map +1 -1
- package/dist/harness/claudeCodeHooks.js +98 -24
- package/dist/harness/claudeCodeHooks.js.map +1 -1
- package/dist/harness/clineHooks.d.ts +0 -1
- package/dist/harness/clineHooks.d.ts.map +1 -1
- package/dist/harness/clineHooks.js +10 -4
- package/dist/harness/clineHooks.js.map +1 -1
- package/dist/harness/codexHooks.d.ts +2 -0
- package/dist/harness/codexHooks.d.ts.map +1 -1
- package/dist/harness/codexHooks.js +12 -4
- package/dist/harness/codexHooks.js.map +1 -1
- package/dist/harness/cursorHooks.d.ts +5 -2
- package/dist/harness/cursorHooks.d.ts.map +1 -1
- package/dist/harness/cursorHooks.js +9 -3
- package/dist/harness/cursorHooks.js.map +1 -1
- package/dist/harness/dshHooks.d.ts +5 -5
- package/dist/harness/dshHooks.d.ts.map +1 -1
- package/dist/harness/dshHooks.js +5 -5
- package/dist/harness/gateArtifacts.d.ts +35 -0
- package/dist/harness/gateArtifacts.d.ts.map +1 -0
- package/dist/harness/gateArtifacts.js +88 -0
- package/dist/harness/gateArtifacts.js.map +1 -0
- package/dist/harness/gateBody.d.ts +186 -69
- package/dist/harness/gateBody.d.ts.map +1 -1
- package/dist/harness/gateBody.js +820 -182
- package/dist/harness/gateBody.js.map +1 -1
- package/dist/harness/gateSightings.d.ts +47 -0
- package/dist/harness/gateSightings.d.ts.map +1 -0
- package/dist/harness/gateSightings.js +159 -0
- package/dist/harness/gateSightings.js.map +1 -0
- package/dist/harness/githubCopilotHooks.d.ts.map +1 -1
- package/dist/harness/githubCopilotHooks.js +7 -1
- package/dist/harness/githubCopilotHooks.js.map +1 -1
- package/dist/harness/gooseHardener.d.ts +0 -1
- package/dist/harness/gooseHardener.d.ts.map +1 -1
- package/dist/harness/gooseHardener.js +1 -1
- package/dist/harness/gooseHardener.js.map +1 -1
- package/dist/harness/gooseHooks.d.ts +14 -1
- package/dist/harness/gooseHooks.d.ts.map +1 -1
- package/dist/harness/gooseHooks.js +55 -29
- package/dist/harness/gooseHooks.js.map +1 -1
- package/dist/harness/grokHooks.d.ts +2 -2
- package/dist/harness/grokHooks.d.ts.map +1 -1
- package/dist/harness/grokHooks.js +11 -6
- package/dist/harness/grokHooks.js.map +1 -1
- package/dist/harness/hermesHooks.d.ts +18 -8
- package/dist/harness/hermesHooks.d.ts.map +1 -1
- package/dist/harness/hermesHooks.js +48 -17
- package/dist/harness/hermesHooks.js.map +1 -1
- package/dist/harness/mcpAutoWrite.d.ts +24 -9
- package/dist/harness/mcpAutoWrite.d.ts.map +1 -1
- package/dist/harness/mcpAutoWrite.js +218 -25
- package/dist/harness/mcpAutoWrite.js.map +1 -1
- package/dist/harness/museHooks.d.ts +3 -3
- package/dist/harness/museHooks.d.ts.map +1 -1
- package/dist/harness/museHooks.js +9 -5
- package/dist/harness/museHooks.js.map +1 -1
- package/dist/harness/n8nHooks.d.ts +0 -1
- package/dist/harness/n8nHooks.d.ts.map +1 -1
- package/dist/harness/n8nHooks.js +4 -1
- package/dist/harness/n8nHooks.js.map +1 -1
- package/dist/harness/openCodeHooks.d.ts +2 -2
- package/dist/harness/openCodeHooks.d.ts.map +1 -1
- package/dist/harness/openCodeHooks.js +7 -3
- package/dist/harness/openCodeHooks.js.map +1 -1
- package/dist/harness/openWebuiHooks.d.ts +0 -1
- package/dist/harness/openWebuiHooks.d.ts.map +1 -1
- package/dist/harness/openWebuiHooks.js +5 -1
- package/dist/harness/openWebuiHooks.js.map +1 -1
- package/dist/harness/openclawHooks.d.ts +70 -18
- package/dist/harness/openclawHooks.d.ts.map +1 -1
- package/dist/harness/openclawHooks.js +213 -161
- package/dist/harness/openclawHooks.js.map +1 -1
- package/dist/harness/openhandsHooks.d.ts +24 -10
- package/dist/harness/openhandsHooks.d.ts.map +1 -1
- package/dist/harness/openhandsHooks.js +49 -48
- package/dist/harness/openhandsHooks.js.map +1 -1
- package/dist/harness/piHooks.d.ts +52 -17
- package/dist/harness/piHooks.d.ts.map +1 -1
- package/dist/harness/piHooks.js +177 -166
- package/dist/harness/piHooks.js.map +1 -1
- package/dist/harness/protectedPaths.d.ts +107 -25
- package/dist/harness/protectedPaths.d.ts.map +1 -1
- package/dist/harness/protectedPaths.js +342 -48
- package/dist/harness/protectedPaths.js.map +1 -1
- package/dist/harness/rulesSection.d.ts +62 -0
- package/dist/harness/rulesSection.d.ts.map +1 -0
- package/dist/harness/rulesSection.js +145 -0
- package/dist/harness/rulesSection.js.map +1 -0
- package/dist/harness/windsurfHooks.d.ts +0 -1
- package/dist/harness/windsurfHooks.d.ts.map +1 -1
- package/dist/harness/windsurfHooks.js +4 -1
- package/dist/harness/windsurfHooks.js.map +1 -1
- package/dist/index.d.ts +12 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -9
- package/dist/index.js.map +1 -1
- package/dist/inventory.d.ts +53 -0
- package/dist/inventory.d.ts.map +1 -0
- package/dist/inventory.js +133 -0
- package/dist/inventory.js.map +1 -0
- package/dist/lib/complianceProbes.d.ts +2 -1
- package/dist/lib/complianceProbes.d.ts.map +1 -1
- package/dist/lib/complianceProbes.js +1 -1
- package/dist/lib/complianceProbes.js.map +1 -1
- package/dist/lib/decisionsDigest.d.ts +34 -16
- package/dist/lib/decisionsDigest.d.ts.map +1 -1
- package/dist/lib/decisionsDigest.js +105 -46
- package/dist/lib/decisionsDigest.js.map +1 -1
- package/dist/lib/egressPolicy.d.ts +2 -2
- package/dist/lib/egressPolicy.js +2 -2
- package/dist/lib/mcpRegistryPy.d.ts +11 -0
- package/dist/lib/mcpRegistryPy.d.ts.map +1 -0
- package/dist/lib/mcpRegistryPy.js +173 -0
- package/dist/lib/mcpRegistryPy.js.map +1 -0
- package/dist/lib/phrasesPy.d.ts +11 -0
- package/dist/lib/phrasesPy.d.ts.map +1 -0
- package/dist/lib/phrasesPy.js +351 -0
- package/dist/lib/phrasesPy.js.map +1 -0
- package/dist/lib/policySnapshot.d.ts +46 -10
- package/dist/lib/policySnapshot.d.ts.map +1 -1
- package/dist/lib/policySnapshot.js +136 -47
- package/dist/lib/policySnapshot.js.map +1 -1
- package/dist/lib/processPoller.d.ts.map +1 -1
- package/dist/lib/processPoller.js +9 -2
- package/dist/lib/processPoller.js.map +1 -1
- package/dist/lib/regexLinearity.d.ts +43 -0
- package/dist/lib/regexLinearity.d.ts.map +1 -0
- package/dist/lib/regexLinearity.js +275 -0
- package/dist/lib/regexLinearity.js.map +1 -0
- package/dist/lib/runtimeEnv.d.ts +1 -3
- package/dist/lib/runtimeEnv.d.ts.map +1 -1
- package/dist/lib/runtimeEnv.js +0 -2
- package/dist/lib/runtimeEnv.js.map +1 -1
- package/dist/lib/sequencePy.d.ts +10 -0
- package/dist/lib/sequencePy.d.ts.map +1 -0
- package/dist/lib/sequencePy.js +102 -0
- package/dist/lib/sequencePy.js.map +1 -0
- package/dist/sessionReporter.d.ts +17 -11
- package/dist/sessionReporter.d.ts.map +1 -1
- package/dist/sessionReporter.js +36 -23
- package/dist/sessionReporter.js.map +1 -1
- package/dist/skillWriter.d.ts +23 -5
- package/dist/skillWriter.d.ts.map +1 -1
- package/dist/skillWriter.js +159 -16
- package/dist/skillWriter.js.map +1 -1
- package/dist/syncCycle.d.ts.map +1 -1
- package/dist/syncCycle.js +21 -9
- package/dist/syncCycle.js.map +1 -1
- package/dist/trajectoryMonitor.d.ts +1 -3
- package/dist/trajectoryMonitor.d.ts.map +1 -1
- package/dist/trajectoryMonitor.js +1 -4
- package/dist/trajectoryMonitor.js.map +1 -1
- package/dist/watcher/driftWatcher.d.ts +0 -1
- package/dist/watcher/driftWatcher.d.ts.map +1 -1
- package/dist/watcher/driftWatcher.js +1 -2
- package/dist/watcher/driftWatcher.js.map +1 -1
- package/dist/watcher/settingsGuard.d.ts +33 -7
- package/dist/watcher/settingsGuard.d.ts.map +1 -1
- package/dist/watcher/settingsGuard.js +373 -61
- package/dist/watcher/settingsGuard.js.map +1 -1
- package/dist/watcher/vscodeHookSettings.d.ts +30 -0
- package/dist/watcher/vscodeHookSettings.d.ts.map +1 -0
- package/dist/watcher/vscodeHookSettings.js +170 -0
- package/dist/watcher/vscodeHookSettings.js.map +1 -0
- package/dist/wsClient.d.ts +0 -1
- package/dist/wsClient.d.ts.map +1 -1
- package/dist/wsClient.js +0 -1
- package/dist/wsClient.js.map +1 -1
- package/package.json +5 -5
- package/dist/harness/claudeDesktopHooks.d.ts +0 -33
- package/dist/harness/claudeDesktopHooks.d.ts.map +0 -1
- package/dist/harness/claudeDesktopHooks.js +0 -256
- package/dist/harness/claudeDesktopHooks.js.map +0 -1
- package/dist/harness/continueHooks.d.ts +0 -63
- package/dist/harness/continueHooks.d.ts.map +0 -1
- package/dist/harness/continueHooks.js +0 -250
- package/dist/harness/continueHooks.js.map +0 -1
- package/dist/harness/gateKind.d.ts +0 -164
- package/dist/harness/gateKind.d.ts.map +0 -1
- package/dist/harness/gateKind.js +0 -144
- package/dist/harness/gateKind.js.map +0 -1
- package/dist/harness/rooCodeHooks.d.ts +0 -31
- package/dist/harness/rooCodeHooks.d.ts.map +0 -1
- package/dist/harness/rooCodeHooks.js +0 -281
- package/dist/harness/rooCodeHooks.js.map +0 -1
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A static check for the regex constructs that make a backtracking engine
|
|
3
|
+
* super-linear, run on every pattern the gates evaluate against a command or
|
|
4
|
+
* a tool's arguments.
|
|
5
|
+
*
|
|
6
|
+
* The JavaScript gates run rule sources as `RegExp`s and the Python ones as
|
|
7
|
+
* `re` patterns; both backtrack. A rule like ` git .*(…)` was correct and took
|
|
8
|
+
* 9.5 s on 200 KB of crafted command, long enough for a harness that treats a
|
|
9
|
+
* hook timeout as "allow" to run the call. The constructs below are the ones
|
|
10
|
+
* that cost time growing faster than the text:
|
|
11
|
+
*
|
|
12
|
+
* - **nested quantifier**: a repeated group that contains a repeated element,
|
|
13
|
+
* `(a+)+` — the classic catastrophic form;
|
|
14
|
+
* - **unbounded wildcard before more pattern**: `.*`, `[\s\S]*`, a negated
|
|
15
|
+
* class or `\S`/`\W`/`\D` repeated without bound and followed by anything —
|
|
16
|
+
* every start rescans to the end of the text;
|
|
17
|
+
* - **unbounded lazy quantifier**: `*?`, `+?`, `{n,}?` — the same rescan, one
|
|
18
|
+
* character at a time;
|
|
19
|
+
* - **adjacent overlapping runs**: two unbounded repetitions whose character
|
|
20
|
+
* sets overlap, with nothing between them that only one can match —
|
|
21
|
+
* `[a-z]*R[a-z]*` tries every split of `RRRR…`.
|
|
22
|
+
*
|
|
23
|
+
* A pattern that needs one of these anyway goes on {@link BACKTRACKING_ALLOWLIST}
|
|
24
|
+
* by rule id, with the reason a reviewer accepted it; the test that walks
|
|
25
|
+
* every gate rule fails on anything else. A rule marked `sequence` is checked
|
|
26
|
+
* step by step, since that is how the JS and Python gates run it.
|
|
27
|
+
*
|
|
28
|
+
* It parses the JS ∩ Python `re` dialect the rules use. Character sets are
|
|
29
|
+
* modelled over ASCII; a class with anything beyond ASCII counts as
|
|
30
|
+
* overlapping everything, which errs toward a finding.
|
|
31
|
+
*/
|
|
32
|
+
const range = (from, to) => {
|
|
33
|
+
const s = new Array(128).fill(false);
|
|
34
|
+
for (let c = from; c <= to; c++)
|
|
35
|
+
s[c] = true;
|
|
36
|
+
return s;
|
|
37
|
+
};
|
|
38
|
+
const union = (a, b) => a.map((v, i) => v || b[i]);
|
|
39
|
+
const invert = (a) => a.map((v) => !v);
|
|
40
|
+
const SPACE = (() => {
|
|
41
|
+
const s = new Array(128).fill(false);
|
|
42
|
+
for (const c of [9, 10, 11, 12, 13, 32])
|
|
43
|
+
s[c] = true;
|
|
44
|
+
return s;
|
|
45
|
+
})();
|
|
46
|
+
const DIGIT = range(48, 57);
|
|
47
|
+
const WORD = union(union(union(range(48, 57), range(65, 90)), range(97, 122)), (() => {
|
|
48
|
+
const s = new Array(128).fill(false);
|
|
49
|
+
s[95] = true;
|
|
50
|
+
return s;
|
|
51
|
+
})());
|
|
52
|
+
const ALL = range(0, 127);
|
|
53
|
+
const single = (ch) => {
|
|
54
|
+
const s = new Array(128).fill(false);
|
|
55
|
+
const c = ch.charCodeAt(0);
|
|
56
|
+
if (c < 128)
|
|
57
|
+
s[c] = true;
|
|
58
|
+
else
|
|
59
|
+
s.fill(true); // beyond ASCII: assume it overlaps everything
|
|
60
|
+
return s;
|
|
61
|
+
};
|
|
62
|
+
/** The set an escape names, and whether it is one of the wide negations. */
|
|
63
|
+
function escapeSet(ch) {
|
|
64
|
+
switch (ch) {
|
|
65
|
+
case 's': return { set: SPACE, wide: false };
|
|
66
|
+
case 'S': return { set: invert(SPACE), wide: true };
|
|
67
|
+
case 'd': return { set: DIGIT, wide: false };
|
|
68
|
+
case 'D': return { set: invert(DIGIT), wide: true };
|
|
69
|
+
case 'w': return { set: WORD, wide: false };
|
|
70
|
+
case 'W': return { set: invert(WORD), wide: true };
|
|
71
|
+
case 'n': return { set: single('\n'), wide: false };
|
|
72
|
+
case 't': return { set: single('\t'), wide: false };
|
|
73
|
+
case 'r': return { set: single('\r'), wide: false };
|
|
74
|
+
default: return { set: single(ch), wide: false };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/** Parses `source` into alternatives of items. Throws on syntax it does not know. */
|
|
78
|
+
function parse(source) {
|
|
79
|
+
let i = 0;
|
|
80
|
+
const alternatives = () => {
|
|
81
|
+
const alts = [[]];
|
|
82
|
+
while (i < source.length) {
|
|
83
|
+
const c = source[i];
|
|
84
|
+
if (c === ')')
|
|
85
|
+
break;
|
|
86
|
+
if (c === '|') {
|
|
87
|
+
i++;
|
|
88
|
+
alts.push([]);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const item = atom();
|
|
92
|
+
if (item) {
|
|
93
|
+
quantifier(item);
|
|
94
|
+
alts[alts.length - 1].push(item);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return alts;
|
|
98
|
+
};
|
|
99
|
+
const atom = () => {
|
|
100
|
+
const c = source[i];
|
|
101
|
+
const base = { group: null, min: 1, max: 1, lazy: false, wide: false };
|
|
102
|
+
if (c === '(') {
|
|
103
|
+
i++;
|
|
104
|
+
if (source[i] === '?') {
|
|
105
|
+
// (?: (?= (?! (?<= (?<! — the group's kind does not change the check.
|
|
106
|
+
i++;
|
|
107
|
+
if (source[i] === '<')
|
|
108
|
+
i++;
|
|
109
|
+
i++;
|
|
110
|
+
}
|
|
111
|
+
const group = alternatives();
|
|
112
|
+
if (source[i] !== ')')
|
|
113
|
+
throw new Error(`unclosed group in ${source}`);
|
|
114
|
+
i++;
|
|
115
|
+
return { ...base, set: null, group };
|
|
116
|
+
}
|
|
117
|
+
if (c === '[')
|
|
118
|
+
return { ...base, ...charClass(), group: null };
|
|
119
|
+
if (c === '\\') {
|
|
120
|
+
const e = source[i + 1] ?? '';
|
|
121
|
+
i += 2;
|
|
122
|
+
if (e === 'b' || e === 'B')
|
|
123
|
+
return null; // an assertion, not a character
|
|
124
|
+
if (/[1-9]/.test(e))
|
|
125
|
+
return { ...base, set: ALL }; // a backreference: counts as one wide character
|
|
126
|
+
const { set, wide } = escapeSet(e);
|
|
127
|
+
return { ...base, set, wide };
|
|
128
|
+
}
|
|
129
|
+
i++;
|
|
130
|
+
if (c === '^' || c === '$')
|
|
131
|
+
return null;
|
|
132
|
+
if (c === '.')
|
|
133
|
+
return { ...base, set: invert(single('\n')), wide: true };
|
|
134
|
+
return { ...base, set: single(c) };
|
|
135
|
+
};
|
|
136
|
+
const charClass = () => {
|
|
137
|
+
i++; // [
|
|
138
|
+
let negated = false;
|
|
139
|
+
if (source[i] === '^') {
|
|
140
|
+
negated = true;
|
|
141
|
+
i++;
|
|
142
|
+
}
|
|
143
|
+
let set = new Array(128).fill(false);
|
|
144
|
+
let first = true;
|
|
145
|
+
while (i < source.length && (source[i] !== ']' || first)) {
|
|
146
|
+
first = false;
|
|
147
|
+
let lo;
|
|
148
|
+
let loChar = '';
|
|
149
|
+
if (source[i] === '\\') {
|
|
150
|
+
const e = source[i + 1] ?? '';
|
|
151
|
+
i += 2;
|
|
152
|
+
lo = escapeSet(e).set;
|
|
153
|
+
if (!/[sSdDwW]/.test(e))
|
|
154
|
+
loChar = e === 'n' ? '\n' : e === 't' ? '\t' : e === 'r' ? '\r' : e;
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
loChar = source[i];
|
|
158
|
+
lo = single(loChar);
|
|
159
|
+
i++;
|
|
160
|
+
}
|
|
161
|
+
if (loChar && source[i] === '-' && source[i + 1] !== ']' && i + 1 < source.length) {
|
|
162
|
+
i++;
|
|
163
|
+
let hiChar = source[i];
|
|
164
|
+
if (hiChar === '\\') {
|
|
165
|
+
hiChar = source[i + 1] ?? '';
|
|
166
|
+
i++;
|
|
167
|
+
}
|
|
168
|
+
i++;
|
|
169
|
+
set = union(set, range(loChar.charCodeAt(0), Math.min(127, hiChar.charCodeAt(0))));
|
|
170
|
+
if (hiChar.charCodeAt(0) > 127)
|
|
171
|
+
set = ALL.slice();
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
set = union(set, lo);
|
|
175
|
+
}
|
|
176
|
+
i++; // ]
|
|
177
|
+
const full = set.every(Boolean);
|
|
178
|
+
return { set: negated ? invert(set) : set, wide: negated || full };
|
|
179
|
+
};
|
|
180
|
+
const quantifier = (item) => {
|
|
181
|
+
const c = source[i];
|
|
182
|
+
if (c === '*')
|
|
183
|
+
[item.min, item.max] = [0, Infinity];
|
|
184
|
+
else if (c === '+')
|
|
185
|
+
[item.min, item.max] = [1, Infinity];
|
|
186
|
+
else if (c === '?')
|
|
187
|
+
[item.min, item.max] = [0, 1];
|
|
188
|
+
else if (c === '{') {
|
|
189
|
+
const m = /^\{(\d+)(,(\d*))?\}/.exec(source.slice(i));
|
|
190
|
+
if (!m)
|
|
191
|
+
return;
|
|
192
|
+
item.min = Number(m[1]);
|
|
193
|
+
item.max = m[2] === undefined ? item.min : m[3] === '' ? Infinity : Number(m[3]);
|
|
194
|
+
i += m[0].length - 1;
|
|
195
|
+
}
|
|
196
|
+
else
|
|
197
|
+
return;
|
|
198
|
+
i++;
|
|
199
|
+
if (source[i] === '?') {
|
|
200
|
+
item.lazy = true;
|
|
201
|
+
i++;
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
const alts = alternatives();
|
|
205
|
+
if (i !== source.length)
|
|
206
|
+
throw new Error(`unbalanced ) in ${source}`);
|
|
207
|
+
return alts;
|
|
208
|
+
}
|
|
209
|
+
const unbounded = (it) => it.max === Infinity;
|
|
210
|
+
const hasUnbounded = (alts) => alts.some((seq) => seq.some((it) => unbounded(it) || (it.group !== null && hasUnbounded(it.group))));
|
|
211
|
+
const overlaps = (a, b) => a.some((v, i) => v && b[i]);
|
|
212
|
+
/** Every construct in `source` that can make a backtracking engine super-linear. */
|
|
213
|
+
export function backtrackingFindings(source) {
|
|
214
|
+
const findings = [];
|
|
215
|
+
const subset = (a, b) => a.every((v, c) => !v || b[c]);
|
|
216
|
+
const walk = (alts, topLevel) => {
|
|
217
|
+
for (const seq of alts) {
|
|
218
|
+
seq.forEach((it, k) => {
|
|
219
|
+
if (it.group && unbounded(it) && hasUnbounded(it.group))
|
|
220
|
+
findings.push('nested quantifier');
|
|
221
|
+
if (it.lazy && unbounded(it))
|
|
222
|
+
findings.push('unbounded lazy quantifier');
|
|
223
|
+
// A wide run is harmless only as the very last thing a match needs.
|
|
224
|
+
if (it.wide && unbounded(it) && !(topLevel && k === seq.length - 1)) {
|
|
225
|
+
findings.push('unbounded wildcard before more pattern');
|
|
226
|
+
}
|
|
227
|
+
if (it.set && unbounded(it)) {
|
|
228
|
+
// Past the fixed characters this run could also have taken, is the
|
|
229
|
+
// next repetition one whose set overlaps it?
|
|
230
|
+
for (let j = k + 1; j < seq.length; j++) {
|
|
231
|
+
const next = seq[j];
|
|
232
|
+
if (!next.set)
|
|
233
|
+
break;
|
|
234
|
+
if (unbounded(next)) {
|
|
235
|
+
if (overlaps(it.set, next.set))
|
|
236
|
+
findings.push('adjacent overlapping runs');
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
if (!subset(next.set, it.set))
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (it.group)
|
|
244
|
+
walk(it.group, false);
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
walk(parse(source), true);
|
|
249
|
+
return [...new Set(findings)];
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Rules allowed a construct {@link backtrackingFindings} reports, by rule id,
|
|
253
|
+
* with the reason a reviewer accepted it. Each entry must still trip the
|
|
254
|
+
* check (a stale entry fails the test), and each such rule has adversarial
|
|
255
|
+
* vectors that every reader must decide in linear time.
|
|
256
|
+
*/
|
|
257
|
+
export const BACKTRACKING_ALLOWLIST = {
|
|
258
|
+
'destructive.rm_rf_root': '`( +-[a-zA-Z-]+)+`: every repetition must begin with a space and the inner run cannot ' +
|
|
259
|
+
'contain one, so there is one way to split the flags; each ` rm` start does work linear in ' +
|
|
260
|
+
'its own flag list and stops at the next ` rm`.',
|
|
261
|
+
'skill_content.*': 'The argPattern wrapper `"key":"(?:[^"\\\\]|\\\\.)*?(?:P)` scans one JSON string lazily and ' +
|
|
262
|
+
'tries P at each position. It starts only at a key, which can appear unescaped in ' +
|
|
263
|
+
'the serialized input only as a key; the two alternatives begin with different ' +
|
|
264
|
+
'characters, so the scan is single-pass; and each P is bounded per position ' +
|
|
265
|
+
'(`{0,40}`-style windows, a lookahead-committed URL in markdown-exfil-link, a 600-character ' +
|
|
266
|
+
'close check in html-comment-hidden-instruction).',
|
|
267
|
+
};
|
|
268
|
+
/** The allowlist entry that covers a rule id, if any (`prefix.*` entries match a family). */
|
|
269
|
+
export function backtrackingAllowance(id) {
|
|
270
|
+
if (BACKTRACKING_ALLOWLIST[id])
|
|
271
|
+
return BACKTRACKING_ALLOWLIST[id];
|
|
272
|
+
const family = Object.keys(BACKTRACKING_ALLOWLIST).find((k) => k.endsWith('.*') && id.startsWith(k.slice(0, -1)));
|
|
273
|
+
return family ? BACKTRACKING_ALLOWLIST[family] : undefined;
|
|
274
|
+
}
|
|
275
|
+
//# sourceMappingURL=regexLinearity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"regexLinearity.js","sourceRoot":"","sources":["../../src/lib/regexLinearity.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/runtimeEnv.d.ts
CHANGED
|
@@ -16,8 +16,6 @@
|
|
|
16
16
|
* INTUTIC_WORKSPACE_ID=ws_...
|
|
17
17
|
* INTUTIC_VALKEY_URL=redis://127.0.0.1:6379 (only when a local Valkey is running)
|
|
18
18
|
*
|
|
19
|
-
* LLD #14 — Dual-path hook telemetry (WS-A1)
|
|
20
|
-
*
|
|
21
19
|
* @module
|
|
22
20
|
*/
|
|
23
21
|
/** Default path to the runtime env file sourced by all generated hook scripts. */
|
|
@@ -39,7 +37,7 @@ export interface RuntimeEnvOptions {
|
|
|
39
37
|
bypassEnforcementTier?: string;
|
|
40
38
|
/**
|
|
41
39
|
* The local Valkey the MCP governance proxies share their anomaly session
|
|
42
|
-
* window through (Wave 5.3
|
|
40
|
+
* window through (Wave 5.3). Written as `INTUTIC_VALKEY_URL` only
|
|
43
41
|
* when the caller has one running; omitted otherwise, so a proxy never
|
|
44
42
|
* probes a Valkey nobody started.
|
|
45
43
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtimeEnv.d.ts","sourceRoot":"","sources":["../../src/lib/runtimeEnv.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"runtimeEnv.d.ts","sourceRoot":"","sources":["../../src/lib/runtimeEnv.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AASH,kFAAkF;AAClF,eAAO,MAAM,wBAAwB,QAA4D,CAAA;AAEjG,MAAM,WAAW,iBAAiB;IAChC,+DAA+D;IAC/D,eAAe,EAAE,MAAM,CAAA;IACvB,yBAAyB;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,4BAA4B;IAC5B,WAAW,EAAE,MAAM,CAAA;IACnB,gEAAgE;IAChE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,mDAAmD;IACnD,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,iEAAiE;IACjE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,2EAA2E;IAC3E,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuC5E"}
|
package/dist/lib/runtimeEnv.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtimeEnv.js","sourceRoot":"","sources":["../../src/lib/runtimeEnv.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"runtimeEnv.js","sourceRoot":"","sources":["../../src/lib/runtimeEnv.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACtC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AACjC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAA;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAE9C,MAAM,GAAG,GAAG,YAAY,CAAC,kBAAkB,CAAC,CAAA;AAE5C,kFAAkF;AAClF,MAAM,CAAC,MAAM,wBAAwB,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,aAAa,CAAC,CAAA;AA0BjG;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAuB;IAC3D,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,wBAAwB,CAAA;IACxD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IAEpC,MAAM,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAE3C,yEAAyE;IACzE,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;IAChE,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;IACtD,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;IAC5D,MAAM,SAAS,GAAG,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;IAE/D,MAAM,OAAO,GAAG;QACd,mEAAmE;QACnE,4FAA4F;QAC5F,4GAA4G;QAC5G,sHAAsH;QACtH,gBAAgB,IAAI,EAAE;QACtB,mBAAmB,GAAG,EAAE;QACxB,wBAAwB,IAAI,EAAE;QAC9B,yBAAyB,CAAC,IAAI,CAAC,oBAAoB,IAAI,MAAM,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE;QAChG,0BAA0B,IAAI,CAAC,YAAY,IAAI,aAAa,EAAE;QAC9D,uBAAuB,IAAI,CAAC,qBAAqB,IAAI,SAAS,EAAE;QAChE,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,sBAAsB,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACzD,EAAE;QACF,iFAAiF;QACjF,wCAAwC;QACxC,yCAAyC;QACzC,4CAA4C;QAC5C,sCAAsC;QACtC,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAEZ,MAAM,OAAO,GAAG,OAAO,GAAG,MAAM,CAAA;IAChC,MAAM,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAA;IAC3D,MAAM,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;IAC9B,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IAEjC,GAAG,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,qBAAqB,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,4BAA4B,CAAC,CAAA;AAC3F,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sequence-rule matcher in Python, for the Open WebUI filter.
|
|
3
|
+
*
|
|
4
|
+
* Byte-identical to `packages/intutic-clawde/intutic_clawde/gate/sequence.py`,
|
|
5
|
+
* which a test compares; edit that file and copy it here. It is the
|
|
6
|
+
* transliteration of `@intutic/shared-types`'s sequence.ts, and both run the
|
|
7
|
+
* shared vectors.
|
|
8
|
+
*/
|
|
9
|
+
export declare const SEQUENCE_PY_SOURCE: string;
|
|
10
|
+
//# sourceMappingURL=sequencePy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sequencePy.d.ts","sourceRoot":"","sources":["../../src/lib/sequencePy.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,QA4F9B,CAAA"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sequence-rule matcher in Python, for the Open WebUI filter.
|
|
3
|
+
*
|
|
4
|
+
* Byte-identical to `packages/intutic-clawde/intutic_clawde/gate/sequence.py`,
|
|
5
|
+
* which a test compares; edit that file and copy it here. It is the
|
|
6
|
+
* transliteration of `@intutic/shared-types`'s sequence.ts, and both run the
|
|
7
|
+
* shared vectors.
|
|
8
|
+
*/
|
|
9
|
+
export const SEQUENCE_PY_SOURCE = String.raw `"""Sequence rules: a gate rule "A.*B" run as "find A, then find B after it".
|
|
10
|
+
|
|
11
|
+
A transliteration of packages/shared-types/src/sequence.ts; read that module's
|
|
12
|
+
docstring for when this means the same as the regex. A rule whose .rules
|
|
13
|
+
flags column contains "s" is cut into alternatives of steps at its top-level
|
|
14
|
+
"|" and ".*", and each step is searched for once, from where the previous one
|
|
15
|
+
ended: linear in the text, where re.search on the whole regex backtracks from
|
|
16
|
+
every start of the first step to the end of the text.
|
|
17
|
+
|
|
18
|
+
Every reader runs packages/shared-types/fixtures/gate-rule-vectors.json, and
|
|
19
|
+
the Open WebUI filter emits this file verbatim
|
|
20
|
+
(services/sync-daemon/src/lib/sequencePy.ts holds a byte-identical copy,
|
|
21
|
+
which a test compares). It must stay self-contained: the standard library
|
|
22
|
+
only, no module state, and no backtick or dollar-brace, which the TypeScript
|
|
23
|
+
copy cannot hold.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
import re
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def sequence_alternatives(source):
|
|
30
|
+
"""Split a sequence rule's source into alternatives of steps."""
|
|
31
|
+
alternatives = []
|
|
32
|
+
steps = []
|
|
33
|
+
current = []
|
|
34
|
+
depth = 0
|
|
35
|
+
in_class = False
|
|
36
|
+
i = 0
|
|
37
|
+
n = len(source)
|
|
38
|
+
while i < n:
|
|
39
|
+
c = source[i]
|
|
40
|
+
if c == "\\":
|
|
41
|
+
current.append(source[i:i + 2])
|
|
42
|
+
i += 2
|
|
43
|
+
continue
|
|
44
|
+
if in_class:
|
|
45
|
+
current.append(c)
|
|
46
|
+
i += 1
|
|
47
|
+
if c == "]":
|
|
48
|
+
in_class = False
|
|
49
|
+
continue
|
|
50
|
+
if c == "[":
|
|
51
|
+
in_class = True
|
|
52
|
+
current.append(c)
|
|
53
|
+
i += 1
|
|
54
|
+
if source[i:i + 1] == "^":
|
|
55
|
+
current.append("^")
|
|
56
|
+
i += 1
|
|
57
|
+
if source[i:i + 1] == "]":
|
|
58
|
+
current.append("]")
|
|
59
|
+
i += 1
|
|
60
|
+
continue
|
|
61
|
+
if c == "(":
|
|
62
|
+
depth += 1
|
|
63
|
+
elif c == ")":
|
|
64
|
+
depth -= 1
|
|
65
|
+
if depth == 0 and c == "|":
|
|
66
|
+
steps.append("".join(current))
|
|
67
|
+
alternatives.append([s for s in steps if s])
|
|
68
|
+
steps = []
|
|
69
|
+
current = []
|
|
70
|
+
i += 1
|
|
71
|
+
continue
|
|
72
|
+
if depth == 0 and c == "." and source[i + 1:i + 2] == "*":
|
|
73
|
+
steps.append("".join(current))
|
|
74
|
+
current = []
|
|
75
|
+
i += 2
|
|
76
|
+
continue
|
|
77
|
+
current.append(c)
|
|
78
|
+
i += 1
|
|
79
|
+
steps.append("".join(current))
|
|
80
|
+
alternatives.append([s for s in steps if s])
|
|
81
|
+
return alternatives
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def compile_sequence(source, flags=0):
|
|
85
|
+
"""Compile a sequence rule's steps for sequence_match."""
|
|
86
|
+
return [[re.compile(s, flags) for s in steps] for steps in sequence_alternatives(source)]
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def sequence_match(alternatives, text):
|
|
90
|
+
"""Whether some alternative's steps occur in text in order."""
|
|
91
|
+
for steps in alternatives:
|
|
92
|
+
pos = 0
|
|
93
|
+
for step in steps:
|
|
94
|
+
m = step.search(text, pos)
|
|
95
|
+
if m is None:
|
|
96
|
+
break
|
|
97
|
+
pos = m.end()
|
|
98
|
+
else:
|
|
99
|
+
return True
|
|
100
|
+
return False
|
|
101
|
+
`;
|
|
102
|
+
//# sourceMappingURL=sequencePy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sequencePy.js","sourceRoot":"","sources":["../../src/lib/sequencePy.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4F3C,CAAA"}
|
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
* capture and the Jira/Linear/GitHub task-context cascade) had no production
|
|
7
7
|
* caller: sessions only ever existed as synthetic `ssp_` rows minted
|
|
8
8
|
* server-side. The daemon knows everything the route wants — workspace root,
|
|
9
|
-
* harness, git branch and commit — so it reports them
|
|
10
|
-
*
|
|
9
|
+
* harness, git repository, branch and commit — so it reports them when the
|
|
10
|
+
* harness is first detected, and again whenever the repository, branch or
|
|
11
|
+
* HEAD commit changes.
|
|
11
12
|
*
|
|
12
|
-
* WHICH row it reports them onto (
|
|
13
|
+
* WHICH row it reports them onto (Wave 5.6): when a local proxy is
|
|
13
14
|
* reachable, the caller passes that process's `proxyInstanceId` and the
|
|
14
15
|
* control plane puts the context on the proxy's OWN row — the
|
|
15
16
|
* `ssp_<ws>_<harness>_<instance>` session it derives for that process's
|
|
@@ -27,15 +28,19 @@
|
|
|
27
28
|
*
|
|
28
29
|
* Dedupe lives here (module state keyed workspace+harness+instance), so
|
|
29
30
|
* callers (`reportHarnessAgents`, every `intutic connect` cycle) can call
|
|
30
|
-
* `startHarnessSession` every iteration and
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
31
|
+
* `startHarnessSession` every iteration. Git is read on every call and the
|
|
32
|
+
* session is POSTed again only when it changed: the control plane copies the
|
|
33
|
+
* session's git context onto each trace as it records it, which is what makes
|
|
34
|
+
* cost per branch and per commit possible, so a stale commit would file a
|
|
35
|
+
* call under the wrong one. A re-POST updates the same row. Everything is
|
|
36
|
+
* best-effort: a dead control plane costs a warning, never the sync loop.
|
|
34
37
|
*
|
|
35
38
|
* @module
|
|
36
39
|
*/
|
|
37
|
-
import type
|
|
40
|
+
import { type HarnessType } from '@intutic/shared-types';
|
|
38
41
|
export interface GitInfo {
|
|
42
|
+
/** The `origin` remote, normalised: host/path, never credentials. */
|
|
43
|
+
repoUrl?: string;
|
|
39
44
|
branchName?: string;
|
|
40
45
|
commitHash?: string;
|
|
41
46
|
commitMessage?: string;
|
|
@@ -43,9 +48,10 @@ export interface GitInfo {
|
|
|
43
48
|
/** Best-effort git context from the workspace root. */
|
|
44
49
|
export declare function readGitInfo(workspaceRoot: string): Promise<GitInfo>;
|
|
45
50
|
/**
|
|
46
|
-
* Report a harness session
|
|
47
|
-
* `proxyInstanceId` is given (see the module doc), else as a
|
|
48
|
-
*
|
|
51
|
+
* Report a harness session — onto the local proxy's own row when
|
|
52
|
+
* `proxyInstanceId` is given (see the module doc), else as a `ses_` row — and
|
|
53
|
+
* report it again when its git context changes. Returns the sessionId when one
|
|
54
|
+
* is known (new or previously created).
|
|
49
55
|
*/
|
|
50
56
|
export declare function startHarnessSession(opts: {
|
|
51
57
|
controlPlaneUrl: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionReporter.d.ts","sourceRoot":"","sources":["../src/sessionReporter.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"sessionReporter.d.ts","sourceRoot":"","sources":["../src/sessionReporter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAKH,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAqB5E,MAAM,WAAW,OAAO;IACtB,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,uDAAuD;AACvD,wBAAsB,WAAW,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAmBzE;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,eAAe,EAAE,MAAM,CAAA;IACvB,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,WAAW,CAAA;IACxB,aAAa,EAAE,MAAM,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAyCzB;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkB/F"}
|
package/dist/sessionReporter.js
CHANGED
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
* capture and the Jira/Linear/GitHub task-context cascade) had no production
|
|
7
7
|
* caller: sessions only ever existed as synthetic `ssp_` rows minted
|
|
8
8
|
* server-side. The daemon knows everything the route wants — workspace root,
|
|
9
|
-
* harness, git branch and commit — so it reports them
|
|
10
|
-
*
|
|
9
|
+
* harness, git repository, branch and commit — so it reports them when the
|
|
10
|
+
* harness is first detected, and again whenever the repository, branch or
|
|
11
|
+
* HEAD commit changes.
|
|
11
12
|
*
|
|
12
|
-
* WHICH row it reports them onto (
|
|
13
|
+
* WHICH row it reports them onto (Wave 5.6): when a local proxy is
|
|
13
14
|
* reachable, the caller passes that process's `proxyInstanceId` and the
|
|
14
15
|
* control plane puts the context on the proxy's OWN row — the
|
|
15
16
|
* `ssp_<ws>_<harness>_<instance>` session it derives for that process's
|
|
@@ -27,16 +28,19 @@
|
|
|
27
28
|
*
|
|
28
29
|
* Dedupe lives here (module state keyed workspace+harness+instance), so
|
|
29
30
|
* callers (`reportHarnessAgents`, every `intutic connect` cycle) can call
|
|
30
|
-
* `startHarnessSession` every iteration and
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
31
|
+
* `startHarnessSession` every iteration. Git is read on every call and the
|
|
32
|
+
* session is POSTed again only when it changed: the control plane copies the
|
|
33
|
+
* session's git context onto each trace as it records it, which is what makes
|
|
34
|
+
* cost per branch and per commit possible, so a stale commit would file a
|
|
35
|
+
* call under the wrong one. A re-POST updates the same row. Everything is
|
|
36
|
+
* best-effort: a dead control plane costs a warning, never the sync loop.
|
|
34
37
|
*
|
|
35
38
|
* @module
|
|
36
39
|
*/
|
|
37
40
|
import { execFile } from 'node:child_process';
|
|
38
41
|
import { promisify } from 'node:util';
|
|
39
42
|
import { newIso } from '@intutic/id';
|
|
43
|
+
import { normalizeGitRemote } from '@intutic/shared-types';
|
|
40
44
|
const execFileP = promisify(execFile);
|
|
41
45
|
/**
|
|
42
46
|
* sessionIds this daemon run opened AND owns the lifecycle of — the `ses_`
|
|
@@ -48,8 +52,12 @@ const openSessions = new Map();
|
|
|
48
52
|
* `${workspaceId}:${harness}:${proxyInstanceId}`. Dedupe only — never ended.
|
|
49
53
|
*/
|
|
50
54
|
const registeredProxyRows = new Map();
|
|
51
|
-
/**
|
|
52
|
-
|
|
55
|
+
/**
|
|
56
|
+
* The git context last POSTed (or attempted, success or not) per key. One try
|
|
57
|
+
* per key and git state per run: a failing control plane is not retried every
|
|
58
|
+
* cycle, but a branch switch or a new commit is reported.
|
|
59
|
+
*/
|
|
60
|
+
const attempted = new Map();
|
|
53
61
|
/** Best-effort git context from the workspace root. */
|
|
54
62
|
export async function readGitInfo(workspaceRoot) {
|
|
55
63
|
const git = async (...args) => {
|
|
@@ -62,28 +70,31 @@ export async function readGitInfo(workspaceRoot) {
|
|
|
62
70
|
return undefined;
|
|
63
71
|
}
|
|
64
72
|
};
|
|
65
|
-
const [branchName, commitHash, commitMessage] = await Promise.all([
|
|
73
|
+
const [remote, branchName, commitHash, commitMessage] = await Promise.all([
|
|
74
|
+
git('remote', 'get-url', 'origin'),
|
|
66
75
|
git('rev-parse', '--abbrev-ref', 'HEAD'),
|
|
67
76
|
git('rev-parse', 'HEAD'),
|
|
68
77
|
git('log', '-1', '--format=%s'),
|
|
69
78
|
]);
|
|
70
|
-
|
|
79
|
+
// Normalised here, before it is held anywhere: a remote can embed a token.
|
|
80
|
+
const repoUrl = remote ? (normalizeGitRemote(remote) ?? undefined) : undefined;
|
|
81
|
+
return { repoUrl, branchName, commitHash, commitMessage };
|
|
71
82
|
}
|
|
72
83
|
/**
|
|
73
|
-
* Report a harness session
|
|
74
|
-
* `proxyInstanceId` is given (see the module doc), else as a
|
|
75
|
-
*
|
|
84
|
+
* Report a harness session — onto the local proxy's own row when
|
|
85
|
+
* `proxyInstanceId` is given (see the module doc), else as a `ses_` row — and
|
|
86
|
+
* report it again when its git context changes. Returns the sessionId when one
|
|
87
|
+
* is known (new or previously created).
|
|
76
88
|
*/
|
|
77
89
|
export async function startHarnessSession(opts) {
|
|
78
90
|
const key = `${opts.workspaceId}:${opts.harnessType}:${opts.proxyInstanceId ?? ''}`;
|
|
79
91
|
const existing = opts.proxyInstanceId ? registeredProxyRows.get(key) : openSessions.get(key);
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (attempted.
|
|
83
|
-
return null;
|
|
84
|
-
attempted.
|
|
92
|
+
const git = await readGitInfo(opts.workspaceRoot);
|
|
93
|
+
const gitState = JSON.stringify([git.repoUrl, git.branchName, git.commitHash]);
|
|
94
|
+
if (attempted.get(key) === gitState)
|
|
95
|
+
return existing ?? null;
|
|
96
|
+
attempted.set(key, gitState);
|
|
85
97
|
try {
|
|
86
|
-
const git = await readGitInfo(opts.workspaceRoot);
|
|
87
98
|
const res = await fetch(`${opts.controlPlaneUrl}/api/v1/sessions`, {
|
|
88
99
|
method: 'POST',
|
|
89
100
|
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.apiKey}` },
|
|
@@ -92,6 +103,8 @@ export async function startHarnessSession(opts) {
|
|
|
92
103
|
harnessType: opts.harnessType,
|
|
93
104
|
...(opts.agentRole ? { agentRole: opts.agentRole } : {}),
|
|
94
105
|
...(opts.proxyInstanceId ? { proxyInstanceId: opts.proxyInstanceId } : {}),
|
|
106
|
+
// A `ses_` row this run already opened is updated, not opened again.
|
|
107
|
+
...(existing && !opts.proxyInstanceId ? { sessionId: existing } : {}),
|
|
95
108
|
...git,
|
|
96
109
|
reportedAt: newIso(),
|
|
97
110
|
}),
|
|
@@ -99,7 +112,7 @@ export async function startHarnessSession(opts) {
|
|
|
99
112
|
});
|
|
100
113
|
if (!res.ok) {
|
|
101
114
|
console.warn(`[sync-daemon] startHarnessSession failed for ${opts.harnessType}: ${res.status}`);
|
|
102
|
-
return null;
|
|
115
|
+
return existing ?? null;
|
|
103
116
|
}
|
|
104
117
|
const body = (await res.json());
|
|
105
118
|
if (body.sessionId) {
|
|
@@ -107,11 +120,11 @@ export async function startHarnessSession(opts) {
|
|
|
107
120
|
(opts.proxyInstanceId ? registeredProxyRows : openSessions).set(key, body.sessionId);
|
|
108
121
|
return body.sessionId;
|
|
109
122
|
}
|
|
110
|
-
return null;
|
|
123
|
+
return existing ?? null;
|
|
111
124
|
}
|
|
112
125
|
catch (err) {
|
|
113
126
|
console.warn(`[sync-daemon] startHarnessSession error for ${opts.harnessType}:`, err instanceof Error ? err.message : err);
|
|
114
|
-
return null;
|
|
127
|
+
return existing ?? null;
|
|
115
128
|
}
|
|
116
129
|
}
|
|
117
130
|
/**
|