augure 0.5.0 → 0.6.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.
Files changed (2) hide show
  1. package/dist/bin.js +1035 -80
  2. package/package.json +10 -9
package/dist/bin.js CHANGED
@@ -135,6 +135,11 @@ var AppConfigSchema = z.object({
135
135
  checkInterval: z.string().min(1).default("24h"),
136
136
  notifyChannel: z.string().min(1).default("telegram")
137
137
  }).optional()
138
+ }).optional(),
139
+ codeMode: z.object({
140
+ runtime: z.enum(["vm", "docker", "auto"]).default("auto"),
141
+ timeout: z.number().int().positive().default(30),
142
+ memoryLimit: z.number().int().positive().default(128)
138
143
  }).optional()
139
144
  });
140
145
  function interpolateEnvVars(raw) {
@@ -153,19 +158,33 @@ async function loadConfig(path) {
153
158
  return AppConfigSchema.parse(parsed);
154
159
  }
155
160
 
161
+ // ../types/dist/logger.js
162
+ var noop = () => {
163
+ };
164
+ var noopLogger = {
165
+ debug: noop,
166
+ info: noop,
167
+ warn: noop,
168
+ error: noop,
169
+ child: () => noopLogger
170
+ };
171
+
156
172
  // ../core/dist/llm.js
157
173
  var OpenRouterClient = class {
158
174
  apiKey;
159
175
  model;
160
176
  maxTokens;
161
177
  baseUrl;
178
+ log;
162
179
  constructor(config) {
163
180
  this.apiKey = config.apiKey;
164
181
  this.model = config.model;
165
182
  this.maxTokens = config.maxTokens;
166
183
  this.baseUrl = config.baseUrl ?? "https://openrouter.ai/api/v1";
184
+ this.log = config.logger ?? noopLogger;
167
185
  }
168
186
  async chat(messages, tools) {
187
+ this.log.debug(`Request: model=${this.model} messages=${messages.length} tools=${tools?.length ?? 0}`);
169
188
  const response = await fetch(`${this.baseUrl}/chat/completions`, {
170
189
  method: "POST",
171
190
  headers: {
@@ -199,6 +218,7 @@ var OpenRouterClient = class {
199
218
  }
200
219
  const data = await response.json();
201
220
  const choice = data.choices[0];
221
+ this.log.debug(`Response: ${response.status} ${data.usage.prompt_tokens}+${data.usage.completion_tokens} tokens`);
202
222
  return {
203
223
  content: choice.message.content ?? "",
204
224
  toolCalls: (choice.message.tool_calls ?? []).map((tc) => {
@@ -206,7 +226,7 @@ var OpenRouterClient = class {
206
226
  try {
207
227
  args = tc.function.arguments ? JSON.parse(tc.function.arguments) : {};
208
228
  } catch {
209
- console.error(`[augure] Failed to parse tool call arguments for ${tc.function.name}:`, tc.function.arguments);
229
+ this.log.warn(`Failed to parse tool call arguments for ${tc.function.name}`);
210
230
  }
211
231
  return { id: tc.id, name: tc.function.name, arguments: args };
212
232
  }),
@@ -222,6 +242,19 @@ var OpenRouterClient = class {
222
242
  function assembleContext(input) {
223
243
  const { systemPrompt, memoryContent, conversationHistory, persona } = input;
224
244
  let system = systemPrompt;
245
+ const now = /* @__PURE__ */ new Date();
246
+ const humanDate = new Intl.DateTimeFormat("en-US", {
247
+ weekday: "long",
248
+ year: "numeric",
249
+ month: "long",
250
+ day: "numeric",
251
+ hour: "2-digit",
252
+ minute: "2-digit",
253
+ timeZoneName: "short"
254
+ }).format(now);
255
+ system += `
256
+
257
+ Current date and time: ${now.toISOString()} (${humanDate})`;
225
258
  if (persona) {
226
259
  system += `
227
260
 
@@ -239,6 +272,403 @@ ${memoryContent}`;
239
272
  return messages;
240
273
  }
241
274
 
275
+ // ../code-mode/dist/typegen.js
276
+ var JSON_TO_TS = {
277
+ string: "string",
278
+ number: "number",
279
+ integer: "number",
280
+ boolean: "boolean",
281
+ array: "unknown[]",
282
+ object: "Record<string, unknown>"
283
+ };
284
+ function sanitizeName(name) {
285
+ return name.replace(/[-. ]/g, "_");
286
+ }
287
+ function toPascalCase(name) {
288
+ return sanitizeName(name).split("_").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("");
289
+ }
290
+ function mapType(schema) {
291
+ const t = schema.type;
292
+ if (schema.enum) {
293
+ return schema.enum.map((v) => `"${v}"`).join(" | ");
294
+ }
295
+ return JSON_TO_TS[t ?? "string"] ?? "unknown";
296
+ }
297
+ function generateDeclarations(registry) {
298
+ const tools = registry.list();
299
+ const blocks = [];
300
+ const apiEntries = [];
301
+ for (const tool of tools) {
302
+ const safeName = sanitizeName(tool.name);
303
+ const interfaceName = `${toPascalCase(tool.name)}Input`;
304
+ const params = tool.parameters;
305
+ const properties = params.properties ?? {};
306
+ const required = new Set(params.required ?? []);
307
+ const fields = [];
308
+ for (const [key, schema] of Object.entries(properties)) {
309
+ const optional = required.has(key) ? "" : "?";
310
+ const tsType = mapType(schema);
311
+ const desc = schema.description;
312
+ if (desc) {
313
+ fields.push(` /** ${desc} */
314
+ ${key}${optional}: ${tsType};`);
315
+ } else {
316
+ fields.push(` ${key}${optional}: ${tsType};`);
317
+ }
318
+ }
319
+ blocks.push(`interface ${interfaceName} {
320
+ ${fields.join("\n")}
321
+ }`);
322
+ apiEntries.push(` /** ${tool.description} */
323
+ ${safeName}: (input: ${interfaceName}) => Promise<{ success: boolean; output: string }>;`);
324
+ }
325
+ const apiBlock = `declare const api: {
326
+ ${apiEntries.join("\n")}
327
+ };`;
328
+ return [...blocks, "", apiBlock].join("\n");
329
+ }
330
+
331
+ // ../code-mode/dist/bridge.js
332
+ function createBridgeHandler(registry) {
333
+ return async (toolName, input) => {
334
+ try {
335
+ return await registry.execute(toolName, input);
336
+ } catch (err2) {
337
+ return {
338
+ success: false,
339
+ output: `Bridge error calling ${toolName}: ${err2 instanceof Error ? err2.message : String(err2)}`
340
+ };
341
+ }
342
+ };
343
+ }
344
+ function generateHarnessCode(userCode) {
345
+ return `
346
+ const __logs = [];
347
+ const __originalLog = console.log;
348
+ const __originalWarn = console.warn;
349
+ const __originalError = console.error;
350
+ console.log = (...args) => __logs.push(args.map(String).join(" "));
351
+ console.warn = (...args) => __logs.push("[warn] " + args.map(String).join(" "));
352
+ console.error = (...args) => __logs.push("[error] " + args.map(String).join(" "));
353
+
354
+ let __toolCalls = 0;
355
+
356
+ const api = new Proxy({}, {
357
+ get: (_target, toolName) => {
358
+ return async (input) => {
359
+ __toolCalls++;
360
+ return await __bridge(String(toolName), input);
361
+ };
362
+ }
363
+ });
364
+
365
+ async function __run() {
366
+ ${userCode}
367
+ }
368
+
369
+ try {
370
+ const __result = await __run();
371
+ __originalLog(JSON.stringify({
372
+ success: true,
373
+ output: __result,
374
+ logs: __logs,
375
+ toolCalls: __toolCalls,
376
+ }));
377
+ } catch (err) {
378
+ __originalLog(JSON.stringify({
379
+ success: false,
380
+ error: err.message ?? String(err),
381
+ logs: __logs,
382
+ toolCalls: __toolCalls,
383
+ }));
384
+ }
385
+ `;
386
+ }
387
+
388
+ // ../code-mode/dist/vm-sandbox.js
389
+ import { createContext, runInContext } from "vm";
390
+ import { transform } from "esbuild";
391
+ var VmExecutor = class {
392
+ registry;
393
+ config;
394
+ constructor(registry, config) {
395
+ this.registry = registry;
396
+ this.config = config;
397
+ }
398
+ async execute(code) {
399
+ const start = performance.now();
400
+ try {
401
+ const harnessTs = generateHarnessCode(code);
402
+ const { code: harnessJs } = await transform(harnessTs, {
403
+ loader: "ts",
404
+ target: "es2024"
405
+ });
406
+ const bridgeHandler = createBridgeHandler(this.registry);
407
+ const consoleLogs = [];
408
+ const captureConsole = {
409
+ log: (...args) => consoleLogs.push(args.map(String).join(" ")),
410
+ warn: (...args) => consoleLogs.push("[warn] " + args.map(String).join(" ")),
411
+ error: (...args) => consoleLogs.push("[error] " + args.map(String).join(" "))
412
+ };
413
+ const context = createContext({
414
+ console: captureConsole,
415
+ __bridge: bridgeHandler,
416
+ JSON,
417
+ String,
418
+ Number,
419
+ Boolean,
420
+ Array,
421
+ Object,
422
+ Error,
423
+ Promise,
424
+ Map,
425
+ Set,
426
+ parseInt,
427
+ parseFloat,
428
+ isNaN,
429
+ isFinite,
430
+ setTimeout,
431
+ Date,
432
+ RegExp,
433
+ Math,
434
+ Symbol,
435
+ Uint8Array,
436
+ TextEncoder,
437
+ TextDecoder,
438
+ Buffer,
439
+ URL,
440
+ URLSearchParams
441
+ });
442
+ const wrappedCode = `(async () => { ${harnessJs} })()`;
443
+ const timeoutPromise = new Promise((_, reject) => {
444
+ const timer = setTimeout(() => reject(new Error("Timeout: code execution exceeded time limit")), this.config.timeout);
445
+ timer.unref?.();
446
+ });
447
+ const resultPromise = runInContext(wrappedCode, context, {
448
+ timeout: this.config.timeout
449
+ });
450
+ await Promise.race([resultPromise, timeoutPromise]);
451
+ const durationMs = performance.now() - start;
452
+ const lastLine = consoleLogs[consoleLogs.length - 1];
453
+ if (!lastLine) {
454
+ return {
455
+ success: false,
456
+ output: void 0,
457
+ logs: consoleLogs,
458
+ error: "No output produced by code execution",
459
+ durationMs,
460
+ toolCalls: 0
461
+ };
462
+ }
463
+ const parsed = JSON.parse(lastLine);
464
+ return {
465
+ success: parsed.success,
466
+ output: parsed.output,
467
+ logs: parsed.logs,
468
+ error: parsed.error,
469
+ durationMs,
470
+ toolCalls: parsed.toolCalls
471
+ };
472
+ } catch (err2) {
473
+ const durationMs = performance.now() - start;
474
+ return {
475
+ success: false,
476
+ output: void 0,
477
+ logs: [],
478
+ error: err2 instanceof Error ? err2.message : String(err2),
479
+ durationMs,
480
+ toolCalls: 0
481
+ };
482
+ }
483
+ }
484
+ };
485
+
486
+ // ../code-mode/dist/docker-sandbox.js
487
+ var DOCKER_HARNESS = `
488
+ import { readFile } from "node:fs/promises";
489
+
490
+ const __logs = [];
491
+ const __originalLog = console.log;
492
+ console.log = (...args) => __logs.push(args.map(String).join(" "));
493
+ console.warn = (...args) => __logs.push("[warn] " + args.map(String).join(" "));
494
+ console.error = (...args) => __logs.push("[error] " + args.map(String).join(" "));
495
+
496
+ let __toolCalls = 0;
497
+
498
+ const api = new Proxy({}, {
499
+ get: (_target, toolName) => {
500
+ return async () => {
501
+ __toolCalls++;
502
+ return { success: false, output: "Tool calls not yet supported in Docker executor" };
503
+ };
504
+ }
505
+ });
506
+
507
+ const __userCode = await readFile("/workspace/user-code.js", "utf-8");
508
+ const __fn = new Function("api", "__logs",
509
+ "return (async () => { " + __userCode + " })();"
510
+ );
511
+
512
+ try {
513
+ const __result = await __fn(api, __logs);
514
+ __originalLog(JSON.stringify({
515
+ success: true,
516
+ output: __result,
517
+ logs: __logs,
518
+ toolCalls: __toolCalls,
519
+ }));
520
+ } catch (err) {
521
+ __originalLog(JSON.stringify({
522
+ success: false,
523
+ error: err.message ?? String(err),
524
+ logs: __logs,
525
+ toolCalls: __toolCalls,
526
+ }));
527
+ }
528
+ `;
529
+ var DockerExecutor = class {
530
+ config;
531
+ constructor(config) {
532
+ this.config = config;
533
+ }
534
+ async execute(code) {
535
+ const start = Date.now();
536
+ let container;
537
+ try {
538
+ container = await this.config.pool.acquire({
539
+ trust: "sandboxed",
540
+ timeout: this.config.timeout,
541
+ memory: this.config.memoryLimit,
542
+ cpu: this.config.cpuLimit
543
+ });
544
+ } catch (err2) {
545
+ return {
546
+ success: false,
547
+ output: void 0,
548
+ logs: [],
549
+ toolCalls: 0,
550
+ error: `Failed to acquire container: ${err2 instanceof Error ? err2.message : String(err2)}`,
551
+ durationMs: Date.now() - start
552
+ };
553
+ }
554
+ try {
555
+ await container.exec("mkdir -p /workspace");
556
+ const codeB64 = Buffer.from(code).toString("base64");
557
+ await container.exec(`sh -c 'echo "${codeB64}" | base64 -d > /workspace/user-code.js'`);
558
+ const harnessB64 = Buffer.from(DOCKER_HARNESS).toString("base64");
559
+ await container.exec(`sh -c 'echo "${harnessB64}" | base64 -d > /workspace/harness.ts'`);
560
+ const execResult = await container.exec("npx tsx /workspace/harness.ts", {
561
+ timeout: this.config.timeout,
562
+ cwd: "/workspace"
563
+ });
564
+ if (execResult.exitCode === 0 && execResult.stdout.trim()) {
565
+ try {
566
+ const lastLine = execResult.stdout.trim().split("\n").pop();
567
+ const parsed = JSON.parse(lastLine);
568
+ return {
569
+ success: parsed.success,
570
+ output: parsed.output,
571
+ logs: parsed.logs ?? [],
572
+ error: parsed.error,
573
+ durationMs: Date.now() - start,
574
+ toolCalls: parsed.toolCalls ?? 0
575
+ };
576
+ } catch {
577
+ return {
578
+ success: true,
579
+ output: execResult.stdout.trim(),
580
+ logs: [],
581
+ durationMs: Date.now() - start,
582
+ toolCalls: 0
583
+ };
584
+ }
585
+ }
586
+ return {
587
+ success: false,
588
+ output: void 0,
589
+ logs: [],
590
+ toolCalls: 0,
591
+ error: execResult.stderr || execResult.stdout || "Unknown error",
592
+ durationMs: Date.now() - start
593
+ };
594
+ } catch (err2) {
595
+ return {
596
+ success: false,
597
+ output: void 0,
598
+ logs: [],
599
+ toolCalls: 0,
600
+ error: err2 instanceof Error ? err2.message : String(err2),
601
+ durationMs: Date.now() - start
602
+ };
603
+ } finally {
604
+ await this.config.pool.release(container);
605
+ }
606
+ }
607
+ };
608
+
609
+ // ../code-mode/dist/tool.js
610
+ function createCodeModeTool(registry, executor) {
611
+ const declarations = generateDeclarations(registry);
612
+ return {
613
+ name: "execute_code",
614
+ description: `Execute TypeScript code with access to the agent's APIs. Write the body of an async function.
615
+
616
+ Available APIs:
617
+
618
+ \`\`\`typescript
619
+ ${declarations}
620
+ \`\`\`
621
+
622
+ Each API call returns { success: boolean, output: string }.
623
+ Use console.log() for intermediate output. Return your final result.`,
624
+ parameters: {
625
+ type: "object",
626
+ properties: {
627
+ code: {
628
+ type: "string",
629
+ description: "The body of an async TypeScript function. Use the 'api' object to call tools."
630
+ }
631
+ },
632
+ required: ["code"]
633
+ },
634
+ execute: async (params) => {
635
+ const { code } = params;
636
+ const result = await executor.execute(code);
637
+ if (result.success) {
638
+ const parts = [];
639
+ if (result.logs.length > 0) {
640
+ parts.push(`[logs]
641
+ ${result.logs.join("\n")}`);
642
+ }
643
+ parts.push(typeof result.output === "string" ? result.output : JSON.stringify(result.output));
644
+ return { success: true, output: parts.join("\n\n") };
645
+ }
646
+ return {
647
+ success: false,
648
+ output: result.error ?? "Code execution failed"
649
+ };
650
+ }
651
+ };
652
+ }
653
+
654
+ // ../code-mode/dist/auto-executor.js
655
+ var AutoExecutor = class {
656
+ primary;
657
+ fallback;
658
+ constructor(primary, fallback) {
659
+ this.primary = primary;
660
+ this.fallback = fallback;
661
+ }
662
+ async execute(code) {
663
+ try {
664
+ const result = await this.primary.execute(code);
665
+ return result;
666
+ } catch {
667
+ return this.fallback.execute(code);
668
+ }
669
+ }
670
+ };
671
+
242
672
  // ../core/dist/audit.js
243
673
  import { appendFile, mkdir } from "fs/promises";
244
674
  import { join } from "path";
@@ -249,13 +679,15 @@ function summarize(text, maxLen = 200) {
249
679
  }
250
680
  var FileAuditLogger = class {
251
681
  basePath;
682
+ logger;
252
683
  pendingWrite = Promise.resolve();
253
684
  initialized = false;
254
- constructor(basePath) {
685
+ constructor(basePath, logger) {
255
686
  this.basePath = basePath;
687
+ this.logger = logger ?? noopLogger;
256
688
  }
257
689
  log(entry) {
258
- this.pendingWrite = this.pendingWrite.then(() => this.writeEntry(entry)).catch((err2) => console.error("[augure] Audit write error:", err2));
690
+ this.pendingWrite = this.pendingWrite.then(() => this.writeEntry(entry)).catch((err2) => this.logger.error("Audit write error:", err2));
259
691
  }
260
692
  async close() {
261
693
  await this.pendingWrite;
@@ -281,10 +713,12 @@ var NullAuditLogger = class {
281
713
  // ../core/dist/agent.js
282
714
  var Agent = class {
283
715
  config;
716
+ log;
284
717
  conversations = /* @__PURE__ */ new Map();
285
718
  state = "running";
286
719
  constructor(config) {
287
720
  this.config = config;
721
+ this.log = config.logger ?? noopLogger;
288
722
  }
289
723
  getState() {
290
724
  return this.state;
@@ -317,6 +751,19 @@ var Agent = class {
317
751
  const maxLoops = this.config.maxToolLoops ?? 10;
318
752
  let loopCount = 0;
319
753
  const toolSchemas = this.config.tools.toFunctionSchemas();
754
+ let effectiveSchemas = toolSchemas;
755
+ let codeModeTool;
756
+ if (this.config.codeModeExecutor) {
757
+ codeModeTool = createCodeModeTool(this.config.tools, this.config.codeModeExecutor);
758
+ effectiveSchemas = [{
759
+ type: "function",
760
+ function: {
761
+ name: codeModeTool.name,
762
+ description: codeModeTool.description,
763
+ parameters: codeModeTool.parameters
764
+ }
765
+ }];
766
+ }
320
767
  while (loopCount < maxLoops) {
321
768
  const messages = assembleContext({
322
769
  systemPrompt: this.config.systemPrompt,
@@ -324,12 +771,14 @@ var Agent = class {
324
771
  conversationHistory: history,
325
772
  persona: this.config.persona
326
773
  });
327
- const response = await this.config.llm.chat(messages, toolSchemas);
774
+ this.log.debug(`LLM call #${loopCount + 1} (${messages.length} messages)`);
775
+ const response = await this.config.llm.chat(messages, effectiveSchemas);
328
776
  if (response.toolCalls.length === 0) {
329
777
  history.push({
330
778
  role: "assistant",
331
779
  content: response.content
332
780
  });
781
+ this.log.debug(`Response: ${response.usage.inputTokens}+${response.usage.outputTokens} tokens, ${Date.now() - start}ms`);
333
782
  if (this.config.audit) {
334
783
  this.config.audit.log({
335
784
  ts: (/* @__PURE__ */ new Date()).toISOString(),
@@ -347,7 +796,7 @@ var Agent = class {
347
796
  });
348
797
  }
349
798
  if (this.config.ingester) {
350
- this.config.ingester.ingest(history).catch((err2) => console.error("[augure] Ingestion error:", err2));
799
+ this.config.ingester.ingest(history).catch((err2) => this.log.error("Ingestion error:", err2));
351
800
  }
352
801
  return response.content;
353
802
  }
@@ -358,7 +807,14 @@ var Agent = class {
358
807
  });
359
808
  for (const toolCall of response.toolCalls) {
360
809
  const toolStart = Date.now();
361
- const result = await this.config.tools.execute(toolCall.name, toolCall.arguments);
810
+ this.log.debug(`Tool: ${toolCall.name}`);
811
+ let result;
812
+ if (codeModeTool && toolCall.name === "execute_code") {
813
+ result = await codeModeTool.execute(toolCall.arguments, {});
814
+ } else {
815
+ result = await this.config.tools.execute(toolCall.name, toolCall.arguments);
816
+ }
817
+ this.log.debug(`Tool ${toolCall.name}: ${result.success ? "ok" : "fail"} (${Date.now() - toolStart}ms)`);
362
818
  history.push({
363
819
  role: "tool",
364
820
  content: result.output,
@@ -566,6 +1022,56 @@ var ContextGuard = class {
566
1022
  }
567
1023
  };
568
1024
 
1025
+ // ../core/dist/logger.js
1026
+ import { styleText } from "util";
1027
+ var LEVELS = {
1028
+ debug: 0,
1029
+ info: 1,
1030
+ warn: 2,
1031
+ error: 3,
1032
+ silent: 4
1033
+ };
1034
+ function tag(level) {
1035
+ switch (level) {
1036
+ case "debug":
1037
+ return styleText("magenta", "DBG");
1038
+ case "info":
1039
+ return styleText("cyan", "INF");
1040
+ case "warn":
1041
+ return styleText("yellow", "WRN");
1042
+ case "error":
1043
+ return styleText("red", "ERR");
1044
+ }
1045
+ }
1046
+ function createLogger(opts = {}) {
1047
+ const min = LEVELS[opts.level ?? "info"];
1048
+ const scope = opts.scope;
1049
+ function emit(level, msg, args) {
1050
+ if (LEVELS[level] < min)
1051
+ return;
1052
+ const ts = styleText("dim", (/* @__PURE__ */ new Date()).toISOString().slice(11, 23));
1053
+ const lvl = tag(level);
1054
+ const sc = scope ? ` ${styleText("dim", scope)}` : "";
1055
+ const prefix2 = `${styleText("yellow", "\u25B2")} ${ts} ${lvl}${sc}`;
1056
+ const fn = level === "error" ? console.error : level === "warn" ? console.warn : console.log;
1057
+ if (args.length > 0) {
1058
+ fn(prefix2, msg, ...args);
1059
+ } else {
1060
+ fn(prefix2, msg);
1061
+ }
1062
+ }
1063
+ return {
1064
+ debug: (msg, ...args) => emit("debug", msg, args),
1065
+ info: (msg, ...args) => emit("info", msg, args),
1066
+ warn: (msg, ...args) => emit("warn", msg, args),
1067
+ error: (msg, ...args) => emit("error", msg, args),
1068
+ child: (childScope) => createLogger({
1069
+ level: opts.level,
1070
+ scope: scope ? `${scope}:${childScope}` : childScope
1071
+ })
1072
+ };
1073
+ }
1074
+
569
1075
  // ../channels/dist/telegram/telegram.js
570
1076
  import { Bot } from "grammy";
571
1077
 
@@ -786,11 +1292,13 @@ var TelegramChannel = class {
786
1292
  allowedUsers;
787
1293
  handlers = [];
788
1294
  sendPipeline;
1295
+ log;
789
1296
  constructor(config) {
1297
+ this.log = config.logger ?? noopLogger;
790
1298
  this.bot = new Bot(config.botToken);
791
1299
  this.allowedUsers = new Set(config.allowedUsers);
792
1300
  this.bot.catch((err2) => {
793
- console.error("[augure:telegram] Bot error:", err2.message ?? err2);
1301
+ this.log.error("Bot error:", err2.message ?? err2);
794
1302
  });
795
1303
  this.bot.on("message:text", async (ctx) => {
796
1304
  const userId = ctx.from.id;
@@ -819,7 +1327,7 @@ var TelegramChannel = class {
819
1327
  ...replyOpts
820
1328
  }), { maxRetries: 3, baseDelayMs: 500 }).catch(async () => {
821
1329
  await this.bot.api.sendMessage(Number(msg.userId), msg.text, replyOpts).catch((fallbackErr) => {
822
- console.error("[augure:telegram] Fallback send also failed:", fallbackErr);
1330
+ this.log.error("Fallback send also failed:", fallbackErr);
823
1331
  throw fallbackErr;
824
1332
  });
825
1333
  });
@@ -830,7 +1338,7 @@ var TelegramChannel = class {
830
1338
  return this.allowedUsers.has(userId);
831
1339
  }
832
1340
  handleRejected(userId, unixTimestamp, rejectMessage) {
833
- console.warn(`[augure:telegram] Rejected message from unauthorized user ${userId} at ${new Date(unixTimestamp * 1e3).toISOString()}`);
1341
+ this.log.warn(`Rejected message from unauthorized user ${userId} at ${new Date(unixTimestamp * 1e3).toISOString()}`);
834
1342
  if (rejectMessage) {
835
1343
  this.bot.api.sendMessage(userId, rejectMessage).catch(() => {
836
1344
  });
@@ -864,14 +1372,27 @@ var ToolRegistry = class {
864
1372
  return Array.from(this.tools.values());
865
1373
  }
866
1374
  toFunctionSchemas() {
867
- return this.list().map((tool) => ({
868
- type: "function",
869
- function: {
870
- name: tool.name,
871
- description: tool.description,
872
- parameters: tool.parameters
1375
+ return this.list().map((tool) => {
1376
+ let description = tool.description;
1377
+ if (tool.configCheck && this.context) {
1378
+ try {
1379
+ const warning = tool.configCheck(this.context);
1380
+ if (warning) {
1381
+ description += `
1382
+ [NOT CONFIGURED] ${warning}`;
1383
+ }
1384
+ } catch {
1385
+ }
873
1386
  }
874
- }));
1387
+ return {
1388
+ type: "function",
1389
+ function: {
1390
+ name: tool.name,
1391
+ description,
1392
+ parameters: tool.parameters
1393
+ }
1394
+ };
1395
+ });
875
1396
  }
876
1397
  async execute(name, params) {
877
1398
  const tool = this.tools.get(name);
@@ -1011,10 +1532,54 @@ var scheduleTool = {
1011
1532
  }
1012
1533
  };
1013
1534
 
1535
+ // ../tools/dist/datetime.js
1536
+ var datetimeTool = {
1537
+ name: "datetime",
1538
+ description: "Get the current date and time, optionally in a specific timezone",
1539
+ parameters: {
1540
+ type: "object",
1541
+ properties: {
1542
+ timezone: {
1543
+ type: "string",
1544
+ description: "IANA timezone (e.g. 'Europe/Paris', 'America/New_York'). Defaults to the system timezone."
1545
+ }
1546
+ }
1547
+ },
1548
+ execute: async (params) => {
1549
+ const { timezone } = params;
1550
+ const now = /* @__PURE__ */ new Date();
1551
+ const options = {
1552
+ weekday: "long",
1553
+ year: "numeric",
1554
+ month: "long",
1555
+ day: "numeric",
1556
+ hour: "2-digit",
1557
+ minute: "2-digit",
1558
+ second: "2-digit",
1559
+ timeZoneName: "longOffset"
1560
+ };
1561
+ if (timezone) {
1562
+ options.timeZone = timezone;
1563
+ }
1564
+ try {
1565
+ const formatted = new Intl.DateTimeFormat("en-US", options).format(now);
1566
+ return {
1567
+ success: true,
1568
+ output: `${formatted}
1569
+ ISO 8601 (UTC): ${now.toISOString()}
1570
+ Unix timestamp: ${Math.floor(now.getTime() / 1e3)}`
1571
+ };
1572
+ } catch {
1573
+ return { success: false, output: `Invalid timezone: ${timezone}` };
1574
+ }
1575
+ }
1576
+ };
1577
+
1014
1578
  // ../tools/dist/web-search.js
1015
1579
  var webSearchTool = {
1016
1580
  name: "web_search",
1017
1581
  description: "Search the web using the configured search provider (Tavily, Exa, or SearXNG)",
1582
+ configCheck: (ctx) => ctx.config.tools?.webSearch ? null : "This tool requires configuration. See https://augure.dev/docs/tools/web-search",
1018
1583
  parameters: {
1019
1584
  type: "object",
1020
1585
  properties: {
@@ -1226,6 +1791,273 @@ ${text}`;
1226
1791
  // ../tools/dist/email.js
1227
1792
  import { ImapFlow } from "imapflow";
1228
1793
  import { createTransport } from "nodemailer";
1794
+ var MAX_BODY_CHARS = 4e3;
1795
+ function stripHtml(html) {
1796
+ return html.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, "").replace(/<script[^>]*>[\s\S]*?<\/script>/gi, "").replace(/<br\s*\/?>/gi, "\n").replace(/<\/p>/gi, "\n\n").replace(/<\/div>/gi, "\n").replace(/<[^>]+>/g, "").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/\n{3,}/g, "\n\n").trim();
1797
+ }
1798
+ function findTextPart(structure) {
1799
+ if (structure.type === "text/plain" && structure.part) {
1800
+ return { part: structure.part, isHtml: false };
1801
+ }
1802
+ if (structure.type === "text/html" && structure.part) {
1803
+ return { part: structure.part, isHtml: true };
1804
+ }
1805
+ if (structure.childNodes) {
1806
+ let htmlFallback = null;
1807
+ for (const child of structure.childNodes) {
1808
+ const found = findTextPart(child);
1809
+ if (found && !found.isHtml)
1810
+ return found;
1811
+ if (found && found.isHtml)
1812
+ htmlFallback = found;
1813
+ }
1814
+ return htmlFallback;
1815
+ }
1816
+ return null;
1817
+ }
1818
+ async function withImapClient(config, fn) {
1819
+ const client = new ImapFlow({
1820
+ host: config.host,
1821
+ port: config.port,
1822
+ secure: config.port === 993,
1823
+ auth: { user: config.user, pass: config.password },
1824
+ logger: false
1825
+ });
1826
+ let connected = false;
1827
+ try {
1828
+ await client.connect();
1829
+ connected = true;
1830
+ return await fn(client);
1831
+ } finally {
1832
+ if (connected) {
1833
+ await client.logout();
1834
+ }
1835
+ }
1836
+ }
1837
+ function formatSummaries(emails) {
1838
+ if (emails.length === 0)
1839
+ return "No emails found.";
1840
+ return emails.map((e, i) => `${i + 1}. ${e.seen ? "" : "[UNREAD] "}UID:${e.uid} Subject: ${e.subject} | From: ${e.from} | Date: ${e.date}`).join("\n");
1841
+ }
1842
+ function extractAddress(addr) {
1843
+ if (!addr)
1844
+ return "unknown";
1845
+ if (Array.isArray(addr)) {
1846
+ const first = addr[0];
1847
+ if (first && typeof first === "object" && "address" in first) {
1848
+ return first.address;
1849
+ }
1850
+ return String(first ?? "unknown");
1851
+ }
1852
+ if (typeof addr === "object" && "address" in addr) {
1853
+ return addr.address;
1854
+ }
1855
+ return String(addr);
1856
+ }
1857
+ async function handleList(params, imapConfig) {
1858
+ const folder = params.folder ?? "INBOX";
1859
+ const limit = params.limit ?? 10;
1860
+ return withImapClient(imapConfig, async (client) => {
1861
+ const lock = await client.getMailboxLock(folder);
1862
+ try {
1863
+ const status = client.mailbox;
1864
+ if (!status || status.exists === 0)
1865
+ return "Mailbox is empty.";
1866
+ const start = Math.max(1, status.exists - limit + 1);
1867
+ const emails = [];
1868
+ for await (const msg of client.fetch(`${start}:*`, {
1869
+ envelope: true,
1870
+ flags: true
1871
+ })) {
1872
+ emails.push({
1873
+ uid: msg.uid,
1874
+ subject: msg.envelope?.subject ?? "(no subject)",
1875
+ from: extractAddress(msg.envelope?.from),
1876
+ date: msg.envelope?.date?.toISOString() ?? "unknown",
1877
+ seen: msg.flags?.has("\\Seen") ?? false
1878
+ });
1879
+ }
1880
+ return formatSummaries(emails.slice(-limit));
1881
+ } finally {
1882
+ lock.release();
1883
+ }
1884
+ });
1885
+ }
1886
+ async function handleRead(params, imapConfig) {
1887
+ const folder = params.folder ?? "INBOX";
1888
+ return withImapClient(imapConfig, async (client) => {
1889
+ const lock = await client.getMailboxLock(folder);
1890
+ try {
1891
+ const msg = await client.fetchOne(String(params.uid), {
1892
+ envelope: true,
1893
+ bodyStructure: true,
1894
+ flags: true,
1895
+ uid: true
1896
+ });
1897
+ if (!msg)
1898
+ return `No email found with UID ${params.uid}.`;
1899
+ let bodyText = "";
1900
+ const textPart = msg.bodyStructure ? findTextPart(msg.bodyStructure) : null;
1901
+ if (textPart) {
1902
+ const { content } = await client.download(String(params.uid), textPart.part, {
1903
+ uid: true
1904
+ });
1905
+ const chunks = [];
1906
+ for await (const chunk of content) {
1907
+ chunks.push(Buffer.from(chunk));
1908
+ }
1909
+ bodyText = Buffer.concat(chunks).toString("utf-8");
1910
+ if (textPart.isHtml)
1911
+ bodyText = stripHtml(bodyText);
1912
+ }
1913
+ if (bodyText.length > MAX_BODY_CHARS) {
1914
+ bodyText = bodyText.slice(0, MAX_BODY_CHARS) + "\n[truncated]";
1915
+ }
1916
+ const wasSeen = msg.flags?.has("\\Seen") ?? false;
1917
+ await client.messageFlagsAdd(String(params.uid), ["\\Seen"], { uid: true });
1918
+ const subject = msg.envelope?.subject ?? "(no subject)";
1919
+ const from = extractAddress(msg.envelope?.from);
1920
+ const date = msg.envelope?.date?.toISOString() ?? "unknown";
1921
+ return `UID: ${params.uid}
1922
+ Subject: ${subject}
1923
+ From: ${from}
1924
+ Date: ${date}
1925
+ Status: ${wasSeen ? "was read" : "was unread, marked read"}
1926
+
1927
+ ${bodyText}`;
1928
+ } finally {
1929
+ lock.release();
1930
+ }
1931
+ });
1932
+ }
1933
+ async function handleSearch(params, imapConfig) {
1934
+ const folder = params.folder ?? "INBOX";
1935
+ const limit = params.limit ?? 10;
1936
+ return withImapClient(imapConfig, async (client) => {
1937
+ const lock = await client.getMailboxLock(folder);
1938
+ try {
1939
+ const criteria = {};
1940
+ if (params.from)
1941
+ criteria.from = params.from;
1942
+ if (params.subject)
1943
+ criteria.subject = params.subject;
1944
+ if (params.since)
1945
+ criteria.since = new Date(params.since);
1946
+ if (params.unseen)
1947
+ criteria.seen = false;
1948
+ const result = await client.search(criteria, { uid: true });
1949
+ const uids = Array.isArray(result) ? result : [];
1950
+ if (uids.length === 0)
1951
+ return "No emails match the search criteria.";
1952
+ const selected = uids.slice(-limit);
1953
+ const emails = [];
1954
+ for await (const msg of client.fetch(selected, { envelope: true, flags: true }, { uid: true })) {
1955
+ emails.push({
1956
+ uid: msg.uid,
1957
+ subject: msg.envelope?.subject ?? "(no subject)",
1958
+ from: extractAddress(msg.envelope?.from),
1959
+ date: msg.envelope?.date?.toISOString() ?? "unknown",
1960
+ seen: msg.flags?.has("\\Seen") ?? false
1961
+ });
1962
+ }
1963
+ return formatSummaries(emails);
1964
+ } finally {
1965
+ lock.release();
1966
+ }
1967
+ });
1968
+ }
1969
+ async function handleSend(params, smtpConfig) {
1970
+ const transport = createTransport({
1971
+ host: smtpConfig.host,
1972
+ port: smtpConfig.port,
1973
+ secure: smtpConfig.port === 465,
1974
+ auth: { user: smtpConfig.user, pass: smtpConfig.password }
1975
+ });
1976
+ const info = await transport.sendMail({
1977
+ from: smtpConfig.user,
1978
+ to: params.to,
1979
+ subject: params.subject,
1980
+ text: params.body,
1981
+ cc: params.cc,
1982
+ bcc: params.bcc
1983
+ });
1984
+ return `Email sent. Message ID: ${info.messageId}`;
1985
+ }
1986
+ var emailTool = {
1987
+ name: "email",
1988
+ description: "Manage email: list recent messages, read by UID, search with criteria, or send an email via SMTP",
1989
+ configCheck: (ctx) => ctx.config.tools?.email ? null : "This tool requires configuration. See https://augure.dev/docs/tools/email",
1990
+ parameters: {
1991
+ type: "object",
1992
+ properties: {
1993
+ action: {
1994
+ type: "string",
1995
+ enum: ["list", "read", "search", "send"],
1996
+ description: "The email action to perform"
1997
+ },
1998
+ folder: {
1999
+ type: "string",
2000
+ description: 'IMAP folder (default: "INBOX"). Used by list, read, search.'
2001
+ },
2002
+ limit: {
2003
+ type: "number",
2004
+ description: "Max emails to return (default: 10). Used by list, search."
2005
+ },
2006
+ uid: { type: "number", description: "Email UID to read. Required for read." },
2007
+ from: { type: "string", description: "Filter by sender address. Used by search." },
2008
+ subject: {
2009
+ type: "string",
2010
+ description: "Filter by subject (search) or email subject (send)."
2011
+ },
2012
+ since: {
2013
+ type: "string",
2014
+ description: "ISO 8601 date \u2014 emails since this date. Used by search."
2015
+ },
2016
+ unseen: { type: "boolean", description: "Only unread emails. Used by search." },
2017
+ to: { type: "string", description: "Recipient address. Required for send." },
2018
+ body: { type: "string", description: "Email body text. Required for send." },
2019
+ cc: { type: "string", description: "CC recipients. Used by send." },
2020
+ bcc: { type: "string", description: "BCC recipients. Used by send." }
2021
+ },
2022
+ required: ["action"]
2023
+ },
2024
+ execute: async (params, ctx) => {
2025
+ const p = params;
2026
+ const emailConfig = ctx.config.tools?.email;
2027
+ if (!emailConfig) {
2028
+ return { success: false, output: "Email is not configured. Add tools.email to your config." };
2029
+ }
2030
+ try {
2031
+ switch (p.action) {
2032
+ case "list":
2033
+ return { success: true, output: await handleList(p, emailConfig.imap) };
2034
+ case "read":
2035
+ if (!p.uid)
2036
+ return { success: false, output: "Missing required field: uid" };
2037
+ return { success: true, output: await handleRead(p, emailConfig.imap) };
2038
+ case "search":
2039
+ if (!p.from && !p.subject && !p.since && p.unseen === void 0)
2040
+ return { success: false, output: "At least one search criterion is required (from, subject, since, or unseen)." };
2041
+ return { success: true, output: await handleSearch(p, emailConfig.imap) };
2042
+ case "send":
2043
+ if (!p.to)
2044
+ return { success: false, output: "Missing required field: to" };
2045
+ if (!p.subject)
2046
+ return { success: false, output: "Missing required field: subject" };
2047
+ if (!p.body)
2048
+ return { success: false, output: "Missing required field: body" };
2049
+ return { success: true, output: await handleSend(p, emailConfig.smtp) };
2050
+ default:
2051
+ return { success: false, output: `Unknown action: ${p.action}` };
2052
+ }
2053
+ } catch (err2) {
2054
+ return {
2055
+ success: false,
2056
+ output: err2 instanceof Error ? err2.message : String(err2)
2057
+ };
2058
+ }
2059
+ }
2060
+ };
1229
2061
 
1230
2062
  // ../tools/dist/sandbox-exec.js
1231
2063
  var sandboxExecTool = {
@@ -1304,6 +2136,7 @@ function shellEscape(s) {
1304
2136
  var opencodeTool = {
1305
2137
  name: "opencode",
1306
2138
  description: "Run a code agent (claude-code, opencode, codex CLI) in a Docker container to perform a coding task.",
2139
+ configCheck: (ctx) => ctx.config.sandbox.codeAgent ? null : "This tool requires sandbox.codeAgent configuration. See https://augure.dev/docs/sandbox",
1307
2140
  parameters: {
1308
2141
  type: "object",
1309
2142
  properties: {
@@ -1515,6 +2348,10 @@ var DockerContainer = class {
1515
2348
  }
1516
2349
  });
1517
2350
  this.demux(stream, stdoutPT, stderrPT);
2351
+ stream.on("end", () => {
2352
+ stdoutPT.end();
2353
+ stderrPT.end();
2354
+ });
1518
2355
  });
1519
2356
  }
1520
2357
  };
@@ -1540,6 +2377,7 @@ var DockerContainerPool = class {
1540
2377
  docker;
1541
2378
  image;
1542
2379
  maxTotal;
2380
+ log;
1543
2381
  // C3: idle cache keyed by trust level to prevent cross-trust reuse
1544
2382
  idle = /* @__PURE__ */ new Map([
1545
2383
  ["sandboxed", /* @__PURE__ */ new Set()],
@@ -1551,6 +2389,7 @@ var DockerContainerPool = class {
1551
2389
  this.docker = docker;
1552
2390
  this.image = config.image;
1553
2391
  this.maxTotal = config.maxTotal;
2392
+ this.log = config.logger ?? noopLogger;
1554
2393
  }
1555
2394
  get idleCount() {
1556
2395
  let count = 0;
@@ -1560,18 +2399,22 @@ var DockerContainerPool = class {
1560
2399
  }
1561
2400
  /* ---- acquire ---- */
1562
2401
  async acquire(opts) {
2402
+ this.log.debug(`Acquiring container: trust=${opts.trust} memory=${opts.memory} cpu=${opts.cpu}`);
1563
2403
  const trustIdle = this.idle.get(opts.trust);
1564
2404
  const cached = trustIdle.values().next();
1565
2405
  if (!cached.done) {
1566
2406
  const container2 = cached.value;
1567
2407
  trustIdle.delete(container2);
1568
2408
  this.busy.add(container2);
2409
+ this.log.debug(`Reusing cached container: ${container2.id.slice(0, 12)}`);
1569
2410
  return container2;
1570
2411
  }
1571
2412
  const total = this.idleCount + this.busy.size;
1572
2413
  if (total >= this.maxTotal) {
2414
+ this.log.error(`Pool limit reached: ${total}/${this.maxTotal}`);
1573
2415
  throw new Error("Pool limit reached");
1574
2416
  }
2417
+ this.log.debug("Creating new container...");
1575
2418
  const raw = await this.docker.createContainer(this.buildCreateOpts(opts));
1576
2419
  await raw.start();
1577
2420
  const modem = this.docker.modem;
@@ -1579,6 +2422,7 @@ var DockerContainerPool = class {
1579
2422
  const container = new DockerContainer(raw, demux);
1580
2423
  this.containerTrust.set(container.id, opts.trust);
1581
2424
  this.busy.add(container);
2425
+ this.log.debug(`Container created: ${container.id.slice(0, 12)}`);
1582
2426
  return container;
1583
2427
  }
1584
2428
  /* ---- release ---- */
@@ -1590,6 +2434,7 @@ var DockerContainerPool = class {
1590
2434
  }
1591
2435
  const trust = this.containerTrust.get(container.id) ?? "sandboxed";
1592
2436
  this.idle.get(trust).add(container);
2437
+ this.log.debug(`Container released: ${container.id.slice(0, 12)} \u2192 idle (${trust})`);
1593
2438
  }
1594
2439
  /* ---- destroy ---- */
1595
2440
  async destroy(container) {
@@ -1678,16 +2523,19 @@ function buildTar(content) {
1678
2523
  const end = Buffer.alloc(1024, 0);
1679
2524
  return Buffer.concat([header, dataPadded, end]);
1680
2525
  }
1681
- async function ensureImage(docker, imageName) {
2526
+ async function ensureImage(docker, imageName, logger) {
2527
+ const log = logger ?? noopLogger;
2528
+ log.debug(`Checking image: ${imageName}`);
1682
2529
  try {
1683
2530
  await docker.getImage(imageName).inspect();
2531
+ log.debug("Image exists");
1684
2532
  return;
1685
2533
  } catch (err2) {
1686
2534
  const statusCode = err2.statusCode;
1687
2535
  if (statusCode !== void 0 && statusCode !== 404)
1688
2536
  throw err2;
1689
2537
  }
1690
- console.log(`[augure] Image "${imageName}" not found, building...`);
2538
+ log.info(`Image "${imageName}" not found, building...`);
1691
2539
  const tar = buildTar(DOCKERFILE);
1692
2540
  const stream = await docker.buildImage(Readable.from(tar), {
1693
2541
  t: imageName
@@ -1699,11 +2547,14 @@ async function ensureImage(docker, imageName) {
1699
2547
  else
1700
2548
  resolve5();
1701
2549
  }, (event) => {
1702
- if (event.stream)
1703
- process.stdout.write(event.stream);
2550
+ if (event.stream) {
2551
+ const line = event.stream.trim();
2552
+ if (line)
2553
+ log.debug(line);
2554
+ }
1704
2555
  });
1705
2556
  });
1706
- console.log(`[augure] Image "${imageName}" built successfully`);
2557
+ log.info(`Image "${imageName}" built`);
1707
2558
  }
1708
2559
 
1709
2560
  // ../memory/dist/store.js
@@ -1872,6 +2723,7 @@ var CronScheduler = class {
1872
2723
  timers = /* @__PURE__ */ new Map();
1873
2724
  handlers = [];
1874
2725
  persistChain = Promise.resolve();
2726
+ running = false;
1875
2727
  constructor(store) {
1876
2728
  this.store = store;
1877
2729
  }
@@ -1889,12 +2741,21 @@ var CronScheduler = class {
1889
2741
  throw new Error(`Invalid runAt date: ${job.runAt}`);
1890
2742
  }
1891
2743
  this.jobs.set(job.id, job);
2744
+ console.log(`[scheduler] Added job ${job.id} (${job.cron ? `cron: ${job.cron}` : `runAt: ${job.runAt}`})`);
1892
2745
  if (job.enabled && job.cron) {
1893
2746
  const task = createTask(job.cron, () => {
2747
+ console.log(`[scheduler] Cron fired for job ${job.id}`);
1894
2748
  void this.executeHandlers(job);
1895
2749
  });
2750
+ if (this.running) {
2751
+ task.start();
2752
+ console.log(`[scheduler] Started cron task for ${job.id} immediately (scheduler already running)`);
2753
+ }
1896
2754
  this.tasks.set(job.id, task);
1897
2755
  }
2756
+ if (this.running && job.enabled && job.runAt && !job.cron) {
2757
+ this.scheduleOneShot(job);
2758
+ }
1898
2759
  this.persist();
1899
2760
  }
1900
2761
  removeJob(id) {
@@ -1909,6 +2770,7 @@ var CronScheduler = class {
1909
2770
  this.timers.delete(id);
1910
2771
  }
1911
2772
  this.jobs.delete(id);
2773
+ console.log(`[scheduler] Removed job ${id}`);
1912
2774
  this.persist();
1913
2775
  }
1914
2776
  listJobs() {
@@ -1925,16 +2787,21 @@ var CronScheduler = class {
1925
2787
  if (!this.store)
1926
2788
  return;
1927
2789
  const jobs = await this.store.load();
2790
+ console.log(`[scheduler] Loading ${jobs.length} persisted jobs`);
1928
2791
  for (const job of jobs) {
1929
2792
  if (job.runAt && Date.parse(job.runAt) <= Date.now()) {
2793
+ console.log(`[scheduler] Skipping expired one-shot job ${job.id} (runAt: ${job.runAt})`);
1930
2794
  continue;
1931
2795
  }
1932
2796
  this.addJob(job);
1933
2797
  }
1934
2798
  }
1935
2799
  start() {
1936
- for (const task of this.tasks.values()) {
2800
+ this.running = true;
2801
+ console.log(`[scheduler] Starting with ${this.tasks.size} cron tasks and ${this.handlers.length} handlers`);
2802
+ for (const [id, task] of this.tasks) {
1937
2803
  task.start();
2804
+ console.log(`[scheduler] Started cron task: ${id}`);
1938
2805
  }
1939
2806
  for (const job of this.jobs.values()) {
1940
2807
  if (job.enabled && job.runAt && !job.cron) {
@@ -1943,6 +2810,7 @@ var CronScheduler = class {
1943
2810
  }
1944
2811
  }
1945
2812
  stop() {
2813
+ this.running = false;
1946
2814
  for (const task of this.tasks.values()) {
1947
2815
  task.stop();
1948
2816
  }
@@ -1953,9 +2821,13 @@ var CronScheduler = class {
1953
2821
  }
1954
2822
  scheduleOneShot(job) {
1955
2823
  const delayMs = Date.parse(job.runAt) - Date.now();
1956
- if (delayMs <= 0)
2824
+ if (delayMs <= 0) {
2825
+ console.log(`[scheduler] One-shot job ${job.id} already expired (delay: ${delayMs}ms), skipping`);
1957
2826
  return;
2827
+ }
2828
+ console.log(`[scheduler] Scheduled one-shot job ${job.id} in ${Math.round(delayMs / 1e3)}s (${job.runAt})`);
1958
2829
  const timer = setTimeout(() => {
2830
+ console.log(`[scheduler] One-shot job ${job.id} firing now`);
1959
2831
  this.timers.delete(job.id);
1960
2832
  void this.executeHandlers(job).then(() => {
1961
2833
  this.removeJob(job.id);
@@ -1970,6 +2842,7 @@ var CronScheduler = class {
1970
2842
  this.persistChain = this.persistChain.then(() => this.store.save(jobs));
1971
2843
  }
1972
2844
  async executeHandlers(job) {
2845
+ console.log(`[scheduler] Executing ${this.handlers.length} handlers for job ${job.id}`);
1973
2846
  for (const handler of this.handlers) {
1974
2847
  await handler(job);
1975
2848
  }
@@ -2016,10 +2889,13 @@ Be concise. Only suggest actions that are clearly needed based on the memory con
2016
2889
  var Heartbeat = class {
2017
2890
  config;
2018
2891
  timer;
2892
+ log;
2019
2893
  constructor(config) {
2020
2894
  this.config = config;
2895
+ this.log = config.logger ?? noopLogger;
2021
2896
  }
2022
2897
  async tick() {
2898
+ this.log.debug("Heartbeat tick");
2023
2899
  const memoryContent = await this.loadMemory();
2024
2900
  const messages = [
2025
2901
  { role: "system", content: HEARTBEAT_PROMPT },
@@ -2034,12 +2910,15 @@ ${memoryContent}`
2034
2910
  const response = await this.config.llm.chat(messages);
2035
2911
  const action = this.parseAction(response.content);
2036
2912
  if (action && action.toLowerCase() !== "none") {
2913
+ this.log.debug(`Heartbeat action: ${action}`);
2037
2914
  await this.config.onAction(action);
2915
+ } else {
2916
+ this.log.debug("Heartbeat: no action needed");
2038
2917
  }
2039
2918
  }
2040
2919
  start() {
2041
2920
  this.timer = setInterval(() => {
2042
- this.tick().catch((err2) => console.error("[augure] Heartbeat error:", err2));
2921
+ this.tick().catch((err2) => this.log.error("Heartbeat error:", err2));
2043
2922
  }, this.config.intervalMs);
2044
2923
  }
2045
2924
  stop() {
@@ -2886,9 +3765,11 @@ var JOB_PREFIX = "skill:";
2886
3765
  var SkillSchedulerBridge = class {
2887
3766
  scheduler;
2888
3767
  manager;
2889
- constructor(scheduler, manager) {
3768
+ log;
3769
+ constructor(scheduler, manager, logger) {
2890
3770
  this.scheduler = scheduler;
2891
3771
  this.manager = manager;
3772
+ this.log = logger ?? noopLogger;
2892
3773
  }
2893
3774
  /** Register cron jobs for all active cron-triggered skills */
2894
3775
  async syncAll() {
@@ -2907,7 +3788,7 @@ var SkillSchedulerBridge = class {
2907
3788
  enabled: true
2908
3789
  });
2909
3790
  } catch (err2) {
2910
- console.error(`[skills] Failed to register cron for ${skill.id}:`, err2);
3791
+ this.log.error(`Failed to register cron for ${skill.id}:`, err2);
2911
3792
  }
2912
3793
  }
2913
3794
  existingJobs.delete(jobId);
@@ -3401,27 +4282,48 @@ var VersionChecker = class _VersionChecker {
3401
4282
  };
3402
4283
 
3403
4284
  // ../core/dist/main.js
3404
- var SYSTEM_PROMPT = `You are Augure, a personal AI assistant. You are proactive, helpful, and concise.
4285
+ var BASE_SYSTEM_PROMPT = `You are Augure, a personal AI assistant. You are proactive, helpful, and concise.
3405
4286
  You speak the same language as the user. You have access to tools and persistent memory.
3406
- Always be direct and actionable.`;
3407
- function resolveLLMClient(config, usage) {
4287
+ Always be direct and actionable.
4288
+
4289
+ ## Your capabilities
4290
+
4291
+ You have access to tools that let you interact with the outside world. Use the datetime tool when the user needs precise time information beyond what is shown in the current date above. Use memory tools to remember and recall information across conversations. Use the schedule tool to create recurring or one-shot tasks.
4292
+
4293
+ If a tool is marked as [NOT CONFIGURED], let the user know it needs to be set up first and share the documentation link from the tool description.`;
4294
+ var SKILLS_PROMPT = `
4295
+ ## Skills
4296
+
4297
+ You can create and manage "skills" \u2014 autonomous code units that run in isolated Docker containers. Skills are powerful: they let you automate tasks, run on a schedule, and self-heal when they break.
4298
+
4299
+ - Use skill_list to see existing skills and their status
4300
+ - Use skill_generate to create a new skill from a natural language description
4301
+ - Use skill_run to execute a skill manually
4302
+ - Use skill_heal to fix a broken skill
4303
+ - Use skill_install to install a skill from the hub
4304
+
4305
+ When a user asks to automate a recurring task (e.g. "check this every morning", "send me a summary daily"), suggest creating a skill with a cron trigger. Skills can also be triggered manually or by events.`;
4306
+ function resolveLLMClient(config, usage, logger) {
3408
4307
  const override = usage !== "default" ? config[usage] : void 0;
3409
4308
  return new OpenRouterClient({
3410
4309
  apiKey: override?.apiKey ?? config.default.apiKey,
3411
4310
  model: override?.model ?? config.default.model,
3412
- maxTokens: override?.maxTokens ?? config.default.maxTokens
4311
+ maxTokens: override?.maxTokens ?? config.default.maxTokens,
4312
+ logger: logger.child("llm")
3413
4313
  });
3414
4314
  }
3415
- async function startAgent(configPath) {
4315
+ async function startAgent(configPath, opts) {
4316
+ const log = createLogger({ level: opts?.debug ? "debug" : "info" });
3416
4317
  const config = await loadConfig(configPath);
3417
- console.log(`[augure] Loaded config: ${config.identity.name}`);
4318
+ log.info(`Loaded config: ${config.identity.name}`);
4319
+ log.debug(`Config path: ${configPath}`);
3418
4320
  let telegram;
3419
- const llm = resolveLLMClient(config.llm, "default");
3420
- const ingestionLLM = resolveLLMClient(config.llm, "ingestion");
3421
- const monitoringLLM = resolveLLMClient(config.llm, "monitoring");
4321
+ const llm = resolveLLMClient(config.llm, "default", log);
4322
+ const ingestionLLM = resolveLLMClient(config.llm, "ingestion", log);
4323
+ const monitoringLLM = resolveLLMClient(config.llm, "monitoring", log);
3422
4324
  const memoryPath = resolve(configPath, "..", config.memory.path);
3423
4325
  const memory = new FileMemoryStore(memoryPath);
3424
- console.log(`[augure] Memory store: ${memoryPath}`);
4326
+ log.info(`Memory store: ${memoryPath}`);
3425
4327
  const retriever = new MemoryRetriever(memory, {
3426
4328
  maxTokens: config.memory.maxRetrievalTokens
3427
4329
  });
@@ -3430,15 +4332,17 @@ async function startAgent(configPath) {
3430
4332
  tools.register(memoryReadTool);
3431
4333
  tools.register(memoryWriteTool);
3432
4334
  tools.register(scheduleTool);
4335
+ tools.register(datetimeTool);
3433
4336
  tools.register(webSearchTool);
3434
4337
  tools.register(httpTool);
4338
+ tools.register(emailTool);
3435
4339
  tools.register(sandboxExecTool);
3436
4340
  tools.register(opencodeTool);
3437
4341
  const jobStorePath = resolve(configPath, "..", "jobs.json");
3438
4342
  const jobStore = new JobStore(jobStorePath);
3439
4343
  const scheduler = new CronScheduler(jobStore);
3440
4344
  await scheduler.loadPersistedJobs();
3441
- console.log(`[augure] Loaded ${scheduler.listJobs().length} persisted jobs`);
4345
+ log.info(`Loaded ${scheduler.listJobs().length} persisted jobs`);
3442
4346
  for (const job of config.scheduler.jobs) {
3443
4347
  if (!scheduler.listJobs().some((j) => j.id === job.id)) {
3444
4348
  scheduler.addJob({ ...job, enabled: true });
@@ -3446,17 +4350,19 @@ async function startAgent(configPath) {
3446
4350
  }
3447
4351
  const docker = new Dockerode();
3448
4352
  const sandboxImage = config.sandbox.image ?? "augure-sandbox:latest";
3449
- await ensureImage(docker, sandboxImage);
4353
+ const sandboxLog = log.child("sandbox");
4354
+ await ensureImage(docker, sandboxImage, sandboxLog);
3450
4355
  const pool = new DockerContainerPool(docker, {
3451
4356
  image: sandboxImage,
3452
- maxTotal: config.security.maxConcurrentSandboxes
4357
+ maxTotal: config.security.maxConcurrentSandboxes,
4358
+ logger: sandboxLog
3453
4359
  });
3454
- console.log(`[augure] Container pool created (max: ${config.security.maxConcurrentSandboxes})`);
4360
+ log.info(`Container pool: max=${config.security.maxConcurrentSandboxes}`);
3455
4361
  let skillManagerRef;
3456
4362
  let skillUpdater;
3457
4363
  if (config.skills) {
3458
4364
  const skillsPath = resolve(configPath, "..", config.skills.path);
3459
- const codingLLM = resolveLLMClient(config.llm, "coding");
4365
+ const codingLLM = resolveLLMClient(config.llm, "coding", log);
3460
4366
  const skillManager = new SkillManager(skillsPath);
3461
4367
  const skillGenerator = new SkillGenerator(codingLLM);
3462
4368
  const skillRunner = new SkillRunner({
@@ -3500,29 +4406,63 @@ async function startAgent(configPath) {
3500
4406
  const updated = updateResults.filter((r) => r.success);
3501
4407
  const failed = updateResults.filter((r) => !r.success);
3502
4408
  if (updated.length > 0) {
3503
- console.log(`[augure] Skills updated: ${updated.map((r) => `${r.skillId} (v${r.fromVersion}\u2192v${r.toVersion})`).join(", ")}`);
4409
+ log.info(`Skills updated: ${updated.map((r) => `${r.skillId} (v${r.fromVersion}\u2192v${r.toVersion})`).join(", ")}`);
3504
4410
  }
3505
4411
  if (failed.length > 0) {
3506
- console.log(`[augure] Skill updates failed: ${failed.map((r) => `${r.skillId}: ${r.error}`).join(", ")}`);
4412
+ log.warn(`Skill updates failed: ${failed.map((r) => `${r.skillId}: ${r.error}`).join(", ")}`);
3507
4413
  }
3508
4414
  } catch (err2) {
3509
- console.error("[augure] Skill update check failed:", err2);
4415
+ log.error("Skill update check failed:", err2);
3510
4416
  }
3511
4417
  }
3512
4418
  skillManagerRef = skillManager;
3513
- console.log(`[augure] Skills system initialized at ${skillsPath}`);
4419
+ log.info(`Skills initialized: ${skillsPath}`);
3514
4420
  }
3515
4421
  tools.setContext({ config, memory, scheduler, pool });
4422
+ let codeModeExecutor;
4423
+ if (config.codeMode) {
4424
+ const cmConfig = config.codeMode;
4425
+ if (cmConfig.runtime === "vm") {
4426
+ codeModeExecutor = new VmExecutor(tools, {
4427
+ timeout: cmConfig.timeout * 1e3,
4428
+ // VmExecutor expects ms
4429
+ memoryLimit: cmConfig.memoryLimit
4430
+ });
4431
+ } else if (cmConfig.runtime === "docker") {
4432
+ codeModeExecutor = new DockerExecutor({
4433
+ registry: tools,
4434
+ pool,
4435
+ timeout: cmConfig.timeout,
4436
+ // DockerExecutor expects seconds
4437
+ memoryLimit: config.sandbox.defaults.memoryLimit,
4438
+ cpuLimit: config.sandbox.defaults.cpuLimit
4439
+ });
4440
+ } else {
4441
+ const vmExec = new VmExecutor(tools, {
4442
+ timeout: cmConfig.timeout * 1e3,
4443
+ memoryLimit: cmConfig.memoryLimit
4444
+ });
4445
+ const dockerExec = new DockerExecutor({
4446
+ registry: tools,
4447
+ pool,
4448
+ timeout: cmConfig.timeout,
4449
+ memoryLimit: config.sandbox.defaults.memoryLimit,
4450
+ cpuLimit: config.sandbox.defaults.cpuLimit
4451
+ });
4452
+ codeModeExecutor = new AutoExecutor(vmExec, dockerExec);
4453
+ }
4454
+ log.info(`Code Mode enabled: runtime=${cmConfig.runtime}, timeout=${cmConfig.timeout}s`);
4455
+ }
3516
4456
  const auditConfig = config.audit ?? { path: "./logs", enabled: true };
3517
4457
  const auditPath = resolve(configPath, "..", auditConfig.path);
3518
- const audit = auditConfig.enabled ? new FileAuditLogger(auditPath) : new NullAuditLogger();
3519
- console.log(`[augure] Audit logger: ${auditConfig.enabled ? auditPath : "disabled"}`);
4458
+ const audit = auditConfig.enabled ? new FileAuditLogger(auditPath, log.child("audit")) : new NullAuditLogger();
4459
+ log.info(`Audit: ${auditConfig.enabled ? auditPath : "disabled"}`);
3520
4460
  let personaResolver;
3521
4461
  if (config.persona) {
3522
4462
  const personaPath = resolve(configPath, "..", config.persona.path);
3523
4463
  personaResolver = new PersonaResolver(personaPath);
3524
4464
  await personaResolver.loadAll();
3525
- console.log(`[augure] Personas loaded from ${personaPath}`);
4465
+ log.info(`Personas: ${personaPath}`);
3526
4466
  }
3527
4467
  let cliVersion;
3528
4468
  try {
@@ -3538,29 +4478,34 @@ async function startAgent(configPath) {
3538
4478
  });
3539
4479
  const versionResult = await versionChecker.check();
3540
4480
  if (versionResult.updateAvailable) {
3541
- console.log(`[augure] Update available: v${versionResult.latestVersion} (current: v${versionResult.currentVersion}). Run: npm update -g augure`);
4481
+ log.warn(`Update available: v${versionResult.latestVersion} (current: v${versionResult.currentVersion}). Run: npm update -g augure`);
3542
4482
  }
3543
4483
  }
3544
4484
  const guard = new ContextGuard({
3545
4485
  maxContextTokens: 2e5,
3546
4486
  reservedForOutput: config.llm.default.maxTokens ?? 8192
3547
4487
  });
4488
+ const systemPrompt = config.skills ? BASE_SYSTEM_PROMPT + SKILLS_PROMPT : BASE_SYSTEM_PROMPT;
3548
4489
  const agent = new Agent({
3549
4490
  llm,
3550
4491
  tools,
3551
- systemPrompt: SYSTEM_PROMPT,
4492
+ systemPrompt,
3552
4493
  memoryContent: "",
3553
4494
  retriever,
3554
4495
  ingester,
3555
4496
  audit,
3556
4497
  guard,
3557
- modelName: config.llm.default.model
4498
+ modelName: config.llm.default.model,
4499
+ logger: log.child("agent"),
4500
+ codeModeExecutor
3558
4501
  });
3559
4502
  if (config.channels.telegram?.enabled) {
4503
+ const telegramLog = log.child("telegram");
3560
4504
  telegram = new TelegramChannel({
3561
4505
  botToken: config.channels.telegram.botToken,
3562
4506
  allowedUsers: config.channels.telegram.allowedUsers,
3563
- rejectMessage: config.channels.telegram.rejectMessage
4507
+ rejectMessage: config.channels.telegram.rejectMessage,
4508
+ logger: telegramLog
3564
4509
  });
3565
4510
  const tg = telegram;
3566
4511
  const commandCtx = {
@@ -3570,7 +4515,7 @@ async function startAgent(configPath) {
3570
4515
  skillManager: skillManagerRef
3571
4516
  };
3572
4517
  tg.onMessage(async (msg) => {
3573
- console.log(`[augure] Message from ${msg.userId}: ${msg.text}`);
4518
+ log.info(`Message from ${msg.userId}: ${msg.text}`);
3574
4519
  try {
3575
4520
  const cmdResult = await handleCommand(msg.text, commandCtx);
3576
4521
  if (cmdResult.handled) {
@@ -3593,7 +4538,7 @@ async function startAgent(configPath) {
3593
4538
  replyTo: msg.id
3594
4539
  });
3595
4540
  } catch (err2) {
3596
- console.error("[augure] Error handling message:", err2);
4541
+ log.error("Error handling message:", err2);
3597
4542
  await tg.send({
3598
4543
  channelType: "telegram",
3599
4544
  userId: msg.userId,
@@ -3602,15 +4547,16 @@ async function startAgent(configPath) {
3602
4547
  }
3603
4548
  });
3604
4549
  await tg.start();
3605
- console.log("[augure] Telegram bot started. Waiting for messages...");
4550
+ log.info("Telegram bot started");
3606
4551
  }
3607
4552
  const heartbeatIntervalMs = parseInterval(config.scheduler.heartbeatInterval);
3608
4553
  const heartbeat = new Heartbeat({
3609
4554
  llm: monitoringLLM,
3610
4555
  memory,
3611
4556
  intervalMs: heartbeatIntervalMs,
4557
+ logger: log.child("heartbeat"),
3612
4558
  onAction: async (action) => {
3613
- console.log(`[augure] Heartbeat action: ${action}`);
4559
+ log.info(`Heartbeat action: ${action}`);
3614
4560
  const response = await agent.handleMessage({
3615
4561
  id: `heartbeat-${Date.now()}`,
3616
4562
  channelType: "system",
@@ -3618,11 +4564,11 @@ async function startAgent(configPath) {
3618
4564
  text: `[Heartbeat] ${action}`,
3619
4565
  timestamp: /* @__PURE__ */ new Date()
3620
4566
  });
3621
- console.log(`[augure] Heartbeat response: ${response}`);
4567
+ log.debug(`Heartbeat response: ${response.slice(0, 200)}`);
3622
4568
  }
3623
4569
  });
3624
4570
  scheduler.onJobTrigger(async (job) => {
3625
- console.log(`[augure] Job triggered: ${job.id}`);
4571
+ log.info(`Job triggered: ${job.id}`);
3626
4572
  const response = await agent.handleMessage({
3627
4573
  id: `job-${job.id}-${Date.now()}`,
3628
4574
  channelType: "system",
@@ -3640,11 +4586,11 @@ async function startAgent(configPath) {
3640
4586
  });
3641
4587
  }
3642
4588
  }
3643
- console.log(`[augure] Job ${job.id} completed`);
4589
+ log.debug(`Job ${job.id} completed`);
3644
4590
  });
3645
4591
  scheduler.start();
3646
4592
  heartbeat.start();
3647
- console.log(`[augure] Scheduler started with ${scheduler.listJobs().length} jobs. Heartbeat every ${config.scheduler.heartbeatInterval}.`);
4593
+ log.info(`Scheduler started: ${scheduler.listJobs().length} jobs, heartbeat every ${config.scheduler.heartbeatInterval}`);
3648
4594
  const updateTimers = [];
3649
4595
  if (skillUpdater && config.updates?.skills?.checkInterval) {
3650
4596
  const su = skillUpdater;
@@ -3654,13 +4600,13 @@ async function startAgent(configPath) {
3654
4600
  const results = await su.checkAndApply();
3655
4601
  for (const r of results) {
3656
4602
  if (r.success) {
3657
- console.log(`[augure] Skill auto-updated: ${r.skillId} v${r.fromVersion}\u2192v${r.toVersion}`);
4603
+ log.info(`Skill auto-updated: ${r.skillId} v${r.fromVersion}\u2192v${r.toVersion}`);
3658
4604
  } else if (r.rolledBack) {
3659
- console.log(`[augure] Skill update rolled back: ${r.skillId} - ${r.error}`);
4605
+ log.warn(`Skill update rolled back: ${r.skillId} - ${r.error}`);
3660
4606
  }
3661
4607
  }
3662
4608
  } catch (err2) {
3663
- console.error("[augure] Periodic skill update check failed:", err2);
4609
+ log.error("Periodic skill update check failed:", err2);
3664
4610
  }
3665
4611
  }, skillCheckMs));
3666
4612
  }
@@ -3685,12 +4631,12 @@ Run: \`npm update -g augure\``
3685
4631
  }
3686
4632
  }
3687
4633
  } catch (err2) {
3688
- console.error("[augure] CLI version check failed:", err2);
4634
+ log.error("CLI version check failed:", err2);
3689
4635
  }
3690
4636
  }, cliCheckMs));
3691
4637
  }
3692
4638
  const shutdown = async () => {
3693
- console.log("\n[augure] Shutting down...");
4639
+ log.info("Shutting down...");
3694
4640
  for (const timer of updateTimers)
3695
4641
  clearInterval(timer);
3696
4642
  heartbeat.stop();
@@ -3699,23 +4645,13 @@ Run: \`npm update -g augure\``
3699
4645
  await telegram.stop();
3700
4646
  await pool.destroyAll();
3701
4647
  await audit.close();
3702
- console.log("[augure] All containers destroyed");
4648
+ log.info("All containers destroyed");
3703
4649
  process.exit(0);
3704
4650
  };
3705
4651
  process.on("SIGINT", shutdown);
3706
4652
  process.on("SIGTERM", shutdown);
3707
4653
  }
3708
4654
 
3709
- // src/colors.ts
3710
- import { styleText } from "util";
3711
- var brand = (s) => styleText("yellow", s);
3712
- var ok = (s) => styleText("green", s);
3713
- var err = (s) => styleText("red", s);
3714
- var dim = (s) => styleText("dim", s);
3715
- var bold = (s) => styleText("bold", s);
3716
- var cyan = (s) => styleText("cyan", s);
3717
- var prefix = brand("\u25B2 augure");
3718
-
3719
4655
  // src/commands/start.ts
3720
4656
  var startCommand = defineCommand({
3721
4657
  meta: {
@@ -3733,21 +4669,28 @@ var startCommand = defineCommand({
3733
4669
  type: "string",
3734
4670
  description: "Path to .env file",
3735
4671
  alias: "e"
4672
+ },
4673
+ debug: {
4674
+ type: "boolean",
4675
+ description: "Enable debug logging",
4676
+ alias: "d",
4677
+ default: false
3736
4678
  }
3737
4679
  },
3738
4680
  async run({ args }) {
3739
4681
  const configPath = resolve2(args.config);
4682
+ const log = createLogger({ level: args.debug ? "debug" : "info" });
3740
4683
  const envPath = args.env ? resolve2(args.env) : join6(dirname4(configPath), ".env");
3741
4684
  try {
3742
4685
  process.loadEnvFile(envPath);
3743
- console.log(`${prefix} Loaded env from ${dim(envPath)}`);
4686
+ log.debug(`Loaded env from ${envPath}`);
3744
4687
  } catch {
3745
4688
  }
3746
- console.log(`${prefix} Starting with config: ${dim(configPath)}`);
4689
+ log.info(`Starting with config: ${configPath}`);
3747
4690
  try {
3748
- await startAgent(configPath);
4691
+ await startAgent(configPath, { debug: args.debug });
3749
4692
  } catch (e) {
3750
- console.error(`${prefix} ${err("Fatal error:")} ${e instanceof Error ? e.message : e}`);
4693
+ log.error("Fatal:", e instanceof Error ? e.message : String(e));
3751
4694
  process.exit(1);
3752
4695
  }
3753
4696
  }
@@ -3757,6 +4700,18 @@ var startCommand = defineCommand({
3757
4700
  import { defineCommand as defineCommand2 } from "citty";
3758
4701
  import { writeFile as writeFile5, access as access3 } from "fs/promises";
3759
4702
  import { resolve as resolve3 } from "path";
4703
+
4704
+ // src/colors.ts
4705
+ import { styleText as styleText2 } from "util";
4706
+ var brand = (s) => styleText2("yellow", s);
4707
+ var ok = (s) => styleText2("green", s);
4708
+ var err = (s) => styleText2("red", s);
4709
+ var dim = (s) => styleText2("dim", s);
4710
+ var bold = (s) => styleText2("bold", s);
4711
+ var cyan = (s) => styleText2("cyan", s);
4712
+ var prefix = brand("\u25B2 augure");
4713
+
4714
+ // src/commands/init.ts
3760
4715
  var CONFIG_TEMPLATE = `{
3761
4716
  // Identity
3762
4717
  identity: {