Commit ·
c83f5fe
1
Parent(s): 7b761b9
acer: extend kimi surface scanner to cover the exec substrate (closes acer's daimon catch)
Browse filesliris's v1 scanner walks app.asar only — which structurally misses the local
code-execution substrate (it lives in resources/resources/, outside the asar).
Adds classifyExecSubstrate + probeExecSubstrate (read-only metadata: existence +
size, NEVER extracts the tar) and a KIMISURFACEEXEC row covering
daimon-bundle.tar.gz (python+uv+git), gateway.asar, runtime/node.exe.
Live-verified on acer's real install: daimon_bundle_present=1, ~527MB. This is the
mechanism behind "up to 300 local workers." Scanner unit 6/6, full pyramid 158/158.
Read-only throughout; no token/chat read; no Kimi action.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- tests/kimi-desktop-surface-scan.unit.test.mjs +14 -1
- tests/kimi-desktop-surface-scan.unit.test.mjs.sha256 +1 -1
- tools/behcs/kimi-desktop-surface-scan.hbp +4 -3
- tools/behcs/kimi-desktop-surface-scan.hbp.sha256 +1 -1
- tools/behcs/kimi-desktop-surface-scan.mjs +38 -1
- tools/behcs/kimi-desktop-surface-scan.mjs.sha256 +1 -1
tests/kimi-desktop-surface-scan.unit.test.mjs
CHANGED
|
@@ -2,6 +2,7 @@ import assert from 'node:assert/strict';
|
|
| 2 |
import test from 'node:test';
|
| 3 |
|
| 4 |
import {
|
|
|
|
| 5 |
classifyKimiSurface,
|
| 6 |
emitSurfaceRows,
|
| 7 |
extractBridgeChannels,
|
|
@@ -40,11 +41,23 @@ test('classifies Kimi agent surfaces from a synthetic file table', () => {
|
|
| 40 |
test('emits HBP rows without reading private stores or invoking Kimi actions', () => {
|
| 41 |
const c = classifyKimiSurface(['node_modules/@agentclientprotocol/sdk/package.json']);
|
| 42 |
const rows = emitSurfaceRows({ classification: c, appAsarPresent: true, webbridgePresent: true, webbridgeSize: 7 });
|
| 43 |
-
assert.equal(rows.length,
|
| 44 |
assert.ok(rows.every((row) => row.endsWith('|json=0')));
|
| 45 |
assert.ok(rows.join('\n').includes('no-token-read-no-private-chat-read-no-kimi-action'));
|
| 46 |
});
|
| 47 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
test('walkAsarPaths returns nested slash paths', () => {
|
| 49 |
const paths = walkAsarPaths({ files: { a: { files: { b: { files: { 'c.js': { size: 1 } } } } } } });
|
| 50 |
assert.deepEqual(paths, ['a', 'a/b', 'a/b/c.js']);
|
|
|
|
| 2 |
import test from 'node:test';
|
| 3 |
|
| 4 |
import {
|
| 5 |
+
classifyExecSubstrate,
|
| 6 |
classifyKimiSurface,
|
| 7 |
emitSurfaceRows,
|
| 8 |
extractBridgeChannels,
|
|
|
|
| 41 |
test('emits HBP rows without reading private stores or invoking Kimi actions', () => {
|
| 42 |
const c = classifyKimiSurface(['node_modules/@agentclientprotocol/sdk/package.json']);
|
| 43 |
const rows = emitSurfaceRows({ classification: c, appAsarPresent: true, webbridgePresent: true, webbridgeSize: 7 });
|
| 44 |
+
assert.equal(rows.length, 6);
|
| 45 |
assert.ok(rows.every((row) => row.endsWith('|json=0')));
|
| 46 |
assert.ok(rows.join('\n').includes('no-token-read-no-private-chat-read-no-kimi-action'));
|
| 47 |
});
|
| 48 |
|
| 49 |
+
test('acer catch: exec substrate OUTSIDE app.asar is classified and emitted (read-only metadata)', () => {
|
| 50 |
+
const ex = classifyExecSubstrate({ daimonBundle: { present: true, size: 527000000 }, nodeRuntime: { present: true, size: 87000000 } });
|
| 51 |
+
assert.equal(ex.daimonBundle.present, true);
|
| 52 |
+
assert.equal(ex.daimonBundle.size, 527000000);
|
| 53 |
+
assert.equal(ex.gatewayAsar.present, false);
|
| 54 |
+
assert.equal(ex.gatewayAsar.size, 0);
|
| 55 |
+
const c = classifyKimiSurface([]);
|
| 56 |
+
const row = emitSurfaceRows({ classification: c, execSubstrate: ex }).find((r) => r.startsWith('KIMISURFACEEXEC|'));
|
| 57 |
+
assert.ok(row.includes('daimon_bundle_present=1') && row.includes('node_runtime_present=1'));
|
| 58 |
+
assert.ok(row.endsWith('|json=0'));
|
| 59 |
+
});
|
| 60 |
+
|
| 61 |
test('walkAsarPaths returns nested slash paths', () => {
|
| 62 |
const paths = walkAsarPaths({ files: { a: { files: { b: { files: { 'c.js': { size: 1 } } } } } } });
|
| 63 |
assert.deepEqual(paths, ['a', 'a/b', 'a/b/c.js']);
|
tests/kimi-desktop-surface-scan.unit.test.mjs.sha256
CHANGED
|
@@ -1 +1 @@
|
|
| 1 |
-
|
|
|
|
| 1 |
+
563c367cbbf42f5332a60ba64364cdbddf7ee4b2680e115b798afaeeb55accb8 kimi-desktop-surface-scan.unit.test.mjs
|
tools/behcs/kimi-desktop-surface-scan.hbp
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
-
KIMISURFACETOOL|tool=tools/behcs/kimi-desktop-surface-scan.mjs|status=READONLY-INSPECTION-V1|scope=parse-Kimi-app.asar-file-table
|
| 2 |
-
KIMISURFACEPRIVACY|never_reads=bridge-store-token-store+private-chat+localStorage+cookies+account-session|never_invokes=Kimi-IPC+MCP+Skill+Sandbox+WebAgent-actions|json=0
|
| 3 |
-
KIMISURFACEOUTPUT|rows=KIMISURFACEHDR+KIMISURFACEPATHS+KIMISURFACEMARKERS+KIMISURFACEBRIDGE+KIMISURFACEABSORB|format=HBP-only-json0|json=0
|
|
|
|
| 4 |
KIMISURFACEABSORB|patterns=ACP-client-protocol+MCP-registry+SkillService+SandboxService+WebAgent+local-webbridge+workspace-overrides+cron-workspace|target=Asolaria-readonly-observability-and-agent-bridge-design|json=0
|
| 5 |
KIMISURFACEGUARD|classification=necessary-not-sufficient|present-marker-means-bundled-surface-not-proof-of-enabled-runtime-capability|json=0
|
| 6 |
KIMISURFACEFTR|state=SEALED-READONLY-SCANNER|json=0
|
|
|
|
| 1 |
+
KIMISURFACETOOL|tool=tools/behcs/kimi-desktop-surface-scan.mjs|status=READONLY-INSPECTION-V1.1|scope=parse-Kimi-app.asar-file-table+webbridge-binary-metadata+resources-resources-exec-substrate-metadata-only|json=0
|
| 2 |
+
KIMISURFACEPRIVACY|never_reads=bridge-store-token-store+private-chat+localStorage+cookies+account-session|never_invokes=Kimi-IPC+MCP+Skill+Sandbox+WebAgent-actions|never_extracts=daimon-bundle-tar-contents(presence+size-only)|json=0
|
| 3 |
+
KIMISURFACEOUTPUT|rows=KIMISURFACEHDR+KIMISURFACEPATHS+KIMISURFACEMARKERS+KIMISURFACEBRIDGE+KIMISURFACEEXEC+KIMISURFACEABSORB|format=HBP-only-json0|json=0
|
| 4 |
+
KIMISURFACEACERCATCH|added-by=acer-v1.1|catch=app.asar-only-walk-UNDER-REPORTS-the-local-exec-substrate|now-covered=resources/resources/daimon-bundle.tar.gz(python+uv+git)+gateway.asar+runtime/node.exe-metadata-presence-and-size|why=this-is-the-mechanism-behind-up-to-300-local-workers|json=0
|
| 5 |
KIMISURFACEABSORB|patterns=ACP-client-protocol+MCP-registry+SkillService+SandboxService+WebAgent+local-webbridge+workspace-overrides+cron-workspace|target=Asolaria-readonly-observability-and-agent-bridge-design|json=0
|
| 6 |
KIMISURFACEGUARD|classification=necessary-not-sufficient|present-marker-means-bundled-surface-not-proof-of-enabled-runtime-capability|json=0
|
| 7 |
KIMISURFACEFTR|state=SEALED-READONLY-SCANNER|json=0
|
tools/behcs/kimi-desktop-surface-scan.hbp.sha256
CHANGED
|
@@ -1 +1 @@
|
|
| 1 |
-
|
|
|
|
| 1 |
+
2c616c64b1f49dbf58e79ef1ae6de77383e2a78e715650fd14c723b73c889f4c kimi-desktop-surface-scan.hbp
|
tools/behcs/kimi-desktop-surface-scan.mjs
CHANGED
|
@@ -89,18 +89,49 @@ export function extractBridgeChannels(text) {
|
|
| 89 |
return IPC_MARKERS.filter((marker) => channelText.includes(marker));
|
| 90 |
}
|
| 91 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
export function emitSurfaceRows(scan) {
|
| 93 |
const s = scan || {};
|
| 94 |
const c = s.classification || classifyKimiSurface([]);
|
| 95 |
const found = c.found || {};
|
| 96 |
const counts = c.counts || {};
|
| 97 |
const present = Object.entries(found).filter(([, v]) => v).map(([k]) => k).sort();
|
|
|
|
| 98 |
return [
|
| 99 |
`KIMISURFACEHDR|scanner=${SCANNER_ID}|app_asar_present=${s.appAsarPresent ? 1 : 0}|webbridge_present=${s.webbridgePresent ? 1 : 0}|privacy=token-store-and-private-chat-not-read|json=0`,
|
| 100 |
`KIMISURFACEPATHS|total_paths=${counts.totalPaths || 0}|kimi_proto_paths=${counts.kimiProtoCount || 0}|proto_service_paths=${counts.protoServiceCount || 0}|renderer_agent_assets=${counts.rendererAgentAssets || 0}|path_digest16=${c.digest || sha16('')}|json=0`,
|
| 101 |
`KIMISURFACEMARKERS|present=${present.join('+') || 'none'}|missing=${Object.keys(found).filter((k) => !found[k]).sort().join('+') || 'none'}|json=0`,
|
| 102 |
`KIMISURFACEBRIDGE|local_listener_observed=${s.localListenerObserved || 'not-observed-by-this-scanner'}|webbridge_size=${s.webbridgeSize || 0}|webbridge_version=${s.webbridgeVersion || 'unknown'}|json=0`,
|
| 103 |
-
`
|
|
|
|
| 104 |
];
|
| 105 |
}
|
| 106 |
|
|
@@ -110,6 +141,7 @@ export function scanKimiInstall(options = {}) {
|
|
| 110 |
const appAsar = options.appAsar || join(localAppData, 'Programs', 'kimi-desktop', 'resources', 'app.asar');
|
| 111 |
const webbridgeExe = options.webbridgeExe || join(userHome, '.kimi-webbridge', 'bin', 'kimi-webbridge.exe');
|
| 112 |
const webbridgeVersionFile = options.webbridgeVersionFile || join(userHome, '.kimi-webbridge', 'bin', 'kimi-webbridge.version');
|
|
|
|
| 113 |
|
| 114 |
let paths = [];
|
| 115 |
let appAsarPresent = false;
|
|
@@ -132,6 +164,7 @@ export function scanKimiInstall(options = {}) {
|
|
| 132 |
webbridgeSize,
|
| 133 |
webbridgeVersion,
|
| 134 |
classification: classifyKimiSurface(paths),
|
|
|
|
| 135 |
};
|
| 136 |
}
|
| 137 |
|
|
@@ -167,6 +200,10 @@ export function selfTest() {
|
|
| 167 |
['detects-bridge-protocol', c.found.bridgeProtocol],
|
| 168 |
['hbp-rows-only', emitSurfaceRows({ classification: c }).every((row) => row.endsWith('|json=0') && !row.includes('\n'))],
|
| 169 |
['channels-extract', extractBridgeChannels('GET_WORKSPACE_ROOT INSTALL_SKILL OPEN_AS_TEXT').length === 3],
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
].map(([name, ok]) => ({ name, ok: Boolean(ok) }));
|
| 171 |
return { ok: checks.every((c) => c.ok), checks };
|
| 172 |
}
|
|
|
|
| 89 |
return IPC_MARKERS.filter((marker) => channelText.includes(marker));
|
| 90 |
}
|
| 91 |
|
| 92 |
+
// acer catch (ACER-KIMI-DAIMON-CATCH): the local code-execution substrate lives
|
| 93 |
+
// OUTSIDE app.asar in resources/resources/ -- daimon-bundle.tar.gz (bundles
|
| 94 |
+
// CPython+uv+git), gateway.asar, runtime/node.exe. An app.asar-only walk misses it.
|
| 95 |
+
// Pure classifier over a presence/size probe so it is testable with no Kimi install.
|
| 96 |
+
export function classifyExecSubstrate(probe) {
|
| 97 |
+
const p = probe || {};
|
| 98 |
+
const pick = (k) => ({
|
| 99 |
+
present: Boolean(p[k] && p[k].present),
|
| 100 |
+
size: (p[k] && Number.isFinite(p[k].size) && p[k].size > 0) ? p[k].size : 0,
|
| 101 |
+
});
|
| 102 |
+
return { daimonBundle: pick('daimonBundle'), gatewayAsar: pick('gatewayAsar'), nodeRuntime: pick('nodeRuntime') };
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
// read-only metadata probe: existence + size only, NEVER extract the tar or read contents.
|
| 106 |
+
export function probeExecSubstrate(resourcesResourcesDir) {
|
| 107 |
+
const base = resourcesResourcesDir || '';
|
| 108 |
+
const targets = {
|
| 109 |
+
daimonBundle: join(base, 'daimon-bundle.tar.gz'),
|
| 110 |
+
gatewayAsar: join(base, 'gateway.asar'),
|
| 111 |
+
nodeRuntime: join(base, 'runtime', 'node.exe'),
|
| 112 |
+
};
|
| 113 |
+
const probe = {};
|
| 114 |
+
for (const [k, f] of Object.entries(targets)) {
|
| 115 |
+
const present = Boolean(base) && existsSync(f);
|
| 116 |
+
probe[k] = { present, size: present ? statSync(f).size : 0 };
|
| 117 |
+
}
|
| 118 |
+
return classifyExecSubstrate(probe);
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
export function emitSurfaceRows(scan) {
|
| 122 |
const s = scan || {};
|
| 123 |
const c = s.classification || classifyKimiSurface([]);
|
| 124 |
const found = c.found || {};
|
| 125 |
const counts = c.counts || {};
|
| 126 |
const present = Object.entries(found).filter(([, v]) => v).map(([k]) => k).sort();
|
| 127 |
+
const ex = s.execSubstrate || classifyExecSubstrate({});
|
| 128 |
return [
|
| 129 |
`KIMISURFACEHDR|scanner=${SCANNER_ID}|app_asar_present=${s.appAsarPresent ? 1 : 0}|webbridge_present=${s.webbridgePresent ? 1 : 0}|privacy=token-store-and-private-chat-not-read|json=0`,
|
| 130 |
`KIMISURFACEPATHS|total_paths=${counts.totalPaths || 0}|kimi_proto_paths=${counts.kimiProtoCount || 0}|proto_service_paths=${counts.protoServiceCount || 0}|renderer_agent_assets=${counts.rendererAgentAssets || 0}|path_digest16=${c.digest || sha16('')}|json=0`,
|
| 131 |
`KIMISURFACEMARKERS|present=${present.join('+') || 'none'}|missing=${Object.keys(found).filter((k) => !found[k]).sort().join('+') || 'none'}|json=0`,
|
| 132 |
`KIMISURFACEBRIDGE|local_listener_observed=${s.localListenerObserved || 'not-observed-by-this-scanner'}|webbridge_size=${s.webbridgeSize || 0}|webbridge_version=${s.webbridgeVersion || 'unknown'}|json=0`,
|
| 133 |
+
`KIMISURFACEEXEC|daimon_bundle_present=${ex.daimonBundle.present ? 1 : 0}|gateway_asar_present=${ex.gatewayAsar.present ? 1 : 0}|node_runtime_present=${ex.nodeRuntime.present ? 1 : 0}|daimon_bundle_bytes=${ex.daimonBundle.size}|note=local-exec-substrate-OUTSIDE-app.asar-bundles-python-uv-git-metadata-only-NOT-extracted|json=0`,
|
| 134 |
+
`KIMISURFACEABSORB|patterns=ACP-client-protocol+MCP-registry+SkillService+SandboxService+WebAgent+local-webbridge+workspace-overrides+cron-workspace+daimon-bundle-local-exec-substrate|guard=read-only-inspection-no-token-read-no-private-chat-read-no-kimi-action|json=0`,
|
| 135 |
];
|
| 136 |
}
|
| 137 |
|
|
|
|
| 141 |
const appAsar = options.appAsar || join(localAppData, 'Programs', 'kimi-desktop', 'resources', 'app.asar');
|
| 142 |
const webbridgeExe = options.webbridgeExe || join(userHome, '.kimi-webbridge', 'bin', 'kimi-webbridge.exe');
|
| 143 |
const webbridgeVersionFile = options.webbridgeVersionFile || join(userHome, '.kimi-webbridge', 'bin', 'kimi-webbridge.version');
|
| 144 |
+
const resourcesResourcesDir = options.resourcesResourcesDir || join(localAppData, 'Programs', 'kimi-desktop', 'resources', 'resources');
|
| 145 |
|
| 146 |
let paths = [];
|
| 147 |
let appAsarPresent = false;
|
|
|
|
| 164 |
webbridgeSize,
|
| 165 |
webbridgeVersion,
|
| 166 |
classification: classifyKimiSurface(paths),
|
| 167 |
+
execSubstrate: probeExecSubstrate(resourcesResourcesDir),
|
| 168 |
};
|
| 169 |
}
|
| 170 |
|
|
|
|
| 200 |
['detects-bridge-protocol', c.found.bridgeProtocol],
|
| 201 |
['hbp-rows-only', emitSurfaceRows({ classification: c }).every((row) => row.endsWith('|json=0') && !row.includes('\n'))],
|
| 202 |
['channels-extract', extractBridgeChannels('GET_WORKSPACE_ROOT INSTALL_SKILL OPEN_AS_TEXT').length === 3],
|
| 203 |
+
['detects-exec-substrate', classifyExecSubstrate({ daimonBundle: { present: true, size: 527 } }).daimonBundle.present
|
| 204 |
+
&& classifyExecSubstrate({ daimonBundle: { present: true, size: 527 } }).gatewayAsar.present === false],
|
| 205 |
+
['exec-row-emitted', emitSurfaceRows({ classification: c, execSubstrate: classifyExecSubstrate({ daimonBundle: { present: true, size: 5 } }) })
|
| 206 |
+
.some((row) => row.startsWith('KIMISURFACEEXEC|') && row.includes('daimon_bundle_present=1'))],
|
| 207 |
].map(([name, ok]) => ({ name, ok: Boolean(ok) }));
|
| 208 |
return { ok: checks.every((c) => c.ok), checks };
|
| 209 |
}
|
tools/behcs/kimi-desktop-surface-scan.mjs.sha256
CHANGED
|
@@ -1 +1 @@
|
|
| 1 |
-
|
|
|
|
| 1 |
+
521f678f4547ed98a601f77ea1e6873d326eb02a769163a80c26fef88d5860e2 kimi-desktop-surface-scan.mjs
|