apt-mcp-agent-setup 3.2.5 → 3.2.6
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 +109 -109
- package/bin/cli.js +1 -1
- package/bundle/NOTICES.md +0 -0
- package/bundle/core.enc +0 -0
- package/bundle/mcp-rules.enc +0 -0
- package/bundle/skills-aso.enc +0 -0
- package/bundle/skills-ba.enc +0 -0
- package/bundle/skills-base.enc +0 -0
- package/bundle/skills-be.enc +0 -0
- package/bundle/skills-design.enc +0 -0
- package/bundle/skills-fe.enc +0 -0
- package/bundle/skills-mobile.enc +0 -0
- package/bundle/skills-pm.enc +0 -0
- package/integrity-manifest.json +78 -77
- package/package.json +1 -1
- package/release-check.js +318 -310
- package/src/backends/browser-tools-0.0.82.json +375 -375
- package/src/backends/browser-tools.js +1 -1
- package/src/backends/codegraph-1.6.0.json +180 -180
- package/src/backends/index-command.js +1 -1
- package/src/backends/index-store.js +1 -1
- package/src/backends/profiles.js +1 -1
- package/src/backends/review_graph.py +30 -30
- package/src/core/aso-import.js +1 -1
- package/src/core/catalog.js +1 -1
- package/src/core/codex-host-metadata.js +1 -1
- package/src/core/context-metrics.js +1 -1
- package/src/core/doctor.js +1 -1
- package/src/core/execution.js +1 -1
- package/src/core/hook-bridge.js +1 -1
- package/src/core/host-adapters.js +1 -1
- package/src/core/memory-store.js +1 -1
- package/src/core/model-inventory.js +1 -1
- package/src/core/model-routing.js +1 -1
- package/src/core/npm-cli.js +1 -1
- package/src/core/owned-lock.js +1 -1
- package/src/core/presentations.js +1 -1
- package/src/core/quality.js +1 -1
- package/src/core/runtime-info.js +1 -0
- package/src/core/session.js +1 -1
- package/src/core/skill-names.js +1 -1
- package/src/core/workspace-path.js +1 -1
- package/src/core/xlsx-reader.py +62 -62
- package/src/installer/bounded-command.js +1 -1
- package/src/installer/context-legacy-hashes.json +42 -42
- package/src/installer/global-setup.js +1 -1
- package/src/installer/host-hooks.js +1 -1
- package/src/installer/managed-config.js +1 -1
- package/src/installer/platform-config.js +1 -1
- package/src/installer/prerequisites.js +1 -1
- package/src/installer/presentations-requirements.txt +14 -14
- package/src/installer/presentations.js +1 -1
- package/src/installer/project-setup.js +1 -1
- package/src/installer/runtime-lock.js +1 -1
- package/src/installer/runtime-store.js +1 -1
- package/src/installer/setup-wizard.js +1 -1
- package/src/license/crypto.js +1 -1
- package/src/license/fingerprint.js +1 -1
- package/src/license/terms.js +1 -1
- package/src/license/verify.js +1 -1
- package/src/presets/index.js +1 -1
- package/src/proxy/backends.js +1 -1
- package/src/proxy/browser-sessions.js +1 -1
- package/src/proxy/core-tools.js +1 -1
- package/src/proxy/pipeline.js +1 -1
- package/src/proxy/router.config.js +1 -1
- package/src/proxy/router.js +1 -1
- package/src/proxy/server.js +1 -1
- package/src/templates/AGENTS.md +13 -13
- package/src/templates/CLAUDE.md +13 -13
- package/src/templates/GEMINI.md +13 -13
- package/src/templates/apt-runtime.md +16 -16
- package/src/templates/copilot-instructions.md +13 -13
- package/src/templates/cursorrules.mdc +18 -18
- package/src/templates/design-config.md +52 -52
- package/src/templates/gdrive-config.md +57 -57
- package/src/templates/mcp-tools.md +18 -18
- package/src/templates/windsurfrules.md +13 -13
package/release-check.js
CHANGED
|
@@ -2,50 +2,55 @@
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const os = require('os');
|
|
4
4
|
const crypto = require('crypto');
|
|
5
|
-
const { spawn, spawnSync, execFileSync } = require('child_process');
|
|
5
|
+
const { spawn, spawnSync, execFileSync } = require('child_process');
|
|
6
6
|
const assert = require('assert/strict');
|
|
7
7
|
|
|
8
8
|
// Standalone: this file is also shipped as the signed dist prepublish gate.
|
|
9
|
-
async function handshake(installed, workspace, fixture, realBackends = false, launcherArgs = [installed.launcherPath, '--path', workspace]) {
|
|
10
|
-
const child = spawn(process.execPath, ['--require', fixture, ...launcherArgs], {
|
|
9
|
+
async function handshake(installed, workspace, fixture, realBackends = false, launcherArgs = [installed.launcherPath, '--path', workspace]) {
|
|
10
|
+
const child = spawn(process.execPath, ['--require', fixture, ...launcherArgs], {
|
|
11
11
|
windowsHide: true,
|
|
12
|
-
env: { ...process.env, APT_TEST_RELEASE: installed.path, APT_GATE_REAL: realBackends ? '1' : '0', MCP_SKIP_LICENSE_CHECK: '1', MCP_SKIP_INTEGRITY_CHECK: '0' },
|
|
12
|
+
env: { ...process.env, APT_TEST_RELEASE: installed.path, APT_GATE_REAL: realBackends ? '1' : '0', MCP_SKIP_LICENSE_CHECK: '1', MCP_SKIP_INTEGRITY_CHECK: '0' },
|
|
13
13
|
stdio: ['pipe', 'pipe', 'pipe']
|
|
14
14
|
});
|
|
15
|
-
let buffer = '', stderr = '', initialized = false, listed = false;
|
|
16
|
-
const checkBootstrappedWorkspace = message => {
|
|
17
|
-
const content = message.result?.content?.find(item => item.type === 'text');
|
|
18
|
-
assert.ok(content, 'Missing bootstrap result');
|
|
19
|
-
const
|
|
20
|
-
const
|
|
15
|
+
let buffer = '', stderr = '', initialized = false, listed = false;
|
|
16
|
+
const checkBootstrappedWorkspace = message => {
|
|
17
|
+
const content = message.result?.content?.find(item => item.type === 'text');
|
|
18
|
+
assert.ok(content, 'Missing bootstrap result');
|
|
19
|
+
const bootstrap = JSON.parse(content.text);
|
|
20
|
+
const actual = bootstrap.workspace;
|
|
21
|
+
const identity = value => process.platform === 'win32' ? path.resolve(value).toLowerCase() : path.resolve(value);
|
|
21
22
|
assert.equal(identity(actual), identity(fs.realpathSync(workspace)), 'Launcher ignored its workspace binding');
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
['
|
|
29
|
-
['
|
|
30
|
-
['
|
|
31
|
-
['
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
};
|
|
23
|
+
assert.equal(bootstrap.runtime.loadedVersion, installed.version, 'Bootstrap did not report the extracted runtime version');
|
|
24
|
+
assert.equal(bootstrap.runtime.currentVersion, installed.version, 'Bootstrap read the wrong runtime root');
|
|
25
|
+
assert.equal(bootstrap.runtime.currentDigest, installed.digest, 'Bootstrap read a different runtime pointer');
|
|
26
|
+
assert.equal(bootstrap.runtime.bindingSource, 'explicit', 'Launcher lost the explicit --path binding');
|
|
27
|
+
};
|
|
28
|
+
const checks = realBackends ? [
|
|
29
|
+
['session_bootstrap', {sessionId:'package-gate'}, checkBootstrappedWorkspace],
|
|
30
|
+
['model_list', {sessionId:'package-gate'}, /sources/],
|
|
31
|
+
['code_search', {query:'callee'}, /callee/],
|
|
32
|
+
['find_callers', {symbol:'callee'}, /caller/],
|
|
33
|
+
['find_callees', {symbol:'caller'}, /callee/],
|
|
34
|
+
['explore_code', {query:'callee'}, /callee/],
|
|
35
|
+
['list_code_files', {pattern:'sample.py'}, /sample\.py/],
|
|
36
|
+
['impact_analysis', {changed_files:['sample.py'],repo_root:workspace}, /sample\.py/]
|
|
37
|
+
] : [['session_bootstrap', {sessionId:'package-gate'}, checkBootstrappedWorkspace]];
|
|
38
|
+
checks.push(['route_request', {sessionId:'package-gate',requestId:'package-readonly-route',
|
|
39
|
+
prompt:'Read-only inspection of Node.js backend sample.js. This is not a web or mobile application. Do not edit source.',
|
|
40
|
+
stack:'nodejs',target:'sample.js'}, message => {
|
|
41
|
+
const result = JSON.parse(message.result.content.find(item => item.type === 'text').text);
|
|
42
|
+
assert.equal(result.pipeline, 'read-only', 'Negated edit instruction was routed as a change');
|
|
43
|
+
assert.equal(result.authorizesEdits, false);
|
|
44
|
+
assert.notEqual(result.workflow, 'implement');
|
|
45
|
+
}]);
|
|
46
|
+
let completed = 0;
|
|
47
|
+
const send = message => child.stdin.write(JSON.stringify({ jsonrpc: '2.0', ...message }) + '\n');
|
|
48
|
+
const next = () => {
|
|
49
|
+
if (completed === checks.length) return child.stdin.end();
|
|
50
|
+
send({id:3+completed,method:'tools/call',params:{name:checks[completed][0],arguments:checks[completed][1]}});
|
|
51
|
+
};
|
|
47
52
|
await new Promise((resolve, reject) => {
|
|
48
|
-
const timer = setTimeout(() => fail(new Error(`Launcher handshake/EOF timed out: ${stderr}`)), realBackends ? 120000 : 20000);
|
|
53
|
+
const timer = setTimeout(() => fail(new Error(`Launcher handshake/EOF timed out: ${stderr}`)), realBackends ? 120000 : 20000);
|
|
49
54
|
const fail = error => { clearTimeout(timer); child.kill(); reject(error); };
|
|
50
55
|
child.on('error', fail);
|
|
51
56
|
child.stdin.on('error', fail);
|
|
@@ -65,139 +70,142 @@ async function handshake(installed, workspace, fixture, realBackends = false, la
|
|
|
65
70
|
send({ id: 2, method: 'tools/list', params: {} });
|
|
66
71
|
} else if (message.id === 2) {
|
|
67
72
|
assert.ok(initialized);
|
|
68
|
-
for (const name of ['session_bootstrap', 'route_request', 'model_list', 'context_load', 'pipeline_status']) {
|
|
73
|
+
for (const name of ['session_bootstrap', 'route_request', 'model_list', 'context_load', 'pipeline_status']) {
|
|
69
74
|
assert.ok(message.result?.tools?.some(tool => tool.name === name), `Missing ${name}: ${JSON.stringify(message)}`);
|
|
70
75
|
}
|
|
71
|
-
listed = true;
|
|
72
|
-
next();
|
|
73
|
-
} else if (message.id === 3 + completed && completed < checks.length) {
|
|
74
|
-
assert.ok(!message.error && !message.result?.isError, `${JSON.stringify(message)}\n${stderr}`);
|
|
75
|
-
const check = checks[completed][2];
|
|
76
|
-
if (typeof check === 'function') check(message);
|
|
77
|
-
else assert.match(JSON.stringify(message.result), check);
|
|
78
|
-
completed++;
|
|
79
|
-
next();
|
|
76
|
+
listed = true;
|
|
77
|
+
next();
|
|
78
|
+
} else if (message.id === 3 + completed && completed < checks.length) {
|
|
79
|
+
assert.ok(!message.error && !message.result?.isError, `${JSON.stringify(message)}\n${stderr}`);
|
|
80
|
+
const check = checks[completed][2];
|
|
81
|
+
if (typeof check === 'function') check(message);
|
|
82
|
+
else assert.match(JSON.stringify(message.result), check);
|
|
83
|
+
completed++;
|
|
84
|
+
next();
|
|
80
85
|
}
|
|
81
86
|
}
|
|
82
87
|
} catch (error) { fail(error); }
|
|
83
88
|
});
|
|
84
89
|
child.on('close', code => {
|
|
85
90
|
clearTimeout(timer);
|
|
86
|
-
try { assert.equal(code, 0, stderr); assert.ok(initialized && listed, `No complete MCP handshake: ${stderr}`); assert.equal(completed,checks.length); assert.equal(buffer, ''); resolve(); }
|
|
91
|
+
try { assert.equal(code, 0, stderr); assert.ok(initialized && listed, `No complete MCP handshake: ${stderr}`); assert.equal(completed,checks.length); assert.equal(buffer, ''); resolve(); }
|
|
87
92
|
catch (error) { reject(error); }
|
|
88
93
|
});
|
|
89
94
|
send({ id: 1, method: 'initialize', params: { protocolVersion: '2024-11-05', capabilities: {}, clientInfo: { name: 'apt-package-gate', version: '1' } } });
|
|
90
95
|
});
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function verifyPackagedQualityGate(installed, temp) {
|
|
94
|
-
const { assessReport } = require(path.join(installed.path, 'src/core/quality.js'));
|
|
95
|
-
const flutterStart = { type: 'testStart', test: { id: 1, name: 'native behavior' } };
|
|
96
|
-
const flutterDone = { type: 'testDone', testID: 1, result: 'success', skipped: false, hidden: false };
|
|
97
|
-
const completed = { type: 'done', success: true };
|
|
98
|
-
const flutterResult = events => assessReport('flutter-machine', events.map(event => JSON.stringify(event)).join('\n'),
|
|
99
|
-
{ format: 'flutter-machine', testIds: ['native behavior'] }).status;
|
|
100
|
-
assert.equal(flutterResult([flutterStart, flutterDone, completed]), 'passed');
|
|
101
|
-
assert.equal(flutterResult([flutterStart, { ...flutterDone, skipped: true }, completed]), 'unverified');
|
|
102
|
-
assert.equal(flutterResult([flutterStart, { ...flutterDone, hidden: true }, completed]), 'unverified');
|
|
103
|
-
assert.equal(flutterResult([flutterStart, flutterDone]), 'unverified');
|
|
104
|
-
assert.notEqual(flutterResult([flutterStart, flutterDone, { ...completed, success: false }]), 'passed');
|
|
105
|
-
const { PipelineManager } = require(path.join(installed.path, 'src/proxy/pipeline.js'));
|
|
106
|
-
const workspace = path.join(temp, 'quality workspace');
|
|
107
|
-
fs.mkdirSync(workspace);
|
|
108
|
-
fs.writeFileSync(path.join(workspace, 'code.js'), 'exports.add = (a, b) => a + b;\n');
|
|
109
|
-
fs.writeFileSync(path.join(workspace, 'check.test.js'),
|
|
110
|
-
"const { test } = require('node:test'); const assert = require('node:assert/strict'); test('adds', () => assert.equal(require('./code').add(2, 3), 5));\n");
|
|
111
|
-
fs.writeFileSync(path.join(workspace, 'failing.test.js'),
|
|
112
|
-
"const { test } = require('node:test'); const assert = require('node:assert/strict'); test('adds', () => assert.equal(require('./code').add(2, 3), 6));\n");
|
|
113
|
-
fs.writeFileSync(path.join(workspace, 'package.json'), JSON.stringify({ scripts: {
|
|
114
|
-
test: 'node --test --test-reporter=tap check.test.js'
|
|
115
|
-
} }));
|
|
116
|
-
for (const skill of ['review', 'testing-patterns', 'tdd-loop', 'code-review-checklist']) {
|
|
117
|
-
const folder = path.join(workspace, '.agents', 'skills', skill);
|
|
118
|
-
fs.mkdirSync(folder, { recursive: true });
|
|
119
|
-
fs.writeFileSync(path.join(folder, 'SKILL.md'), skill);
|
|
120
|
-
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function verifyPackagedQualityGate(installed, temp) {
|
|
99
|
+
const { assessReport } = require(path.join(installed.path, 'src/core/quality.js'));
|
|
100
|
+
const flutterStart = { type: 'testStart', test: { id: 1, name: 'native behavior' } };
|
|
101
|
+
const flutterDone = { type: 'testDone', testID: 1, result: 'success', skipped: false, hidden: false };
|
|
102
|
+
const completed = { type: 'done', success: true };
|
|
103
|
+
const flutterResult = events => assessReport('flutter-machine', events.map(event => JSON.stringify(event)).join('\n'),
|
|
104
|
+
{ format: 'flutter-machine', testIds: ['native behavior'] }).status;
|
|
105
|
+
assert.equal(flutterResult([flutterStart, flutterDone, completed]), 'passed');
|
|
106
|
+
assert.equal(flutterResult([flutterStart, { ...flutterDone, skipped: true }, completed]), 'unverified');
|
|
107
|
+
assert.equal(flutterResult([flutterStart, { ...flutterDone, hidden: true }, completed]), 'unverified');
|
|
108
|
+
assert.equal(flutterResult([flutterStart, flutterDone]), 'unverified');
|
|
109
|
+
assert.notEqual(flutterResult([flutterStart, flutterDone, { ...completed, success: false }]), 'passed');
|
|
110
|
+
const { PipelineManager } = require(path.join(installed.path, 'src/proxy/pipeline.js'));
|
|
111
|
+
const workspace = path.join(temp, 'quality workspace');
|
|
112
|
+
fs.mkdirSync(workspace);
|
|
113
|
+
fs.writeFileSync(path.join(workspace, 'code.js'), 'exports.add = (a, b) => a + b;\n');
|
|
114
|
+
fs.writeFileSync(path.join(workspace, 'check.test.js'),
|
|
115
|
+
"const { test } = require('node:test'); const assert = require('node:assert/strict'); test('adds', () => assert.equal(require('./code').add(2, 3), 5));\n");
|
|
116
|
+
fs.writeFileSync(path.join(workspace, 'failing.test.js'),
|
|
117
|
+
"const { test } = require('node:test'); const assert = require('node:assert/strict'); test('adds', () => assert.equal(require('./code').add(2, 3), 6));\n");
|
|
118
|
+
fs.writeFileSync(path.join(workspace, 'package.json'), JSON.stringify({ scripts: {
|
|
119
|
+
test: 'node --test --test-reporter=tap check.test.js'
|
|
120
|
+
} }));
|
|
121
|
+
for (const skill of ['review', 'testing-patterns', 'tdd-loop', 'code-review-checklist']) {
|
|
122
|
+
const folder = path.join(workspace, '.agents', 'skills', skill);
|
|
123
|
+
fs.mkdirSync(folder, { recursive: true });
|
|
124
|
+
fs.writeFileSync(path.join(folder, 'SKILL.md'), skill);
|
|
125
|
+
}
|
|
121
126
|
const manager = new PipelineManager(workspace);
|
|
122
127
|
manager.env = { ...process.env }; delete manager.env.NODE_TEST_CONTEXT;
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
assert.
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
assert.
|
|
136
|
-
assert.equal(
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
assert.equal(
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
const
|
|
156
|
-
command: ['
|
|
157
|
-
assert.equal(
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
assert.equal(
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
const
|
|
170
|
-
action: 'review', review: { stage: 'technical', verdict
|
|
171
|
-
findings: [{ id: 'regression', required:
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
assert.equal(
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
assert.equal(
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
assert.equal(
|
|
186
|
-
assert.equal(checkpoint(reviewer, { evidenceIds: [
|
|
187
|
-
|
|
128
|
+
const malformed = manager.start({ task: 'wrong-workspace', pipeline: 'readonly', workspace: workspace });
|
|
129
|
+
assert.equal(malformed.code, 'INVALID_WORKSPACE');
|
|
130
|
+
assert.equal(manager.pendingCreations('wrong-workspace').length, 0);
|
|
131
|
+
const plan = { criteria: [{ id: 'adds', expectedOutcome: 'add(2,3) is 5', source: 'user-request', checkIds: ['add-test'] }],
|
|
132
|
+
checks: [{ id: 'add-test', criterionIds: ['adds'], format: 'node-tap', testIds: ['adds'], required: true }],
|
|
133
|
+
reviews: [{ id: 'technical', required: true }] };
|
|
134
|
+
const start = options => manager.start({ task: options.task, pipeline: 'hotfix', sessionId: 'package-quality',
|
|
135
|
+
acceptanceCriteria: ['add(2,3) is 5'], workspace: { mode: 'current', confirmed: true }, ...options });
|
|
136
|
+
const routed = start({ task: 'web-quality', productImpact: true, productTarget: 'web' });
|
|
137
|
+
assert.equal(routed.success, true, JSON.stringify(routed));
|
|
138
|
+
const routedState = manager.readRun('web-quality', routed.runId);
|
|
139
|
+
assert.deepEqual(routedState.quality.plan.platforms, [{ id: 'web', checkIds: ['platform-web'] }]);
|
|
140
|
+
assert.ok(routedState.quality.plan.reviews.some(item => item.id === 'product'));
|
|
141
|
+
assert.equal(start({ task: 'web-bypass', qualityPlan: plan, productImpact: true, productTarget: 'web' }).code, 'INVALID_QUALITY_PLAN');
|
|
142
|
+
const lowered = start({ task: 'web-lowered', qualityPlan: plan, productImpact: false });
|
|
143
|
+
assert.equal(lowered.code, 'ACCEPTANCE_ALREADY_ACTIVE');
|
|
144
|
+
assert.equal(lowered.task, 'web-quality');
|
|
145
|
+
assert.equal(manager.reset({ task: 'web-quality', runId: routed.runId, sessionId: 'package-quality', confirm: true }).success, true);
|
|
146
|
+
const started = start({ task: 'functional-quality', qualityPlan: plan });
|
|
147
|
+
assert.equal(started.success, true, JSON.stringify(started));
|
|
148
|
+
const base = { task: 'functional-quality', runId: started.runId, sessionId: 'package-quality' };
|
|
149
|
+
let serial = 0;
|
|
150
|
+
const next = () => manager.next({ ...base, requestId: `package-${++serial}` });
|
|
151
|
+
const checkpoint = (attempt, extra = {}) => manager.checkpoint({ ...base, attemptId: attempt.attemptId,
|
|
152
|
+
actorId: attempt.actorId, step: attempt.step, status: 'completed', ...extra });
|
|
153
|
+
assert.equal(checkpoint(next()).success, true);
|
|
154
|
+
const writer = next();
|
|
155
|
+
const unrelated = manager.recordVerification({ ...base, attemptId: writer.attemptId, actorId: writer.actorId,
|
|
156
|
+
command: [process.execPath, '-e', 'process.exit(0)'], checkId: 'add-test' });
|
|
157
|
+
assert.equal(unrelated.evidence.quality.status, 'unverified');
|
|
158
|
+
assert.equal(checkpoint(writer, { evidenceIds: [unrelated.evidence.id] }).code, 'QUALITY_CHECK_REQUIRED');
|
|
159
|
+
const command = [process.execPath, '--test', '--test-reporter=tap', 'check.test.js'];
|
|
160
|
+
const failed = manager.recordVerification({ ...base, attemptId: writer.attemptId, actorId: writer.actorId,
|
|
161
|
+
command: [process.execPath, '--test', '--test-reporter=tap', 'failing.test.js'], checkId: 'add-test', reportFormat: 'node-tap' });
|
|
162
|
+
assert.equal(failed.evidence.quality.status, 'failed');
|
|
163
|
+
const passed = manager.recordVerification({ ...base, attemptId: writer.attemptId, actorId: writer.actorId,
|
|
164
|
+
command: ['npm', 'test'], checkId: 'add-test', reportFormat: 'node-tap' });
|
|
165
|
+
assert.equal(passed.evidence.quality.status, 'passed');
|
|
166
|
+
assert.deepEqual(passed.evidence.command, ['npm', 'test']);
|
|
167
|
+
if (process.platform === 'win32') assert.match(passed.evidence.executedCommand[1], /npm-cli\.js$/);
|
|
168
|
+
assert.equal(checkpoint(writer, { evidenceIds: [passed.evidence.id] }).success, true);
|
|
169
|
+
const reviewer = next();
|
|
170
|
+
const legacy = manager.checkpoint({ ...base, attemptId: reviewer.attemptId, actorId: reviewer.actorId,
|
|
171
|
+
action: 'review', review: { stage: 'quality', verdict: 'pass', reviewedScope: ['code.js'], findings: [] } });
|
|
172
|
+
assert.equal(legacy.code, 'REVIEW_STAGE_NOT_REQUIRED');
|
|
173
|
+
assert.deepEqual(legacy.requiredStages, ['technical']);
|
|
174
|
+
const review = verdict => manager.checkpoint({ ...base, attemptId: reviewer.attemptId, actorId: reviewer.actorId,
|
|
175
|
+
action: 'review', review: { stage: 'technical', verdict, reviewedScope: ['code.js'],
|
|
176
|
+
findings: verdict === 'fail' ? [{ id: 'regression', required: true, severity: 'high', message: 'Review finding remains open' }] : [] } });
|
|
177
|
+
const optional = manager.checkpoint({ ...base, attemptId: reviewer.attemptId, actorId: reviewer.actorId,
|
|
178
|
+
action: 'review', review: { stage: 'technical', verdict: 'pass', reviewedScope: ['code.js'],
|
|
179
|
+
findings: [{ id: 'regression', required: false, severity: 'low', message: 'Optional observation before escalation' }] } });
|
|
180
|
+
assert.equal(optional.success, true);
|
|
181
|
+
const defaultSeverity = manager.checkpoint({ ...base, attemptId: reviewer.attemptId, actorId: reviewer.actorId,
|
|
182
|
+
action: 'review', review: { stage: 'technical', verdict: 'pass', reviewedScope: ['code.js'],
|
|
183
|
+
findings: [{ id: 'regression', required: false, message: 'Implicit normal severity before escalation' }] } });
|
|
184
|
+
assert.equal(defaultSeverity.success, true);
|
|
185
|
+
assert.equal(manager.readRun(base.task, base.runId).quality.findings.regression.severity, 'normal');
|
|
186
|
+
const rejected = review('fail');
|
|
187
|
+
assert.equal(rejected.success, true, JSON.stringify({ reviewer, rejected }));
|
|
188
|
+
const escalated = manager.readRun(base.task, base.runId).quality.findings.regression;
|
|
189
|
+
assert.equal(escalated.required, true, 'A later required finding must promote the existing stable ID');
|
|
190
|
+
assert.equal(escalated.severity, 'high');
|
|
191
|
+
assert.equal(checkpoint(reviewer, { evidenceIds: [rejected.evidence.id] }).code, 'REVIEW_REQUIRED');
|
|
192
|
+
const omitted = review('pass');
|
|
193
|
+
assert.equal(omitted.success, true);
|
|
194
|
+
assert.equal(checkpoint(reviewer, { evidenceIds: [omitted.evidence.id] }).code, 'OPEN_FINDINGS');
|
|
195
|
+
}
|
|
188
196
|
|
|
189
197
|
async function main() {
|
|
190
198
|
const args = process.argv.slice(2);
|
|
191
199
|
const value = name => { const i = args.indexOf(name); return i < 0 ? null : args[i + 1]; };
|
|
192
|
-
const temp = fs.mkdtempSync(path.join(os.tmpdir(), 'apt-package-gate-'));
|
|
193
|
-
const root = path.resolve(__dirname, '..');
|
|
194
|
-
const keep = args.includes('--keep');
|
|
195
|
-
try {
|
|
196
|
-
let dist = value('--dist'), publicKey;
|
|
197
|
-
const archive = value('--package') ? path.resolve(value('--package')) : null;
|
|
198
|
-
if (!dist && !archive) {
|
|
200
|
+
const temp = fs.mkdtempSync(path.join(os.tmpdir(), 'apt-package-gate-'));
|
|
201
|
+
const root = path.resolve(__dirname, '..');
|
|
202
|
+
const keep = args.includes('--keep');
|
|
203
|
+
try {
|
|
204
|
+
let dist = value('--dist'), publicKey;
|
|
205
|
+
const archive = value('--package') ? path.resolve(value('--package')) : null;
|
|
206
|
+
if (!dist && !archive) {
|
|
199
207
|
const build = path.join(temp, 'build'); fs.mkdirSync(build);
|
|
200
|
-
for (const item of ['src', 'bin', 'scripts', '.agents', 'docs', 'test', 'package.json', 'package-lock.json', 'README.md', 'LICENSE', '.npmignore']) {
|
|
208
|
+
for (const item of ['src', 'bin', 'scripts', '.agents', 'docs', 'test', 'package.json', 'package-lock.json', 'README.md', 'LICENSE', '.npmignore']) {
|
|
201
209
|
fs.cpSync(path.join(root, item), path.join(build, item), { recursive: true });
|
|
202
210
|
}
|
|
203
211
|
// Dependencies only; no source fallback and no mutation of the live checkout.
|
|
@@ -212,180 +220,180 @@ async function main() {
|
|
|
212
220
|
finally { fs.closeSync(log); }
|
|
213
221
|
dist = path.join(build, 'dist');
|
|
214
222
|
execFileSync(process.execPath, ['-r', './test/setup.js', '--test', 'test/installer/runtime-store.test.js', 'test/proxy/transport-reliability.test.js'], { cwd: build, windowsHide: true, stdio: 'inherit' });
|
|
215
|
-
} else if (dist) {
|
|
216
|
-
dist = path.resolve(dist);
|
|
217
|
-
publicKey = value('--public-key') ? fs.readFileSync(value('--public-key'), 'utf8') : require(path.join(dist, 'src/license/verify.js')).PRODUCTION_PUBLIC_KEY;
|
|
218
|
-
} else {
|
|
219
|
-
assert.ok(fs.existsSync(archive), `Package archive is missing: ${archive}`);
|
|
220
|
-
publicKey = value('--public-key') ? fs.readFileSync(value('--public-key'), 'utf8') : null;
|
|
221
|
-
}
|
|
222
|
-
let packed;
|
|
223
|
-
if (archive) packed = [{ filename: path.basename(archive) }];
|
|
224
|
-
else {
|
|
225
|
-
const npm = require(path.join(dist, 'src/core/npm-cli.js'))();
|
|
226
|
-
packed = JSON.parse(execFileSync(process.execPath, [npm, 'pack', '--ignore-scripts', '--json', '--pack-destination', temp], { cwd: dist, windowsHide: true, encoding: 'utf8' }));
|
|
227
|
-
}
|
|
228
|
-
execFileSync('tar', ['-xzf', archive || path.join(temp, packed[0].filename), '-C', temp], { windowsHide: true });
|
|
229
|
-
const pkg = path.join(temp, 'package');
|
|
230
|
-
if (!publicKey) publicKey = require(path.join(pkg, 'src/license/verify.js')).PRODUCTION_PUBLIC_KEY;
|
|
231
|
-
const installer = require(path.join(pkg, 'src/installer/runtime-store.js'));
|
|
232
|
-
const hostConfig = require(path.join(pkg, 'src/installer/platform-config.js'));
|
|
233
|
-
const runtimeRoot = path.join(temp, 'runtime tiếng Việt');
|
|
234
|
-
const installed = installer.installRuntime(pkg, { root: runtimeRoot, publicKey });
|
|
235
|
-
verifyPackagedQualityGate(installed, temp);
|
|
236
|
-
const globalConfig = path.join(temp, 'antigravity-global.json');
|
|
237
|
-
const workspaceA = path.join(temp, 'workspace A');
|
|
238
|
-
const workspaceB = path.join(temp, 'workspace B');
|
|
239
|
-
fs.mkdirSync(workspaceA); fs.mkdirSync(workspaceB);
|
|
240
|
-
hostConfig.deployProjectConfig('claude', workspaceA, installed.launcherPath);
|
|
241
|
-
const claudeServer = JSON.parse(fs.readFileSync(path.join(workspaceA, '.mcp.json'), 'utf8')).mcpServers['apt-mcp-agent'];
|
|
242
|
-
assert.equal(claudeServer.command, 'node');
|
|
243
|
-
assert.deepEqual(claudeServer.args, [installed.launcherPath.replace(/\\/g, '/'), '--path', workspaceA.replace(/\\/g, '/')]);
|
|
244
|
-
const { buildHookConfig } = require(path.join(pkg, 'src/core/host-adapters.js'));
|
|
245
|
-
const claudeHooks = buildHookConfig('claude-code', path.join(pkg, 'src/core/hook-bridge.js'), workspaceA).config.hooks;
|
|
246
|
-
for (const event of ['SessionStart', 'PreToolUse']) {
|
|
247
|
-
const handler = claudeHooks[event][0].hooks[0];
|
|
248
|
-
assert.equal(handler.command, 'node');
|
|
249
|
-
assert.deepEqual(handler.args.slice(0, 1), ['-e']);
|
|
250
|
-
const input = { session_id: 'claude-package-gate', cwd: workspaceA, permission_mode: 'default',
|
|
251
|
-
...(event === 'PreToolUse' ? { tool_name: 'Read', tool_input: { file_path: path.join(workspaceA, 'sample.js') } } : {}) };
|
|
252
|
-
const result = spawnSync(handler.command, handler.args, { input: JSON.stringify(input), encoding: 'utf8', timeout: 10000, windowsHide: true });
|
|
253
|
-
assert.equal(result.status, 0, `${event}: ${result.stderr}`);
|
|
254
|
-
assert.ok(JSON.parse(result.stdout));
|
|
255
|
-
}
|
|
256
|
-
const { SessionRuntime } = require(path.join(pkg, 'src/core/session.js'));
|
|
257
|
-
const claudeSession = new SessionRuntime(workspaceA).status({ sessionId: 'claude-package-gate' });
|
|
258
|
-
assert.deepEqual(claudeSession.hookObservations['claude-code'].events.sort(), ['PreToolUse', 'SessionStart']);
|
|
259
|
-
fs.writeFileSync(globalConfig, JSON.stringify({ mcpServers: { custom: { command: 'custom' } } }));
|
|
260
|
-
for (const workspacePath of [workspaceA, workspaceB, workspaceA]) {
|
|
261
|
-
hostConfig.deployProjectConfig('antigravity', workspacePath, installed.launcherPath);
|
|
262
|
-
hostConfig.configureIDE('antigravity', installed.launcherPath, { configPathOverride: globalConfig, projectPath: workspacePath });
|
|
263
|
-
}
|
|
264
|
-
const { workspaceServerAlias } = require(path.join(pkg, 'src/core/workspace-path.js'));
|
|
265
|
-
const aliases = [workspaceA, workspaceB].map(workspaceServerAlias);
|
|
266
|
-
const globalServers = JSON.parse(fs.readFileSync(globalConfig, 'utf8')).mcpServers;
|
|
267
|
-
assert.notEqual(aliases[0], aliases[1]);
|
|
268
|
-
assert.equal(globalServers.custom.command, 'custom');
|
|
269
|
-
const packageHook = require(path.join(pkg, 'src/core/hook-bridge.js'));
|
|
270
|
-
const packageLicense = require(path.join(pkg, 'src/license/verify.js'));
|
|
271
|
-
const savedPublicKey = packageLicense.PRODUCTION_PUBLIC_KEY;
|
|
272
|
-
packageLicense.PRODUCTION_PUBLIC_KEY = publicKey;
|
|
273
|
-
try {
|
|
274
|
-
const signedCli = path.join(installed.path, 'bin/cli.js').replace(/\\/g, '/');
|
|
275
|
-
assert.equal(packageHook.isWriteTool('run_command', { command: `node "${signedCli}" doctor --project .` }, workspaceA), false);
|
|
276
|
-
assert.equal(packageHook.isWriteTool('run_command', { command: `node "${signedCli}" doctor --project . 2>&1` }, workspaceA), false);
|
|
277
|
-
assert.equal(packageHook.isWriteTool('run_command', { command: `node "${signedCli}" doctor --project . 2>&1 > sample.js` }, workspaceA), true);
|
|
278
|
-
assert.equal(packageHook.isWriteTool('run_command', { command: `node "${signedCli}" doctor --project . 2>&1; echo unsafe` }, workspaceA), true);
|
|
279
|
-
assert.equal(packageHook.isWriteTool('run_command', { command: 'npm test 2>&1' }, workspaceA), false);
|
|
280
|
-
assert.equal(packageHook.isWriteTool('run_command', { command: 'git diff 2>&1' }, workspaceA), false);
|
|
281
|
-
assert.equal(packageHook.isWriteTool('run_command', { command: 'npm test 2>&1 > sample.js' }, workspaceA), true);
|
|
282
|
-
assert.equal(packageHook.isWriteTool('run_command', { command: `node "${signedCli}" update --project .` }, workspaceA), true);
|
|
283
|
-
assert.equal(packageHook.isWriteTool('run_command', { command: `node "${signedCli}" doctor --project .; echo unsafe` }, workspaceA), true);
|
|
284
|
-
} finally { packageLicense.PRODUCTION_PUBLIC_KEY = savedPublicKey; }
|
|
285
|
-
for (const [index, workspacePath] of [workspaceA, workspaceB].entries()) {
|
|
286
|
-
assert.deepEqual(globalServers[aliases[index]].args, [installed.launcherPath.replace(/\\/g, '/'), '--path', workspacePath.replace(/\\/g, '/')]);
|
|
287
|
-
const localServers = JSON.parse(fs.readFileSync(path.join(workspacePath, '.agents/mcp_config.json'), 'utf8')).mcpServers;
|
|
288
|
-
assert.ok(localServers[aliases[index]]);
|
|
289
|
-
assert.equal(localServers['apt-mcp-agent'], undefined);
|
|
290
|
-
}
|
|
291
|
-
const metadataWorkspace = path.join(temp, 'codex metadata workspace');
|
|
292
|
-
fs.mkdirSync(metadataWorkspace);
|
|
293
|
-
const metadataScript = path.join(temp, 'codex-metadata-fixture.js');
|
|
294
|
-
const metadataSession = '01a0e102-b189-7b70-bde8-f93a55ac6594';
|
|
295
|
-
const metadataAttempt = 'd5ac530c-8201-423e-b7c9-f2203132ee71';
|
|
296
|
-
const metadataName = `apt_${metadataAttempt.replace(/-/g, '')}`;
|
|
297
|
-
const metadataHome = path.join(temp, 'codex-home');
|
|
298
|
-
const metadataSessions = path.join(metadataHome, 'sessions', '2026', '09', '27');
|
|
299
|
-
fs.mkdirSync(metadataSessions, { recursive: true });
|
|
300
|
-
const metadataChildId = '01a0e103-b7d1-7650-a63b-fe2290282b4e';
|
|
301
|
-
const metadataRollout = path.join(metadataSessions, `rollout-2026-09-27T10-58-32-${metadataChildId}.jsonl`);
|
|
302
|
-
const metadataNow = Math.floor(Date.now() / 1000);
|
|
303
|
-
fs.writeFileSync(metadataRollout, JSON.stringify({ type: 'turn_context', timestamp: new Date().toISOString(),
|
|
304
|
-
payload: { model: 'gpt-6-luna', effort: 'low' } }) + '\n');
|
|
305
|
-
const metadataThread = { id: metadataChildId, model: 'stale-thread-model', reasoningEffort: 'high', path: metadataRollout,
|
|
306
|
-
parentThreadId: metadataSession, cwd: metadataWorkspace, createdAt: metadataNow,
|
|
307
|
-
source: { subAgent: { thread_spawn: { parent_thread_id: metadataSession,
|
|
308
|
-
agent_path: `/root/${metadataName}` } } } };
|
|
309
|
-
fs.writeFileSync(metadataScript, `const readline = require('readline');
|
|
310
|
-
readline.createInterface({ input: process.stdin }).on('line', line => {
|
|
311
|
-
const message = JSON.parse(line);
|
|
312
|
-
if (message.method === 'initialize') process.stdout.write(JSON.stringify({ id: message.id, result: {} }) + '\\n');
|
|
313
|
-
if (message.method === 'thread/list') process.stdout.write(JSON.stringify({ id: message.id,
|
|
314
|
-
result: { data: [${JSON.stringify(metadataThread)}], nextCursor: null } }) + '\\n');
|
|
315
|
-
if (message.method === 'thread/turns/list') process.stdout.write(JSON.stringify({ id: message.id,
|
|
316
|
-
result: { data: [{ status: 'completed', startedAt: ${metadataNow}, completedAt: ${metadataNow + 2} }], nextCursor: null } }) + '\\n');
|
|
317
|
-
});`);
|
|
318
|
-
const metadata = require(path.join(installed.path, 'src/core/codex-host-metadata.js'));
|
|
319
|
-
assert.deepEqual(await metadata.verifyWorker({ workspace: metadataWorkspace, sessionId: metadataSession,
|
|
320
|
-
attemptId: metadataAttempt, nativeTaskName: metadataName, reservedAt: new Date().toISOString() },
|
|
321
|
-
{ command: process.execPath, args: [metadataScript], timeoutMs: 3000, codexHome: metadataHome }),
|
|
322
|
-
{ hostWorkerId: metadataChildId, model: 'gpt-6-luna', reasoningEffort: 'low', source: 'codex-app-server+rollout' });
|
|
223
|
+
} else if (dist) {
|
|
224
|
+
dist = path.resolve(dist);
|
|
225
|
+
publicKey = value('--public-key') ? fs.readFileSync(value('--public-key'), 'utf8') : require(path.join(dist, 'src/license/verify.js')).PRODUCTION_PUBLIC_KEY;
|
|
226
|
+
} else {
|
|
227
|
+
assert.ok(fs.existsSync(archive), `Package archive is missing: ${archive}`);
|
|
228
|
+
publicKey = value('--public-key') ? fs.readFileSync(value('--public-key'), 'utf8') : null;
|
|
229
|
+
}
|
|
230
|
+
let packed;
|
|
231
|
+
if (archive) packed = [{ filename: path.basename(archive) }];
|
|
232
|
+
else {
|
|
233
|
+
const npm = require(path.join(dist, 'src/core/npm-cli.js'))();
|
|
234
|
+
packed = JSON.parse(execFileSync(process.execPath, [npm, 'pack', '--ignore-scripts', '--json', '--pack-destination', temp], { cwd: dist, windowsHide: true, encoding: 'utf8' }));
|
|
235
|
+
}
|
|
236
|
+
execFileSync('tar', ['-xzf', archive || path.join(temp, packed[0].filename), '-C', temp], { windowsHide: true });
|
|
237
|
+
const pkg = path.join(temp, 'package');
|
|
238
|
+
if (!publicKey) publicKey = require(path.join(pkg, 'src/license/verify.js')).PRODUCTION_PUBLIC_KEY;
|
|
239
|
+
const installer = require(path.join(pkg, 'src/installer/runtime-store.js'));
|
|
240
|
+
const hostConfig = require(path.join(pkg, 'src/installer/platform-config.js'));
|
|
241
|
+
const runtimeRoot = path.join(temp, 'runtime tiếng Việt');
|
|
242
|
+
const installed = installer.installRuntime(pkg, { root: runtimeRoot, publicKey });
|
|
243
|
+
verifyPackagedQualityGate(installed, temp);
|
|
244
|
+
const globalConfig = path.join(temp, 'antigravity-global.json');
|
|
245
|
+
const workspaceA = path.join(temp, 'workspace A');
|
|
246
|
+
const workspaceB = path.join(temp, 'workspace B');
|
|
247
|
+
fs.mkdirSync(workspaceA); fs.mkdirSync(workspaceB);
|
|
248
|
+
hostConfig.deployProjectConfig('claude', workspaceA, installed.launcherPath);
|
|
249
|
+
const claudeServer = JSON.parse(fs.readFileSync(path.join(workspaceA, '.mcp.json'), 'utf8')).mcpServers['apt-mcp-agent'];
|
|
250
|
+
assert.equal(claudeServer.command, 'node');
|
|
251
|
+
assert.deepEqual(claudeServer.args, [installed.launcherPath.replace(/\\/g, '/'), '--path', workspaceA.replace(/\\/g, '/')]);
|
|
252
|
+
const { buildHookConfig } = require(path.join(pkg, 'src/core/host-adapters.js'));
|
|
253
|
+
const claudeHooks = buildHookConfig('claude-code', path.join(pkg, 'src/core/hook-bridge.js'), workspaceA).config.hooks;
|
|
254
|
+
for (const event of ['SessionStart', 'PreToolUse']) {
|
|
255
|
+
const handler = claudeHooks[event][0].hooks[0];
|
|
256
|
+
assert.equal(handler.command, 'node');
|
|
257
|
+
assert.deepEqual(handler.args.slice(0, 1), ['-e']);
|
|
258
|
+
const input = { session_id: 'claude-package-gate', cwd: workspaceA, permission_mode: 'default',
|
|
259
|
+
...(event === 'PreToolUse' ? { tool_name: 'Read', tool_input: { file_path: path.join(workspaceA, 'sample.js') } } : {}) };
|
|
260
|
+
const result = spawnSync(handler.command, handler.args, { input: JSON.stringify(input), encoding: 'utf8', timeout: 10000, windowsHide: true });
|
|
261
|
+
assert.equal(result.status, 0, `${event}: ${result.stderr}`);
|
|
262
|
+
assert.ok(JSON.parse(result.stdout));
|
|
263
|
+
}
|
|
264
|
+
const { SessionRuntime } = require(path.join(pkg, 'src/core/session.js'));
|
|
265
|
+
const claudeSession = new SessionRuntime(workspaceA).status({ sessionId: 'claude-package-gate' });
|
|
266
|
+
assert.deepEqual(claudeSession.hookObservations['claude-code'].events.sort(), ['PreToolUse', 'SessionStart']);
|
|
267
|
+
fs.writeFileSync(globalConfig, JSON.stringify({ mcpServers: { custom: { command: 'custom' } } }));
|
|
268
|
+
for (const workspacePath of [workspaceA, workspaceB, workspaceA]) {
|
|
269
|
+
hostConfig.deployProjectConfig('antigravity', workspacePath, installed.launcherPath);
|
|
270
|
+
hostConfig.configureIDE('antigravity', installed.launcherPath, { configPathOverride: globalConfig, projectPath: workspacePath });
|
|
271
|
+
}
|
|
272
|
+
const { workspaceServerAlias } = require(path.join(pkg, 'src/core/workspace-path.js'));
|
|
273
|
+
const aliases = [workspaceA, workspaceB].map(workspaceServerAlias);
|
|
274
|
+
const globalServers = JSON.parse(fs.readFileSync(globalConfig, 'utf8')).mcpServers;
|
|
275
|
+
assert.notEqual(aliases[0], aliases[1]);
|
|
276
|
+
assert.equal(globalServers.custom.command, 'custom');
|
|
277
|
+
const packageHook = require(path.join(pkg, 'src/core/hook-bridge.js'));
|
|
278
|
+
const packageLicense = require(path.join(pkg, 'src/license/verify.js'));
|
|
279
|
+
const savedPublicKey = packageLicense.PRODUCTION_PUBLIC_KEY;
|
|
280
|
+
packageLicense.PRODUCTION_PUBLIC_KEY = publicKey;
|
|
281
|
+
try {
|
|
282
|
+
const signedCli = path.join(installed.path, 'bin/cli.js').replace(/\\/g, '/');
|
|
283
|
+
assert.equal(packageHook.isWriteTool('run_command', { command: `node "${signedCli}" doctor --project .` }, workspaceA), false);
|
|
284
|
+
assert.equal(packageHook.isWriteTool('run_command', { command: `node "${signedCli}" doctor --project . 2>&1` }, workspaceA), false);
|
|
285
|
+
assert.equal(packageHook.isWriteTool('run_command', { command: `node "${signedCli}" doctor --project . 2>&1 > sample.js` }, workspaceA), true);
|
|
286
|
+
assert.equal(packageHook.isWriteTool('run_command', { command: `node "${signedCli}" doctor --project . 2>&1; echo unsafe` }, workspaceA), true);
|
|
287
|
+
assert.equal(packageHook.isWriteTool('run_command', { command: 'npm test 2>&1' }, workspaceA), false);
|
|
288
|
+
assert.equal(packageHook.isWriteTool('run_command', { command: 'git diff 2>&1' }, workspaceA), false);
|
|
289
|
+
assert.equal(packageHook.isWriteTool('run_command', { command: 'npm test 2>&1 > sample.js' }, workspaceA), true);
|
|
290
|
+
assert.equal(packageHook.isWriteTool('run_command', { command: `node "${signedCli}" update --project .` }, workspaceA), true);
|
|
291
|
+
assert.equal(packageHook.isWriteTool('run_command', { command: `node "${signedCli}" doctor --project .; echo unsafe` }, workspaceA), true);
|
|
292
|
+
} finally { packageLicense.PRODUCTION_PUBLIC_KEY = savedPublicKey; }
|
|
293
|
+
for (const [index, workspacePath] of [workspaceA, workspaceB].entries()) {
|
|
294
|
+
assert.deepEqual(globalServers[aliases[index]].args, [installed.launcherPath.replace(/\\/g, '/'), '--path', workspacePath.replace(/\\/g, '/')]);
|
|
295
|
+
const localServers = JSON.parse(fs.readFileSync(path.join(workspacePath, '.agents/mcp_config.json'), 'utf8')).mcpServers;
|
|
296
|
+
assert.ok(localServers[aliases[index]]);
|
|
297
|
+
assert.equal(localServers['apt-mcp-agent'], undefined);
|
|
298
|
+
}
|
|
299
|
+
const metadataWorkspace = path.join(temp, 'codex metadata workspace');
|
|
300
|
+
fs.mkdirSync(metadataWorkspace);
|
|
301
|
+
const metadataScript = path.join(temp, 'codex-metadata-fixture.js');
|
|
302
|
+
const metadataSession = '01a0e102-b189-7b70-bde8-f93a55ac6594';
|
|
303
|
+
const metadataAttempt = 'd5ac530c-8201-423e-b7c9-f2203132ee71';
|
|
304
|
+
const metadataName = `apt_${metadataAttempt.replace(/-/g, '')}`;
|
|
305
|
+
const metadataHome = path.join(temp, 'codex-home');
|
|
306
|
+
const metadataSessions = path.join(metadataHome, 'sessions', '2026', '09', '27');
|
|
307
|
+
fs.mkdirSync(metadataSessions, { recursive: true });
|
|
308
|
+
const metadataChildId = '01a0e103-b7d1-7650-a63b-fe2290282b4e';
|
|
309
|
+
const metadataRollout = path.join(metadataSessions, `rollout-2026-09-27T10-58-32-${metadataChildId}.jsonl`);
|
|
310
|
+
const metadataNow = Math.floor(Date.now() / 1000);
|
|
311
|
+
fs.writeFileSync(metadataRollout, JSON.stringify({ type: 'turn_context', timestamp: new Date().toISOString(),
|
|
312
|
+
payload: { model: 'gpt-6-luna', effort: 'low' } }) + '\n');
|
|
313
|
+
const metadataThread = { id: metadataChildId, model: 'stale-thread-model', reasoningEffort: 'high', path: metadataRollout,
|
|
314
|
+
parentThreadId: metadataSession, cwd: metadataWorkspace, createdAt: metadataNow,
|
|
315
|
+
source: { subAgent: { thread_spawn: { parent_thread_id: metadataSession,
|
|
316
|
+
agent_path: `/root/${metadataName}` } } } };
|
|
317
|
+
fs.writeFileSync(metadataScript, `const readline = require('readline');
|
|
318
|
+
readline.createInterface({ input: process.stdin }).on('line', line => {
|
|
319
|
+
const message = JSON.parse(line);
|
|
320
|
+
if (message.method === 'initialize') process.stdout.write(JSON.stringify({ id: message.id, result: {} }) + '\\n');
|
|
321
|
+
if (message.method === 'thread/list') process.stdout.write(JSON.stringify({ id: message.id,
|
|
322
|
+
result: { data: [${JSON.stringify(metadataThread)}], nextCursor: null } }) + '\\n');
|
|
323
|
+
if (message.method === 'thread/turns/list') process.stdout.write(JSON.stringify({ id: message.id,
|
|
324
|
+
result: { data: [{ status: 'completed', startedAt: ${metadataNow}, completedAt: ${metadataNow + 2} }], nextCursor: null } }) + '\\n');
|
|
325
|
+
});`);
|
|
326
|
+
const metadata = require(path.join(installed.path, 'src/core/codex-host-metadata.js'));
|
|
327
|
+
assert.deepEqual(await metadata.verifyWorker({ workspace: metadataWorkspace, sessionId: metadataSession,
|
|
328
|
+
attemptId: metadataAttempt, nativeTaskName: metadataName, reservedAt: new Date().toISOString() },
|
|
329
|
+
{ command: process.execPath, args: [metadataScript], timeoutMs: 3000, codexHome: metadataHome }),
|
|
330
|
+
{ hostWorkerId: metadataChildId, model: 'gpt-6-luna', reasoningEffort: 'low', source: 'codex-app-server+rollout' });
|
|
323
331
|
fs.writeFileSync(path.join(runtimeRoot, 'updates.json'), JSON.stringify({ checkedAt: Date.now() }));
|
|
324
|
-
const workspace = path.join(temp, 'workspace thử nghiệm'); fs.mkdirSync(path.join(workspace, '.agents'), { recursive: true });
|
|
332
|
+
const workspace = path.join(temp, 'workspace thử nghiệm'); fs.mkdirSync(path.join(workspace, '.agents'), { recursive: true });
|
|
325
333
|
const fixture = path.join(temp, 'backend-fixture.cjs');
|
|
326
|
-
fs.writeFileSync(fixture, `const path = require('path'), Module = require('module');
|
|
334
|
+
fs.writeFileSync(fixture, `const path = require('path'), Module = require('module');
|
|
327
335
|
const root = process.env.APT_TEST_RELEASE, load = Module._load;
|
|
328
336
|
Module._load = function(id, parent, isMain) {
|
|
329
337
|
const result = load.apply(this, arguments);
|
|
330
338
|
const file = Module._resolveFilename(id, parent);
|
|
331
|
-
if (file === path.join(root, 'src/proxy/backends.js')) {
|
|
332
|
-
const original = result.spawnBackends;
|
|
333
|
-
result.spawnBackends = workspace => process.env.APT_GATE_REAL === '1'
|
|
334
|
-
? Object.fromEntries(Object.entries(original(workspace)).filter(([name]) => ['codegraph','code-review-graph','server-memory'].includes(name))) : {};
|
|
335
|
-
}
|
|
339
|
+
if (file === path.join(root, 'src/proxy/backends.js')) {
|
|
340
|
+
const original = result.spawnBackends;
|
|
341
|
+
result.spawnBackends = workspace => process.env.APT_GATE_REAL === '1'
|
|
342
|
+
? Object.fromEntries(Object.entries(original(workspace)).filter(([name]) => ['codegraph','code-review-graph','server-memory'].includes(name))) : {};
|
|
343
|
+
}
|
|
336
344
|
if (file === path.join(root, 'src/proxy/server.js')) result.ProxyServer.prototype.checkLatestVersion = async () => {};
|
|
337
345
|
return result;
|
|
338
|
-
};`);
|
|
339
|
-
for (const [index, workspacePath] of [workspaceA, workspaceB].entries()) {
|
|
340
|
-
await handshake(installed, workspacePath, fixture, false, globalServers[aliases[index]].args);
|
|
341
|
-
}
|
|
342
|
-
await handshake(installed, workspaceA, fixture, false, claudeServer.args);
|
|
343
|
-
await handshake(installed, workspace, fixture);
|
|
346
|
+
};`);
|
|
347
|
+
for (const [index, workspacePath] of [workspaceA, workspaceB].entries()) {
|
|
348
|
+
await handshake(installed, workspacePath, fixture, false, globalServers[aliases[index]].args);
|
|
349
|
+
}
|
|
350
|
+
await handshake(installed, workspaceA, fixture, false, claudeServer.args);
|
|
351
|
+
await handshake(installed, workspace, fixture);
|
|
344
352
|
const good = fs.readFileSync(installed.launcherPath);
|
|
345
|
-
for (const old of ['_0x5e52();', "require('./server.js');"]) {
|
|
353
|
+
for (const old of ['_0x5e52();', "require('./server.js');"]) {
|
|
346
354
|
fs.writeFileSync(installed.launcherPath, old);
|
|
347
355
|
installer.installRuntime(pkg, { root: runtimeRoot, publicKey });
|
|
348
356
|
assert.ok(fs.readFileSync(installed.launcherPath).equals(good));
|
|
349
357
|
const backup = path.join(runtimeRoot, 'launcher-backups', crypto.createHash('sha256').update(old).digest('hex') + '.js');
|
|
350
358
|
assert.equal(fs.readFileSync(backup, 'utf8'), old);
|
|
351
|
-
await handshake(installed, workspace, fixture);
|
|
352
|
-
}
|
|
353
|
-
// Exercise the extracted signed runtime with real pinned backends. No source fallback.
|
|
354
|
-
const realWorkspace = path.join(temp, 'real backend workspace');
|
|
355
|
-
fs.mkdirSync(realWorkspace);
|
|
356
|
-
fs.writeFileSync(path.join(realWorkspace, 'sample.py'), 'def callee():\n return 1\ndef caller():\n return callee()\n');
|
|
357
|
-
const indexCli = path.join(installed.path, 'src/backends/index-store.js');
|
|
358
|
-
const reportFile = path.join(realWorkspace, '.agents/runtime/backends/index-build-last.json');
|
|
359
|
-
for (let cycle = 0; cycle < 3; cycle++) {
|
|
360
|
-
if (cycle === 2) {
|
|
361
|
-
// Cross CodeGraph's 500-file tool visibility boundary on restart.
|
|
362
|
-
const sources=path.join(realWorkspace,'sources'); fs.mkdirSync(sources);
|
|
363
|
-
for (let i=0;i<500;i++) fs.writeFileSync(path.join(sources,`unit_${i}.py`), `def fixture_${i}():\n return ${i}\n`);
|
|
364
|
-
}
|
|
365
|
-
// Simulate the upstream two-minute stale-lock threshold in this fixture.
|
|
366
|
-
// Never age a lock unless its recorded PID is already confirmed dead.
|
|
367
|
-
const nativeLock = path.join(realWorkspace, `.codegraph-${process.platform}-${process.arch}`, 'codegraph.lock');
|
|
368
|
-
if (cycle && fs.existsSync(nativeLock)) {
|
|
369
|
-
const pid = Number(fs.readFileSync(nativeLock, 'utf8'));
|
|
370
|
-
assert.ok(Number.isSafeInteger(pid) && pid > 0);
|
|
371
|
-
assert.throws(() => process.kill(pid, 0), {code:'ESRCH'});
|
|
372
|
-
fs.utimesSync(nativeLock, new Date(0), new Date(0));
|
|
373
|
-
}
|
|
374
|
-
const reviewCache = path.join(realWorkspace, '.agents/.data/graph-2.3.9');
|
|
375
|
-
if (cycle === 1) fs.writeFileSync(path.join(reviewCache, 'graph.db'), 'package recovery fixture');
|
|
376
|
-
execFileSync(process.execPath, [indexCli, realWorkspace], { windowsHide:true, stdio:'inherit', timeout:120000 });
|
|
377
|
-
const report = JSON.parse(fs.readFileSync(reportFile, 'utf8'));
|
|
378
|
-
assert.equal(report.status, 'built');
|
|
379
|
-
assert.equal(report.backends.length, 2);
|
|
380
|
-
for (const backend of report.backends) assert.equal(backend.functionalReady, true);
|
|
381
|
-
if (cycle === 1) {
|
|
382
|
-
const review = report.backends.find(backend=>backend.backend === 'code-review-graph');
|
|
383
|
-
assert.equal(review.recoveryStatus, 'recovered');
|
|
384
|
-
assert.equal(fs.readFileSync(path.join(review.backup, 'graph.db'),'utf8'), 'package recovery fixture');
|
|
385
|
-
}
|
|
386
|
-
await handshake(installed, realWorkspace, fixture, true);
|
|
387
|
-
}
|
|
388
|
-
console.log(`Package gate passed: ${packed[0].filename}; quality policy, fresh install + two repairs, initialize/tools/list/EOF, signature verification enabled.`);
|
|
359
|
+
await handshake(installed, workspace, fixture);
|
|
360
|
+
}
|
|
361
|
+
// Exercise the extracted signed runtime with real pinned backends. No source fallback.
|
|
362
|
+
const realWorkspace = path.join(temp, 'real backend workspace');
|
|
363
|
+
fs.mkdirSync(realWorkspace);
|
|
364
|
+
fs.writeFileSync(path.join(realWorkspace, 'sample.py'), 'def callee():\n return 1\ndef caller():\n return callee()\n');
|
|
365
|
+
const indexCli = path.join(installed.path, 'src/backends/index-store.js');
|
|
366
|
+
const reportFile = path.join(realWorkspace, '.agents/runtime/backends/index-build-last.json');
|
|
367
|
+
for (let cycle = 0; cycle < 3; cycle++) {
|
|
368
|
+
if (cycle === 2) {
|
|
369
|
+
// Cross CodeGraph's 500-file tool visibility boundary on restart.
|
|
370
|
+
const sources=path.join(realWorkspace,'sources'); fs.mkdirSync(sources);
|
|
371
|
+
for (let i=0;i<500;i++) fs.writeFileSync(path.join(sources,`unit_${i}.py`), `def fixture_${i}():\n return ${i}\n`);
|
|
372
|
+
}
|
|
373
|
+
// Simulate the upstream two-minute stale-lock threshold in this fixture.
|
|
374
|
+
// Never age a lock unless its recorded PID is already confirmed dead.
|
|
375
|
+
const nativeLock = path.join(realWorkspace, `.codegraph-${process.platform}-${process.arch}`, 'codegraph.lock');
|
|
376
|
+
if (cycle && fs.existsSync(nativeLock)) {
|
|
377
|
+
const pid = Number(fs.readFileSync(nativeLock, 'utf8'));
|
|
378
|
+
assert.ok(Number.isSafeInteger(pid) && pid > 0);
|
|
379
|
+
assert.throws(() => process.kill(pid, 0), {code:'ESRCH'});
|
|
380
|
+
fs.utimesSync(nativeLock, new Date(0), new Date(0));
|
|
381
|
+
}
|
|
382
|
+
const reviewCache = path.join(realWorkspace, '.agents/.data/graph-2.3.9');
|
|
383
|
+
if (cycle === 1) fs.writeFileSync(path.join(reviewCache, 'graph.db'), 'package recovery fixture');
|
|
384
|
+
execFileSync(process.execPath, [indexCli, realWorkspace], { windowsHide:true, stdio:'inherit', timeout:120000 });
|
|
385
|
+
const report = JSON.parse(fs.readFileSync(reportFile, 'utf8'));
|
|
386
|
+
assert.equal(report.status, 'built');
|
|
387
|
+
assert.equal(report.backends.length, 2);
|
|
388
|
+
for (const backend of report.backends) assert.equal(backend.functionalReady, true);
|
|
389
|
+
if (cycle === 1) {
|
|
390
|
+
const review = report.backends.find(backend=>backend.backend === 'code-review-graph');
|
|
391
|
+
assert.equal(review.recoveryStatus, 'recovered');
|
|
392
|
+
assert.equal(fs.readFileSync(path.join(review.backup, 'graph.db'),'utf8'), 'package recovery fixture');
|
|
393
|
+
}
|
|
394
|
+
await handshake(installed, realWorkspace, fixture, true);
|
|
395
|
+
}
|
|
396
|
+
console.log(`Package gate passed: ${packed[0].filename}; quality policy, fresh install + two repairs, initialize/tools/list/EOF, signature verification enabled.`);
|
|
389
397
|
} finally {
|
|
390
398
|
if (keep) console.log(`Validation artifacts: ${temp}`);
|
|
391
399
|
else fs.rmSync(temp, { recursive: true, force: true });
|