@cortexkit/anthropic-auth-core 1.22.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/accounts.d.ts +52 -8
- package/dist/cachekeep.d.ts +27 -1
- package/dist/cch.d.ts +11 -1
- package/dist/claude-code.d.ts +23 -1
- package/dist/claustrum-enrollment.d.ts +72 -0
- package/dist/claustrum-scoped-roster.d.ts +27 -0
- package/dist/claustrum-scoped-runtime.d.ts +31 -0
- package/dist/claustrum-scoped.d.ts +53 -0
- package/dist/claustrum.d.ts +16 -82
- package/dist/commands/account.d.ts +38 -11
- package/dist/constants.d.ts +3 -2
- package/dist/custom-headers.d.ts +3 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +29700 -31
- package/dist/internal-types/LICENSE +21 -0
- package/dist/internal-types/commands/builtins.d.ts +71 -0
- package/dist/internal-types/commands/index.d.ts +10 -0
- package/dist/internal-types/commands/menu.d.ts +61 -0
- package/dist/internal-types/commands/model.d.ts +238 -0
- package/dist/internal-types/commands/pi.d.ts +23 -0
- package/dist/internal-types/commands/seam.d.ts +72 -0
- package/dist/internal-types/fs/refresh-file-lock.d.ts +33 -0
- package/dist/internal-types/logger/capture-sink.d.ts +14 -0
- package/dist/internal-types/logger/engine.d.ts +100 -0
- package/dist/internal-types/logger/index.d.ts +6 -0
- package/dist/internal-types/logger/redact.d.ts +11 -0
- package/dist/internal-types/pi-slot/index.d.ts +3 -0
- package/dist/internal-types/pi-slot/slot.d.ts +49 -0
- package/dist/internal-types/quota/codec.d.ts +11 -0
- package/dist/internal-types/quota/format.d.ts +46 -0
- package/dist/internal-types/quota/index.d.ts +10 -0
- package/dist/internal-types/quota/map.d.ts +63 -0
- package/dist/internal-types/quota/merge.d.ts +48 -0
- package/dist/internal-types/quota/projection.d.ts +64 -0
- package/dist/internal-types/store/attribution.d.ts +28 -0
- package/dist/internal-types/store/errors.d.ts +55 -0
- package/dist/internal-types/store/hooks.d.ts +12 -0
- package/dist/internal-types/store/identity.d.ts +39 -0
- package/dist/internal-types/store/index.d.ts +21 -0
- package/dist/internal-types/store/mutate.d.ts +189 -0
- package/dist/internal-types/store/pool.d.ts +196 -0
- package/dist/internal-types/store/provider-state.d.ts +131 -0
- package/dist/internal-types/store/publication.d.ts +47 -0
- package/dist/internal-types/store/pull.d.ts +36 -0
- package/dist/internal-types/store/refresh-lock.d.ts +63 -0
- package/dist/internal-types/store/refresh.d.ts +72 -0
- package/dist/internal-types/store/rows.d.ts +313 -0
- package/dist/internal-types/store/runtime.d.ts +36 -0
- package/dist/internal-types/store/schema.d.ts +443 -0
- package/dist/internal-types/store/settings.d.ts +63 -0
- package/dist/internal-types/store/torn.d.ts +78 -0
- package/dist/migration-source.d.ts +33 -0
- package/dist/model-remap.d.ts +27 -0
- package/dist/models.d.ts +60 -0
- package/dist/native-account-runtime.d.ts +121 -0
- package/dist/native-account-view.d.ts +126 -0
- package/dist/native-command-effects.d.ts +59 -0
- package/dist/native-credential-validation.d.ts +42 -0
- package/dist/native-custody-activation.d.ts +45 -0
- package/dist/native-custody.d.ts +114 -0
- package/dist/native-enrollment-authority.d.ts +2 -0
- package/dist/native-host-auth-read.d.ts +3 -0
- package/dist/native-host-auth-write.d.ts +51 -0
- package/dist/native-host-auth.d.ts +12 -0
- package/dist/native-local-credential-service.d.ts +76 -0
- package/dist/native-local-runtime-readers.d.ts +22 -0
- package/dist/native-lock-observer.d.ts +12 -0
- package/dist/native-menu-executor.d.ts +243 -0
- package/dist/native-menu-model.d.ts +142 -0
- package/dist/native-migration-proof.d.ts +28 -0
- package/dist/native-migration-source.d.ts +47 -0
- package/dist/native-migration.d.ts +66 -0
- package/dist/native-quota-codec.d.ts +32 -0
- package/dist/native-refresh-coordinator.d.ts +240 -0
- package/dist/native-roster-seed.d.ts +115 -0
- package/dist/native-runtime-registry.d.ts +19 -0
- package/dist/native-runtime.d.ts +204 -0
- package/dist/native-transient-account.d.ts +38 -0
- package/dist/native-ui.d.ts +45 -0
- package/dist/native-usage-publication.d.ts +11 -0
- package/dist/native-vault-admission.d.ts +8 -0
- package/dist/native-vault-connection.d.ts +33 -0
- package/dist/native-vault-paths.d.ts +13 -0
- package/dist/native-vault-runtime.d.ts +102 -0
- package/dist/native-vault-seed.d.ts +16 -0
- package/dist/oauth-profile.d.ts +2 -1
- package/dist/pool-authority.d.ts +159 -0
- package/dist/pool-binding.d.ts +32 -0
- package/dist/pool-paths.d.ts +21 -0
- package/dist/pool-store.d.ts +32 -0
- package/dist/prime.d.ts +11 -3
- package/dist/provider-error.d.ts +139 -0
- package/dist/quota-header-feed.d.ts +13 -0
- package/dist/quota-manager.d.ts +30 -5
- package/dist/relay.d.ts +22 -1
- package/dist/request-history.d.ts +34 -0
- package/dist/sse.d.ts +81 -0
- package/dist/sticky-routing.d.ts +29 -0
- package/package.json +9 -3
- package/dist/accounts.js +0 -3330
- package/dist/auth.js +0 -182
- package/dist/cache1h.js +0 -97
- package/dist/cachekeep-registry.js +0 -124
- package/dist/cachekeep.js +0 -578
- package/dist/cch.js +0 -127
- package/dist/claude-code.js +0 -388
- package/dist/claustrum.js +0 -529
- package/dist/commands/account.js +0 -239
- package/dist/constants.js +0 -82
- package/dist/dump.js +0 -616
- package/dist/fast.js +0 -66
- package/dist/json.js +0 -10
- package/dist/killswitch.js +0 -132
- package/dist/logger.js +0 -286
- package/dist/logging.js +0 -59
- package/dist/mid-conversation-output-config.js +0 -89
- package/dist/models.js +0 -141
- package/dist/network-errors.js +0 -27
- package/dist/oauth-profile.js +0 -54
- package/dist/pkce.js +0 -17
- package/dist/prime.js +0 -823
- package/dist/provider.js +0 -0
- package/dist/quota-header-feed.js +0 -279
- package/dist/quota-headers.js +0 -121
- package/dist/quota-manager.js +0 -805
- package/dist/quotas.js +0 -141
- package/dist/relay.js +0 -1243
- package/dist/routing.js +0 -94
- package/dist/start.js +0 -29
- package/dist/sticky-routing.js +0 -523
- package/dist/thinking-binding.js +0 -54
- package/dist/token-fingerprint.js +0 -8
package/dist/killswitch.js
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import { DEFAULT_KILLSWITCH_THRESHOLDS as DEFAULT_THRESHOLDS, normalizeKillswitchThresholds, } from './accounts.js';
|
|
2
|
-
export const KILLSWITCH_COMMAND_NAME = 'claude-killswitch';
|
|
3
|
-
export function parseKillswitchCommandAction(argumentsText) {
|
|
4
|
-
const parts = argumentsText.trim().split(/\s+/).filter(Boolean);
|
|
5
|
-
if (parts.length === 0)
|
|
6
|
-
return { type: 'status' };
|
|
7
|
-
if (parts.length === 1 && parts[0] === 'on')
|
|
8
|
-
return { type: 'on' };
|
|
9
|
-
if (parts.length === 1 && parts[0] === 'off')
|
|
10
|
-
return { type: 'off' };
|
|
11
|
-
if (parts[0] === 'set') {
|
|
12
|
-
const entries = [];
|
|
13
|
-
for (let i = 1; i < parts.length; i++) {
|
|
14
|
-
const match = parts[i]?.match(/^([^:]+):(\d+),(\d+)(?:,(\d+))?$/);
|
|
15
|
-
if (!match)
|
|
16
|
-
return { type: 'usage' };
|
|
17
|
-
const [, account, fhStr, sdStr, scopedStr] = match;
|
|
18
|
-
const scoped = typeof scopedStr === 'string' && scopedStr.length > 0
|
|
19
|
-
? Number.parseInt(scopedStr, 10)
|
|
20
|
-
: undefined;
|
|
21
|
-
const entry = {
|
|
22
|
-
account,
|
|
23
|
-
fh: Number.parseInt(fhStr, 10),
|
|
24
|
-
sd: Number.parseInt(sdStr, 10),
|
|
25
|
-
};
|
|
26
|
-
if (scoped !== undefined)
|
|
27
|
-
entry.scoped = scoped;
|
|
28
|
-
entries.push(entry);
|
|
29
|
-
}
|
|
30
|
-
if (entries.length === 0)
|
|
31
|
-
return { type: 'usage' };
|
|
32
|
-
return { type: 'set', entries };
|
|
33
|
-
}
|
|
34
|
-
return { type: 'usage' };
|
|
35
|
-
}
|
|
36
|
-
function buildStatusTable(config, accountIds) {
|
|
37
|
-
const enabled = config.enabled === true;
|
|
38
|
-
const lines = [
|
|
39
|
-
'## Killswitch',
|
|
40
|
-
'',
|
|
41
|
-
`Status: **${enabled ? 'ON' : 'OFF'}**`,
|
|
42
|
-
];
|
|
43
|
-
if (enabled) {
|
|
44
|
-
lines.push('');
|
|
45
|
-
lines.push('| Account | 5h threshold | 1w threshold | Scoped |');
|
|
46
|
-
lines.push('| ------- | ------------ | ------------ | ------ |');
|
|
47
|
-
const mainT = normalizeKillswitchThresholds(config.main);
|
|
48
|
-
lines.push(`| main | \u2265 ${mainT.five_hour}% | \u2265 ${mainT.seven_day}% | \u2264 ${mainT.scoped}% |`);
|
|
49
|
-
for (const id of accountIds) {
|
|
50
|
-
const t = normalizeKillswitchThresholds(config.accounts?.[id] ?? config.main);
|
|
51
|
-
lines.push(`| ${id} | \u2265 ${t.five_hour}% | \u2265 ${t.seven_day}% | \u2264 ${t.scoped}% |`);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
return lines.join('\n');
|
|
55
|
-
}
|
|
56
|
-
const USAGE_TEXT = [
|
|
57
|
-
'## Killswitch Commands',
|
|
58
|
-
'',
|
|
59
|
-
'```',
|
|
60
|
-
`/${KILLSWITCH_COMMAND_NAME} — show status`,
|
|
61
|
-
`/${KILLSWITCH_COMMAND_NAME} on — enable with current or default thresholds`,
|
|
62
|
-
`/${KILLSWITCH_COMMAND_NAME} off — disable`,
|
|
63
|
-
`/${KILLSWITCH_COMMAND_NAME} set all:5,10 — set all accounts to 5h≥5%, 1w≥10%`,
|
|
64
|
-
`/${KILLSWITCH_COMMAND_NAME} set main:3,8,0 — set 5h≥3%, 1w≥8%, scoped≤0%`,
|
|
65
|
-
`/${KILLSWITCH_COMMAND_NAME} set main:3,8 work-alt:5,10 — per-account`,
|
|
66
|
-
'```',
|
|
67
|
-
].join('\n');
|
|
68
|
-
export function executeKillswitchCommand(input) {
|
|
69
|
-
const action = parseKillswitchCommandAction(input.argumentsText);
|
|
70
|
-
if (action.type === 'status') {
|
|
71
|
-
const status = buildStatusTable(input.config, input.accountIds);
|
|
72
|
-
return { text: `${status}\n\n${USAGE_TEXT}` };
|
|
73
|
-
}
|
|
74
|
-
if (action.type === 'on') {
|
|
75
|
-
const updated = {
|
|
76
|
-
...input.config,
|
|
77
|
-
enabled: true,
|
|
78
|
-
main: input.config.main ?? {
|
|
79
|
-
five_hour: DEFAULT_THRESHOLDS.five_hour,
|
|
80
|
-
seven_day: DEFAULT_THRESHOLDS.seven_day,
|
|
81
|
-
},
|
|
82
|
-
};
|
|
83
|
-
const status = buildStatusTable(updated, input.accountIds);
|
|
84
|
-
return {
|
|
85
|
-
text: `## Killswitch Enabled\n\n${status}`,
|
|
86
|
-
updatedConfig: updated,
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
if (action.type === 'off') {
|
|
90
|
-
const updated = { ...input.config, enabled: false };
|
|
91
|
-
return {
|
|
92
|
-
text: '## Killswitch Disabled',
|
|
93
|
-
updatedConfig: updated,
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
if (action.type === 'set') {
|
|
97
|
-
const accounts = { ...(input.config.accounts ?? {}) };
|
|
98
|
-
const updated = {
|
|
99
|
-
...input.config,
|
|
100
|
-
enabled: true,
|
|
101
|
-
accounts,
|
|
102
|
-
};
|
|
103
|
-
for (const entry of action.entries) {
|
|
104
|
-
const thresholds = {
|
|
105
|
-
five_hour: entry.fh,
|
|
106
|
-
seven_day: entry.sd,
|
|
107
|
-
};
|
|
108
|
-
if (entry.scoped !== undefined)
|
|
109
|
-
thresholds.scoped = entry.scoped;
|
|
110
|
-
if (entry.account === 'main') {
|
|
111
|
-
updated.main = thresholds;
|
|
112
|
-
}
|
|
113
|
-
else if (entry.account === 'all') {
|
|
114
|
-
updated.main = thresholds;
|
|
115
|
-
for (const id of input.accountIds) {
|
|
116
|
-
accounts[id] = thresholds;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
else {
|
|
120
|
-
accounts[entry.account] = thresholds;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
const status = buildStatusTable(updated, input.accountIds);
|
|
124
|
-
return {
|
|
125
|
-
text: `## Killswitch Updated\n\n${status}`,
|
|
126
|
-
updatedConfig: updated,
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
// usage
|
|
130
|
-
const status = buildStatusTable(input.config, input.accountIds);
|
|
131
|
-
return { text: `${status}\n\n${USAGE_TEXT}` };
|
|
132
|
-
}
|
package/dist/logger.js
DELETED
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
import * as fs from 'node:fs';
|
|
2
|
-
import * as os from 'node:os';
|
|
3
|
-
import * as path from 'node:path';
|
|
4
|
-
const LEVEL_ORDER = {
|
|
5
|
-
error: 0,
|
|
6
|
-
warn: 1,
|
|
7
|
-
info: 2,
|
|
8
|
-
debug: 3,
|
|
9
|
-
trace: 4,
|
|
10
|
-
};
|
|
11
|
-
const VALID_LEVELS = new Set(Object.keys(LEVEL_ORDER));
|
|
12
|
-
function parseLogLevel(value) {
|
|
13
|
-
if (!value)
|
|
14
|
-
return null;
|
|
15
|
-
const normalized = value.trim().toLowerCase();
|
|
16
|
-
return VALID_LEVELS.has(normalized) ? normalized : null;
|
|
17
|
-
}
|
|
18
|
-
const envLevel = parseLogLevel(process.env.OPENCODE_ANTHROPIC_AUTH_LOG_LEVEL);
|
|
19
|
-
let currentLevel = envLevel ?? 'info';
|
|
20
|
-
export function setLogLevel(level) {
|
|
21
|
-
currentLevel = level;
|
|
22
|
-
}
|
|
23
|
-
export function getLogLevel() {
|
|
24
|
-
return currentLevel;
|
|
25
|
-
}
|
|
26
|
-
export { parseLogLevel };
|
|
27
|
-
// -- Emission control ------------------------------------------------------
|
|
28
|
-
export function shouldEmit(level) {
|
|
29
|
-
return LEVEL_ORDER[level] <= LEVEL_ORDER[currentLevel];
|
|
30
|
-
}
|
|
31
|
-
// -- File path -------------------------------------------------------------
|
|
32
|
-
const LOG_FILE = process.env.OPENCODE_ANTHROPIC_AUTH_LOG_FILE ??
|
|
33
|
-
path.join(os.tmpdir(), 'opencode-anthropic-auth.log');
|
|
34
|
-
export function getLogFilePath() {
|
|
35
|
-
return LOG_FILE;
|
|
36
|
-
}
|
|
37
|
-
// -- Rotation --------------------------------------------------------------
|
|
38
|
-
const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5 MB
|
|
39
|
-
const MAX_GENERATIONS = 3;
|
|
40
|
-
function rotateLogFile() {
|
|
41
|
-
try {
|
|
42
|
-
if (!fs.existsSync(LOG_FILE))
|
|
43
|
-
return;
|
|
44
|
-
const stat = fs.statSync(LOG_FILE);
|
|
45
|
-
if (stat.size < MAX_FILE_SIZE)
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
catch {
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
try {
|
|
52
|
-
for (let i = MAX_GENERATIONS; i >= 1; i--) {
|
|
53
|
-
const oldPath = i === 1 ? LOG_FILE : `${LOG_FILE}.${i - 1}`;
|
|
54
|
-
const newPath = `${LOG_FILE}.${i}`;
|
|
55
|
-
try {
|
|
56
|
-
if (i === MAX_GENERATIONS) {
|
|
57
|
-
try {
|
|
58
|
-
fs.unlinkSync(newPath);
|
|
59
|
-
}
|
|
60
|
-
catch {
|
|
61
|
-
// .3 might not exist
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
if (fs.existsSync(oldPath)) {
|
|
65
|
-
fs.renameSync(oldPath, newPath);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
catch {
|
|
69
|
-
// Rotation best-effort — never throw
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
catch {
|
|
74
|
-
// Rotation must never throw
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
// -- Redaction ------------------------------------------------------------
|
|
78
|
-
export const SECRET_KEY_EXACT = /^(authorization|x-api-key|cookie|set-cookie|refresh|access|token)$/i;
|
|
79
|
-
export function isSecretKey(key) {
|
|
80
|
-
if (SECRET_KEY_EXACT.test(key))
|
|
81
|
-
return true;
|
|
82
|
-
const k = key.toLowerCase().replace(/[-_]/g, '');
|
|
83
|
-
if (k.includes('apikey'))
|
|
84
|
-
return true;
|
|
85
|
-
if (k.endsWith('secret') || k.endsWith('password'))
|
|
86
|
-
return true;
|
|
87
|
-
if (k.endsWith('token') && !k.endsWith('tokens'))
|
|
88
|
-
return true;
|
|
89
|
-
return false;
|
|
90
|
-
}
|
|
91
|
-
const REDACT_VALUE_PATTERNS = [
|
|
92
|
-
/Bearer\s+\S+/,
|
|
93
|
-
/sk-[A-Za-z0-9-]+/,
|
|
94
|
-
/eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/,
|
|
95
|
-
];
|
|
96
|
-
function isRedactableValue(value) {
|
|
97
|
-
if (typeof value !== 'string')
|
|
98
|
-
return false;
|
|
99
|
-
return REDACT_VALUE_PATTERNS.some((pattern) => pattern.test(value));
|
|
100
|
-
}
|
|
101
|
-
export function redactPayload(payload) {
|
|
102
|
-
if (payload == null || Object.keys(payload).length === 0)
|
|
103
|
-
return undefined;
|
|
104
|
-
const seen = new WeakSet();
|
|
105
|
-
function walk(value) {
|
|
106
|
-
if (value == null || typeof value !== 'object') {
|
|
107
|
-
if (isRedactableValue(value))
|
|
108
|
-
return '***REDACTED***';
|
|
109
|
-
return value;
|
|
110
|
-
}
|
|
111
|
-
if (seen.has(value))
|
|
112
|
-
return '[Circular]';
|
|
113
|
-
seen.add(value);
|
|
114
|
-
try {
|
|
115
|
-
if (Array.isArray(value))
|
|
116
|
-
return value.map(walk);
|
|
117
|
-
const obj = value;
|
|
118
|
-
const result = {};
|
|
119
|
-
for (const [key, entry] of Object.entries(obj)) {
|
|
120
|
-
if (isSecretKey(key)) {
|
|
121
|
-
result[key] = '***REDACTED***';
|
|
122
|
-
continue;
|
|
123
|
-
}
|
|
124
|
-
result[key] = walk(entry);
|
|
125
|
-
}
|
|
126
|
-
return result;
|
|
127
|
-
}
|
|
128
|
-
finally {
|
|
129
|
-
seen.delete(value);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
return walk(payload);
|
|
133
|
-
}
|
|
134
|
-
// -- Line formatting ------------------------------------------------------
|
|
135
|
-
export function formatLogLine(level, channel, message, payload) {
|
|
136
|
-
const now = new Date().toISOString();
|
|
137
|
-
const levelUpper = level.toUpperCase().padEnd(5);
|
|
138
|
-
const channelSegment = channel ? ` [${channel}]` : '';
|
|
139
|
-
const payloadJson = (() => {
|
|
140
|
-
try {
|
|
141
|
-
const redacted = redactPayload(payload);
|
|
142
|
-
const withPid = redacted
|
|
143
|
-
? { ...redacted, pid: process.pid }
|
|
144
|
-
: { pid: process.pid };
|
|
145
|
-
return ` ${JSON.stringify(withPid)}`;
|
|
146
|
-
}
|
|
147
|
-
catch {
|
|
148
|
-
return ` {"pid":${process.pid},"payload":"[unserializable]"}`;
|
|
149
|
-
}
|
|
150
|
-
})();
|
|
151
|
-
return `[${now}] ${levelUpper}${channelSegment} ${message}${payloadJson}`;
|
|
152
|
-
}
|
|
153
|
-
let testSink = null;
|
|
154
|
-
export function __setLogTestSink(sink) {
|
|
155
|
-
testSink = sink;
|
|
156
|
-
}
|
|
157
|
-
// -- Leveled API ----------------------------------------------------------
|
|
158
|
-
function emit(level, channel, message, payload) {
|
|
159
|
-
if (!shouldEmit(level))
|
|
160
|
-
return;
|
|
161
|
-
if (testSink) {
|
|
162
|
-
try {
|
|
163
|
-
testSink({ level, channel, message, payload: redactPayload(payload) });
|
|
164
|
-
}
|
|
165
|
-
catch {
|
|
166
|
-
// Sink must never throw into production.
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
if (isTestEnv)
|
|
170
|
-
return;
|
|
171
|
-
try {
|
|
172
|
-
const line = `${formatLogLine(level, channel, message, payload)}\n`;
|
|
173
|
-
buffer.push(line);
|
|
174
|
-
if (buffer.length >= BUFFER_SIZE_LIMIT) {
|
|
175
|
-
flush();
|
|
176
|
-
}
|
|
177
|
-
else {
|
|
178
|
-
scheduleFlush();
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
catch {
|
|
182
|
-
// Logging must never throw.
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
export const logger = {
|
|
186
|
-
error(channel, message, payload) {
|
|
187
|
-
emit('error', channel, message, payload);
|
|
188
|
-
},
|
|
189
|
-
warn(channel, message, payload) {
|
|
190
|
-
emit('warn', channel, message, payload);
|
|
191
|
-
},
|
|
192
|
-
info(channel, message, payload) {
|
|
193
|
-
emit('info', channel, message, payload);
|
|
194
|
-
},
|
|
195
|
-
debug(channel, message, payload) {
|
|
196
|
-
emit('debug', channel, message, payload);
|
|
197
|
-
},
|
|
198
|
-
trace(channel, message, payload) {
|
|
199
|
-
emit('trace', channel, message, payload);
|
|
200
|
-
},
|
|
201
|
-
};
|
|
202
|
-
// -- Buffered writes ------------------------------------------------------
|
|
203
|
-
const isTestEnv = process.env.NODE_ENV === 'test';
|
|
204
|
-
const FLUSH_INTERVAL_MS = 500;
|
|
205
|
-
const BUFFER_SIZE_LIMIT = 50;
|
|
206
|
-
let buffer = [];
|
|
207
|
-
let flushTimer = null;
|
|
208
|
-
function flush() {
|
|
209
|
-
if (flushTimer) {
|
|
210
|
-
clearTimeout(flushTimer);
|
|
211
|
-
flushTimer = null;
|
|
212
|
-
}
|
|
213
|
-
if (buffer.length === 0)
|
|
214
|
-
return;
|
|
215
|
-
const data = buffer.join('');
|
|
216
|
-
buffer = [];
|
|
217
|
-
try {
|
|
218
|
-
rotateLogFile();
|
|
219
|
-
fs.appendFileSync(LOG_FILE, data);
|
|
220
|
-
}
|
|
221
|
-
catch {
|
|
222
|
-
// Logging must never throw.
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
function scheduleFlush() {
|
|
226
|
-
if (flushTimer)
|
|
227
|
-
return;
|
|
228
|
-
flushTimer = setTimeout(() => {
|
|
229
|
-
flushTimer = null;
|
|
230
|
-
flush();
|
|
231
|
-
}, FLUSH_INTERVAL_MS);
|
|
232
|
-
}
|
|
233
|
-
// -- Back-compat shims ----------------------------------------------------
|
|
234
|
-
const CHANNEL_REGEX = /^\[([\w-]+)\]\s*/;
|
|
235
|
-
export function log(message, data) {
|
|
236
|
-
if (!shouldEmit('debug'))
|
|
237
|
-
return;
|
|
238
|
-
if (isTestEnv)
|
|
239
|
-
return;
|
|
240
|
-
try {
|
|
241
|
-
let channel = '';
|
|
242
|
-
let msg = message;
|
|
243
|
-
const match = message.match(CHANNEL_REGEX);
|
|
244
|
-
if (match) {
|
|
245
|
-
channel = match[1] ?? '';
|
|
246
|
-
msg = message.slice(match[0].length);
|
|
247
|
-
}
|
|
248
|
-
let payload;
|
|
249
|
-
if (data != null) {
|
|
250
|
-
if (data instanceof Error) {
|
|
251
|
-
payload = {
|
|
252
|
-
error: `${data.message}${data.stack ? `\n${data.stack}` : ''}`,
|
|
253
|
-
};
|
|
254
|
-
}
|
|
255
|
-
else if (typeof data === 'object') {
|
|
256
|
-
payload = data;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
emit('debug', channel, msg, payload);
|
|
260
|
-
}
|
|
261
|
-
catch {
|
|
262
|
-
// Logging must never throw.
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
export function relayLog(message, data) {
|
|
266
|
-
if (!shouldEmit('debug'))
|
|
267
|
-
return;
|
|
268
|
-
if (isTestEnv)
|
|
269
|
-
return;
|
|
270
|
-
try {
|
|
271
|
-
let payload;
|
|
272
|
-
if (data != null) {
|
|
273
|
-
if (typeof data === 'object' && !(data instanceof Error)) {
|
|
274
|
-
payload = data;
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
emit('debug', 'relay', message, payload);
|
|
278
|
-
}
|
|
279
|
-
catch {
|
|
280
|
-
// Logging must never throw.
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
// -- Exit flush -----------------------------------------------------------
|
|
284
|
-
if (!isTestEnv) {
|
|
285
|
-
process.on('exit', flush);
|
|
286
|
-
}
|
package/dist/logging.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
// Known limitation: the TUI bundle is a SEPARATE module instance from the loader,
|
|
2
|
-
// so /claude-logging sets the SERVER-side (loader) logger level and persists it
|
|
3
|
-
// (applied on next boot); the TUI-side logger level is only raised via the
|
|
4
|
-
// OPENCODE_ANTHROPIC_AUTH_LOG_LEVEL env override. The command still correctly
|
|
5
|
-
// persists and applies server-side — just note this asymmetry.
|
|
6
|
-
export const CLAUDE_LOGGING_COMMAND_NAME = 'claude-logging';
|
|
7
|
-
export const LOGGING_LEVELS = [
|
|
8
|
-
'error',
|
|
9
|
-
'warn',
|
|
10
|
-
'info',
|
|
11
|
-
'debug',
|
|
12
|
-
'trace',
|
|
13
|
-
];
|
|
14
|
-
const LOGGING_USAGE = 'Usage: `/claude-logging`, `/claude-logging error|warn|info|debug|trace`.';
|
|
15
|
-
export function parseLoggingCommandAction(argumentsText) {
|
|
16
|
-
const tokens = argumentsText.trim().toLowerCase().split(/\s+/).filter(Boolean);
|
|
17
|
-
if (tokens.length === 0)
|
|
18
|
-
return { type: 'status' };
|
|
19
|
-
if (tokens.length === 1 && LOGGING_LEVELS.includes(tokens[0])) {
|
|
20
|
-
return { type: 'level', level: tokens[0] };
|
|
21
|
-
}
|
|
22
|
-
return { type: 'usage' };
|
|
23
|
-
}
|
|
24
|
-
export function buildLoggingStatusSummary(input) {
|
|
25
|
-
const level = input?.level ?? 'info';
|
|
26
|
-
return [
|
|
27
|
-
'## Claude Log Level',
|
|
28
|
-
'',
|
|
29
|
-
`Current log level: \`${level}\``,
|
|
30
|
-
'- Persisted: ~/.config/opencode/anthropic-auth.json',
|
|
31
|
-
'- Valid levels: error, warn, info, debug, trace',
|
|
32
|
-
'',
|
|
33
|
-
LOGGING_USAGE,
|
|
34
|
-
].join('\n');
|
|
35
|
-
}
|
|
36
|
-
export function executeLoggingCommand(input) {
|
|
37
|
-
const action = parseLoggingCommandAction(input.argumentsText);
|
|
38
|
-
const level = input.level ?? 'info';
|
|
39
|
-
if (action.type === 'status')
|
|
40
|
-
return buildLoggingStatusSummary({ level });
|
|
41
|
-
if (action.type === 'level') {
|
|
42
|
-
return [
|
|
43
|
-
'## Claude Log Level Updated',
|
|
44
|
-
'',
|
|
45
|
-
`Level set to \`${action.level}\`.`,
|
|
46
|
-
'',
|
|
47
|
-
...buildLoggingStatusSummary({ level: action.level })
|
|
48
|
-
.split('\n')
|
|
49
|
-
.slice(2),
|
|
50
|
-
].join('\n');
|
|
51
|
-
}
|
|
52
|
-
return [
|
|
53
|
-
'## Claude Log Level Usage',
|
|
54
|
-
'',
|
|
55
|
-
LOGGING_USAGE,
|
|
56
|
-
'',
|
|
57
|
-
...buildLoggingStatusSummary({ level }).split('\n').slice(2),
|
|
58
|
-
].join('\n');
|
|
59
|
-
}
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { isClaudeFable51Model } from './models.js';
|
|
2
|
-
export const MID_CONVERSATION_OUTPUT_CONFIG_BETA = 'mid-conversation-output-config-2026-07-01';
|
|
3
|
-
function isRecord(value) {
|
|
4
|
-
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
5
|
-
}
|
|
6
|
-
export function normalizeAdaptiveEffort(value) {
|
|
7
|
-
if (value === 'minimal')
|
|
8
|
-
return 'low';
|
|
9
|
-
if (value === 'low' ||
|
|
10
|
-
value === 'medium' ||
|
|
11
|
-
value === 'high' ||
|
|
12
|
-
value === 'xhigh' ||
|
|
13
|
-
value === 'max') {
|
|
14
|
-
return value;
|
|
15
|
-
}
|
|
16
|
-
return undefined;
|
|
17
|
-
}
|
|
18
|
-
export function usesMidConversationOutputConfig(body) {
|
|
19
|
-
return isClaudeFable51Model(body.model);
|
|
20
|
-
}
|
|
21
|
-
function compactTransitions(transitions) {
|
|
22
|
-
const compacted = [];
|
|
23
|
-
for (const transition of transitions) {
|
|
24
|
-
if (!Number.isSafeInteger(transition.afterAssistantMessages) ||
|
|
25
|
-
transition.afterAssistantMessages < 0 ||
|
|
26
|
-
!normalizeAdaptiveEffort(transition.effort)) {
|
|
27
|
-
continue;
|
|
28
|
-
}
|
|
29
|
-
const normalized = {
|
|
30
|
-
afterAssistantMessages: transition.afterAssistantMessages,
|
|
31
|
-
effort: transition.effort,
|
|
32
|
-
};
|
|
33
|
-
const previous = compacted.at(-1);
|
|
34
|
-
if (previous &&
|
|
35
|
-
previous.afterAssistantMessages === normalized.afterAssistantMessages) {
|
|
36
|
-
previous.effort = normalized.effort;
|
|
37
|
-
continue;
|
|
38
|
-
}
|
|
39
|
-
if (previous?.effort === normalized.effort)
|
|
40
|
-
continue;
|
|
41
|
-
compacted.push(normalized);
|
|
42
|
-
}
|
|
43
|
-
return compacted;
|
|
44
|
-
}
|
|
45
|
-
export function applyMidConversationOutputConfig(body, transitions) {
|
|
46
|
-
if (!usesMidConversationOutputConfig(body) || !Array.isArray(body.messages)) {
|
|
47
|
-
return { applied: false, inserted: 0 };
|
|
48
|
-
}
|
|
49
|
-
const compacted = compactTransitions(transitions);
|
|
50
|
-
const currentOutputConfig = isRecord(body.output_config)
|
|
51
|
-
? body.output_config
|
|
52
|
-
: {};
|
|
53
|
-
const baseline = compacted[0]?.effort ??
|
|
54
|
-
normalizeAdaptiveEffort(currentOutputConfig.effort) ??
|
|
55
|
-
'high';
|
|
56
|
-
body.output_config = { ...currentOutputConfig, effort: baseline };
|
|
57
|
-
if (compacted.length < 2)
|
|
58
|
-
return { applied: true, inserted: 0 };
|
|
59
|
-
const messages = body.messages;
|
|
60
|
-
const transitionsByBoundary = new Map();
|
|
61
|
-
for (const transition of compacted.slice(1)) {
|
|
62
|
-
transitionsByBoundary.set(transition.afterAssistantMessages, transition.effort);
|
|
63
|
-
}
|
|
64
|
-
let assistantMessages = 0;
|
|
65
|
-
let activeEffort = baseline;
|
|
66
|
-
let inserted = 0;
|
|
67
|
-
const rewritten = [];
|
|
68
|
-
for (const message of messages) {
|
|
69
|
-
if (isRecord(message) &&
|
|
70
|
-
message.role === 'user' &&
|
|
71
|
-
transitionsByBoundary.has(assistantMessages)) {
|
|
72
|
-
const effort = transitionsByBoundary.get(assistantMessages);
|
|
73
|
-
if (effort && effort !== activeEffort) {
|
|
74
|
-
rewritten.push({
|
|
75
|
-
role: 'system',
|
|
76
|
-
content: [],
|
|
77
|
-
output_config: { effort },
|
|
78
|
-
});
|
|
79
|
-
activeEffort = effort;
|
|
80
|
-
inserted++;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
rewritten.push(message);
|
|
84
|
-
if (isRecord(message) && message.role === 'assistant')
|
|
85
|
-
assistantMessages++;
|
|
86
|
-
}
|
|
87
|
-
body.messages = rewritten;
|
|
88
|
-
return { applied: true, inserted };
|
|
89
|
-
}
|