@brunobracaioli/aibrain 0.3.0-beta.7 → 0.4.0-beta.2
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 +80 -15
- package/dist/assets/claude/.claude-plugin/plugin.json +1 -1
- package/dist/assets/claude/hooks/context-compaction.ts +1100 -77
- package/dist/assets/claude/hooks/native-host-contract-runtime.ts +18 -0
- package/dist/assets/claude/hooks/native-host-contract.test.ts +51 -0
- package/dist/assets/codex-context-compaction.mjs +2179 -194
- package/dist/assets/jev-paid-pilot-terminal.mjs +334 -35
- package/dist/claude-compatibility.mjs +506 -0
- package/dist/claude-observation.mjs +117 -3
- package/dist/cli.mjs +105 -28
- package/dist/codex-compatibility.mjs +481 -0
- package/dist/codex-diagnostics.mjs +39 -3
- package/dist/codex-protocol-fingerprint.json +131 -0
- package/dist/engineering-pack-public-key.json +10 -0
- package/dist/engineering-pack.mjs +722 -0
- package/dist/engineering.mjs +194 -0
- package/dist/launch.mjs +71 -14
- package/dist/mcp.mjs +8 -8
- package/dist/package.json +1 -1
- package/dist/platform.mjs +47 -3
- package/package.json +3 -2
|
@@ -16,10 +16,11 @@ export const MAX_LOG_FILES = 3;
|
|
|
16
16
|
const LOCK_WAIT_MS = 250;
|
|
17
17
|
const LOCK_STALE_MS = 30_000;
|
|
18
18
|
const ADMISSION_MS = 60 * 60 * 1000;
|
|
19
|
-
export const ADAPTER_VERSION = '0.
|
|
19
|
+
export const ADAPTER_VERSION = '0.4.0-beta.2';
|
|
20
20
|
const MAX_DIAGNOSTIC_COUNT = 10_000_000;
|
|
21
21
|
const MAX_DIAGNOSTIC_BYTES = 128 * 1024 * 1024;
|
|
22
22
|
const CHECKPOINT_BACKENDS = new Set(['native_store', 'private_file']);
|
|
23
|
+
const PROVIDER_RESPONSE_FORMATS = new Set(['structured', 'text', 'both', 'missing']);
|
|
23
24
|
const DIAGNOSTIC_REASONS = new Set([
|
|
24
25
|
'all_recent',
|
|
25
26
|
'goal_missing',
|
|
@@ -38,6 +39,27 @@ const DIAGNOSTIC_REASONS = new Set([
|
|
|
38
39
|
'proof_expired',
|
|
39
40
|
'proof_mismatch',
|
|
40
41
|
'native_fallback_unconfirmed',
|
|
42
|
+
'native_summary_proof_expired',
|
|
43
|
+
'native_summary_host_view_mismatch',
|
|
44
|
+
'native_summary_host_view_ambiguous',
|
|
45
|
+
'native_summary_host_view_unavailable',
|
|
46
|
+
'native_summary_note_read_failed',
|
|
47
|
+
'native_summary_attachment_uncertain',
|
|
48
|
+
'plan_session_mismatch',
|
|
49
|
+
'plan_revision_mismatch',
|
|
50
|
+
'plan_projection_mismatch',
|
|
51
|
+
'plan_options_mismatch',
|
|
52
|
+
'plan_expired',
|
|
53
|
+
'plan_parse_envelope_invalid',
|
|
54
|
+
'plan_parse_metadata_invalid',
|
|
55
|
+
'plan_parse_decisions_invalid',
|
|
56
|
+
'plan_parse_fitting_invalid',
|
|
57
|
+
'plan_parse_stats_invalid',
|
|
58
|
+
'plan_parse_response_too_large',
|
|
59
|
+
'plan_parse_failed',
|
|
60
|
+
'session_changed_during_planning',
|
|
61
|
+
'snapshot_changed_during_planning',
|
|
62
|
+
'historical_notes_changed_during_planning',
|
|
41
63
|
]);
|
|
42
64
|
const ADMISSION_DETAILS = new Set(['state_budget_exceeded', 'shared_admission_denied']);
|
|
43
65
|
const ADMISSION_REASONS = new Set([
|
|
@@ -80,6 +102,7 @@ const CHECKPOINT_ERRORS = new Set([
|
|
|
80
102
|
const COMPACT_ERROR_CODES = new Set([
|
|
81
103
|
'state_budget_exceeded',
|
|
82
104
|
'shared_admission_exceeded',
|
|
105
|
+
'budget_response_invalid',
|
|
83
106
|
'provider_budget_exceeded',
|
|
84
107
|
'provider_unavailable',
|
|
85
108
|
'provider_auth_denied',
|
|
@@ -113,6 +136,8 @@ const DIAGNOSTIC_STAGES = new Set([
|
|
|
113
136
|
'fallback',
|
|
114
137
|
'compact_entry',
|
|
115
138
|
'compact_exit',
|
|
139
|
+
'native_summary_proof',
|
|
140
|
+
'native_fallback_proof',
|
|
116
141
|
'native_error',
|
|
117
142
|
]);
|
|
118
143
|
const DIAGNOSTIC_CATEGORIES = new Set([
|
|
@@ -370,9 +395,19 @@ function isSafeLogRecord(record) {
|
|
|
370
395
|
'request_id',
|
|
371
396
|
'correlation_id',
|
|
372
397
|
'retry_after_ms',
|
|
398
|
+
'proof_expected_count',
|
|
399
|
+
'proof_actual_count',
|
|
400
|
+
'proof_match',
|
|
401
|
+
'proof_match_offset',
|
|
402
|
+
'proof_view_source',
|
|
403
|
+
'proof_api_view_match',
|
|
404
|
+
'proof_api_count',
|
|
405
|
+
'proof_delivery_source',
|
|
406
|
+
'proof_delivery_match_count',
|
|
373
407
|
'byte_count',
|
|
374
408
|
'char_count',
|
|
375
409
|
'rpc_status',
|
|
410
|
+
'provider_response_format',
|
|
376
411
|
'would_keep',
|
|
377
412
|
'applied',
|
|
378
413
|
'provider_confirmed',
|
|
@@ -422,10 +457,26 @@ function isSafeLogRecord(record) {
|
|
|
422
457
|
!Number.isSafeInteger(record.retry_after_ms) ||
|
|
423
458
|
record.retry_after_ms < 0 ||
|
|
424
459
|
record.retry_after_ms > 3_600_000)) ||
|
|
460
|
+
(record.proof_match !== undefined &&
|
|
461
|
+
(typeof record.proof_match !== 'string' ||
|
|
462
|
+
!['exact', 'active_suffix', 'mismatch', 'ambiguous'].includes(record.proof_match))) ||
|
|
463
|
+
(record.proof_view_source !== undefined &&
|
|
464
|
+
(typeof record.proof_view_source !== 'string' ||
|
|
465
|
+
!['default', 'api'].includes(record.proof_view_source))) ||
|
|
466
|
+
(record.proof_api_view_match !== undefined &&
|
|
467
|
+
(typeof record.proof_api_view_match !== 'string' ||
|
|
468
|
+
!['exact', 'mismatch', 'unavailable', 'not_checked'].includes(
|
|
469
|
+
record.proof_api_view_match,
|
|
470
|
+
))) ||
|
|
471
|
+
(record.proof_delivery_source !== undefined &&
|
|
472
|
+
(typeof record.proof_delivery_source !== 'string' ||
|
|
473
|
+
!['atomic_result', 'legacy_append'].includes(record.proof_delivery_source))) ||
|
|
425
474
|
(record.hook_version !== undefined && !validVersion(record.hook_version)) ||
|
|
426
475
|
(record.checkpoint_backend !== undefined &&
|
|
427
476
|
(typeof record.checkpoint_backend !== 'string' ||
|
|
428
|
-
!CHECKPOINT_BACKENDS.has(record.checkpoint_backend)))
|
|
477
|
+
!CHECKPOINT_BACKENDS.has(record.checkpoint_backend))) ||
|
|
478
|
+
(record.provider_response_format !== undefined &&
|
|
479
|
+
!PROVIDER_RESPONSE_FORMATS.has(String(record.provider_response_format)))
|
|
429
480
|
)
|
|
430
481
|
return false;
|
|
431
482
|
for (const key of [
|
|
@@ -441,6 +492,11 @@ function isSafeLogRecord(record) {
|
|
|
441
492
|
'projection_total',
|
|
442
493
|
'selected_count',
|
|
443
494
|
'deferred_count',
|
|
495
|
+
'proof_expected_count',
|
|
496
|
+
'proof_actual_count',
|
|
497
|
+
'proof_match_offset',
|
|
498
|
+
'proof_api_count',
|
|
499
|
+
'proof_delivery_match_count',
|
|
444
500
|
]) {
|
|
445
501
|
const value = record[key];
|
|
446
502
|
const lowerBound = key === 'rpc_status' ? -100_000 : 0;
|
|
@@ -733,8 +789,18 @@ function diagnosticRecord(record) {
|
|
|
733
789
|
'request_id',
|
|
734
790
|
'correlation_id',
|
|
735
791
|
'retry_after_ms',
|
|
792
|
+
'proof_expected_count',
|
|
793
|
+
'proof_actual_count',
|
|
794
|
+
'proof_match',
|
|
795
|
+
'proof_match_offset',
|
|
796
|
+
'proof_view_source',
|
|
797
|
+
'proof_api_view_match',
|
|
798
|
+
'proof_api_count',
|
|
799
|
+
'proof_delivery_source',
|
|
800
|
+
'proof_delivery_match_count',
|
|
736
801
|
'byte_count',
|
|
737
802
|
'rpc_status',
|
|
803
|
+
'provider_response_format',
|
|
738
804
|
'reason',
|
|
739
805
|
]);
|
|
740
806
|
if (
|
|
@@ -745,7 +811,23 @@ function diagnosticRecord(record) {
|
|
|
745
811
|
!MODES.has(String(record.mode)) ||
|
|
746
812
|
!validVersion(record.client_version) ||
|
|
747
813
|
!ISO.test(String(record.observed_at)) ||
|
|
748
|
-
!Number.isFinite(Date.parse(String(record.observed_at)))
|
|
814
|
+
!Number.isFinite(Date.parse(String(record.observed_at))) ||
|
|
815
|
+
(record.proof_match !== undefined &&
|
|
816
|
+
(typeof record.proof_match !== 'string' ||
|
|
817
|
+
!['exact', 'active_suffix', 'mismatch', 'ambiguous'].includes(record.proof_match))) ||
|
|
818
|
+
(record.proof_view_source !== undefined &&
|
|
819
|
+
(typeof record.proof_view_source !== 'string' ||
|
|
820
|
+
!['default', 'api'].includes(record.proof_view_source))) ||
|
|
821
|
+
(record.proof_api_view_match !== undefined &&
|
|
822
|
+
(typeof record.proof_api_view_match !== 'string' ||
|
|
823
|
+
!['exact', 'mismatch', 'unavailable', 'not_checked'].includes(
|
|
824
|
+
record.proof_api_view_match,
|
|
825
|
+
))) ||
|
|
826
|
+
(record.proof_delivery_source !== undefined &&
|
|
827
|
+
(typeof record.proof_delivery_source !== 'string' ||
|
|
828
|
+
!['atomic_result', 'legacy_append'].includes(record.proof_delivery_source))) ||
|
|
829
|
+
(record.provider_response_format !== undefined &&
|
|
830
|
+
!PROVIDER_RESPONSE_FORMATS.has(String(record.provider_response_format)))
|
|
749
831
|
)
|
|
750
832
|
throw new Error('invalid_input');
|
|
751
833
|
/** @type {Record<string, unknown>} */
|
|
@@ -824,6 +906,25 @@ function diagnosticRecord(record) {
|
|
|
824
906
|
throw new Error('invalid_input');
|
|
825
907
|
output.retry_after_ms = record.retry_after_ms;
|
|
826
908
|
}
|
|
909
|
+
for (const key of ['proof_expected_count', 'proof_actual_count', 'proof_match_offset']) {
|
|
910
|
+
const value = record[key];
|
|
911
|
+
if (
|
|
912
|
+
value !== undefined &&
|
|
913
|
+
(typeof value !== 'number' ||
|
|
914
|
+
!Number.isSafeInteger(value) ||
|
|
915
|
+
value < 0 ||
|
|
916
|
+
value > MAX_DIAGNOSTIC_COUNT)
|
|
917
|
+
)
|
|
918
|
+
throw new Error('invalid_input');
|
|
919
|
+
if (value !== undefined) output[key] = value;
|
|
920
|
+
}
|
|
921
|
+
if (record.proof_match !== undefined) output.proof_match = String(record.proof_match);
|
|
922
|
+
if (record.proof_view_source !== undefined)
|
|
923
|
+
output.proof_view_source = String(record.proof_view_source);
|
|
924
|
+
if (record.proof_api_view_match !== undefined)
|
|
925
|
+
output.proof_api_view_match = String(record.proof_api_view_match);
|
|
926
|
+
if (record.proof_delivery_source !== undefined)
|
|
927
|
+
output.proof_delivery_source = String(record.proof_delivery_source);
|
|
827
928
|
if (record.hook_version !== undefined) {
|
|
828
929
|
if (!validVersion(record.hook_version)) throw new Error('invalid_input');
|
|
829
930
|
output.hook_version = record.hook_version;
|
|
@@ -836,6 +937,14 @@ function diagnosticRecord(record) {
|
|
|
836
937
|
throw new Error('invalid_input');
|
|
837
938
|
output.checkpoint_backend = record.checkpoint_backend;
|
|
838
939
|
}
|
|
940
|
+
if (record.provider_response_format !== undefined) {
|
|
941
|
+
if (
|
|
942
|
+
typeof record.provider_response_format !== 'string' ||
|
|
943
|
+
!PROVIDER_RESPONSE_FORMATS.has(record.provider_response_format)
|
|
944
|
+
)
|
|
945
|
+
throw new Error('invalid_input');
|
|
946
|
+
output.provider_response_format = record.provider_response_format;
|
|
947
|
+
}
|
|
839
948
|
for (const key of [
|
|
840
949
|
'duration_ms',
|
|
841
950
|
'item_count',
|
|
@@ -847,6 +956,11 @@ function diagnosticRecord(record) {
|
|
|
847
956
|
'projection_total',
|
|
848
957
|
'selected_count',
|
|
849
958
|
'deferred_count',
|
|
959
|
+
'proof_expected_count',
|
|
960
|
+
'proof_actual_count',
|
|
961
|
+
'proof_match_offset',
|
|
962
|
+
'proof_api_count',
|
|
963
|
+
'proof_delivery_match_count',
|
|
850
964
|
]) {
|
|
851
965
|
const numeric = record[key];
|
|
852
966
|
if (numeric !== undefined) {
|
package/dist/cli.mjs
CHANGED
|
@@ -15,21 +15,38 @@ import {
|
|
|
15
15
|
stateRoot,
|
|
16
16
|
tokenDigest,
|
|
17
17
|
} from './state.mjs';
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
captureLockPlatformCheck,
|
|
20
|
+
nativeVersion,
|
|
21
|
+
platformCheck,
|
|
22
|
+
resolveNative,
|
|
23
|
+
} from './platform.mjs';
|
|
19
24
|
import { launchClaude, launchCodex } from './launch.mjs';
|
|
25
|
+
import { claudeCompatibilityError, resolveClaudeCompatibility } from './claude-compatibility.mjs';
|
|
26
|
+
import { codexCompatibilityError, resolveCodexCompatibility } from './codex-compatibility.mjs';
|
|
20
27
|
import { providerFreeProbe } from './mcp.mjs';
|
|
21
28
|
import { codexPolicyJson, makePolicy, publicPolicy, isProfile } from './policy.mjs';
|
|
22
29
|
import { readDiagnostics } from './claude-observation.mjs';
|
|
23
30
|
import { readCodexDiagnostics } from './codex-diagnostics.mjs';
|
|
31
|
+
import { checkEngineeringLicense, licenseLine, unavailableLicense } from './engineering.mjs';
|
|
32
|
+
import {
|
|
33
|
+
isPackLocale,
|
|
34
|
+
readLastLaunch,
|
|
35
|
+
readStoredLocale,
|
|
36
|
+
resolvePackLocale,
|
|
37
|
+
writeStoredLocale,
|
|
38
|
+
} from './engineering-pack.mjs';
|
|
24
39
|
|
|
25
|
-
const VERSION = '0.
|
|
40
|
+
const VERSION = '0.4.0-beta.2';
|
|
41
|
+
// The command is `aisac`; `aibrain` is an alias installed from the same entry.
|
|
42
|
+
const COMMAND = 'aisac';
|
|
26
43
|
const ENDPOINT = 'https://mcp.ai-brain.aisac.cloud/mcp';
|
|
27
44
|
const PACKAGE_ROOT = dirname(fileURLToPath(import.meta.url));
|
|
28
45
|
const LEGACY_DISCLOSURE_VERSION = 'aibrain-paid-context-v1-2026-10-09';
|
|
29
46
|
|
|
30
47
|
function usage() {
|
|
31
48
|
console.log(
|
|
32
|
-
|
|
49
|
+
`${COMMAND} ${VERSION}\n\nUsage:\n ${COMMAND} setup [--client claude|codex|both] [--context-profile upstream|conservative]\n [--compact-at 1..95] [--keep-threshold 0..1] [--preserve-recent 1..100]\n [--min-reduction 0..1] [--truncate-head-chars 0..4096]\n [--max-state-tokens 1000..25000] [--max-request-tokens 1000..30000]\n [--tool-policy compatible|read_only] [--goal TEXT]\n ${COMMAND} doctor [--json]\n ${COMMAND} status [--json]\n ${COMMAND} disable\n ${COMMAND} setup --undo\n ${COMMAND} claude [-- native-args...]\n ${COMMAND} codex [-- native-args...]\n\nPolicy notes:\n Automatic monitoring asks for compaction at compact-at percent; state/request\n limits are estimated upper bounds and do not override server quotas.\n min-reduction, truncate-head-chars and tool-policy apply only to Claude;\n Codex keeps native compaction and same-session recovery.`,
|
|
33
50
|
);
|
|
34
51
|
console.log(
|
|
35
52
|
'Telemetry: setup --telemetry on|off (omitted preserves the stored choice; fresh defaults off).',
|
|
@@ -37,11 +54,14 @@ function usage() {
|
|
|
37
54
|
console.log(
|
|
38
55
|
'Claude shadow: setup --claude-shadow on|off and --claude-diagnostics on|off (preview stays applied=false).',
|
|
39
56
|
);
|
|
57
|
+
console.log(
|
|
58
|
+
'AISAC Engineering: `aisac claude` loads the licensed method; setup --lang pt-BR|en picks its language; setup and doctor report the license; status stays offline. `aibrain` is an alias of `aisac`.',
|
|
59
|
+
);
|
|
40
60
|
}
|
|
41
61
|
|
|
42
62
|
// Telemetry is opt-in; setup omits the flag to preserve the stored choice.
|
|
43
63
|
function version() {
|
|
44
|
-
console.log(
|
|
64
|
+
console.log(`${COMMAND} ${VERSION}`);
|
|
45
65
|
}
|
|
46
66
|
|
|
47
67
|
async function maskedPrompt() {
|
|
@@ -297,6 +317,26 @@ async function updateLocalOptOut(previous, args) {
|
|
|
297
317
|
return true;
|
|
298
318
|
}
|
|
299
319
|
|
|
320
|
+
/** Store the AISAC Engineering pack language; local only, no network call. @param {'pt-BR' | 'en'} locale */
|
|
321
|
+
async function setPackLocale(locale) {
|
|
322
|
+
const root = await ensureStateRoot();
|
|
323
|
+
await writeStoredLocale(root, locale);
|
|
324
|
+
console.log(
|
|
325
|
+
`AISAC Engineering pack language set to ${locale} for future launches; no network call was made.`,
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/** Offline view of the pack language and the last launch (status, doctor). */
|
|
330
|
+
async function engineeringPackState() {
|
|
331
|
+
const root = stateRoot();
|
|
332
|
+
const stored = await readStoredLocale(root);
|
|
333
|
+
return {
|
|
334
|
+
locale: resolvePackLocale(stored),
|
|
335
|
+
localeSource: stored === null ? 'system' : 'setup',
|
|
336
|
+
lastLaunch: await readLastLaunch(root),
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
|
|
300
340
|
/** @param {string} endpoint */
|
|
301
341
|
function validateEndpoint(endpoint) {
|
|
302
342
|
if (endpoint.length > 2048) throw new Error('endpoint_too_long');
|
|
@@ -372,6 +412,7 @@ async function setup(args) {
|
|
|
372
412
|
'--telemetry',
|
|
373
413
|
'--claude-shadow',
|
|
374
414
|
'--claude-diagnostics',
|
|
415
|
+
'--lang',
|
|
375
416
|
]),
|
|
376
417
|
new Set([
|
|
377
418
|
'--client',
|
|
@@ -383,10 +424,14 @@ async function setup(args) {
|
|
|
383
424
|
'--telemetry',
|
|
384
425
|
'--claude-shadow',
|
|
385
426
|
'--claude-diagnostics',
|
|
427
|
+
'--lang',
|
|
386
428
|
]),
|
|
387
429
|
);
|
|
388
430
|
if (args.includes('--undo') && args.length !== 1)
|
|
389
431
|
throw new Error('setup_undo_cannot_have_options');
|
|
432
|
+
const lang = option(args, '--lang');
|
|
433
|
+
if (lang !== undefined && !isPackLocale(lang)) throw new Error('invalid_lang');
|
|
434
|
+
if (lang !== undefined && args.length === 2) return setPackLocale(lang);
|
|
390
435
|
const previous = await readConfig();
|
|
391
436
|
if (await updateLocalOptOut(previous, args)) return;
|
|
392
437
|
const localOptOut =
|
|
@@ -437,14 +482,20 @@ async function setup(args) {
|
|
|
437
482
|
if ((clients === 'claude' || clients === 'both') && !claude) throw new Error('claude_not_found');
|
|
438
483
|
if ((clients === 'codex' || clients === 'both') && (!codex || !node))
|
|
439
484
|
throw new Error('codex_or_node_not_found');
|
|
440
|
-
const
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
if (
|
|
445
|
-
throw new Error(
|
|
446
|
-
|
|
447
|
-
|
|
485
|
+
const claudeCompatibility =
|
|
486
|
+
(clients === 'claude' || clients === 'both') && claude !== null
|
|
487
|
+
? await resolveClaudeCompatibility(claude, PACKAGE_ROOT)
|
|
488
|
+
: null;
|
|
489
|
+
if (claudeCompatibility?.status === 'rejected')
|
|
490
|
+
throw new Error(claudeCompatibilityError(claudeCompatibility));
|
|
491
|
+
const claudeVersion = claudeCompatibility?.version ?? (claude ? nativeVersion(claude) : null);
|
|
492
|
+
let codexCompatibility = null;
|
|
493
|
+
if (clients === 'codex' || clients === 'both') {
|
|
494
|
+
codexCompatibility = codex ? await resolveCodexCompatibility(codex) : null;
|
|
495
|
+
if (codexCompatibility?.status === 'rejected')
|
|
496
|
+
throw new Error(codexCompatibilityError(codexCompatibility));
|
|
497
|
+
}
|
|
498
|
+
const codexVersion = codexCompatibility?.version ?? (codex ? nativeVersion(codex) : null);
|
|
448
499
|
const config = {
|
|
449
500
|
schemaVersion: selection.v2 ? 2 : 1,
|
|
450
501
|
packageVersion: VERSION,
|
|
@@ -482,6 +533,10 @@ async function setup(args) {
|
|
|
482
533
|
console.log(
|
|
483
534
|
`Configured ${clients} in ${root}. Provider-free access verified; no provider batch was used.`,
|
|
484
535
|
);
|
|
536
|
+
if (lang !== undefined) await setPackLocale(lang);
|
|
537
|
+
// Display only: the server decides again on every pack request (ADR-0047).
|
|
538
|
+
const line = licenseLine(await checkEngineeringLicense(endpoint, token));
|
|
539
|
+
if (line !== null) console.log(line);
|
|
485
540
|
}
|
|
486
541
|
|
|
487
542
|
/** @param {boolean} json */
|
|
@@ -509,19 +564,36 @@ async function doctor(json) {
|
|
|
509
564
|
codex: resolveNative('codex'),
|
|
510
565
|
node: resolveNative('node'),
|
|
511
566
|
};
|
|
512
|
-
const
|
|
513
|
-
|
|
567
|
+
const claudeCompatibility =
|
|
568
|
+
native.claude !== null ? await resolveClaudeCompatibility(native.claude, PACKAGE_ROOT) : null;
|
|
569
|
+
const codexCompatibility =
|
|
570
|
+
native.codex !== null ? await resolveCodexCompatibility(native.codex) : null;
|
|
571
|
+
const rawNativeVersions = {
|
|
572
|
+
claude: claudeCompatibility?.version ?? '',
|
|
514
573
|
codex: native.codex ? nativeVersion(native.codex) : '',
|
|
515
574
|
};
|
|
575
|
+
const nativeVersions = {
|
|
576
|
+
...rawNativeVersions,
|
|
577
|
+
codex: codexCompatibility?.version ?? rawNativeVersions.codex,
|
|
578
|
+
};
|
|
579
|
+
// Optional capability: its state never changes doctor's exit code.
|
|
580
|
+
const engineering = config
|
|
581
|
+
? await checkEngineeringLicense(config.endpoint, config.token)
|
|
582
|
+
: unavailableLicense('not_configured');
|
|
516
583
|
const needsClaude = config?.clientSelection === 'claude' || config?.clientSelection === 'both';
|
|
517
584
|
const needsCodex = config?.clientSelection === 'codex' || config?.clientSelection === 'both';
|
|
585
|
+
const captureLockPlatform = needsCodex ? captureLockPlatformCheck() : null;
|
|
518
586
|
const nativeReady =
|
|
519
587
|
(!needsClaude ||
|
|
520
|
-
(native.claude !== null &&
|
|
588
|
+
(native.claude !== null &&
|
|
589
|
+
(claudeCompatibility?.status === 'qualified' ||
|
|
590
|
+
claudeCompatibility?.status === 'host_checked'))) &&
|
|
521
591
|
(!needsCodex ||
|
|
522
592
|
(native.codex !== null &&
|
|
523
593
|
native.node !== null &&
|
|
524
|
-
|
|
594
|
+
captureLockPlatform?.ok === true &&
|
|
595
|
+
(codexCompatibility?.status === 'qualified' ||
|
|
596
|
+
codexCompatibility?.status === 'protocol_match')));
|
|
525
597
|
const result = {
|
|
526
598
|
version: VERSION,
|
|
527
599
|
platform: platform.ok ? process.platform : platform.code,
|
|
@@ -535,6 +607,16 @@ async function doctor(json) {
|
|
|
535
607
|
node: native.node !== null,
|
|
536
608
|
},
|
|
537
609
|
nativeVersions,
|
|
610
|
+
claudeCompatibility: claudeCompatibility?.status ?? 'unavailable',
|
|
611
|
+
claudeCompatibilityReason: claudeCompatibility?.reason ?? 'claude_not_found',
|
|
612
|
+
claudeCompatibilityVersion: claudeCompatibility?.version ?? null,
|
|
613
|
+
codexCompatibility: codexCompatibility?.status ?? 'unavailable',
|
|
614
|
+
codexCompatibilityReason: codexCompatibility?.reason ?? 'codex_not_found',
|
|
615
|
+
codexCompatibilityVersion: codexCompatibility?.version ?? null,
|
|
616
|
+
captureLockBackend:
|
|
617
|
+
captureLockPlatform?.ok === true
|
|
618
|
+
? 'available'
|
|
619
|
+
: (captureLockPlatform?.code ?? 'not_required'),
|
|
538
620
|
nativeReady,
|
|
539
621
|
context: publicPolicy(policy),
|
|
540
622
|
telemetry: {
|
|
@@ -549,6 +631,8 @@ async function doctor(json) {
|
|
|
549
631
|
config?.claudeObservation?.disclosedAt !== null &&
|
|
550
632
|
config?.claudeObservation?.disclosedAt !== undefined,
|
|
551
633
|
},
|
|
634
|
+
engineering,
|
|
635
|
+
engineeringPack: await engineeringPackState(),
|
|
552
636
|
paidOrPilot: probe?.ok
|
|
553
637
|
? 'provider_free_probe_ok; paid entitlement or pilot invitation remains server-enforced'
|
|
554
638
|
: config
|
|
@@ -584,6 +668,7 @@ async function status(json) {
|
|
|
584
668
|
config?.claudeObservation?.disclosedAt !== null &&
|
|
585
669
|
config?.claudeObservation?.disclosedAt !== undefined,
|
|
586
670
|
},
|
|
671
|
+
engineeringPack: await engineeringPackState(),
|
|
587
672
|
monitoredSession: null,
|
|
588
673
|
monitoringStatus: 'not_observed',
|
|
589
674
|
};
|
|
@@ -643,17 +728,9 @@ async function main(argv) {
|
|
|
643
728
|
throw new Error('disclosure_outdated');
|
|
644
729
|
if (config.clientSelection !== command && config.clientSelection !== 'both')
|
|
645
730
|
throw new Error('client_not_configured');
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
!isTestedNativeVersion('claude', config.claudeVersion))
|
|
650
|
-
)
|
|
651
|
-
throw new Error('claude_version_unverified');
|
|
652
|
-
if (
|
|
653
|
-
command === 'codex' &&
|
|
654
|
-
(typeof config.codexVersion !== 'string' ||
|
|
655
|
-
!isTestedNativeVersion('codex', config.codexVersion))
|
|
656
|
-
)
|
|
731
|
+
// The native executable is authoritative. The stored setup version is
|
|
732
|
+
// metadata only, so patch updates do not block a fresh compatibility check.
|
|
733
|
+
if (command === 'codex' && typeof config.codexVersion !== 'string')
|
|
657
734
|
throw new Error('codex_version_unverified');
|
|
658
735
|
const root = stateRoot();
|
|
659
736
|
const result = await (command === 'claude'
|
|
@@ -688,7 +765,7 @@ main(cliArgs).catch((error) => {
|
|
|
688
765
|
}),
|
|
689
766
|
);
|
|
690
767
|
} else {
|
|
691
|
-
console.error(
|
|
768
|
+
console.error(`${COMMAND}: ${errorMessage(error)}`);
|
|
692
769
|
}
|
|
693
770
|
process.exitCode = 1;
|
|
694
771
|
});
|