@link-assistant/agent 0.5.3 → 0.6.1
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/package.json +4 -3
- package/src/auth/claude-oauth.ts +50 -24
- package/src/auth/plugins.ts +245 -28
- package/src/bun/index.ts +33 -27
- package/src/bus/index.ts +3 -5
- package/src/config/config.ts +39 -22
- package/src/file/ripgrep.ts +1 -1
- package/src/file/time.ts +1 -1
- package/src/file/watcher.ts +10 -5
- package/src/format/index.ts +12 -10
- package/src/index.js +30 -35
- package/src/mcp/index.ts +32 -15
- package/src/patch/index.ts +8 -4
- package/src/project/project.ts +1 -1
- package/src/project/state.ts +15 -7
- package/src/provider/models.ts +4 -5
- package/src/provider/provider.ts +29 -21
- package/src/server/server.ts +4 -5
- package/src/session/agent.js +16 -2
- package/src/session/compaction.ts +4 -6
- package/src/session/index.ts +2 -2
- package/src/session/processor.ts +3 -7
- package/src/session/prompt.ts +78 -49
- package/src/session/revert.ts +1 -1
- package/src/session/summary.ts +2 -2
- package/src/snapshot/index.ts +27 -12
- package/src/storage/storage.ts +18 -18
- package/src/util/log-lazy.ts +291 -0
- package/src/util/log.ts +205 -28
package/src/snapshot/index.ts
CHANGED
|
@@ -28,7 +28,7 @@ export namespace Snapshot {
|
|
|
28
28
|
await $`git --git-dir ${git} config core.autocrlf false`
|
|
29
29
|
.quiet()
|
|
30
30
|
.nothrow();
|
|
31
|
-
log.info('initialized');
|
|
31
|
+
log.info(() => ({ message: 'initialized' }));
|
|
32
32
|
}
|
|
33
33
|
await $`git --git-dir ${git} --work-tree ${Instance.worktree} add .`
|
|
34
34
|
.quiet()
|
|
@@ -40,7 +40,12 @@ export namespace Snapshot {
|
|
|
40
40
|
.cwd(Instance.directory)
|
|
41
41
|
.nothrow()
|
|
42
42
|
.text();
|
|
43
|
-
log.info(
|
|
43
|
+
log.info(() => ({
|
|
44
|
+
message: 'tracking',
|
|
45
|
+
hash,
|
|
46
|
+
cwd: Instance.directory,
|
|
47
|
+
git,
|
|
48
|
+
}));
|
|
44
49
|
return hash.trim();
|
|
45
50
|
}
|
|
46
51
|
|
|
@@ -64,7 +69,11 @@ export namespace Snapshot {
|
|
|
64
69
|
|
|
65
70
|
// If git diff fails, return empty patch
|
|
66
71
|
if (result.exitCode !== 0) {
|
|
67
|
-
log.warn(
|
|
72
|
+
log.warn(() => ({
|
|
73
|
+
message: 'failed to get diff',
|
|
74
|
+
hash,
|
|
75
|
+
exitCode: result.exitCode,
|
|
76
|
+
}));
|
|
68
77
|
return { hash, files: [] };
|
|
69
78
|
}
|
|
70
79
|
|
|
@@ -81,7 +90,7 @@ export namespace Snapshot {
|
|
|
81
90
|
}
|
|
82
91
|
|
|
83
92
|
export async function restore(snapshot: string) {
|
|
84
|
-
log.info('restore',
|
|
93
|
+
log.info(() => ({ message: 'restore', commit: snapshot }));
|
|
85
94
|
const git = gitdir();
|
|
86
95
|
const result =
|
|
87
96
|
await $`git --git-dir ${git} --work-tree ${Instance.worktree} read-tree ${snapshot} && git --git-dir ${git} --work-tree ${Instance.worktree} checkout-index -a -f`
|
|
@@ -90,12 +99,13 @@ export namespace Snapshot {
|
|
|
90
99
|
.nothrow();
|
|
91
100
|
|
|
92
101
|
if (result.exitCode !== 0) {
|
|
93
|
-
log.error(
|
|
102
|
+
log.error(() => ({
|
|
103
|
+
message: 'failed to restore snapshot',
|
|
94
104
|
snapshot,
|
|
95
105
|
exitCode: result.exitCode,
|
|
96
106
|
stderr: result.stderr.toString(),
|
|
97
107
|
stdout: result.stdout.toString(),
|
|
98
|
-
});
|
|
108
|
+
}));
|
|
99
109
|
}
|
|
100
110
|
}
|
|
101
111
|
|
|
@@ -105,7 +115,7 @@ export namespace Snapshot {
|
|
|
105
115
|
for (const item of patches) {
|
|
106
116
|
for (const file of item.files) {
|
|
107
117
|
if (files.has(file)) continue;
|
|
108
|
-
log.info('reverting',
|
|
118
|
+
log.info(() => ({ message: 'reverting', file, hash: item.hash }));
|
|
109
119
|
const result =
|
|
110
120
|
await $`git --git-dir ${git} --work-tree ${Instance.worktree} checkout ${item.hash} -- ${file}`
|
|
111
121
|
.quiet()
|
|
@@ -119,11 +129,15 @@ export namespace Snapshot {
|
|
|
119
129
|
.cwd(Instance.worktree)
|
|
120
130
|
.nothrow();
|
|
121
131
|
if (checkTree.exitCode === 0 && checkTree.text().trim()) {
|
|
122
|
-
log.info(
|
|
132
|
+
log.info(() => ({
|
|
133
|
+
message: 'file existed in snapshot but checkout failed, keeping',
|
|
123
134
|
file,
|
|
124
|
-
});
|
|
135
|
+
}));
|
|
125
136
|
} else {
|
|
126
|
-
log.info(
|
|
137
|
+
log.info(() => ({
|
|
138
|
+
message: 'file did not exist in snapshot, deleting',
|
|
139
|
+
file,
|
|
140
|
+
}));
|
|
127
141
|
await fs.unlink(file).catch(() => {});
|
|
128
142
|
}
|
|
129
143
|
}
|
|
@@ -145,12 +159,13 @@ export namespace Snapshot {
|
|
|
145
159
|
.nothrow();
|
|
146
160
|
|
|
147
161
|
if (result.exitCode !== 0) {
|
|
148
|
-
log.warn(
|
|
162
|
+
log.warn(() => ({
|
|
163
|
+
message: 'failed to get diff',
|
|
149
164
|
hash,
|
|
150
165
|
exitCode: result.exitCode,
|
|
151
166
|
stderr: result.stderr.toString(),
|
|
152
167
|
stdout: result.stdout.toString(),
|
|
153
|
-
});
|
|
168
|
+
}));
|
|
154
169
|
return '';
|
|
155
170
|
}
|
|
156
171
|
|
package/src/storage/storage.ts
CHANGED
|
@@ -28,7 +28,7 @@ export namespace Storage {
|
|
|
28
28
|
cwd: project,
|
|
29
29
|
onlyFiles: false,
|
|
30
30
|
})) {
|
|
31
|
-
log.info(
|
|
31
|
+
log.info(() => ({ message: 'migrating project', projectDir }));
|
|
32
32
|
let projectID = projectDir;
|
|
33
33
|
const fullProjectDir = path.join(project, projectDir);
|
|
34
34
|
let worktree = '/';
|
|
@@ -74,7 +74,10 @@ export namespace Storage {
|
|
|
74
74
|
})
|
|
75
75
|
);
|
|
76
76
|
|
|
77
|
-
log.info(
|
|
77
|
+
log.info(() => ({
|
|
78
|
+
message: 'migrating sessions for project',
|
|
79
|
+
projectID,
|
|
80
|
+
}));
|
|
78
81
|
for await (const sessionFile of new Bun.Glob(
|
|
79
82
|
'storage/session/info/*.json'
|
|
80
83
|
).scan({
|
|
@@ -87,13 +90,13 @@ export namespace Storage {
|
|
|
87
90
|
projectID,
|
|
88
91
|
path.basename(sessionFile)
|
|
89
92
|
);
|
|
90
|
-
log.info('copying',
|
|
91
|
-
sessionFile,
|
|
92
|
-
dest,
|
|
93
|
-
});
|
|
93
|
+
log.info(() => ({ message: 'copying', sessionFile, dest }));
|
|
94
94
|
const session = await Bun.file(sessionFile).json();
|
|
95
95
|
await Bun.write(dest, JSON.stringify(session));
|
|
96
|
-
log.info(
|
|
96
|
+
log.info(() => ({
|
|
97
|
+
message: 'migrating messages for session',
|
|
98
|
+
sessionID: session.id,
|
|
99
|
+
}));
|
|
97
100
|
for await (const msgFile of new Bun.Glob(
|
|
98
101
|
`storage/session/message/${session.id}/*.json`
|
|
99
102
|
).scan({
|
|
@@ -106,14 +109,14 @@ export namespace Storage {
|
|
|
106
109
|
session.id,
|
|
107
110
|
path.basename(msgFile)
|
|
108
111
|
);
|
|
109
|
-
log.info('copying',
|
|
110
|
-
msgFile,
|
|
111
|
-
dest,
|
|
112
|
-
});
|
|
112
|
+
log.info(() => ({ message: 'copying', msgFile, dest }));
|
|
113
113
|
const message = await Bun.file(msgFile).json();
|
|
114
114
|
await Bun.write(dest, JSON.stringify(message));
|
|
115
115
|
|
|
116
|
-
log.info(
|
|
116
|
+
log.info(() => ({
|
|
117
|
+
message: 'migrating parts for message',
|
|
118
|
+
messageID: message.id,
|
|
119
|
+
}));
|
|
117
120
|
for await (const partFile of new Bun.Glob(
|
|
118
121
|
`storage/session/part/${session.id}/${message.id}/*.json`
|
|
119
122
|
).scan({
|
|
@@ -127,10 +130,7 @@ export namespace Storage {
|
|
|
127
130
|
path.basename(partFile)
|
|
128
131
|
);
|
|
129
132
|
const part = await Bun.file(partFile).json();
|
|
130
|
-
log.info('copying',
|
|
131
|
-
partFile,
|
|
132
|
-
dest,
|
|
133
|
-
});
|
|
133
|
+
log.info(() => ({ message: 'copying', partFile, dest }));
|
|
134
134
|
await Bun.write(dest, JSON.stringify(part));
|
|
135
135
|
}
|
|
136
136
|
}
|
|
@@ -178,10 +178,10 @@ export namespace Storage {
|
|
|
178
178
|
.then((x) => parseInt(x))
|
|
179
179
|
.catch(() => 0);
|
|
180
180
|
for (let index = migration; index < MIGRATIONS.length; index++) {
|
|
181
|
-
log.info('running migration',
|
|
181
|
+
log.info(() => ({ message: 'running migration', index }));
|
|
182
182
|
const migration = MIGRATIONS[index];
|
|
183
183
|
await migration(dir).catch(() =>
|
|
184
|
-
log.error('failed to run migration',
|
|
184
|
+
log.error(() => ({ message: 'failed to run migration', index }))
|
|
185
185
|
);
|
|
186
186
|
await Bun.write(path.join(dir, 'migration'), (index + 1).toString());
|
|
187
187
|
}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import makeLog, { levels, LogLevel } from 'log-lazy';
|
|
2
|
+
import { Flag } from '../flag/flag.ts';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* JSON Lazy Logger
|
|
6
|
+
*
|
|
7
|
+
* Implements lazy logging pattern using log-lazy library.
|
|
8
|
+
* All log output is JSON formatted and wrapped in { log: { ... } } structure
|
|
9
|
+
* for easy parsing alongside regular JSON output.
|
|
10
|
+
*
|
|
11
|
+
* Key features:
|
|
12
|
+
* - Lazy evaluation: log arguments are only computed if logging is enabled
|
|
13
|
+
* - JSON output: all logs are parsable JSON in { log: { ... } } format
|
|
14
|
+
* - Level control: logs respect --verbose flag and LINK_ASSISTANT_AGENT_VERBOSE env
|
|
15
|
+
* - Type-safe: full TypeScript support
|
|
16
|
+
*
|
|
17
|
+
* Usage:
|
|
18
|
+
* import { lazyLog } from './util/log-lazy.ts';
|
|
19
|
+
*
|
|
20
|
+
* // Simple string message
|
|
21
|
+
* lazyLog.info(() => 'Starting process');
|
|
22
|
+
*
|
|
23
|
+
* // Object data (preferred - avoids expensive JSON.stringify when disabled)
|
|
24
|
+
* lazyLog.debug(() => ({ action: 'fetch', url: someUrl }));
|
|
25
|
+
*
|
|
26
|
+
* // Complex computed message
|
|
27
|
+
* lazyLog.verbose(() => `Processed ${items.length} items: ${JSON.stringify(items)}`);
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
// Custom log levels using bit flags for fine-grained control
|
|
31
|
+
const LEVEL_DISABLED = 0;
|
|
32
|
+
const LEVEL_ERROR = levels.error;
|
|
33
|
+
const LEVEL_WARN = levels.warn | LEVEL_ERROR;
|
|
34
|
+
const LEVEL_INFO = levels.info | LEVEL_WARN;
|
|
35
|
+
const LEVEL_DEBUG = levels.debug | LEVEL_INFO;
|
|
36
|
+
const LEVEL_VERBOSE = levels.verbose | LEVEL_DEBUG;
|
|
37
|
+
const LEVEL_TRACE = levels.trace | LEVEL_VERBOSE;
|
|
38
|
+
|
|
39
|
+
// Map of preset level configurations
|
|
40
|
+
const LEVEL_PRESETS = {
|
|
41
|
+
disabled: LEVEL_DISABLED,
|
|
42
|
+
error: LEVEL_ERROR,
|
|
43
|
+
warn: LEVEL_WARN,
|
|
44
|
+
info: LEVEL_INFO,
|
|
45
|
+
debug: LEVEL_DEBUG,
|
|
46
|
+
verbose: LEVEL_VERBOSE,
|
|
47
|
+
trace: LEVEL_TRACE,
|
|
48
|
+
// Convenience aliases
|
|
49
|
+
production: LEVEL_WARN,
|
|
50
|
+
development: LEVEL_DEBUG,
|
|
51
|
+
} as const;
|
|
52
|
+
|
|
53
|
+
type LevelPreset = keyof typeof LEVEL_PRESETS;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Format a log entry as JSON object wrapped in { log: { ... } }
|
|
57
|
+
*/
|
|
58
|
+
function formatLogEntry(
|
|
59
|
+
level: string,
|
|
60
|
+
data: unknown,
|
|
61
|
+
tags?: Record<string, unknown>
|
|
62
|
+
): string {
|
|
63
|
+
const timestamp = new Date().toISOString();
|
|
64
|
+
const logEntry: Record<string, unknown> = {
|
|
65
|
+
level,
|
|
66
|
+
timestamp,
|
|
67
|
+
...tags,
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// Handle different data types
|
|
71
|
+
if (typeof data === 'string') {
|
|
72
|
+
logEntry.message = data;
|
|
73
|
+
} else if (data instanceof Error) {
|
|
74
|
+
logEntry.message = data.message;
|
|
75
|
+
logEntry.error = {
|
|
76
|
+
name: data.name,
|
|
77
|
+
message: data.message,
|
|
78
|
+
stack: data.stack,
|
|
79
|
+
};
|
|
80
|
+
} else if (typeof data === 'object' && data !== null) {
|
|
81
|
+
// Spread object properties into the log entry
|
|
82
|
+
Object.assign(logEntry, data);
|
|
83
|
+
} else {
|
|
84
|
+
logEntry.message = String(data);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return JSON.stringify({ log: logEntry });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Create the output function that writes to stderr
|
|
92
|
+
*/
|
|
93
|
+
function createOutput(
|
|
94
|
+
level: string,
|
|
95
|
+
tags?: Record<string, unknown>
|
|
96
|
+
): (data: unknown) => void {
|
|
97
|
+
return (data: unknown) => {
|
|
98
|
+
const json = formatLogEntry(level, data, tags);
|
|
99
|
+
// Use stderr to avoid interfering with stdout JSON output
|
|
100
|
+
process.stderr.write(json + '\n');
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* LazyLogger interface extending log-lazy with JSON output
|
|
106
|
+
*/
|
|
107
|
+
export interface LazyLogger {
|
|
108
|
+
// Log at info level (default)
|
|
109
|
+
(fn: () => unknown): void;
|
|
110
|
+
|
|
111
|
+
// Log levels
|
|
112
|
+
error(fn: () => unknown): void;
|
|
113
|
+
warn(fn: () => unknown): void;
|
|
114
|
+
info(fn: () => unknown): void;
|
|
115
|
+
debug(fn: () => unknown): void;
|
|
116
|
+
verbose(fn: () => unknown): void;
|
|
117
|
+
trace(fn: () => unknown): void;
|
|
118
|
+
|
|
119
|
+
// Level management
|
|
120
|
+
enableLevel(level: LogLevel): void;
|
|
121
|
+
disableLevel(level: LogLevel): void;
|
|
122
|
+
setLevel(level: LevelPreset | number): void;
|
|
123
|
+
getEnabledLevels(): LogLevel[];
|
|
124
|
+
shouldLog(level: LogLevel): boolean;
|
|
125
|
+
|
|
126
|
+
// Tag support
|
|
127
|
+
tag(key: string, value: unknown): LazyLogger;
|
|
128
|
+
clone(): LazyLogger;
|
|
129
|
+
|
|
130
|
+
// Configuration
|
|
131
|
+
readonly enabled: boolean;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Create a lazy logger with JSON output format
|
|
136
|
+
*/
|
|
137
|
+
export function createLazyLogger(
|
|
138
|
+
initialTags?: Record<string, unknown>
|
|
139
|
+
): LazyLogger {
|
|
140
|
+
// Determine initial log level based on verbose flag
|
|
141
|
+
const initialLevel = Flag.OPENCODE_VERBOSE ? LEVEL_VERBOSE : LEVEL_DISABLED;
|
|
142
|
+
|
|
143
|
+
// Create base log-lazy instance
|
|
144
|
+
const baseLog = makeLog({ level: initialLevel });
|
|
145
|
+
const tags = { ...initialTags };
|
|
146
|
+
|
|
147
|
+
// Custom output functions that format as JSON
|
|
148
|
+
const outputError = createOutput('error', tags);
|
|
149
|
+
const outputWarn = createOutput('warn', tags);
|
|
150
|
+
const outputInfo = createOutput('info', tags);
|
|
151
|
+
const outputDebug = createOutput('debug', tags);
|
|
152
|
+
const outputVerbose = createOutput('verbose', tags);
|
|
153
|
+
const outputTrace = createOutput('trace', tags);
|
|
154
|
+
|
|
155
|
+
// Create wrapper that uses JSON output
|
|
156
|
+
const wrappedLog = function (fn: () => unknown): void {
|
|
157
|
+
baseLog.info(() => {
|
|
158
|
+
const result = fn();
|
|
159
|
+
outputInfo(result);
|
|
160
|
+
return ''; // Return empty string as the base logger just needs something
|
|
161
|
+
});
|
|
162
|
+
} as LazyLogger;
|
|
163
|
+
|
|
164
|
+
wrappedLog.error = (fn: () => unknown): void => {
|
|
165
|
+
baseLog.error(() => {
|
|
166
|
+
const result = fn();
|
|
167
|
+
outputError(result);
|
|
168
|
+
return '';
|
|
169
|
+
});
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
wrappedLog.warn = (fn: () => unknown): void => {
|
|
173
|
+
baseLog.warn(() => {
|
|
174
|
+
const result = fn();
|
|
175
|
+
outputWarn(result);
|
|
176
|
+
return '';
|
|
177
|
+
});
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
wrappedLog.info = (fn: () => unknown): void => {
|
|
181
|
+
baseLog.info(() => {
|
|
182
|
+
const result = fn();
|
|
183
|
+
outputInfo(result);
|
|
184
|
+
return '';
|
|
185
|
+
});
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
wrappedLog.debug = (fn: () => unknown): void => {
|
|
189
|
+
baseLog.debug(() => {
|
|
190
|
+
const result = fn();
|
|
191
|
+
outputDebug(result);
|
|
192
|
+
return '';
|
|
193
|
+
});
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
wrappedLog.verbose = (fn: () => unknown): void => {
|
|
197
|
+
baseLog.verbose(() => {
|
|
198
|
+
const result = fn();
|
|
199
|
+
outputVerbose(result);
|
|
200
|
+
return '';
|
|
201
|
+
});
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
wrappedLog.trace = (fn: () => unknown): void => {
|
|
205
|
+
baseLog.trace(() => {
|
|
206
|
+
const result = fn();
|
|
207
|
+
outputTrace(result);
|
|
208
|
+
return '';
|
|
209
|
+
});
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// Level management
|
|
213
|
+
wrappedLog.enableLevel = (level: LogLevel): void => {
|
|
214
|
+
baseLog.enableLevel(level);
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
wrappedLog.disableLevel = (level: LogLevel): void => {
|
|
218
|
+
baseLog.disableLevel(level);
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
wrappedLog.setLevel = (level: LevelPreset | number): void => {
|
|
222
|
+
const numericLevel =
|
|
223
|
+
typeof level === 'string' ? LEVEL_PRESETS[level] : level;
|
|
224
|
+
|
|
225
|
+
// Reset all levels and enable the new one
|
|
226
|
+
Object.values([
|
|
227
|
+
'error',
|
|
228
|
+
'warn',
|
|
229
|
+
'info',
|
|
230
|
+
'debug',
|
|
231
|
+
'verbose',
|
|
232
|
+
'trace',
|
|
233
|
+
]).forEach((l) => baseLog.disableLevel(l as LogLevel));
|
|
234
|
+
|
|
235
|
+
// Enable appropriate levels based on the numeric level
|
|
236
|
+
if (numericLevel & levels.error) baseLog.enableLevel('error');
|
|
237
|
+
if (numericLevel & levels.warn) baseLog.enableLevel('warn');
|
|
238
|
+
if (numericLevel & levels.info) baseLog.enableLevel('info');
|
|
239
|
+
if (numericLevel & levels.debug) baseLog.enableLevel('debug');
|
|
240
|
+
if (numericLevel & levels.verbose) baseLog.enableLevel('verbose');
|
|
241
|
+
if (numericLevel & levels.trace) baseLog.enableLevel('trace');
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
wrappedLog.getEnabledLevels = (): LogLevel[] => {
|
|
245
|
+
return baseLog.getEnabledLevels();
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
wrappedLog.shouldLog = (level: LogLevel): boolean => {
|
|
249
|
+
return baseLog.shouldLog(level);
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
// Tag support
|
|
253
|
+
wrappedLog.tag = (key: string, value: unknown): LazyLogger => {
|
|
254
|
+
tags[key] = value;
|
|
255
|
+
return wrappedLog;
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
wrappedLog.clone = (): LazyLogger => {
|
|
259
|
+
return createLazyLogger({ ...tags });
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
// Configuration
|
|
263
|
+
Object.defineProperty(wrappedLog, 'enabled', {
|
|
264
|
+
get: () => Flag.OPENCODE_VERBOSE,
|
|
265
|
+
enumerable: true,
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
return wrappedLog;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Default lazy logger instance
|
|
273
|
+
* Enabled only when --verbose flag or LINK_ASSISTANT_AGENT_VERBOSE env is set
|
|
274
|
+
*/
|
|
275
|
+
export const lazyLog = createLazyLogger({ service: 'agent' });
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Utility to update the global logger level at runtime
|
|
279
|
+
* Call this after Flag.setVerbose() to sync the logger state
|
|
280
|
+
*/
|
|
281
|
+
export function syncLoggerWithVerboseFlag(): void {
|
|
282
|
+
if (Flag.OPENCODE_VERBOSE) {
|
|
283
|
+
lazyLog.setLevel('verbose');
|
|
284
|
+
} else {
|
|
285
|
+
lazyLog.setLevel('disabled');
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Export level constants for external use
|
|
290
|
+
export { levels, LEVEL_PRESETS };
|
|
291
|
+
export type { LevelPreset };
|