@drewpayment/mink 0.4.0 → 0.5.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/dist/cli.js CHANGED
@@ -200,6 +200,8 @@ __export(exports_paths, {
200
200
  designReportPath: () => designReportPath,
201
201
  designCapturesDir: () => designCapturesDir,
202
202
  configPath: () => configPath,
203
+ channelPidPath: () => channelPidPath,
204
+ channelLogPath: () => channelLogPath,
203
205
  bugMemoryPath: () => bugMemoryPath,
204
206
  backupDirPath: () => backupDirPath,
205
207
  actionLogPath: () => actionLogPath
@@ -246,6 +248,12 @@ function schedulerLogPath() {
246
248
  function schedulerManifestPath(cwd) {
247
249
  return join(projectDir(cwd), "scheduler-manifest.json");
248
250
  }
251
+ function channelPidPath() {
252
+ return join(MINK_ROOT, "channel.pid");
253
+ }
254
+ function channelLogPath() {
255
+ return join(MINK_ROOT, "channel.log");
256
+ }
249
257
  function globalConfigPath() {
250
258
  return join(MINK_ROOT, "config");
251
259
  }
@@ -637,6 +645,34 @@ var init_config = __esm(() => {
637
645
  envVar: "MINK_SYNC_LAST_PULL",
638
646
  description: "ISO timestamp of last successful sync pull",
639
647
  scope: "local"
648
+ },
649
+ {
650
+ key: "channel.discord.bot-token",
651
+ default: "",
652
+ envVar: "MINK_CHANNEL_DISCORD_BOT_TOKEN",
653
+ description: "Discord bot token for Claude Code Channels",
654
+ scope: "local"
655
+ },
656
+ {
657
+ key: "channel.discord.enabled",
658
+ default: "false",
659
+ envVar: "MINK_CHANNEL_DISCORD_ENABLED",
660
+ description: "Auto-start Discord channel when daemon starts",
661
+ scope: "local"
662
+ },
663
+ {
664
+ key: "channel.default-platform",
665
+ default: "discord",
666
+ envVar: "MINK_CHANNEL_DEFAULT_PLATFORM",
667
+ description: "Default platform for mink channel start",
668
+ scope: "shared"
669
+ },
670
+ {
671
+ key: "channel.skip-permissions",
672
+ default: "true",
673
+ envVar: "MINK_CHANNEL_SKIP_PERMISSIONS",
674
+ description: "Pass --dangerously-skip-permissions so the channel can run without terminal prompts",
675
+ scope: "shared"
640
676
  }
641
677
  ];
642
678
  VALID_KEYS = new Set(CONFIG_KEYS.map((k) => k.key));
@@ -2095,6 +2131,8 @@ __export(exports_paths2, {
2095
2131
  designReportPath: () => designReportPath2,
2096
2132
  designCapturesDir: () => designCapturesDir2,
2097
2133
  configPath: () => configPath2,
2134
+ channelPidPath: () => channelPidPath2,
2135
+ channelLogPath: () => channelLogPath2,
2098
2136
  bugMemoryPath: () => bugMemoryPath2,
2099
2137
  backupDirPath: () => backupDirPath2,
2100
2138
  actionLogPath: () => actionLogPath2
@@ -2141,6 +2179,12 @@ function schedulerLogPath2() {
2141
2179
  function schedulerManifestPath2(cwd) {
2142
2180
  return join7(projectDir2(cwd), "scheduler-manifest.json");
2143
2181
  }
2182
+ function channelPidPath2() {
2183
+ return join7(MINK_ROOT2, "channel.pid");
2184
+ }
2185
+ function channelLogPath2() {
2186
+ return join7(MINK_ROOT2, "channel.log");
2187
+ }
2144
2188
  function globalConfigPath2() {
2145
2189
  return join7(MINK_ROOT2, "config");
2146
2190
  }
@@ -3064,13 +3108,362 @@ var init_init = __esm(() => {
3064
3108
  init_vault();
3065
3109
  });
3066
3110
 
3111
+ // src/core/channel-templates.ts
3112
+ import { join as join13 } from "path";
3113
+ import { existsSync as existsSync10, writeFileSync as writeFileSync5, mkdirSync as mkdirSync7 } from "fs";
3114
+ function writeCompanionClaudeMd(vaultPath, overwrite = false) {
3115
+ mkdirSync7(vaultPath, { recursive: true });
3116
+ const claudeMdPath = join13(vaultPath, "CLAUDE.md");
3117
+ if (existsSync10(claudeMdPath) && !overwrite) {
3118
+ return false;
3119
+ }
3120
+ writeFileSync5(claudeMdPath, COMPANION_CLAUDE_MD);
3121
+ return true;
3122
+ }
3123
+ var COMPANION_CLAUDE_MD = `# Mink Knowledge Companion
3124
+
3125
+ You are **Mink**, a personal knowledge companion. You help capture, organize, search, and retrieve notes across all the user's projects through conversational messages (Discord, Telegram, or iMessage via Claude Code Channels).
3126
+
3127
+ Your home is this wiki vault — the directory you're running in. Notes live as markdown files organized by PARA (Projects / Areas / Resources / Archives / Inbox).
3128
+
3129
+ ## Your Role
3130
+
3131
+ You are the **smart orchestrator**. The \`mink\` CLI is the dumb writer — it takes explicit flags and writes files. Your job:
3132
+
3133
+ 1. Understand what the user wants (capture, search, organize, summarize)
3134
+ 2. Gather vault context when useful
3135
+ 3. Call the right \`mink\` command with good flags
3136
+ 4. Reply briefly — the user is likely on mobile
3137
+
3138
+ ## Conversational Style
3139
+
3140
+ - **Brief.** One or two sentences. The user is in a chat app, not a terminal.
3141
+ - **Confirm what happened.** "Saved to \`projects/auth/blocker.md\` with tags \`compliance, blocker\`." — short, specific.
3142
+ - **Suggest, don't interrogate.** If you're unsure about a tag, pick a reasonable default and mention it. Don't ask 3 questions before saving a note.
3143
+ - **Surface related work.** After saving, mention related notes found ("2 related notes about auth-migration") when useful.
3144
+
3145
+ ## Capturing Notes
3146
+
3147
+ When the user's message sounds like a note ("save this...", "log that...", or just describes something factual), **capture it**. Don't ask permission.
3148
+
3149
+ ### Flow
3150
+
3151
+ 1. **Read the message.** Extract: what's this about? Is it project-specific?
3152
+ 2. **Gather context briefly.** Run these when needed (not every time):
3153
+ - \`mink note list --recent 10\` — recent notes for continuity
3154
+ - \`mink wiki status\` — vault overview
3155
+ - Check \`.mink-index.json\` for existing tag vocabulary
3156
+ 3. **Decide metadata:**
3157
+ - **Title** — clear, descriptive (becomes the filename). Not the raw text.
3158
+ - **Category** — one of:
3159
+ - \`projects\` — has a deadline, milestone, or deliverable. Use \`--project <slug>\` if it maps to a known Mink project.
3160
+ - \`areas\` — ongoing responsibility or recurring concern
3161
+ - \`resources\` — reference material, how-to, guide
3162
+ - \`archives\` — completed or historical
3163
+ - \`inbox\` — genuinely unclear (user will sort later)
3164
+ - **Tags** — 2–3 is usually right. **Prefer existing tags** from the vocabulary over inventing new ones. Lowercase, hyphenated.
3165
+ - **Wikilinks** — wrap people, projects, and concepts in \`[[double-brackets]]\` inside the body when they match existing notes.
3166
+ 4. **Call \`mink note\`** with the flags:
3167
+ \`\`\`bash
3168
+ mink note --title "Title" --body "Body with [[wikilinks]]" --category <cat> --tags "a,b,c"
3169
+ # Add --project <slug> if project-linked
3170
+ \`\`\`
3171
+ 5. **Reply.** One line: where it landed, category, tags. Optionally: related notes.
3172
+
3173
+ ### Daily Notes
3174
+
3175
+ If the user says "add to my daily" or "daily" or "today":
3176
+ \`\`\`bash
3177
+ mink note --daily "Content to append"
3178
+ \`\`\`
3179
+
3180
+ ### Meeting Notes
3181
+
3182
+ If the user describes a meeting (attendees, topic, discussion):
3183
+ \`\`\`bash
3184
+ mink note --template meeting --title "Meeting: Topic" --body "..." --category areas --tags "meeting,..."
3185
+ \`\`\`
3186
+
3187
+ ## Searching and Retrieving
3188
+
3189
+ When the user asks about past work — "what did I write about X?", "show me notes from last week", "find my notes on auth" — use:
3190
+
3191
+ - \`mink note search <term>\` — full-text search (title, description, tags, path)
3192
+ - \`mink note list --recent N\` — recent notes
3193
+ - \`mink note list --category projects\` — filter by category
3194
+ - \`mink note list --tag auth\` — filter by tag
3195
+
3196
+ **Return results briefly.** Top 3–5 matches with one-line summaries. If there are more, say so.
3197
+
3198
+ Example reply:
3199
+ > Found 3 notes about auth-migration:
3200
+ > • \`projects/auth/compliance-blocker.md\` (today) — blocked on session token storage
3201
+ > • \`projects/auth/architecture.md\` (Apr 10) — middleware rewrite plan
3202
+ > • \`areas/daily/2026-04-12.md\` — standup update
3203
+
3204
+ ## Organization
3205
+
3206
+ If the user says "move this to projects", "tag this with X", or "categorize my inbox":
3207
+
3208
+ - For a single note: read it, rewrite it in the new category with \`mink note --file\` (ingestion). The CLI doesn't have a move command — you move by rewriting.
3209
+ - For inbox triage: list with \`mink note list --category inbox\`, propose categorization, execute on confirmation.
3210
+
3211
+ ## Daily Summaries
3212
+
3213
+ If the user asks "what did I work on today?" or "give me a summary":
3214
+
3215
+ 1. Read today's daily note: \`mink note list --tag daily --recent 1\` → read the file
3216
+ 2. Check recent notes: \`mink note list --recent 20\`
3217
+ 3. Synthesize a short summary (3–5 bullets)
3218
+
3219
+ ## Cross-Project Awareness
3220
+
3221
+ Notes may be linked to projects via \`source_project\` in frontmatter. To find notes for a specific project:
3222
+ \`\`\`bash
3223
+ mink note list --category projects
3224
+ mink note search <project-slug>
3225
+ \`\`\`
3226
+
3227
+ Use wikilinks generously: \`[[project-name]]\`, \`[[person-name]]\`, \`[[concept]]\`. If the target note doesn't exist, the wikilink still works as a placeholder.
3228
+
3229
+ ## Session Kickoff
3230
+
3231
+ At the start of a fresh conversation (first user message), it's fine to silently run:
3232
+ \`\`\`bash
3233
+ mink wiki status
3234
+ mink note list --recent 5
3235
+ \`\`\`
3236
+
3237
+ Don't announce this. Just have the context.
3238
+
3239
+ ## What NOT to Do
3240
+
3241
+ - Don't ask "what category should this be?" — pick one, move on.
3242
+ - Don't paste long output. Summarize.
3243
+ - Don't invent tags that exist with slight variations. Check vocabulary first.
3244
+ - Don't open files or directories unrelated to the vault. Stay focused on notes and wiki operations.
3245
+ - Don't edit source code in this vault — this is a knowledge repo, not a codebase.
3246
+
3247
+ ## CLI Reference (Cheat Sheet)
3248
+
3249
+ \`\`\`bash
3250
+ # Capture
3251
+ mink note "quick thought" # inbox capture
3252
+ mink note --title T --body B --category areas --tags a,b
3253
+ mink note --daily "content" # daily note
3254
+ mink note --template meeting --title "..." --body "..."
3255
+ mink note --file ./external.md --category resources
3256
+
3257
+ # Search / list
3258
+ mink note search <term>
3259
+ mink note list [--category X] [--tag Y] [--recent N]
3260
+
3261
+ # Vault
3262
+ mink wiki status
3263
+ mink wiki rebuild-index
3264
+ \`\`\`
3265
+ `;
3266
+ var init_channel_templates = () => {};
3267
+
3268
+ // src/core/channel-process.ts
3269
+ import { readFileSync as readFileSync11, writeFileSync as writeFileSync6, unlinkSync as unlinkSync2, mkdirSync as mkdirSync8, existsSync as existsSync11 } from "fs";
3270
+ import { dirname as dirname5, join as join14 } from "path";
3271
+ import { spawnSync } from "child_process";
3272
+ function readChannelPidFile() {
3273
+ try {
3274
+ const raw = readFileSync11(channelPidPath(), "utf-8");
3275
+ const data = JSON.parse(raw);
3276
+ if (data && typeof data.session === "string" && typeof data.platform === "string" && typeof data.startedAt === "string" && typeof data.vaultPath === "string") {
3277
+ return data;
3278
+ }
3279
+ return null;
3280
+ } catch {
3281
+ return null;
3282
+ }
3283
+ }
3284
+ function writeChannelPidFile(data) {
3285
+ const pidPath = channelPidPath();
3286
+ mkdirSync8(dirname5(pidPath), { recursive: true });
3287
+ writeFileSync6(pidPath, JSON.stringify(data, null, 2));
3288
+ }
3289
+ function removeChannelPidFile() {
3290
+ try {
3291
+ unlinkSync2(channelPidPath());
3292
+ } catch {}
3293
+ }
3294
+ function sessionName(platform2) {
3295
+ return `${SESSION_PREFIX}${platform2}`;
3296
+ }
3297
+ function isScreenInstalled() {
3298
+ const result = spawnSync("screen", ["-ls"], { stdio: "ignore" });
3299
+ return !result.error;
3300
+ }
3301
+ function screenSessionExists(session) {
3302
+ const result = spawnSync("screen", ["-ls", session], {
3303
+ stdio: ["ignore", "pipe", "ignore"],
3304
+ encoding: "utf-8"
3305
+ });
3306
+ const output = typeof result.stdout === "string" ? result.stdout : "";
3307
+ return new RegExp(`\\d+\\.${session}\\b`).test(output);
3308
+ }
3309
+ function shellEscape(s) {
3310
+ if (/^[a-zA-Z0-9_@%+=:,./\-]+$/.test(s))
3311
+ return s;
3312
+ return "'" + s.replace(/'/g, "'\\''") + "'";
3313
+ }
3314
+ async function startChannelProcess(opts) {
3315
+ if (!isScreenInstalled()) {
3316
+ throw new Error(`GNU screen is required but was not found on PATH.
3317
+ ` + `macOS: screen is pre-installed — check your shell environment.
3318
+ ` + "Linux: install with `sudo apt install screen` (or your package manager).");
3319
+ }
3320
+ const session = sessionName(opts.platform);
3321
+ if (screenSessionExists(session)) {
3322
+ writeChannelPidFile({
3323
+ session,
3324
+ platform: opts.platform,
3325
+ startedAt: new Date().toISOString(),
3326
+ vaultPath: opts.vaultPath
3327
+ });
3328
+ return { session, alreadyRunning: true };
3329
+ }
3330
+ const claudeCmd = opts.claudeCommand ?? "claude";
3331
+ const pluginSpec = PLUGIN_SPECS[opts.platform];
3332
+ const tokenEnvVar = TOKEN_ENV_VARS[opts.platform];
3333
+ const claudeFlags = ["--channels", shellEscape(pluginSpec)];
3334
+ if (opts.skipPermissions) {
3335
+ claudeFlags.push("--dangerously-skip-permissions");
3336
+ }
3337
+ const parts = [];
3338
+ parts.push(`cd ${shellEscape(opts.vaultPath)}`);
3339
+ if (opts.token) {
3340
+ parts.push(`export ${tokenEnvVar}=${shellEscape(opts.token)}`);
3341
+ }
3342
+ parts.push(`exec ${shellEscape(claudeCmd)} ${claudeFlags.join(" ")}`);
3343
+ const innerCmd = parts.join("; ");
3344
+ const result = spawnSync("screen", ["-T", "screen-256color", "-dmS", session, "bash", "-c", innerCmd], { stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" });
3345
+ if (result.status !== 0) {
3346
+ const stderr = typeof result.stderr === "string" ? result.stderr : "";
3347
+ throw new Error(`screen failed to create session (exit ${result.status}): ${stderr || "(no output)"}`);
3348
+ }
3349
+ await new Promise((r) => setTimeout(r, 700));
3350
+ if (!screenSessionExists(session)) {
3351
+ throw new Error("channel session died immediately after starting. " + "This usually means `claude` failed to launch. Check:\n" + " • Is `claude` on your PATH? Run `which claude`.\n" + " • Have you installed the plugin? Run `claude` then `/plugin install discord@claude-plugins-official`.\n" + ` • Try running the command manually to see the error:
3352
+ ` + ` cd ${opts.vaultPath} && claude --channels ${pluginSpec}`);
3353
+ }
3354
+ writeChannelPidFile({
3355
+ session,
3356
+ platform: opts.platform,
3357
+ startedAt: new Date().toISOString(),
3358
+ vaultPath: opts.vaultPath
3359
+ });
3360
+ return { session, alreadyRunning: false };
3361
+ }
3362
+ async function stopChannelProcess() {
3363
+ const pidData = readChannelPidFile();
3364
+ if (!pidData) {
3365
+ return "not-running";
3366
+ }
3367
+ if (!screenSessionExists(pidData.session)) {
3368
+ removeChannelPidFile();
3369
+ return "not-running";
3370
+ }
3371
+ spawnSync("screen", ["-S", pidData.session, "-X", "quit"], { stdio: "ignore" });
3372
+ for (let i = 0;i < 30; i++) {
3373
+ if (!screenSessionExists(pidData.session)) {
3374
+ removeChannelPidFile();
3375
+ return "stopped";
3376
+ }
3377
+ await new Promise((r) => setTimeout(r, 100));
3378
+ }
3379
+ removeChannelPidFile();
3380
+ return "stopped";
3381
+ }
3382
+ function isChannelRunning() {
3383
+ const pidData = readChannelPidFile();
3384
+ if (!pidData)
3385
+ return false;
3386
+ if (!screenSessionExists(pidData.session)) {
3387
+ removeChannelPidFile();
3388
+ return false;
3389
+ }
3390
+ return true;
3391
+ }
3392
+ function getChannelStatus() {
3393
+ const pidData = readChannelPidFile();
3394
+ if (!pidData)
3395
+ return null;
3396
+ if (!screenSessionExists(pidData.session)) {
3397
+ removeChannelPidFile();
3398
+ return null;
3399
+ }
3400
+ const startedMs = Date.parse(pidData.startedAt);
3401
+ const uptimeSec = Number.isFinite(startedMs) ? Math.max(0, Math.floor((Date.now() - startedMs) / 1000)) : 0;
3402
+ return {
3403
+ session: pidData.session,
3404
+ platform: pidData.platform,
3405
+ startedAt: pidData.startedAt,
3406
+ vaultPath: pidData.vaultPath,
3407
+ uptime: uptimeSec
3408
+ };
3409
+ }
3410
+ function getChannelLogs() {
3411
+ const pidData = readChannelPidFile();
3412
+ if (!pidData)
3413
+ return null;
3414
+ if (!screenSessionExists(pidData.session))
3415
+ return null;
3416
+ const tmpPath = join14(minkRoot(), `.channel-capture-${Date.now()}-${process.pid}.txt`);
3417
+ const result = spawnSync("screen", ["-S", pidData.session, "-X", "hardcopy", "-h", tmpPath], { stdio: "ignore" });
3418
+ if (result.status !== 0)
3419
+ return null;
3420
+ for (let i = 0;i < 20; i++) {
3421
+ if (existsSync11(tmpPath))
3422
+ break;
3423
+ const delayUntil = Date.now() + 50;
3424
+ while (Date.now() < delayUntil) {}
3425
+ }
3426
+ try {
3427
+ const content = readFileSync11(tmpPath, "utf-8");
3428
+ try {
3429
+ unlinkSync2(tmpPath);
3430
+ } catch {}
3431
+ return content;
3432
+ } catch {
3433
+ return null;
3434
+ }
3435
+ }
3436
+ function attachChannel() {
3437
+ const pidData = readChannelPidFile();
3438
+ if (!pidData)
3439
+ return "not-running";
3440
+ if (!screenSessionExists(pidData.session)) {
3441
+ removeChannelPidFile();
3442
+ return "not-running";
3443
+ }
3444
+ spawnSync("screen", ["-r", pidData.session], { stdio: "inherit" });
3445
+ return "attached";
3446
+ }
3447
+ var SESSION_PREFIX = "mink-channel-", PLUGIN_SPECS, TOKEN_ENV_VARS;
3448
+ var init_channel_process = __esm(() => {
3449
+ init_paths();
3450
+ PLUGIN_SPECS = {
3451
+ discord: "plugin:discord@claude-plugins-official",
3452
+ telegram: "plugin:telegram@claude-plugins-official"
3453
+ };
3454
+ TOKEN_ENV_VARS = {
3455
+ discord: "DISCORD_BOT_TOKEN",
3456
+ telegram: "TELEGRAM_BOT_TOKEN"
3457
+ };
3458
+ });
3459
+
3067
3460
  // src/core/daemon.ts
3068
- import { readFileSync as readFileSync11, writeFileSync as writeFileSync5, unlinkSync as unlinkSync2, openSync } from "fs";
3069
- import { mkdirSync as mkdirSync7 } from "fs";
3070
- import { dirname as dirname5, resolve as resolve3 } from "path";
3461
+ import { readFileSync as readFileSync12, writeFileSync as writeFileSync7, unlinkSync as unlinkSync3, openSync } from "fs";
3462
+ import { mkdirSync as mkdirSync9 } from "fs";
3463
+ import { dirname as dirname6, resolve as resolve3 } from "path";
3071
3464
  function readPidFile() {
3072
3465
  try {
3073
- const raw = readFileSync11(schedulerPidPath(), "utf-8");
3466
+ const raw = readFileSync12(schedulerPidPath(), "utf-8");
3074
3467
  const data = JSON.parse(raw);
3075
3468
  if (data && typeof data.pid === "number" && typeof data.startedAt === "string" && typeof data.projectCwd === "string") {
3076
3469
  return data;
@@ -3082,12 +3475,12 @@ function readPidFile() {
3082
3475
  }
3083
3476
  function writePidFile(data) {
3084
3477
  const pidPath = schedulerPidPath();
3085
- mkdirSync7(dirname5(pidPath), { recursive: true });
3086
- writeFileSync5(pidPath, JSON.stringify(data, null, 2));
3478
+ mkdirSync9(dirname6(pidPath), { recursive: true });
3479
+ writeFileSync7(pidPath, JSON.stringify(data, null, 2));
3087
3480
  }
3088
3481
  function removePidFile() {
3089
3482
  try {
3090
- unlinkSync2(schedulerPidPath());
3483
+ unlinkSync3(schedulerPidPath());
3091
3484
  } catch {}
3092
3485
  }
3093
3486
  function isProcessAlive(pid) {
@@ -3107,10 +3500,10 @@ function startDaemon(cwd) {
3107
3500
  if (existing) {
3108
3501
  removePidFile();
3109
3502
  }
3110
- const __dir = dirname5(new URL(import.meta.url).pathname);
3503
+ const __dir = dirname6(new URL(import.meta.url).pathname);
3111
3504
  const cliPath = resolve3(__dir, "../cli.ts");
3112
3505
  const logPath = schedulerLogPath();
3113
- mkdirSync7(dirname5(logPath), { recursive: true });
3506
+ mkdirSync9(dirname6(logPath), { recursive: true });
3114
3507
  const logFd = openSync(logPath, "a");
3115
3508
  const proc = Bun.spawn(["bun", "run", cliPath, "cron", "__daemon"], {
3116
3509
  cwd,
@@ -3127,8 +3520,37 @@ function startDaemon(cwd) {
3127
3520
  });
3128
3521
  console.log(`[mink] scheduler started (PID: ${proc.pid})`);
3129
3522
  console.log(`[mink] log: ${logPath}`);
3523
+ maybeStartChannel().catch((err) => {
3524
+ console.error(`[mink] failed to start channel: ${err instanceof Error ? err.message : String(err)}`);
3525
+ });
3526
+ }
3527
+ async function maybeStartChannel() {
3528
+ const enabled = resolveConfigValue("channel.discord.enabled").value === "true";
3529
+ if (!enabled)
3530
+ return;
3531
+ if (!isVaultInitialized()) {
3532
+ console.log("[mink] channel enabled but vault not initialized — skipping channel start");
3533
+ return;
3534
+ }
3535
+ const token = resolveConfigValue("channel.discord.bot-token").value;
3536
+ if (!token) {
3537
+ console.log("[mink] channel enabled but no Discord bot token configured — skipping channel start");
3538
+ return;
3539
+ }
3540
+ if (isChannelRunning()) {
3541
+ return;
3542
+ }
3543
+ const platform2 = resolveConfigValue("channel.default-platform").value || "discord";
3544
+ const skipPermissions = resolveConfigValue("channel.skip-permissions").value === "true";
3545
+ const vaultPath = resolveVaultPath();
3546
+ writeCompanionClaudeMd(vaultPath, false);
3547
+ const result = await startChannelProcess({ vaultPath, platform: platform2, token, skipPermissions });
3548
+ if (!result.alreadyRunning) {
3549
+ console.log(`[mink] channel started (session: ${result.session}, platform: ${platform2})`);
3550
+ }
3130
3551
  }
3131
3552
  async function stopDaemon() {
3553
+ await stopChannelIfRunning();
3132
3554
  const pidData = readPidFile();
3133
3555
  if (!pidData) {
3134
3556
  console.log("[mink] scheduler is not running (no PID file)");
@@ -3155,24 +3577,38 @@ async function stopDaemon() {
3155
3577
  removePidFile();
3156
3578
  console.log("[mink] scheduler force-stopped (SIGKILL)");
3157
3579
  }
3580
+ async function stopChannelIfRunning() {
3581
+ if (!isChannelRunning())
3582
+ return;
3583
+ const result = await stopChannelProcess();
3584
+ if (result === "stopped") {
3585
+ console.log("[mink] channel stopped");
3586
+ }
3587
+ }
3158
3588
  function getDaemonStatus(cwd) {
3589
+ const channel = getChannelStatus();
3159
3590
  const pidData = readPidFile();
3160
3591
  if (!pidData) {
3161
- return { running: false };
3592
+ return { running: false, channel };
3162
3593
  }
3163
3594
  if (!isProcessAlive(pidData.pid)) {
3164
3595
  removePidFile();
3165
- return { running: false };
3596
+ return { running: false, channel };
3166
3597
  }
3167
3598
  return {
3168
3599
  running: true,
3169
3600
  pid: pidData.pid,
3170
3601
  startedAt: pidData.startedAt,
3171
- projectCwd: pidData.projectCwd
3602
+ projectCwd: pidData.projectCwd,
3603
+ channel
3172
3604
  };
3173
3605
  }
3174
3606
  var init_daemon = __esm(() => {
3175
3607
  init_paths();
3608
+ init_global_config();
3609
+ init_vault();
3610
+ init_channel_templates();
3611
+ init_channel_process();
3176
3612
  });
3177
3613
 
3178
3614
  // src/commands/status.ts
@@ -3180,9 +3616,9 @@ var exports_status = {};
3180
3616
  __export(exports_status, {
3181
3617
  status: () => status
3182
3618
  });
3183
- import { existsSync as existsSync11, readFileSync as readFileSync12, statSync as statSync5 } from "fs";
3619
+ import { existsSync as existsSync13, readFileSync as readFileSync13, statSync as statSync5 } from "fs";
3184
3620
  function checkJsonFile(name, filePath, validator) {
3185
- if (!existsSync11(filePath))
3621
+ if (!existsSync13(filePath))
3186
3622
  return { name, path: filePath, status: "missing" };
3187
3623
  const data = safeReadJson(filePath);
3188
3624
  if (data === null)
@@ -3192,10 +3628,10 @@ function checkJsonFile(name, filePath, validator) {
3192
3628
  return { name, path: filePath, status: "ok" };
3193
3629
  }
3194
3630
  function checkTextFile(name, filePath) {
3195
- if (!existsSync11(filePath))
3631
+ if (!existsSync13(filePath))
3196
3632
  return { name, path: filePath, status: "missing" };
3197
3633
  try {
3198
- readFileSync12(filePath, "utf-8");
3634
+ readFileSync13(filePath, "utf-8");
3199
3635
  return { name, path: filePath, status: "ok" };
3200
3636
  } catch {
3201
3637
  return { name, path: filePath, status: "corrupt" };
@@ -3255,8 +3691,8 @@ function status(cwd) {
3255
3691
  console.log();
3256
3692
  try {
3257
3693
  const memPath = learningMemoryPath(cwd);
3258
- if (existsSync11(memPath)) {
3259
- const content = readFileSync12(memPath, "utf-8");
3694
+ if (existsSync13(memPath)) {
3695
+ const content = readFileSync13(memPath, "utf-8");
3260
3696
  const mem = parseLearningMemory(content);
3261
3697
  const total = totalEntryCount(mem);
3262
3698
  const mtime = statSync5(memPath).mtime;
@@ -3310,8 +3746,8 @@ var exports_scan2 = {};
3310
3746
  __export(exports_scan2, {
3311
3747
  scan: () => scan2
3312
3748
  });
3313
- import { readFileSync as readFileSync13 } from "fs";
3314
- import { join as join13 } from "path";
3749
+ import { readFileSync as readFileSync14 } from "fs";
3750
+ import { join as join15 } from "path";
3315
3751
  function loadExistingIndex2(indexPath) {
3316
3752
  const raw = safeReadJson(indexPath);
3317
3753
  if (isFileIndex(raw))
@@ -3361,10 +3797,10 @@ function scan2(cwd, options) {
3361
3797
  newIndex.header.lifetimeHits = index.header.lifetimeHits;
3362
3798
  newIndex.header.lifetimeMisses = index.header.lifetimeMisses;
3363
3799
  for (const file of scanned) {
3364
- const fullPath = join13(cwd, file.relativePath);
3800
+ const fullPath = join15(cwd, file.relativePath);
3365
3801
  let content;
3366
3802
  try {
3367
- content = readFileSync13(fullPath, "utf-8");
3803
+ content = readFileSync14(fullPath, "utf-8");
3368
3804
  } catch {
3369
3805
  continue;
3370
3806
  }
@@ -3395,13 +3831,13 @@ var exports_reflect2 = {};
3395
3831
  __export(exports_reflect2, {
3396
3832
  reflect: () => reflect2
3397
3833
  });
3398
- import { existsSync as existsSync12, readFileSync as readFileSync14 } from "fs";
3834
+ import { existsSync as existsSync14, readFileSync as readFileSync15 } from "fs";
3399
3835
  function reflect2(projectDir3, memoryPath, configPath3) {
3400
- if (!existsSync12(memoryPath)) {
3836
+ if (!existsSync14(memoryPath)) {
3401
3837
  console.log("[mink] no learning memory found");
3402
3838
  return null;
3403
3839
  }
3404
- const markdown = readFileSync14(memoryPath, "utf-8");
3840
+ const markdown = readFileSync15(memoryPath, "utf-8");
3405
3841
  const mem = parseLearningMemory(markdown);
3406
3842
  const config = safeReadJson(configPath3);
3407
3843
  const tokenBudget = config?.learningMemoryTokenBudget ?? DEFAULT_TOKEN_BUDGET2;
@@ -3682,7 +4118,7 @@ __export(exports_pre_write, {
3682
4118
  analyzePreWrite: () => analyzePreWrite
3683
4119
  });
3684
4120
  import { relative as relative4 } from "path";
3685
- import { readFileSync as readFileSync15 } from "fs";
4121
+ import { readFileSync as readFileSync16 } from "fs";
3686
4122
  function analyzePreWrite(filePath, writeContent, doNotRepeatEntries, bugMemory) {
3687
4123
  const warnings = [];
3688
4124
  const allMatches = [];
@@ -3736,7 +4172,7 @@ async function preWrite(cwd) {
3736
4172
  const writeContent = extractWriteContent(input);
3737
4173
  let doNotRepeatEntries = [];
3738
4174
  try {
3739
- const markdown = readFileSync15(learningMemoryPath(cwd), "utf-8");
4175
+ const markdown = readFileSync16(learningMemoryPath(cwd), "utf-8");
3740
4176
  const mem = parseLearningMemory(markdown);
3741
4177
  doNotRepeatEntries = getEntries(mem, "Do-Not-Repeat");
3742
4178
  } catch {}
@@ -3793,7 +4229,7 @@ __export(exports_post_write, {
3793
4229
  analyzePostWrite: () => analyzePostWrite
3794
4230
  });
3795
4231
  import { relative as relative5 } from "path";
3796
- import { readFileSync as readFileSync16 } from "fs";
4232
+ import { readFileSync as readFileSync17 } from "fs";
3797
4233
  function analyzePostWrite(filePath, fileContent, index) {
3798
4234
  if (isWriteExcluded(filePath)) {
3799
4235
  return {
@@ -3857,7 +4293,7 @@ async function postWrite(cwd) {
3857
4293
  const filePath = relative5(cwd, absolutePath);
3858
4294
  let fileContent = null;
3859
4295
  try {
3860
- fileContent = readFileSync16(absolutePath, "utf-8");
4296
+ fileContent = readFileSync17(absolutePath, "utf-8");
3861
4297
  } catch {}
3862
4298
  const rawState = safeReadJson(sessionPath(cwd));
3863
4299
  const state = isSessionState(rawState) ? rawState : createSessionState();
@@ -4277,10 +4713,10 @@ async function executeTask(taskId, projectCwd) {
4277
4713
  if (task.actionType === "ai-cli") {
4278
4714
  try {
4279
4715
  const { learningMemoryPath: learningMemoryPath4 } = await Promise.resolve().then(() => (init_paths(), exports_paths));
4280
- const { readFileSync: readFileSync17 } = await import("fs");
4716
+ const { readFileSync: readFileSync18 } = await import("fs");
4281
4717
  let memoryContent;
4282
4718
  try {
4283
- memoryContent = readFileSync17(learningMemoryPath4(projectCwd), "utf-8");
4719
+ memoryContent = readFileSync18(learningMemoryPath4(projectCwd), "utf-8");
4284
4720
  } catch {
4285
4721
  console.log("[mink] no learning memory found, skipping reflection");
4286
4722
  return;
@@ -4838,9 +5274,9 @@ var init_design_eval = __esm(() => {
4838
5274
  });
4839
5275
 
4840
5276
  // src/core/dashboard-api.ts
4841
- import { existsSync as existsSync13, readFileSync as readFileSync17 } from "fs";
5277
+ import { existsSync as existsSync15, readFileSync as readFileSync18 } from "fs";
4842
5278
  function checkJsonFile2(name, filePath, validator) {
4843
- if (!existsSync13(filePath))
5279
+ if (!existsSync15(filePath))
4844
5280
  return { name, status: "missing" };
4845
5281
  const data = safeReadJson(filePath);
4846
5282
  if (data === null)
@@ -4850,10 +5286,10 @@ function checkJsonFile2(name, filePath, validator) {
4850
5286
  return { name, status: "ok" };
4851
5287
  }
4852
5288
  function checkTextFile2(name, filePath) {
4853
- if (!existsSync13(filePath))
5289
+ if (!existsSync15(filePath))
4854
5290
  return { name, status: "missing" };
4855
5291
  try {
4856
- readFileSync17(filePath, "utf-8");
5292
+ readFileSync18(filePath, "utf-8");
4857
5293
  return { name, status: "ok" };
4858
5294
  } catch {
4859
5295
  return { name, status: "corrupt" };
@@ -4936,7 +5372,7 @@ function loadSchedulerPanel(cwd) {
4936
5372
  }
4937
5373
  function loadLearningMemoryPanel(cwd) {
4938
5374
  const memPath = learningMemoryPath(cwd);
4939
- if (!existsSync13(memPath)) {
5375
+ if (!existsSync15(memPath)) {
4940
5376
  return {
4941
5377
  projectName: "unknown",
4942
5378
  sections: {
@@ -4948,7 +5384,7 @@ function loadLearningMemoryPanel(cwd) {
4948
5384
  };
4949
5385
  }
4950
5386
  try {
4951
- const content = readFileSync17(memPath, "utf-8");
5387
+ const content = readFileSync18(memPath, "utf-8");
4952
5388
  return parseLearningMemory(content);
4953
5389
  } catch {
4954
5390
  return {
@@ -5050,10 +5486,10 @@ var init_dashboard_api = __esm(() => {
5050
5486
  });
5051
5487
 
5052
5488
  // src/core/project-registry.ts
5053
- import { readdirSync as readdirSync4, existsSync as existsSync14 } from "fs";
5054
- import { join as join14 } from "path";
5489
+ import { readdirSync as readdirSync4, existsSync as existsSync16 } from "fs";
5490
+ import { join as join16 } from "path";
5055
5491
  function getProjectMeta(projDir) {
5056
- const metaPath = join14(projDir, "project-meta.json");
5492
+ const metaPath = join16(projDir, "project-meta.json");
5057
5493
  const raw = safeReadJson(metaPath);
5058
5494
  if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
5059
5495
  return null;
@@ -5070,15 +5506,15 @@ function getProjectMeta(projDir) {
5070
5506
  };
5071
5507
  }
5072
5508
  function listRegisteredProjects() {
5073
- const projectsDir = join14(minkRoot(), "projects");
5074
- if (!existsSync14(projectsDir))
5509
+ const projectsDir = join16(minkRoot(), "projects");
5510
+ if (!existsSync16(projectsDir))
5075
5511
  return [];
5076
5512
  const entries = readdirSync4(projectsDir, { withFileTypes: true });
5077
5513
  const projects = [];
5078
5514
  for (const entry of entries) {
5079
5515
  if (!entry.isDirectory())
5080
5516
  continue;
5081
- const projDir = join14(projectsDir, entry.name);
5517
+ const projDir = join16(projectsDir, entry.name);
5082
5518
  const meta = getProjectMeta(projDir);
5083
5519
  if (meta) {
5084
5520
  projects.push({
@@ -5242,8 +5678,8 @@ __export(exports_dashboard_server, {
5242
5678
  startDashboardServer: () => startDashboardServer
5243
5679
  });
5244
5680
  import { watch } from "fs";
5245
- import { existsSync as existsSync15 } from "fs";
5246
- import { basename as basename7, dirname as dirname6, join as join15, extname as extname2 } from "path";
5681
+ import { existsSync as existsSync17 } from "fs";
5682
+ import { basename as basename7, dirname as dirname7, join as join17, extname as extname2 } from "path";
5247
5683
 
5248
5684
  class SSEManager {
5249
5685
  clients = new Map;
@@ -5416,15 +5852,15 @@ async function startDashboardServer(cwd, options = {}) {
5416
5852
  timestamp: new Date().toISOString()
5417
5853
  });
5418
5854
  });
5419
- const __dir = dirname6(new URL(import.meta.url).pathname);
5855
+ const __dir = dirname7(new URL(import.meta.url).pathname);
5420
5856
  let pkgRoot = __dir;
5421
- while (pkgRoot !== dirname6(pkgRoot)) {
5422
- if (existsSync15(join15(pkgRoot, "package.json")))
5857
+ while (pkgRoot !== dirname7(pkgRoot)) {
5858
+ if (existsSync17(join17(pkgRoot, "package.json")))
5423
5859
  break;
5424
- pkgRoot = dirname6(pkgRoot);
5860
+ pkgRoot = dirname7(pkgRoot);
5425
5861
  }
5426
- const dashboardOutDir = join15(pkgRoot, "dashboard", "out");
5427
- const dashboardBuilt = existsSync15(join15(dashboardOutDir, "index.html"));
5862
+ const dashboardOutDir = join17(pkgRoot, "dashboard", "out");
5863
+ const dashboardBuilt = existsSync17(join17(dashboardOutDir, "index.html"));
5428
5864
  let clientIdCounter = 0;
5429
5865
  if (!dashboardBuilt) {
5430
5866
  console.warn("[mink] dashboard not built. Run: cd dashboard && bun run build");
@@ -5454,9 +5890,9 @@ async function startDashboardServer(cwd, options = {}) {
5454
5890
  } else {
5455
5891
  let filePath;
5456
5892
  if (pathname === "/") {
5457
- filePath = join15(dashboardOutDir, "index.html");
5893
+ filePath = join17(dashboardOutDir, "index.html");
5458
5894
  } else {
5459
- filePath = join15(dashboardOutDir, pathname);
5895
+ filePath = join17(dashboardOutDir, pathname);
5460
5896
  }
5461
5897
  if (!filePath.startsWith(dashboardOutDir)) {
5462
5898
  return jsonResponse({ error: "Forbidden" }, 403);
@@ -5469,7 +5905,7 @@ async function startDashboardServer(cwd, options = {}) {
5469
5905
  const htmlServed = await serveFile(filePath + ".html", "text/html; charset=utf-8");
5470
5906
  if (htmlServed)
5471
5907
  return htmlServed;
5472
- const indexServed = await serveFile(join15(dashboardOutDir, "index.html"), "text/html; charset=utf-8");
5908
+ const indexServed = await serveFile(join17(dashboardOutDir, "index.html"), "text/html; charset=utf-8");
5473
5909
  if (indexServed)
5474
5910
  return indexServed;
5475
5911
  }
@@ -5529,7 +5965,7 @@ retry: 3000
5529
5965
  if (!filename || filename.includes("..") || filename.includes("/")) {
5530
5966
  return jsonResponse({ error: "Invalid filename" }, 400);
5531
5967
  }
5532
- const imgPath = join15(designCapturesDir(resolvedCwd), filename);
5968
+ const imgPath = join17(designCapturesDir(resolvedCwd), filename);
5533
5969
  const served = await serveFile(imgPath, "image/jpeg");
5534
5970
  if (served) {
5535
5971
  served.headers.set("Cache-Control", "public, max-age=60");
@@ -5661,9 +6097,9 @@ var exports_dashboard = {};
5661
6097
  __export(exports_dashboard, {
5662
6098
  dashboard: () => dashboard
5663
6099
  });
5664
- import { existsSync as existsSync16 } from "fs";
6100
+ import { existsSync as existsSync18 } from "fs";
5665
6101
  async function dashboard(cwd, args) {
5666
- if (!existsSync16(projectDir(cwd))) {
6102
+ if (!existsSync18(projectDir(cwd))) {
5667
6103
  console.error("[mink] project not initialized. Run: mink init");
5668
6104
  process.exit(1);
5669
6105
  }
@@ -5685,7 +6121,7 @@ var exports_daemon = {};
5685
6121
  __export(exports_daemon, {
5686
6122
  daemon: () => daemon
5687
6123
  });
5688
- import { readFileSync as readFileSync18, existsSync as existsSync17 } from "fs";
6124
+ import { readFileSync as readFileSync19, existsSync as existsSync19 } from "fs";
5689
6125
  async function daemon(cwd, args) {
5690
6126
  const subcommand = args[0];
5691
6127
  switch (subcommand) {
@@ -5701,12 +6137,12 @@ async function daemon(cwd, args) {
5701
6137
  break;
5702
6138
  case "logs": {
5703
6139
  const logPath = schedulerLogPath();
5704
- if (!existsSync17(logPath)) {
6140
+ if (!existsSync19(logPath)) {
5705
6141
  console.log("[mink] no log file found");
5706
6142
  return;
5707
6143
  }
5708
6144
  try {
5709
- const content = readFileSync18(logPath, "utf-8");
6145
+ const content = readFileSync19(logPath, "utf-8");
5710
6146
  const lines = content.split(`
5711
6147
  `);
5712
6148
  const tail = lines.slice(-50).join(`
@@ -5728,6 +6164,232 @@ var init_daemon2 = __esm(() => {
5728
6164
  init_paths();
5729
6165
  });
5730
6166
 
6167
+ // src/commands/channel.ts
6168
+ var exports_channel = {};
6169
+ __export(exports_channel, {
6170
+ channel: () => channel
6171
+ });
6172
+ function parsePlatform(value) {
6173
+ if (!value)
6174
+ return null;
6175
+ if (SUPPORTED_PLATFORMS.includes(value)) {
6176
+ return value;
6177
+ }
6178
+ return null;
6179
+ }
6180
+ function extractFlag(args, flag) {
6181
+ const idx = args.findIndex((a) => a === flag || a.startsWith(flag + "="));
6182
+ if (idx === -1)
6183
+ return;
6184
+ const arg = args[idx];
6185
+ if (arg.includes("=")) {
6186
+ return arg.slice(arg.indexOf("=") + 1);
6187
+ }
6188
+ return args[idx + 1];
6189
+ }
6190
+ async function channel(args) {
6191
+ const subcommand = args[0];
6192
+ const rest = args.slice(1);
6193
+ switch (subcommand) {
6194
+ case "setup":
6195
+ setupChannel(rest);
6196
+ break;
6197
+ case "start":
6198
+ await startChannel(rest);
6199
+ break;
6200
+ case "stop":
6201
+ await stopChannel();
6202
+ break;
6203
+ case "status":
6204
+ showStatus();
6205
+ break;
6206
+ case "logs":
6207
+ showLogs();
6208
+ break;
6209
+ case "attach":
6210
+ doAttach();
6211
+ break;
6212
+ default:
6213
+ printUsage();
6214
+ process.exit(1);
6215
+ }
6216
+ }
6217
+ function setupChannel(args) {
6218
+ const platform2 = parsePlatform(args[0]);
6219
+ if (!platform2) {
6220
+ console.error("[mink] missing or invalid platform");
6221
+ console.error("Usage: mink channel setup <discord|telegram> --token <token>");
6222
+ process.exit(1);
6223
+ }
6224
+ if (platform2 === "telegram") {
6225
+ console.error("[mink] telegram setup is not yet supported");
6226
+ process.exit(1);
6227
+ }
6228
+ const token = extractFlag(args, "--token");
6229
+ if (!token) {
6230
+ console.log("[mink] Discord Channel Setup");
6231
+ console.log("");
6232
+ console.log("In the Discord Developer Portal (https://discord.com/developers/applications):");
6233
+ console.log("");
6234
+ console.log(" 1. New Application > give it a name");
6235
+ console.log(" 2. Bot > Reset Token > copy the token");
6236
+ console.log(" 3. Bot > scroll to Privileged Gateway Intents:");
6237
+ console.log(" - Enable MESSAGE CONTENT INTENT (required)");
6238
+ console.log(" 4. OAuth2 > URL Generator:");
6239
+ console.log(" - Integration Type: Guild Install (NOT User Install)");
6240
+ console.log(" - Scopes: bot");
6241
+ console.log(" - Bot Permissions: View Channels, Send Messages,");
6242
+ console.log(" Send Messages in Threads, Read Message History,");
6243
+ console.log(" Attach Files, Add Reactions");
6244
+ console.log(" 5. Open the generated URL to invite the bot to a server");
6245
+ console.log(" (create a personal server if you just want to DM the bot)");
6246
+ console.log("");
6247
+ console.log("Then install the channel plugin once inside Claude Code:");
6248
+ console.log(" claude");
6249
+ console.log(" /plugin install discord@claude-plugins-official");
6250
+ console.log(" (exit Claude Code)");
6251
+ console.log("");
6252
+ console.log("Finally, save your token:");
6253
+ console.log(" mink channel setup discord --token <your-token>");
6254
+ console.log("");
6255
+ console.log("Your token is stored locally in ~/.mink/config.local");
6256
+ console.log("and is NOT synced across machines.");
6257
+ return;
6258
+ }
6259
+ if (!/^[\w.-]{30,}$/.test(token)) {
6260
+ console.error("[mink] token format looks invalid — expected a long token string");
6261
+ process.exit(1);
6262
+ }
6263
+ setConfigValue("channel.discord.bot-token", token);
6264
+ setConfigValue("channel.discord.enabled", "true");
6265
+ setConfigValue("channel.default-platform", "discord");
6266
+ console.log("[mink] Discord bot token saved to config.local");
6267
+ console.log("[mink] channel.discord.enabled = true");
6268
+ console.log("[mink] channel.default-platform = discord");
6269
+ console.log("");
6270
+ console.log("Next: mink channel start");
6271
+ }
6272
+ async function startChannel(args) {
6273
+ if (!isVaultInitialized()) {
6274
+ console.error("[mink] wiki vault is not initialized");
6275
+ console.error("Run: mink wiki init");
6276
+ process.exit(1);
6277
+ }
6278
+ const requested = parsePlatform(args[0]);
6279
+ const platform2 = requested ?? parsePlatform(resolveConfigValue("channel.default-platform").value) ?? "discord";
6280
+ if (platform2 === "telegram") {
6281
+ console.error("[mink] telegram is not yet supported");
6282
+ process.exit(1);
6283
+ }
6284
+ const token = resolveConfigValue("channel.discord.bot-token").value;
6285
+ if (!token) {
6286
+ console.error("[mink] no Discord bot token configured");
6287
+ console.error("Run: mink channel setup discord --token <your-token>");
6288
+ process.exit(1);
6289
+ }
6290
+ const vaultPath = resolveVaultPath();
6291
+ const wrote = writeCompanionClaudeMd(vaultPath, false);
6292
+ if (wrote) {
6293
+ console.log(`[mink] created companion CLAUDE.md at ${vaultPath}`);
6294
+ }
6295
+ const skipPermissions = resolveConfigValue("channel.skip-permissions").value === "true";
6296
+ let result;
6297
+ try {
6298
+ result = await startChannelProcess({ vaultPath, platform: platform2, token, skipPermissions });
6299
+ } catch (err) {
6300
+ console.error("[mink] failed to start channel:");
6301
+ console.error(err instanceof Error ? err.message : String(err));
6302
+ process.exit(1);
6303
+ }
6304
+ if (result.alreadyRunning) {
6305
+ console.log(`[mink] channel is already running (screen session: ${result.session})`);
6306
+ return;
6307
+ }
6308
+ console.log(`[mink] channel started`);
6309
+ console.log(`[mink] platform: ${platform2}`);
6310
+ console.log(`[mink] vault: ${vaultPath}`);
6311
+ console.log(`[mink] session: ${result.session} (GNU screen)`);
6312
+ console.log("");
6313
+ console.log("Next:");
6314
+ console.log(" 1. DM your bot on Discord — it replies with a pairing code");
6315
+ console.log(" 2. Attach to the Claude Code session: mink channel attach");
6316
+ console.log(" 3. Inside the session, run: /discord:access pair <code>");
6317
+ console.log(" 4. Then lock down access: /discord:access policy allowlist");
6318
+ console.log(" 5. Detach with Ctrl-a d");
6319
+ console.log("");
6320
+ console.log("See activity: mink channel logs");
6321
+ }
6322
+ async function stopChannel() {
6323
+ const result = await stopChannelProcess();
6324
+ switch (result) {
6325
+ case "not-running":
6326
+ console.log("[mink] channel is not running");
6327
+ break;
6328
+ case "stopped":
6329
+ console.log("[mink] channel stopped");
6330
+ break;
6331
+ }
6332
+ }
6333
+ function showStatus() {
6334
+ const status2 = getChannelStatus();
6335
+ if (!status2) {
6336
+ console.log("[mink] channel is not running");
6337
+ return;
6338
+ }
6339
+ console.log(`running: yes`);
6340
+ console.log(`session: ${status2.session}`);
6341
+ console.log(`platform: ${status2.platform}`);
6342
+ console.log(`vault: ${status2.vaultPath}`);
6343
+ console.log(`started: ${status2.startedAt}`);
6344
+ console.log(`uptime: ${formatUptime(status2.uptime)}`);
6345
+ console.log("");
6346
+ console.log("Attach: mink channel attach");
6347
+ }
6348
+ function formatUptime(seconds) {
6349
+ if (seconds < 60)
6350
+ return `${seconds}s`;
6351
+ const mins = Math.floor(seconds / 60);
6352
+ if (mins < 60)
6353
+ return `${mins}m ${seconds % 60}s`;
6354
+ const hrs = Math.floor(mins / 60);
6355
+ return `${hrs}h ${mins % 60}m`;
6356
+ }
6357
+ function showLogs() {
6358
+ const content = getChannelLogs();
6359
+ if (content == null) {
6360
+ console.log("[mink] channel is not running (no logs to show)");
6361
+ return;
6362
+ }
6363
+ console.log(content.replace(/\n+$/, ""));
6364
+ }
6365
+ function doAttach() {
6366
+ const result = attachChannel();
6367
+ if (result === "not-running") {
6368
+ console.log("[mink] channel is not running");
6369
+ console.log("Start it with: mink channel start");
6370
+ }
6371
+ }
6372
+ function printUsage() {
6373
+ console.error("Usage: mink channel <subcommand>");
6374
+ console.error("");
6375
+ console.error("Subcommands:");
6376
+ console.error(" setup <platform> --token <token> Configure a channel (discord|telegram)");
6377
+ console.error(" start [platform] Launch channel session (in GNU screen)");
6378
+ console.error(" stop Stop channel session");
6379
+ console.error(" status Show channel status");
6380
+ console.error(" logs Show recent channel output");
6381
+ console.error(" attach Attach to the channel's Claude Code session");
6382
+ console.error(" (detach with Ctrl-a then d)");
6383
+ }
6384
+ var SUPPORTED_PLATFORMS;
6385
+ var init_channel = __esm(() => {
6386
+ init_global_config();
6387
+ init_vault();
6388
+ init_channel_templates();
6389
+ init_channel_process();
6390
+ SUPPORTED_PLATFORMS = ["discord", "telegram"];
6391
+ });
6392
+
5731
6393
  // src/commands/config.ts
5732
6394
  var exports_config = {};
5733
6395
  __export(exports_config, {
@@ -5818,8 +6480,8 @@ var init_config2 = __esm(() => {
5818
6480
 
5819
6481
  // src/commands/init.ts
5820
6482
  import { execSync as execSync3 } from "child_process";
5821
- import { mkdirSync as mkdirSync8, existsSync as existsSync18 } from "fs";
5822
- import { resolve as resolve4, dirname as dirname7, basename as basename8, join as join16 } from "path";
6483
+ import { mkdirSync as mkdirSync10, existsSync as existsSync20 } from "fs";
6484
+ import { resolve as resolve4, dirname as dirname8, basename as basename8, join as join18 } from "path";
5823
6485
  function detectRuntime2() {
5824
6486
  try {
5825
6487
  execSync3("bun --version", { stdio: "ignore" });
@@ -5860,7 +6522,7 @@ function isMinkHook2(entry) {
5860
6522
  return false;
5861
6523
  }
5862
6524
  function mergeHooksIntoSettings2(settingsPath, newHooks) {
5863
- mkdirSync8(dirname7(settingsPath), { recursive: true });
6525
+ mkdirSync10(dirname8(settingsPath), { recursive: true });
5864
6526
  const existing = safeReadJson(settingsPath) ?? {};
5865
6527
  const existingHooks = existing.hooks ?? {};
5866
6528
  for (const [event, entries] of Object.entries(newHooks)) {
@@ -5883,7 +6545,7 @@ var exports_update = {};
5883
6545
  __export(exports_update, {
5884
6546
  update: () => update
5885
6547
  });
5886
- import { resolve as resolve5, dirname as dirname8 } from "path";
6548
+ import { resolve as resolve5, dirname as dirname9 } from "path";
5887
6549
  function parseArgs(args) {
5888
6550
  let dryRun = false;
5889
6551
  let project = null;
@@ -5931,7 +6593,7 @@ async function update(cwd, args) {
5931
6593
  return;
5932
6594
  }
5933
6595
  const runtime = detectRuntime2();
5934
- const cliPath = resolve5(dirname8(new URL(import.meta.url).pathname), "../cli.ts");
6596
+ const cliPath = resolve5(dirname9(new URL(import.meta.url).pathname), "../cli.ts");
5935
6597
  const newHooks = buildHooksConfig2(runtime, cliPath);
5936
6598
  for (const target of targets) {
5937
6599
  console.log(`[mink] updating: ${target.name} (${target.id})`);
@@ -6000,8 +6662,8 @@ var init_restore = __esm(() => {
6000
6662
  });
6001
6663
 
6002
6664
  // src/core/design-eval/server-detect.ts
6003
- import { readFileSync as readFileSync19 } from "fs";
6004
- import { join as join17 } from "path";
6665
+ import { readFileSync as readFileSync20 } from "fs";
6666
+ import { join as join19 } from "path";
6005
6667
  async function probePort(port) {
6006
6668
  try {
6007
6669
  const controller = new AbortController;
@@ -6023,7 +6685,7 @@ async function findRunningServer(ports = DEFAULT_PROBE_PORTS) {
6023
6685
  }
6024
6686
  function detectDevCommand(cwd) {
6025
6687
  try {
6026
- const raw = readFileSync19(join17(cwd, "package.json"), "utf-8");
6688
+ const raw = readFileSync20(join19(cwd, "package.json"), "utf-8");
6027
6689
  const pkg = JSON.parse(raw);
6028
6690
  const scripts = pkg.scripts;
6029
6691
  if (!scripts || typeof scripts !== "object")
@@ -6043,10 +6705,10 @@ var init_server_detect = __esm(() => {
6043
6705
  });
6044
6706
 
6045
6707
  // src/core/design-eval/route-detect.ts
6046
- import { existsSync as existsSync19, readdirSync as readdirSync5, statSync as statSync8 } from "fs";
6047
- import { join as join18, relative as relative6, sep } from "path";
6708
+ import { existsSync as existsSync21, readdirSync as readdirSync5, statSync as statSync8 } from "fs";
6709
+ import { join as join20, relative as relative6, sep } from "path";
6048
6710
  function detectFramework(cwd) {
6049
- const has = (name) => ["js", "mjs", "ts", "cjs"].some((ext) => existsSync19(join18(cwd, `${name}.${ext}`))) || existsSync19(join18(cwd, name));
6711
+ const has = (name) => ["js", "mjs", "ts", "cjs"].some((ext) => existsSync21(join20(cwd, `${name}.${ext}`))) || existsSync21(join20(cwd, name));
6050
6712
  if (has("next.config"))
6051
6713
  return "nextjs";
6052
6714
  if (has("svelte.config"))
@@ -6071,8 +6733,8 @@ function detectRoutes(cwd) {
6071
6733
  }
6072
6734
  function detectNextRoutes(cwd) {
6073
6735
  const routes = [];
6074
- const appDir = join18(cwd, "app");
6075
- if (existsSync19(appDir)) {
6736
+ const appDir = join20(cwd, "app");
6737
+ if (existsSync21(appDir)) {
6076
6738
  const pageFiles = findFiles(appDir, /^page\.(tsx?|jsx?)$/);
6077
6739
  for (const file of pageFiles) {
6078
6740
  const rel = relative6(appDir, file);
@@ -6083,8 +6745,8 @@ function detectNextRoutes(cwd) {
6083
6745
  routes.push(route);
6084
6746
  }
6085
6747
  }
6086
- const pagesDir = join18(cwd, "pages");
6087
- if (existsSync19(pagesDir)) {
6748
+ const pagesDir = join20(cwd, "pages");
6749
+ if (existsSync21(pagesDir)) {
6088
6750
  const pageFiles = findFiles(pagesDir, /\.(tsx?|jsx?)$/);
6089
6751
  for (const file of pageFiles) {
6090
6752
  const rel = relative6(pagesDir, file);
@@ -6103,8 +6765,8 @@ function detectNextRoutes(cwd) {
6103
6765
  return unique.length > 0 ? unique.sort() : ["/"];
6104
6766
  }
6105
6767
  function detectSvelteKitRoutes(cwd) {
6106
- const routesDir = join18(cwd, "src", "routes");
6107
- if (!existsSync19(routesDir))
6768
+ const routesDir = join20(cwd, "src", "routes");
6769
+ if (!existsSync21(routesDir))
6108
6770
  return ["/"];
6109
6771
  const routes = [];
6110
6772
  const pageFiles = findFiles(routesDir, /^\+page\.svelte$/);
@@ -6119,8 +6781,8 @@ function detectSvelteKitRoutes(cwd) {
6119
6781
  return routes.length > 0 ? routes.sort() : ["/"];
6120
6782
  }
6121
6783
  function detectNuxtRoutes(cwd) {
6122
- const pagesDir = join18(cwd, "pages");
6123
- if (!existsSync19(pagesDir))
6784
+ const pagesDir = join20(cwd, "pages");
6785
+ if (!existsSync21(pagesDir))
6124
6786
  return ["/"];
6125
6787
  const routes = [];
6126
6788
  const vueFiles = findFiles(pagesDir, /\.vue$/);
@@ -6146,7 +6808,7 @@ function findFiles(dir, pattern) {
6146
6808
  for (const entry of entries) {
6147
6809
  if (entry.startsWith(".") || entry === "node_modules")
6148
6810
  continue;
6149
- const full = join18(current, entry);
6811
+ const full = join20(current, entry);
6150
6812
  try {
6151
6813
  const stat2 = statSync8(full);
6152
6814
  if (stat2.isDirectory()) {
@@ -28796,8 +29458,8 @@ var require_ChannelProxy = __commonJS((exports) => {
28796
29458
  #properties;
28797
29459
  #id = (0, uuid_js_1.uuidv4)();
28798
29460
  #logger;
28799
- constructor(channel, logger) {
28800
- this.#properties = channel;
29461
+ constructor(channel2, logger) {
29462
+ this.#properties = channel2;
28801
29463
  this.#logger = logger;
28802
29464
  }
28803
29465
  async init(realm, eventManager) {
@@ -31490,7 +32152,7 @@ var require_BrowsingContextImpl = __commonJS((exports) => {
31490
32152
  const realm = new WindowRealm_js_1.WindowRealm(this.id, this.#browsingContextStorage, this.#cdpTarget.cdpClient, this.#eventManager, id, this.#logger, origin, uniqueId, this.#realmStorage, sandbox);
31491
32153
  if (auxData.isDefault) {
31492
32154
  this.#defaultRealmDeferred.resolve(realm);
31493
- Promise.all(this.#cdpTarget.getChannels().map((channel) => channel.startListenerFromWindow(realm, this.#eventManager)));
32155
+ Promise.all(this.#cdpTarget.getChannels().map((channel2) => channel2.startListenerFromWindow(realm, this.#eventManager)));
31494
32156
  }
31495
32157
  });
31496
32158
  this.#cdpTarget.cdpClient.on("Runtime.executionContextDestroyed", (params) => {
@@ -38072,7 +38734,7 @@ var init_ExposedFunction = __esm(() => {
38072
38734
  }
38073
38735
  async#initialize() {
38074
38736
  const connection = this.#connection;
38075
- const channel = {
38737
+ const channel2 = {
38076
38738
  type: "channel",
38077
38739
  value: {
38078
38740
  channel: this.#channel,
@@ -38099,11 +38761,11 @@ var init_ExposedFunction = __esm(() => {
38099
38761
  try {
38100
38762
  const [script] = await Promise.all([
38101
38763
  frame.browsingContext.addPreloadScript(functionDeclaration, {
38102
- arguments: [channel],
38764
+ arguments: [channel2],
38103
38765
  sandbox: realm.sandbox
38104
38766
  }),
38105
38767
  realm.realm.callFunction(functionDeclaration, false, {
38106
- arguments: [channel]
38768
+ arguments: [channel2]
38107
38769
  })
38108
38770
  ]);
38109
38771
  this.#scripts.push([frame, script]);
@@ -54850,7 +55512,7 @@ var require_util2 = __commonJS((exports) => {
54850
55512
  return path;
54851
55513
  }
54852
55514
  exports.normalize = normalize;
54853
- function join19(aRoot, aPath) {
55515
+ function join21(aRoot, aPath) {
54854
55516
  if (aRoot === "") {
54855
55517
  aRoot = ".";
54856
55518
  }
@@ -54882,7 +55544,7 @@ var require_util2 = __commonJS((exports) => {
54882
55544
  }
54883
55545
  return joined;
54884
55546
  }
54885
- exports.join = join19;
55547
+ exports.join = join21;
54886
55548
  exports.isAbsolute = function(aPath) {
54887
55549
  return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
54888
55550
  };
@@ -55055,7 +55717,7 @@ var require_util2 = __commonJS((exports) => {
55055
55717
  parsed.path = parsed.path.substring(0, index + 1);
55056
55718
  }
55057
55719
  }
55058
- sourceURL = join19(urlGenerate(parsed), sourceURL);
55720
+ sourceURL = join21(urlGenerate(parsed), sourceURL);
55059
55721
  }
55060
55722
  return normalize(sourceURL);
55061
55723
  }
@@ -56787,7 +57449,7 @@ var require_escodegen = __commonJS((exports) => {
56787
57449
  function noEmptySpace() {
56788
57450
  return space ? space : " ";
56789
57451
  }
56790
- function join19(left, right) {
57452
+ function join21(left, right) {
56791
57453
  var leftSource, rightSource, leftCharCode, rightCharCode;
56792
57454
  leftSource = toSourceNodeWhenNeeded(left).toString();
56793
57455
  if (leftSource.length === 0) {
@@ -57128,8 +57790,8 @@ var require_escodegen = __commonJS((exports) => {
57128
57790
  } else {
57129
57791
  result.push(that.generateExpression(stmt.left, Precedence.Call, E_TTT));
57130
57792
  }
57131
- result = join19(result, operator);
57132
- result = [join19(result, that.generateExpression(stmt.right, Precedence.Assignment, E_TTT)), ")"];
57793
+ result = join21(result, operator);
57794
+ result = [join21(result, that.generateExpression(stmt.right, Precedence.Assignment, E_TTT)), ")"];
57133
57795
  });
57134
57796
  result.push(this.maybeBlock(stmt.body, flags));
57135
57797
  return result;
@@ -57267,11 +57929,11 @@ var require_escodegen = __commonJS((exports) => {
57267
57929
  var result, fragment;
57268
57930
  result = ["class"];
57269
57931
  if (stmt.id) {
57270
- result = join19(result, this.generateExpression(stmt.id, Precedence.Sequence, E_TTT));
57932
+ result = join21(result, this.generateExpression(stmt.id, Precedence.Sequence, E_TTT));
57271
57933
  }
57272
57934
  if (stmt.superClass) {
57273
- fragment = join19("extends", this.generateExpression(stmt.superClass, Precedence.Unary, E_TTT));
57274
- result = join19(result, fragment);
57935
+ fragment = join21("extends", this.generateExpression(stmt.superClass, Precedence.Unary, E_TTT));
57936
+ result = join21(result, fragment);
57275
57937
  }
57276
57938
  result.push(space);
57277
57939
  result.push(this.generateStatement(stmt.body, S_TFFT));
@@ -57284,9 +57946,9 @@ var require_escodegen = __commonJS((exports) => {
57284
57946
  return escapeDirective(stmt.directive) + this.semicolon(flags);
57285
57947
  },
57286
57948
  DoWhileStatement: function(stmt, flags) {
57287
- var result = join19("do", this.maybeBlock(stmt.body, S_TFFF));
57949
+ var result = join21("do", this.maybeBlock(stmt.body, S_TFFF));
57288
57950
  result = this.maybeBlockSuffix(stmt.body, result);
57289
- return join19(result, [
57951
+ return join21(result, [
57290
57952
  "while" + space + "(",
57291
57953
  this.generateExpression(stmt.test, Precedence.Sequence, E_TTT),
57292
57954
  ")" + this.semicolon(flags)
@@ -57322,11 +57984,11 @@ var require_escodegen = __commonJS((exports) => {
57322
57984
  ExportDefaultDeclaration: function(stmt, flags) {
57323
57985
  var result = ["export"], bodyFlags;
57324
57986
  bodyFlags = flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF;
57325
- result = join19(result, "default");
57987
+ result = join21(result, "default");
57326
57988
  if (isStatement(stmt.declaration)) {
57327
- result = join19(result, this.generateStatement(stmt.declaration, bodyFlags));
57989
+ result = join21(result, this.generateStatement(stmt.declaration, bodyFlags));
57328
57990
  } else {
57329
- result = join19(result, this.generateExpression(stmt.declaration, Precedence.Assignment, E_TTT) + this.semicolon(flags));
57991
+ result = join21(result, this.generateExpression(stmt.declaration, Precedence.Assignment, E_TTT) + this.semicolon(flags));
57330
57992
  }
57331
57993
  return result;
57332
57994
  },
@@ -57334,15 +57996,15 @@ var require_escodegen = __commonJS((exports) => {
57334
57996
  var result = ["export"], bodyFlags, that = this;
57335
57997
  bodyFlags = flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF;
57336
57998
  if (stmt.declaration) {
57337
- return join19(result, this.generateStatement(stmt.declaration, bodyFlags));
57999
+ return join21(result, this.generateStatement(stmt.declaration, bodyFlags));
57338
58000
  }
57339
58001
  if (stmt.specifiers) {
57340
58002
  if (stmt.specifiers.length === 0) {
57341
- result = join19(result, "{" + space + "}");
58003
+ result = join21(result, "{" + space + "}");
57342
58004
  } else if (stmt.specifiers[0].type === Syntax.ExportBatchSpecifier) {
57343
- result = join19(result, this.generateExpression(stmt.specifiers[0], Precedence.Sequence, E_TTT));
58005
+ result = join21(result, this.generateExpression(stmt.specifiers[0], Precedence.Sequence, E_TTT));
57344
58006
  } else {
57345
- result = join19(result, "{");
58007
+ result = join21(result, "{");
57346
58008
  withIndent(function(indent2) {
57347
58009
  var i, iz;
57348
58010
  result.push(newline);
@@ -57360,7 +58022,7 @@ var require_escodegen = __commonJS((exports) => {
57360
58022
  result.push(base + "}");
57361
58023
  }
57362
58024
  if (stmt.source) {
57363
- result = join19(result, [
58025
+ result = join21(result, [
57364
58026
  "from" + space,
57365
58027
  this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
57366
58028
  this.semicolon(flags)
@@ -57444,7 +58106,7 @@ var require_escodegen = __commonJS((exports) => {
57444
58106
  ];
57445
58107
  cursor = 0;
57446
58108
  if (stmt.specifiers[cursor].type === Syntax.ImportDefaultSpecifier) {
57447
- result = join19(result, [
58109
+ result = join21(result, [
57448
58110
  this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT)
57449
58111
  ]);
57450
58112
  ++cursor;
@@ -57454,7 +58116,7 @@ var require_escodegen = __commonJS((exports) => {
57454
58116
  result.push(",");
57455
58117
  }
57456
58118
  if (stmt.specifiers[cursor].type === Syntax.ImportNamespaceSpecifier) {
57457
- result = join19(result, [
58119
+ result = join21(result, [
57458
58120
  space,
57459
58121
  this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT)
57460
58122
  ]);
@@ -57483,7 +58145,7 @@ var require_escodegen = __commonJS((exports) => {
57483
58145
  }
57484
58146
  }
57485
58147
  }
57486
- result = join19(result, [
58148
+ result = join21(result, [
57487
58149
  "from" + space,
57488
58150
  this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
57489
58151
  this.semicolon(flags)
@@ -57537,7 +58199,7 @@ var require_escodegen = __commonJS((exports) => {
57537
58199
  return result;
57538
58200
  },
57539
58201
  ThrowStatement: function(stmt, flags) {
57540
- return [join19("throw", this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)), this.semicolon(flags)];
58202
+ return [join21("throw", this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)), this.semicolon(flags)];
57541
58203
  },
57542
58204
  TryStatement: function(stmt, flags) {
57543
58205
  var result, i, iz, guardedHandlers;
@@ -57545,7 +58207,7 @@ var require_escodegen = __commonJS((exports) => {
57545
58207
  result = this.maybeBlockSuffix(stmt.block, result);
57546
58208
  if (stmt.handlers) {
57547
58209
  for (i = 0, iz = stmt.handlers.length;i < iz; ++i) {
57548
- result = join19(result, this.generateStatement(stmt.handlers[i], S_TFFF));
58210
+ result = join21(result, this.generateStatement(stmt.handlers[i], S_TFFF));
57549
58211
  if (stmt.finalizer || i + 1 !== iz) {
57550
58212
  result = this.maybeBlockSuffix(stmt.handlers[i].body, result);
57551
58213
  }
@@ -57553,7 +58215,7 @@ var require_escodegen = __commonJS((exports) => {
57553
58215
  } else {
57554
58216
  guardedHandlers = stmt.guardedHandlers || [];
57555
58217
  for (i = 0, iz = guardedHandlers.length;i < iz; ++i) {
57556
- result = join19(result, this.generateStatement(guardedHandlers[i], S_TFFF));
58218
+ result = join21(result, this.generateStatement(guardedHandlers[i], S_TFFF));
57557
58219
  if (stmt.finalizer || i + 1 !== iz) {
57558
58220
  result = this.maybeBlockSuffix(guardedHandlers[i].body, result);
57559
58221
  }
@@ -57561,13 +58223,13 @@ var require_escodegen = __commonJS((exports) => {
57561
58223
  if (stmt.handler) {
57562
58224
  if (Array.isArray(stmt.handler)) {
57563
58225
  for (i = 0, iz = stmt.handler.length;i < iz; ++i) {
57564
- result = join19(result, this.generateStatement(stmt.handler[i], S_TFFF));
58226
+ result = join21(result, this.generateStatement(stmt.handler[i], S_TFFF));
57565
58227
  if (stmt.finalizer || i + 1 !== iz) {
57566
58228
  result = this.maybeBlockSuffix(stmt.handler[i].body, result);
57567
58229
  }
57568
58230
  }
57569
58231
  } else {
57570
- result = join19(result, this.generateStatement(stmt.handler, S_TFFF));
58232
+ result = join21(result, this.generateStatement(stmt.handler, S_TFFF));
57571
58233
  if (stmt.finalizer) {
57572
58234
  result = this.maybeBlockSuffix(stmt.handler.body, result);
57573
58235
  }
@@ -57575,7 +58237,7 @@ var require_escodegen = __commonJS((exports) => {
57575
58237
  }
57576
58238
  }
57577
58239
  if (stmt.finalizer) {
57578
- result = join19(result, ["finally", this.maybeBlock(stmt.finalizer, S_TFFF)]);
58240
+ result = join21(result, ["finally", this.maybeBlock(stmt.finalizer, S_TFFF)]);
57579
58241
  }
57580
58242
  return result;
57581
58243
  },
@@ -57609,7 +58271,7 @@ var require_escodegen = __commonJS((exports) => {
57609
58271
  withIndent(function() {
57610
58272
  if (stmt.test) {
57611
58273
  result = [
57612
- join19("case", that.generateExpression(stmt.test, Precedence.Sequence, E_TTT)),
58274
+ join21("case", that.generateExpression(stmt.test, Precedence.Sequence, E_TTT)),
57613
58275
  ":"
57614
58276
  ];
57615
58277
  } else {
@@ -57657,9 +58319,9 @@ var require_escodegen = __commonJS((exports) => {
57657
58319
  result.push(this.maybeBlock(stmt.consequent, S_TFFF));
57658
58320
  result = this.maybeBlockSuffix(stmt.consequent, result);
57659
58321
  if (stmt.alternate.type === Syntax.IfStatement) {
57660
- result = join19(result, ["else ", this.generateStatement(stmt.alternate, bodyFlags)]);
58322
+ result = join21(result, ["else ", this.generateStatement(stmt.alternate, bodyFlags)]);
57661
58323
  } else {
57662
- result = join19(result, join19("else", this.maybeBlock(stmt.alternate, bodyFlags)));
58324
+ result = join21(result, join21("else", this.maybeBlock(stmt.alternate, bodyFlags)));
57663
58325
  }
57664
58326
  } else {
57665
58327
  result.push(this.maybeBlock(stmt.consequent, bodyFlags));
@@ -57761,7 +58423,7 @@ var require_escodegen = __commonJS((exports) => {
57761
58423
  },
57762
58424
  ReturnStatement: function(stmt, flags) {
57763
58425
  if (stmt.argument) {
57764
- return [join19("return", this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)), this.semicolon(flags)];
58426
+ return [join21("return", this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)), this.semicolon(flags)];
57765
58427
  }
57766
58428
  return ["return" + this.semicolon(flags)];
57767
58429
  },
@@ -57843,14 +58505,14 @@ var require_escodegen = __commonJS((exports) => {
57843
58505
  if (leftSource.charCodeAt(leftSource.length - 1) === 47 && esutils.code.isIdentifierPartES5(expr.operator.charCodeAt(0))) {
57844
58506
  result = [fragment, noEmptySpace(), expr.operator];
57845
58507
  } else {
57846
- result = join19(fragment, expr.operator);
58508
+ result = join21(fragment, expr.operator);
57847
58509
  }
57848
58510
  fragment = this.generateExpression(expr.right, rightPrecedence, flags);
57849
58511
  if (expr.operator === "/" && fragment.toString().charAt(0) === "/" || expr.operator.slice(-1) === "<" && fragment.toString().slice(0, 3) === "!--") {
57850
58512
  result.push(noEmptySpace());
57851
58513
  result.push(fragment);
57852
58514
  } else {
57853
- result = join19(result, fragment);
58515
+ result = join21(result, fragment);
57854
58516
  }
57855
58517
  if (expr.operator === "in" && !(flags & F_ALLOW_IN)) {
57856
58518
  return ["(", result, ")"];
@@ -57890,7 +58552,7 @@ var require_escodegen = __commonJS((exports) => {
57890
58552
  var result, length, i, iz, itemFlags;
57891
58553
  length = expr["arguments"].length;
57892
58554
  itemFlags = flags & F_ALLOW_UNPARATH_NEW && !parentheses && length === 0 ? E_TFT : E_TFF;
57893
- result = join19("new", this.generateExpression(expr.callee, Precedence.New, itemFlags));
58555
+ result = join21("new", this.generateExpression(expr.callee, Precedence.New, itemFlags));
57894
58556
  if (!(flags & F_ALLOW_UNPARATH_NEW) || parentheses || length > 0) {
57895
58557
  result.push("(");
57896
58558
  for (i = 0, iz = length;i < iz; ++i) {
@@ -57937,11 +58599,11 @@ var require_escodegen = __commonJS((exports) => {
57937
58599
  var result, fragment, rightCharCode, leftSource, leftCharCode;
57938
58600
  fragment = this.generateExpression(expr.argument, Precedence.Unary, E_TTT);
57939
58601
  if (space === "") {
57940
- result = join19(expr.operator, fragment);
58602
+ result = join21(expr.operator, fragment);
57941
58603
  } else {
57942
58604
  result = [expr.operator];
57943
58605
  if (expr.operator.length > 2) {
57944
- result = join19(result, fragment);
58606
+ result = join21(result, fragment);
57945
58607
  } else {
57946
58608
  leftSource = toSourceNodeWhenNeeded(result).toString();
57947
58609
  leftCharCode = leftSource.charCodeAt(leftSource.length - 1);
@@ -57964,12 +58626,12 @@ var require_escodegen = __commonJS((exports) => {
57964
58626
  result = "yield";
57965
58627
  }
57966
58628
  if (expr.argument) {
57967
- result = join19(result, this.generateExpression(expr.argument, Precedence.Yield, E_TTT));
58629
+ result = join21(result, this.generateExpression(expr.argument, Precedence.Yield, E_TTT));
57968
58630
  }
57969
58631
  return parenthesize(result, Precedence.Yield, precedence);
57970
58632
  },
57971
58633
  AwaitExpression: function(expr, precedence, flags) {
57972
- var result = join19(expr.all ? "await*" : "await", this.generateExpression(expr.argument, Precedence.Await, E_TTT));
58634
+ var result = join21(expr.all ? "await*" : "await", this.generateExpression(expr.argument, Precedence.Await, E_TTT));
57973
58635
  return parenthesize(result, Precedence.Await, precedence);
57974
58636
  },
57975
58637
  UpdateExpression: function(expr, precedence, flags) {
@@ -58041,11 +58703,11 @@ var require_escodegen = __commonJS((exports) => {
58041
58703
  var result, fragment;
58042
58704
  result = ["class"];
58043
58705
  if (expr.id) {
58044
- result = join19(result, this.generateExpression(expr.id, Precedence.Sequence, E_TTT));
58706
+ result = join21(result, this.generateExpression(expr.id, Precedence.Sequence, E_TTT));
58045
58707
  }
58046
58708
  if (expr.superClass) {
58047
- fragment = join19("extends", this.generateExpression(expr.superClass, Precedence.Unary, E_TTT));
58048
- result = join19(result, fragment);
58709
+ fragment = join21("extends", this.generateExpression(expr.superClass, Precedence.Unary, E_TTT));
58710
+ result = join21(result, fragment);
58049
58711
  }
58050
58712
  result.push(space);
58051
58713
  result.push(this.generateStatement(expr.body, S_TFFT));
@@ -58060,7 +58722,7 @@ var require_escodegen = __commonJS((exports) => {
58060
58722
  }
58061
58723
  if (expr.kind === "get" || expr.kind === "set") {
58062
58724
  fragment = [
58063
- join19(expr.kind, this.generatePropertyKey(expr.key, expr.computed)),
58725
+ join21(expr.kind, this.generatePropertyKey(expr.key, expr.computed)),
58064
58726
  this.generateFunctionBody(expr.value)
58065
58727
  ];
58066
58728
  } else {
@@ -58070,7 +58732,7 @@ var require_escodegen = __commonJS((exports) => {
58070
58732
  this.generateFunctionBody(expr.value)
58071
58733
  ];
58072
58734
  }
58073
- return join19(result, fragment);
58735
+ return join21(result, fragment);
58074
58736
  },
58075
58737
  Property: function(expr, precedence, flags) {
58076
58738
  if (expr.kind === "get" || expr.kind === "set") {
@@ -58264,7 +58926,7 @@ var require_escodegen = __commonJS((exports) => {
58264
58926
  for (i = 0, iz = expr.blocks.length;i < iz; ++i) {
58265
58927
  fragment = that.generateExpression(expr.blocks[i], Precedence.Sequence, E_TTT);
58266
58928
  if (i > 0 || extra.moz.comprehensionExpressionStartsWithAssignment) {
58267
- result = join19(result, fragment);
58929
+ result = join21(result, fragment);
58268
58930
  } else {
58269
58931
  result.push(fragment);
58270
58932
  }
@@ -58272,13 +58934,13 @@ var require_escodegen = __commonJS((exports) => {
58272
58934
  });
58273
58935
  }
58274
58936
  if (expr.filter) {
58275
- result = join19(result, "if" + space);
58937
+ result = join21(result, "if" + space);
58276
58938
  fragment = this.generateExpression(expr.filter, Precedence.Sequence, E_TTT);
58277
- result = join19(result, ["(", fragment, ")"]);
58939
+ result = join21(result, ["(", fragment, ")"]);
58278
58940
  }
58279
58941
  if (!extra.moz.comprehensionExpressionStartsWithAssignment) {
58280
58942
  fragment = this.generateExpression(expr.body, Precedence.Assignment, E_TTT);
58281
- result = join19(result, fragment);
58943
+ result = join21(result, fragment);
58282
58944
  }
58283
58945
  result.push(expr.type === Syntax.GeneratorExpression ? ")" : "]");
58284
58946
  return result;
@@ -58294,8 +58956,8 @@ var require_escodegen = __commonJS((exports) => {
58294
58956
  } else {
58295
58957
  fragment = this.generateExpression(expr.left, Precedence.Call, E_TTT);
58296
58958
  }
58297
- fragment = join19(fragment, expr.of ? "of" : "in");
58298
- fragment = join19(fragment, this.generateExpression(expr.right, Precedence.Sequence, E_TTT));
58959
+ fragment = join21(fragment, expr.of ? "of" : "in");
58960
+ fragment = join21(fragment, this.generateExpression(expr.right, Precedence.Sequence, E_TTT));
58299
58961
  return ["for" + space + "(", fragment, ")"];
58300
58962
  },
58301
58963
  SpreadElement: function(expr, precedence, flags) {
@@ -72037,13 +72699,13 @@ function relativeExecutablePath(platform2, _buildId) {
72037
72699
  return path.join("chrome-" + folder(platform2), "chrome.exe");
72038
72700
  }
72039
72701
  }
72040
- async function getLastKnownGoodReleaseForChannel(channel) {
72702
+ async function getLastKnownGoodReleaseForChannel(channel2) {
72041
72703
  const data = await getJSON(new URL(`${baseVersionUrl}/last-known-good-versions.json`));
72042
- for (const channel2 of Object.keys(data.channels)) {
72043
- data.channels[channel2.toLowerCase()] = data.channels[channel2];
72044
- delete data.channels[channel2];
72704
+ for (const channel3 of Object.keys(data.channels)) {
72705
+ data.channels[channel3.toLowerCase()] = data.channels[channel3];
72706
+ delete data.channels[channel3];
72045
72707
  }
72046
- return data.channels[channel];
72708
+ return data.channels[channel2];
72047
72709
  }
72048
72710
  async function getLastKnownGoodReleaseForMilestone(milestone) {
72049
72711
  const data = await getJSON(new URL(`${baseVersionUrl}/latest-versions-per-milestone.json`));
@@ -72053,24 +72715,24 @@ async function getLastKnownGoodReleaseForBuild(buildPrefix) {
72053
72715
  const data = await getJSON(new URL(`${baseVersionUrl}/latest-patch-versions-per-build.json`));
72054
72716
  return data.builds[buildPrefix];
72055
72717
  }
72056
- async function resolveBuildId(channel) {
72057
- if (Object.values(ChromeReleaseChannel).includes(channel)) {
72058
- return (await getLastKnownGoodReleaseForChannel(channel)).version;
72718
+ async function resolveBuildId(channel2) {
72719
+ if (Object.values(ChromeReleaseChannel).includes(channel2)) {
72720
+ return (await getLastKnownGoodReleaseForChannel(channel2)).version;
72059
72721
  }
72060
- if (channel.match(/^\d+$/)) {
72061
- return (await getLastKnownGoodReleaseForMilestone(channel))?.version;
72722
+ if (channel2.match(/^\d+$/)) {
72723
+ return (await getLastKnownGoodReleaseForMilestone(channel2))?.version;
72062
72724
  }
72063
- if (channel.match(/^\d+\.\d+\.\d+$/)) {
72064
- return (await getLastKnownGoodReleaseForBuild(channel))?.version;
72725
+ if (channel2.match(/^\d+\.\d+\.\d+$/)) {
72726
+ return (await getLastKnownGoodReleaseForBuild(channel2))?.version;
72065
72727
  }
72066
72728
  return;
72067
72729
  }
72068
- function getChromeWindowsLocation(channel, locationsPrefixes) {
72730
+ function getChromeWindowsLocation(channel2, locationsPrefixes) {
72069
72731
  if (locationsPrefixes.size === 0) {
72070
72732
  throw new Error("Non of the common Windows Env variables were set");
72071
72733
  }
72072
72734
  let suffix;
72073
- switch (channel) {
72735
+ switch (channel2) {
72074
72736
  case ChromeReleaseChannel.STABLE:
72075
72737
  suffix = "Google\\Chrome\\Application\\chrome.exe";
72076
72738
  break;
@@ -72100,7 +72762,7 @@ function getWslVariable(variable) {
72100
72762
  } catch {}
72101
72763
  return;
72102
72764
  }
72103
- function getWslLocation(channel) {
72765
+ function getWslLocation(channel2) {
72104
72766
  const wslVersion = execSync4("wslinfo --version", {
72105
72767
  stdio: ["ignore", "pipe", "ignore"],
72106
72768
  encoding: "utf-8"
@@ -72115,14 +72777,14 @@ function getWslLocation(channel) {
72115
72777
  wslPrefixes.add(wslPrefix);
72116
72778
  }
72117
72779
  }
72118
- const windowsPath = getChromeWindowsLocation(channel, wslPrefixes);
72780
+ const windowsPath = getChromeWindowsLocation(channel2, wslPrefixes);
72119
72781
  return windowsPath.map((path2) => {
72120
72782
  return execSync4(`wslpath "${path2}"`).toString().trim();
72121
72783
  });
72122
72784
  }
72123
- function getChromeLinuxOrWslLocation(channel) {
72785
+ function getChromeLinuxOrWslLocation(channel2) {
72124
72786
  const locations = [];
72125
- switch (channel) {
72787
+ switch (channel2) {
72126
72788
  case ChromeReleaseChannel.STABLE:
72127
72789
  locations.push("/opt/google/chrome/chrome");
72128
72790
  break;
@@ -72137,14 +72799,14 @@ function getChromeLinuxOrWslLocation(channel) {
72137
72799
  break;
72138
72800
  }
72139
72801
  try {
72140
- const wslPath = getWslLocation(channel);
72802
+ const wslPath = getWslLocation(channel2);
72141
72803
  if (wslPath) {
72142
72804
  locations.push(...wslPath);
72143
72805
  }
72144
72806
  } catch {}
72145
72807
  return locations;
72146
72808
  }
72147
- function resolveSystemExecutablePaths(platform2, channel) {
72809
+ function resolveSystemExecutablePaths(platform2, channel2) {
72148
72810
  switch (platform2) {
72149
72811
  case BrowserPlatform.WIN64:
72150
72812
  case BrowserPlatform.WIN32:
@@ -72157,10 +72819,10 @@ function resolveSystemExecutablePaths(platform2, channel) {
72157
72819
  prefixLocation.add("C:\\Program Files (x86)");
72158
72820
  prefixLocation.add("D:\\Program Files");
72159
72821
  prefixLocation.add("D:\\Program Files (x86)");
72160
- return getChromeWindowsLocation(channel, prefixLocation);
72822
+ return getChromeWindowsLocation(channel2, prefixLocation);
72161
72823
  case BrowserPlatform.MAC_ARM:
72162
72824
  case BrowserPlatform.MAC:
72163
- switch (channel) {
72825
+ switch (channel2) {
72164
72826
  case ChromeReleaseChannel.STABLE:
72165
72827
  return [
72166
72828
  "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
@@ -72180,14 +72842,14 @@ function resolveSystemExecutablePaths(platform2, channel) {
72180
72842
  }
72181
72843
  case BrowserPlatform.LINUX_ARM:
72182
72844
  case BrowserPlatform.LINUX:
72183
- return getChromeLinuxOrWslLocation(channel);
72845
+ return getChromeLinuxOrWslLocation(channel2);
72184
72846
  }
72185
72847
  }
72186
- function resolveDefaultUserDataDir(platform2, channel) {
72848
+ function resolveDefaultUserDataDir(platform2, channel2) {
72187
72849
  switch (platform2) {
72188
72850
  case BrowserPlatform.WIN64:
72189
72851
  case BrowserPlatform.WIN32:
72190
- switch (channel) {
72852
+ switch (channel2) {
72191
72853
  case ChromeReleaseChannel.STABLE:
72192
72854
  return path.join(getLocalAppDataWin(), "Google", "Chrome", "User Data");
72193
72855
  case ChromeReleaseChannel.BETA:
@@ -72199,7 +72861,7 @@ function resolveDefaultUserDataDir(platform2, channel) {
72199
72861
  }
72200
72862
  case BrowserPlatform.MAC_ARM:
72201
72863
  case BrowserPlatform.MAC:
72202
- switch (channel) {
72864
+ switch (channel2) {
72203
72865
  case ChromeReleaseChannel.STABLE:
72204
72866
  return path.join(getBaseUserDataDirPathMac(), "Chrome");
72205
72867
  case ChromeReleaseChannel.BETA:
@@ -72211,7 +72873,7 @@ function resolveDefaultUserDataDir(platform2, channel) {
72211
72873
  }
72212
72874
  case BrowserPlatform.LINUX_ARM:
72213
72875
  case BrowserPlatform.LINUX:
72214
- switch (channel) {
72876
+ switch (channel2) {
72215
72877
  case ChromeReleaseChannel.STABLE:
72216
72878
  return path.join(getConfigHomeLinux(), "google-chrome");
72217
72879
  case ChromeReleaseChannel.BETA:
@@ -72464,8 +73126,8 @@ function parseBuildId(buildId) {
72464
73126
  return [FirefoxChannel.NIGHTLY, buildId];
72465
73127
  }
72466
73128
  function resolveDownloadUrl5(platform2, buildId, baseUrl) {
72467
- const [channel] = parseBuildId(buildId);
72468
- switch (channel) {
73129
+ const [channel2] = parseBuildId(buildId);
73130
+ switch (channel2) {
72469
73131
  case FirefoxChannel.NIGHTLY:
72470
73132
  baseUrl ??= "https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central";
72471
73133
  break;
@@ -72481,8 +73143,8 @@ function resolveDownloadUrl5(platform2, buildId, baseUrl) {
72481
73143
  return `${baseUrl}/${resolveDownloadPath5(platform2, buildId).join("/")}`;
72482
73144
  }
72483
73145
  function resolveDownloadPath5(platform2, buildId) {
72484
- const [channel, resolvedBuildId] = parseBuildId(buildId);
72485
- switch (channel) {
73146
+ const [channel2, resolvedBuildId] = parseBuildId(buildId);
73147
+ switch (channel2) {
72486
73148
  case FirefoxChannel.NIGHTLY:
72487
73149
  return [archiveNightly(platform2, resolvedBuildId)];
72488
73150
  case FirefoxChannel.DEVEDITION:
@@ -72498,8 +73160,8 @@ function resolveDownloadPath5(platform2, buildId) {
72498
73160
  }
72499
73161
  }
72500
73162
  function relativeExecutablePath5(platform2, buildId) {
72501
- const [channel] = parseBuildId(buildId);
72502
- switch (channel) {
73163
+ const [channel2] = parseBuildId(buildId);
73164
+ switch (channel2) {
72503
73165
  case FirefoxChannel.NIGHTLY:
72504
73166
  switch (platform2) {
72505
73167
  case BrowserPlatform.MAC_ARM:
@@ -72529,7 +73191,7 @@ function relativeExecutablePath5(platform2, buildId) {
72529
73191
  }
72530
73192
  }
72531
73193
  }
72532
- async function resolveBuildId3(channel = FirefoxChannel.NIGHTLY) {
73194
+ async function resolveBuildId3(channel2 = FirefoxChannel.NIGHTLY) {
72533
73195
  const channelToVersionKey = {
72534
73196
  [FirefoxChannel.ESR]: "FIREFOX_ESR",
72535
73197
  [FirefoxChannel.STABLE]: "LATEST_FIREFOX_VERSION",
@@ -72538,11 +73200,11 @@ async function resolveBuildId3(channel = FirefoxChannel.NIGHTLY) {
72538
73200
  [FirefoxChannel.NIGHTLY]: "FIREFOX_NIGHTLY"
72539
73201
  };
72540
73202
  const versions = await getJSON(new URL(`${baseVersionUrl2}/firefox_versions.json`));
72541
- const version = versions[channelToVersionKey[channel]];
73203
+ const version = versions[channelToVersionKey[channel2]];
72542
73204
  if (!version) {
72543
- throw new Error(`Channel ${channel} is not found.`);
73205
+ throw new Error(`Channel ${channel2} is not found.`);
72544
73206
  }
72545
- return channel + "_" + version;
73207
+ return channel2 + "_" + version;
72546
73208
  }
72547
73209
  async function createProfile(options) {
72548
73210
  if (!fs.existsSync(options.path)) {
@@ -72807,7 +73469,7 @@ async function createProfile2(browser, opts) {
72807
73469
  throw new Error(`Profile creation is not support for ${browser} yet`);
72808
73470
  }
72809
73471
  }
72810
- function resolveDefaultUserDataDir2(browser, platform2, channel) {
73472
+ function resolveDefaultUserDataDir2(browser, platform2, channel2) {
72811
73473
  switch (browser) {
72812
73474
  case Browser6.CHROMEDRIVER:
72813
73475
  case Browser6.CHROMEHEADLESSSHELL:
@@ -72815,10 +73477,10 @@ function resolveDefaultUserDataDir2(browser, platform2, channel) {
72815
73477
  case Browser6.CHROMIUM:
72816
73478
  throw new Error(`Default user dir detection is not supported for ${browser} yet.`);
72817
73479
  case Browser6.CHROME:
72818
- return resolveDefaultUserDataDir(platform2, channel);
73480
+ return resolveDefaultUserDataDir(platform2, channel2);
72819
73481
  }
72820
73482
  }
72821
- function resolveSystemExecutablePaths2(browser, platform2, channel) {
73483
+ function resolveSystemExecutablePaths2(browser, platform2, channel2) {
72822
73484
  switch (browser) {
72823
73485
  case Browser6.CHROMEDRIVER:
72824
73486
  case Browser6.CHROMEHEADLESSSHELL:
@@ -72826,7 +73488,7 @@ function resolveSystemExecutablePaths2(browser, platform2, channel) {
72826
73488
  case Browser6.CHROMIUM:
72827
73489
  throw new Error(`System browser detection is not supported for ${browser} yet.`);
72828
73490
  case Browser6.CHROME:
72829
- return resolveSystemExecutablePaths(platform2, channel);
73491
+ return resolveSystemExecutablePaths(platform2, channel2);
72830
73492
  }
72831
73493
  }
72832
73494
  function getVersionComparator(browser) {
@@ -78262,7 +78924,7 @@ var require_tar_fs = __commonJS((exports) => {
78262
78924
  });
78263
78925
 
78264
78926
  // node_modules/@puppeteer/browsers/lib/esm/fileUtil.js
78265
- import { spawnSync, spawn } from "node:child_process";
78927
+ import { spawnSync as spawnSync2, spawn } from "node:child_process";
78266
78928
  import { createReadStream } from "node:fs";
78267
78929
  import { mkdir, readdir } from "node:fs/promises";
78268
78930
  import * as path7 from "node:path";
@@ -78280,7 +78942,7 @@ async function unpackArchive(archivePath, folderPath) {
78280
78942
  await mkdir(folderPath);
78281
78943
  await installDMG(archivePath, folderPath);
78282
78944
  } else if (archivePath.endsWith(".exe")) {
78283
- const result = spawnSync(archivePath, [`/ExtractDir=${folderPath}`], {
78945
+ const result = spawnSync2(archivePath, [`/ExtractDir=${folderPath}`], {
78284
78946
  env: {
78285
78947
  __compat_layer: "RunAsInvoker"
78286
78948
  }
@@ -78354,7 +79016,7 @@ async function extractTar(tarPath, folderPath, decompressUtilityName) {
78354
79016
  });
78355
79017
  }
78356
79018
  async function installDMG(dmgPath, folderPath) {
78357
- const { stdout } = spawnSync(`hdiutil`, [
79019
+ const { stdout } = spawnSync2(`hdiutil`, [
78358
79020
  "attach",
78359
79021
  "-nobrowse",
78360
79022
  "-noautoopen",
@@ -78374,9 +79036,9 @@ async function installDMG(dmgPath, folderPath) {
78374
79036
  throw new Error(`Cannot find app in ${mountPath}`);
78375
79037
  }
78376
79038
  const mountedPath = path7.join(mountPath, appName);
78377
- spawnSync("cp", ["-R", mountedPath, folderPath]);
79039
+ spawnSync2("cp", ["-R", mountedPath, folderPath]);
78378
79040
  } finally {
78379
- spawnSync("hdiutil", ["detach", mountPath, "-quiet"]);
79041
+ spawnSync2("hdiutil", ["detach", mountPath, "-quiet"]);
78380
79042
  }
78381
79043
  }
78382
79044
  var import_debug4, debugFileUtil, internalConstantsForTesting;
@@ -78391,8 +79053,8 @@ var init_fileUtil = __esm(() => {
78391
79053
 
78392
79054
  // node_modules/@puppeteer/browsers/lib/esm/install.js
78393
79055
  import assert2 from "node:assert";
78394
- import { spawnSync as spawnSync2 } from "node:child_process";
78395
- import { existsSync as existsSync20, readFileSync as readFileSync20 } from "node:fs";
79056
+ import { spawnSync as spawnSync3 } from "node:child_process";
79057
+ import { existsSync as existsSync22, readFileSync as readFileSync21 } from "node:fs";
78396
79058
  import { mkdir as mkdir2, unlink } from "node:fs/promises";
78397
79059
  import os5 from "node:os";
78398
79060
  import path8 from "node:path";
@@ -78445,7 +79107,7 @@ async function installWithProviders(options) {
78445
79107
  continue;
78446
79108
  }
78447
79109
  debugInstall(`Successfully got URL from ${provider.getName()}: ${url}`);
78448
- if (!existsSync20(browserRoot)) {
79110
+ if (!existsSync22(browserRoot)) {
78449
79111
  await mkdir2(browserRoot, { recursive: true });
78450
79112
  }
78451
79113
  return await installUrl(url, options, provider);
@@ -78478,21 +79140,21 @@ async function installDeps(installedBrowser) {
78478
79140
  return;
78479
79141
  }
78480
79142
  const depsPath = path8.join(path8.dirname(installedBrowser.executablePath), "deb.deps");
78481
- if (!existsSync20(depsPath)) {
79143
+ if (!existsSync22(depsPath)) {
78482
79144
  debugInstall(`deb.deps file was not found at ${depsPath}`);
78483
79145
  return;
78484
79146
  }
78485
- const data = readFileSync20(depsPath, "utf-8").split(`
79147
+ const data = readFileSync21(depsPath, "utf-8").split(`
78486
79148
  `).join(",");
78487
79149
  if (process.getuid?.() !== 0) {
78488
79150
  throw new Error("Installing system dependencies requires root privileges");
78489
79151
  }
78490
- let result = spawnSync2("apt-get", ["-v"]);
79152
+ let result = spawnSync3("apt-get", ["-v"]);
78491
79153
  if (result.status !== 0) {
78492
79154
  throw new Error("Failed to install system dependencies: apt-get does not seem to be available");
78493
79155
  }
78494
79156
  debugInstall(`Trying to install dependencies: ${data}`);
78495
- result = spawnSync2("apt-get", [
79157
+ result = spawnSync3("apt-get", [
78496
79158
  "satisfy",
78497
79159
  "-y",
78498
79160
  data,
@@ -78520,11 +79182,11 @@ async function installUrl(url, options, provider) {
78520
79182
  const cache = new Cache(options.cacheDir);
78521
79183
  const browserRoot = cache.browserRoot(options.browser);
78522
79184
  const archivePath = path8.join(browserRoot, `${options.buildId}-${fileName}`);
78523
- if (!existsSync20(browserRoot)) {
79185
+ if (!existsSync22(browserRoot)) {
78524
79186
  await mkdir2(browserRoot, { recursive: true });
78525
79187
  }
78526
79188
  if (!options.unpack) {
78527
- if (existsSync20(archivePath)) {
79189
+ if (existsSync22(archivePath)) {
78528
79190
  return archivePath;
78529
79191
  }
78530
79192
  debugInstall(`Downloading binary from ${url}`);
@@ -78545,8 +79207,8 @@ async function installUrl(url, options, provider) {
78545
79207
  cache.writeExecutablePath(options.browser, options.platform, options.buildId, relativeExecutablePath6);
78546
79208
  }
78547
79209
  try {
78548
- if (existsSync20(outputPath)) {
78549
- if (!existsSync20(installedBrowser.executablePath)) {
79210
+ if (existsSync22(outputPath)) {
79211
+ if (!existsSync22(installedBrowser.executablePath)) {
78550
79212
  throw new Error(`The browser folder (${outputPath}) exists but the executable (${installedBrowser.executablePath}) is missing`);
78551
79213
  }
78552
79214
  await runSetup(installedBrowser);
@@ -78555,7 +79217,7 @@ async function installUrl(url, options, provider) {
78555
79217
  }
78556
79218
  return installedBrowser;
78557
79219
  }
78558
- if (!existsSync20(archivePath)) {
79220
+ if (!existsSync22(archivePath)) {
78559
79221
  debugInstall(`Downloading binary from ${url}`);
78560
79222
  try {
78561
79223
  debugTime("download");
@@ -78584,7 +79246,7 @@ async function installUrl(url, options, provider) {
78584
79246
  }
78585
79247
  return installedBrowser;
78586
79248
  } finally {
78587
- if (existsSync20(archivePath)) {
79249
+ if (existsSync22(archivePath)) {
78588
79250
  await unlink(archivePath);
78589
79251
  }
78590
79252
  }
@@ -78595,10 +79257,10 @@ async function runSetup(installedBrowser) {
78595
79257
  debugTime("permissions");
78596
79258
  const browserDir = path8.dirname(installedBrowser.executablePath);
78597
79259
  const setupExePath = path8.join(browserDir, "setup.exe");
78598
- if (!existsSync20(setupExePath)) {
79260
+ if (!existsSync22(setupExePath)) {
78599
79261
  return;
78600
79262
  }
78601
- spawnSync2(path8.join(browserDir, "setup.exe"), [`--configure-browser-in-directory=` + browserDir], {
79263
+ spawnSync3(path8.join(browserDir, "setup.exe"), [`--configure-browser-in-directory=` + browserDir], {
78602
79264
  shell: true
78603
79265
  });
78604
79266
  } finally {
@@ -78976,19 +79638,19 @@ var init_cliui = __esm(() => {
78976
79638
  });
78977
79639
 
78978
79640
  // node_modules/escalade/sync/index.mjs
78979
- import { dirname as dirname9, resolve as resolve7 } from "path";
79641
+ import { dirname as dirname10, resolve as resolve7 } from "path";
78980
79642
  import { readdirSync as readdirSync6, statSync as statSync9 } from "fs";
78981
79643
  function sync_default(start, callback) {
78982
79644
  let dir = resolve7(".", start);
78983
79645
  let tmp, stats = statSync9(dir);
78984
79646
  if (!stats.isDirectory()) {
78985
- dir = dirname9(dir);
79647
+ dir = dirname10(dir);
78986
79648
  }
78987
79649
  while (true) {
78988
79650
  tmp = callback(dir, readdirSync6(dir));
78989
79651
  if (tmp)
78990
79652
  return resolve7(dir, tmp);
78991
- dir = dirname9(tmp = dir);
79653
+ dir = dirname10(tmp = dir);
78992
79654
  if (tmp === dir)
78993
79655
  break;
78994
79656
  }
@@ -80008,14 +80670,14 @@ var init_yerror = __esm(() => {
80008
80670
  });
80009
80671
 
80010
80672
  // node_modules/y18n/build/lib/platform-shims/node.js
80011
- import { readFileSync as readFileSync21, statSync as statSync10, writeFile } from "fs";
80673
+ import { readFileSync as readFileSync22, statSync as statSync10, writeFile } from "fs";
80012
80674
  import { format as format2 } from "util";
80013
80675
  import { resolve as resolve9 } from "path";
80014
80676
  var node_default;
80015
80677
  var init_node = __esm(() => {
80016
80678
  node_default = {
80017
80679
  fs: {
80018
- readFileSync: readFileSync21,
80680
+ readFileSync: readFileSync22,
80019
80681
  writeFile
80020
80682
  },
80021
80683
  format: format2,
@@ -80200,9 +80862,9 @@ var init_y18n = __esm(() => {
80200
80862
  // node_modules/yargs/lib/platform-shims/esm.mjs
80201
80863
  import { notStrictEqual, strictEqual } from "assert";
80202
80864
  import { inspect } from "util";
80203
- import { readFileSync as readFileSync22 } from "fs";
80865
+ import { readFileSync as readFileSync23 } from "fs";
80204
80866
  import { fileURLToPath } from "url";
80205
- import { basename as basename10, dirname as dirname10, extname as extname3, relative as relative7, resolve as resolve10 } from "path";
80867
+ import { basename as basename10, dirname as dirname11, extname as extname3, relative as relative7, resolve as resolve10 } from "path";
80206
80868
  var REQUIRE_ERROR = "require is not supported by ESM", REQUIRE_DIRECTORY_ERROR = "loading a directory of commands is not supported yet for ESM", __dirname2, mainFilename, esm_default;
80207
80869
  var init_esm = __esm(() => {
80208
80870
  init_cliui();
@@ -80235,7 +80897,7 @@ var init_esm = __esm(() => {
80235
80897
  Parser: lib_default,
80236
80898
  path: {
80237
80899
  basename: basename10,
80238
- dirname: dirname10,
80900
+ dirname: dirname11,
80239
80901
  extname: extname3,
80240
80902
  relative: relative7,
80241
80903
  resolve: resolve10
@@ -80249,7 +80911,7 @@ var init_esm = __esm(() => {
80249
80911
  nextTick: process.nextTick,
80250
80912
  stdColumns: typeof process.stdout.columns !== "undefined" ? process.stdout.columns : null
80251
80913
  },
80252
- readFileSync: readFileSync22,
80914
+ readFileSync: readFileSync23,
80253
80915
  require: () => {
80254
80916
  throw new YError(REQUIRE_ERROR);
80255
80917
  },
@@ -83894,8 +84556,8 @@ var exports_LaunchOptions = {};
83894
84556
  __export(exports_LaunchOptions, {
83895
84557
  convertPuppeteerChannelToBrowsersChannel: () => convertPuppeteerChannelToBrowsersChannel
83896
84558
  });
83897
- function convertPuppeteerChannelToBrowsersChannel(channel) {
83898
- switch (channel) {
84559
+ function convertPuppeteerChannelToBrowsersChannel(channel2) {
84560
+ switch (channel2) {
83899
84561
  case "chrome":
83900
84562
  return ChromeReleaseChannel.STABLE;
83901
84563
  case "chrome-dev":
@@ -83922,8 +84584,8 @@ async function _connectToBrowser(options) {
83922
84584
  }
83923
84585
  }
83924
84586
  async function getConnectionTransport(options) {
83925
- const { browserWSEndpoint, browserURL, channel, transport, headers = {} } = options;
83926
- assert(Number(!!browserWSEndpoint) + Number(!!browserURL) + Number(!!transport) + Number(!!channel) === 1, "Exactly one of browserWSEndpoint, browserURL, transport or channel must be passed to puppeteer.connect");
84587
+ const { browserWSEndpoint, browserURL, channel: channel2, transport, headers = {} } = options;
84588
+ assert(Number(!!browserWSEndpoint) + Number(!!browserURL) + Number(!!transport) + Number(!!channel2) === 1, "Exactly one of browserWSEndpoint, browserURL, transport or channel must be passed to puppeteer.connect");
83927
84589
  if (transport) {
83928
84590
  return { connectionTransport: transport, endpointUrl: "" };
83929
84591
  } else if (browserWSEndpoint) {
@@ -83948,9 +84610,9 @@ async function getConnectionTransport(options) {
83948
84610
  throw new Error("Could not detect required browser platform");
83949
84611
  }
83950
84612
  const { convertPuppeteerChannelToBrowsersChannel: convertPuppeteerChannelToBrowsersChannel2 } = await Promise.resolve().then(() => (init_LaunchOptions(), exports_LaunchOptions));
83951
- const { join: join20 } = await import("node:path");
84613
+ const { join: join22 } = await import("node:path");
83952
84614
  const userDataDir = resolveDefaultUserDataDir3(Browser7.CHROME, platform2, convertPuppeteerChannelToBrowsersChannel2(options.channel));
83953
- const portPath = join20(userDataDir, "DevToolsActivePort");
84615
+ const portPath = join22(userDataDir, "DevToolsActivePort");
83954
84616
  try {
83955
84617
  const fileContent = await environment.value.fs.promises.readFile(portPath, "ascii");
83956
84618
  const [rawPort, rawPath] = fileContent.split(`
@@ -84174,9 +84836,9 @@ var init_PipeTransport = __esm(() => {
84174
84836
  });
84175
84837
 
84176
84838
  // node_modules/puppeteer-core/lib/esm/puppeteer/node/BrowserLauncher.js
84177
- import { existsSync as existsSync21 } from "node:fs";
84839
+ import { existsSync as existsSync23 } from "node:fs";
84178
84840
  import { tmpdir } from "node:os";
84179
- import { join as join20 } from "node:path";
84841
+ import { join as join22 } from "node:path";
84180
84842
 
84181
84843
  class BrowserLauncher {
84182
84844
  #browser;
@@ -84201,7 +84863,7 @@ class BrowserLauncher {
84201
84863
  ...options,
84202
84864
  protocol
84203
84865
  });
84204
- if (!existsSync21(launchArgs.executablePath)) {
84866
+ if (!existsSync23(launchArgs.executablePath)) {
84205
84867
  throw new Error(`Browser was not found at the configured executablePath (${launchArgs.executablePath})`);
84206
84868
  }
84207
84869
  const usePipe = launchArgs.args.includes("--remote-debugging-pipe");
@@ -84276,7 +84938,7 @@ class BrowserLauncher {
84276
84938
  browserCloseCallback();
84277
84939
  const logs = browserProcess.getRecentLogs().join(`
84278
84940
  `);
84279
- if (logs.includes("Failed to create a ProcessSingleton for your profile directory") || process.platform === "win32" && existsSync21(join20(launchArgs.userDataDir, "lockfile"))) {
84941
+ if (logs.includes("Failed to create a ProcessSingleton for your profile directory") || process.platform === "win32" && existsSync23(join22(launchArgs.userDataDir, "lockfile"))) {
84280
84942
  throw new Error(`The browser is already running for ${launchArgs.userDataDir}. Use a different \`userDataDir\` or stop the running browser first.`);
84281
84943
  }
84282
84944
  if (logs.includes("Missing X server") && options.headless === false) {
@@ -84366,12 +85028,12 @@ class BrowserLauncher {
84366
85028
  });
84367
85029
  }
84368
85030
  getProfilePath() {
84369
- return join20(this.puppeteer.configuration.temporaryDirectory ?? tmpdir(), `puppeteer_dev_${this.browser}_profile-`);
85031
+ return join22(this.puppeteer.configuration.temporaryDirectory ?? tmpdir(), `puppeteer_dev_${this.browser}_profile-`);
84370
85032
  }
84371
85033
  resolveExecutablePath(headless, validatePath = true) {
84372
85034
  let executablePath = this.puppeteer.configuration.executablePath;
84373
85035
  if (executablePath) {
84374
- if (validatePath && !existsSync21(executablePath)) {
85036
+ if (validatePath && !existsSync23(executablePath)) {
84375
85037
  throw new Error(`Tried to find the browser at the configured path (${executablePath}), but no executable was found.`);
84376
85038
  }
84377
85039
  return executablePath;
@@ -84394,7 +85056,7 @@ class BrowserLauncher {
84394
85056
  browser: browserType,
84395
85057
  buildId: this.puppeteer.browserVersion
84396
85058
  });
84397
- if (validatePath && !existsSync21(executablePath)) {
85059
+ if (validatePath && !existsSync23(executablePath)) {
84398
85060
  const configVersion = this.puppeteer.configuration?.[this.browser]?.version;
84399
85061
  if (configVersion) {
84400
85062
  throw new Error(`Tried to find the browser at the configured path (${executablePath}) for version ${configVersion}, but no executable was found.`);
@@ -84494,7 +85156,7 @@ var init_ChromeLauncher = __esm(() => {
84494
85156
  return super.launch(options);
84495
85157
  }
84496
85158
  async computeLaunchArguments(options = {}) {
84497
- const { ignoreDefaultArgs = false, args = [], pipe: pipe2 = false, debuggingPort, channel, executablePath } = options;
85159
+ const { ignoreDefaultArgs = false, args = [], pipe: pipe2 = false, debuggingPort, channel: channel2, executablePath } = options;
84498
85160
  const chromeArguments = [];
84499
85161
  if (!ignoreDefaultArgs) {
84500
85162
  chromeArguments.push(...this.defaultArgs(options));
@@ -84528,8 +85190,8 @@ var init_ChromeLauncher = __esm(() => {
84528
85190
  assert(typeof userDataDir === "string", "`--user-data-dir` is malformed");
84529
85191
  let chromeExecutable = executablePath;
84530
85192
  if (!chromeExecutable) {
84531
- assert(channel || !this.puppeteer._isPuppeteerCore, `An \`executablePath\` or \`channel\` must be specified for \`puppeteer-core\``);
84532
- chromeExecutable = channel ? this.executablePath(channel) : this.resolveExecutablePath(options.headless ?? true);
85193
+ assert(channel2 || !this.puppeteer._isPuppeteerCore, `An \`executablePath\` or \`channel\` must be specified for \`puppeteer-core\``);
85194
+ chromeExecutable = channel2 ? this.executablePath(channel2) : this.resolveExecutablePath(options.headless ?? true);
84533
85195
  }
84534
85196
  return {
84535
85197
  executablePath: chromeExecutable,
@@ -84633,11 +85295,11 @@ var init_ChromeLauncher = __esm(() => {
84633
85295
  chromeArguments.push(...args);
84634
85296
  return chromeArguments;
84635
85297
  }
84636
- executablePath(channel, validatePath = true) {
84637
- if (channel) {
85298
+ executablePath(channel2, validatePath = true) {
85299
+ if (channel2) {
84638
85300
  return computeSystemExecutablePath({
84639
85301
  browser: Browser6.CHROME,
84640
- channel: convertPuppeteerChannelToBrowsersChannel(channel)
85302
+ channel: convertPuppeteerChannelToBrowsersChannel(channel2)
84641
85303
  });
84642
85304
  } else {
84643
85305
  return this.resolveExecutablePath(undefined, validatePath);
@@ -84929,10 +85591,10 @@ var init_PuppeteerNode = __esm(() => {
84929
85591
  });
84930
85592
 
84931
85593
  // node_modules/puppeteer-core/lib/esm/puppeteer/node/ScreenRecorder.js
84932
- import { spawn as spawn2, spawnSync as spawnSync3 } from "node:child_process";
85594
+ import { spawn as spawn2, spawnSync as spawnSync4 } from "node:child_process";
84933
85595
  import fs5 from "node:fs";
84934
85596
  import os8 from "node:os";
84935
- import { dirname as dirname11 } from "node:path";
85597
+ import { dirname as dirname12 } from "node:path";
84936
85598
  import { PassThrough } from "node:stream";
84937
85599
  var import_debug6, __runInitializers22 = function(thisArg, initializers, value) {
84938
85600
  var useValue = arguments.length > 2;
@@ -85033,7 +85695,7 @@ var init_ScreenRecorder = __esm(() => {
85033
85695
  colors ??= 256;
85034
85696
  overwrite ??= true;
85035
85697
  this.#fps = fps;
85036
- const { error } = spawnSync3(ffmpegPath);
85698
+ const { error } = spawnSync4(ffmpegPath);
85037
85699
  if (error) {
85038
85700
  throw error;
85039
85701
  }
@@ -85056,7 +85718,7 @@ var init_ScreenRecorder = __esm(() => {
85056
85718
  filters.push(formatArgs.splice(vf, 2).at(-1) ?? "");
85057
85719
  }
85058
85720
  if (path11) {
85059
- fs5.mkdirSync(dirname11(path11), { recursive: overwrite });
85721
+ fs5.mkdirSync(dirname12(path11), { recursive: overwrite });
85060
85722
  }
85061
85723
  this.#process = spawn2(ffmpegPath, [
85062
85724
  ["-loglevel", "error"],
@@ -85209,17 +85871,17 @@ var init_puppeteer_core = __esm(() => {
85209
85871
  });
85210
85872
 
85211
85873
  // src/core/design-eval/capture.ts
85212
- import { mkdirSync as mkdirSync9, statSync as statSync11, existsSync as existsSync22 } from "fs";
85213
- import { join as join21 } from "path";
85874
+ import { mkdirSync as mkdirSync11, statSync as statSync11, existsSync as existsSync24 } from "fs";
85875
+ import { join as join23 } from "path";
85214
85876
  function findBrowser() {
85215
85877
  const platform2 = process.platform;
85216
85878
  const paths = CHROME_PATHS[platform2] ?? [];
85217
85879
  for (const p of paths) {
85218
- if (existsSync22(p))
85880
+ if (existsSync24(p))
85219
85881
  return p;
85220
85882
  }
85221
- const minkBrowsers = join21(minkRoot(), "browsers");
85222
- if (existsSync22(minkBrowsers)) {
85883
+ const minkBrowsers = join23(minkRoot(), "browsers");
85884
+ if (existsSync24(minkBrowsers)) {
85223
85885
  const found = findChromeInDir(minkBrowsers);
85224
85886
  if (found)
85225
85887
  return found;
@@ -85240,7 +85902,7 @@ function findChromeInDir(dir) {
85240
85902
  try {
85241
85903
  const entries = readdirSync7(dir);
85242
85904
  for (const entry of entries) {
85243
- const full = join21(dir, entry);
85905
+ const full = join23(dir, entry);
85244
85906
  try {
85245
85907
  const stat2 = statSync12(full);
85246
85908
  if (stat2.isDirectory()) {
@@ -85288,7 +85950,7 @@ async function captureRoute(page, route, baseUrl, viewport, options) {
85288
85950
  const y = section * viewport.height;
85289
85951
  const clipHeight = Math.min(viewport.height, pageHeight - y);
85290
85952
  const fileName = `${prefix}-${viewport.name}-${section}.jpg`;
85291
- const filePath = join21(options.outputDir, fileName);
85953
+ const filePath = join23(options.outputDir, fileName);
85292
85954
  await page.screenshot({
85293
85955
  path: filePath,
85294
85956
  type: "jpeg",
@@ -85320,7 +85982,7 @@ async function captureRoute(page, route, baseUrl, viewport, options) {
85320
85982
  return results;
85321
85983
  }
85322
85984
  async function captureAllRoutes(routes, baseUrl, viewports, options, outputDir) {
85323
- mkdirSync9(outputDir, { recursive: true });
85985
+ mkdirSync11(outputDir, { recursive: true });
85324
85986
  const executablePath = findBrowser();
85325
85987
  const browser = await puppeteer_core_default.launch({
85326
85988
  executablePath,
@@ -86748,22 +87410,22 @@ var init_framework_advisor2 = __esm(() => {
86748
87410
  });
86749
87411
 
86750
87412
  // src/core/vault-templates.ts
86751
- import { join as join22 } from "path";
86752
- import { existsSync as existsSync23, writeFileSync as writeFileSync6, readFileSync as readFileSync23, mkdirSync as mkdirSync10 } from "fs";
87413
+ import { join as join24 } from "path";
87414
+ import { existsSync as existsSync25, writeFileSync as writeFileSync8, readFileSync as readFileSync24, mkdirSync as mkdirSync12 } from "fs";
86753
87415
  function seedTemplates(templatesDir) {
86754
- mkdirSync10(templatesDir, { recursive: true });
87416
+ mkdirSync12(templatesDir, { recursive: true });
86755
87417
  for (const [name, content] of Object.entries(DEFAULT_TEMPLATES)) {
86756
- const filePath = join22(templatesDir, `${name}.md`);
86757
- if (!existsSync23(filePath)) {
86758
- writeFileSync6(filePath, content);
87418
+ const filePath = join24(templatesDir, `${name}.md`);
87419
+ if (!existsSync25(filePath)) {
87420
+ writeFileSync8(filePath, content);
86759
87421
  }
86760
87422
  }
86761
87423
  }
86762
87424
  function loadTemplate(templatesDir, templateName, vars) {
86763
- const filePath = join22(templatesDir, `${templateName}.md`);
87425
+ const filePath = join24(templatesDir, `${templateName}.md`);
86764
87426
  let content;
86765
- if (existsSync23(filePath)) {
86766
- content = readFileSync23(filePath, "utf-8");
87427
+ if (existsSync25(filePath)) {
87428
+ content = readFileSync24(filePath, "utf-8");
86767
87429
  } else if (DEFAULT_TEMPLATES[templateName]) {
86768
87430
  content = DEFAULT_TEMPLATES[templateName];
86769
87431
  } else {
@@ -86916,8 +87578,8 @@ category: resources
86916
87578
  });
86917
87579
 
86918
87580
  // src/core/note-linker.ts
86919
- import { join as join23 } from "path";
86920
- import { existsSync as existsSync24, readFileSync as readFileSync24, readdirSync as readdirSync7, statSync as statSync12 } from "fs";
87581
+ import { join as join25 } from "path";
87582
+ import { existsSync as existsSync26, readFileSync as readFileSync25, readdirSync as readdirSync7, statSync as statSync12 } from "fs";
86921
87583
  function updateMasterIndex(vaultRootPath) {
86922
87584
  const now = new Date().toISOString().split("T")[0];
86923
87585
  const sections = [
@@ -86939,8 +87601,8 @@ function updateMasterIndex(vaultRootPath) {
86939
87601
  { name: "Patterns", dir: "patterns", emoji: "" }
86940
87602
  ];
86941
87603
  for (const cat of categories) {
86942
- const dirPath = join23(vaultRootPath, cat.dir);
86943
- if (!existsSync24(dirPath))
87604
+ const dirPath = join25(vaultRootPath, cat.dir);
87605
+ if (!existsSync26(dirPath))
86944
87606
  continue;
86945
87607
  const files = collectMarkdownFiles(dirPath, vaultRootPath);
86946
87608
  if (files.length === 0 && cat.dir !== "inbox")
@@ -86969,7 +87631,7 @@ function collectMarkdownFiles(dirPath, rootPath) {
86969
87631
  try {
86970
87632
  const entries = readdirSync7(dirPath, { withFileTypes: true });
86971
87633
  for (const entry of entries) {
86972
- const fullPath = join23(dirPath, entry.name);
87634
+ const fullPath = join25(dirPath, entry.name);
86973
87635
  if (entry.isDirectory()) {
86974
87636
  files.push(...collectMarkdownFiles(fullPath, rootPath));
86975
87637
  } else if (entry.name.endsWith(".md") && !entry.name.startsWith("_")) {
@@ -86992,7 +87654,7 @@ var exports_wiki = {};
86992
87654
  __export(exports_wiki, {
86993
87655
  wiki: () => wiki
86994
87656
  });
86995
- import { existsSync as existsSync25, statSync as statSync13 } from "fs";
87657
+ import { existsSync as existsSync27, statSync as statSync13 } from "fs";
86996
87658
  import { resolve as resolve11 } from "path";
86997
87659
  import { homedir as homedir4 } from "os";
86998
87660
  async function wiki(_cwd, args) {
@@ -87048,7 +87710,7 @@ async function wikiInit(args) {
87048
87710
  console.log(`[mink] initializing vault at ${targetPath}`);
87049
87711
  console.log(" (set a custom path with: mink wiki init /path/to/vault)");
87050
87712
  }
87051
- const isExisting = existsSync25(targetPath) && statSync13(targetPath).isDirectory();
87713
+ const isExisting = existsSync27(targetPath) && statSync13(targetPath).isDirectory();
87052
87714
  setConfigValue("wiki.path", targetPath);
87053
87715
  ensureVaultStructure();
87054
87716
  seedTemplates(vaultTemplates());
@@ -87266,8 +87928,8 @@ var init_wiki = __esm(() => {
87266
87928
  });
87267
87929
 
87268
87930
  // src/core/note-writer.ts
87269
- import { join as join24 } from "path";
87270
- import { existsSync as existsSync26, readFileSync as readFileSync25 } from "fs";
87931
+ import { join as join26 } from "path";
87932
+ import { existsSync as existsSync28, readFileSync as readFileSync26 } from "fs";
87271
87933
  function slugifyTitle(title) {
87272
87934
  return title.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 80);
87273
87935
  }
@@ -87300,7 +87962,7 @@ function createNote(meta) {
87300
87962
  const now = meta.created || new Date().toISOString();
87301
87963
  const slug = slugifyTitle(meta.title);
87302
87964
  const dir = categoryToDir(meta.category, meta.projectSlug);
87303
- const filePath = join24(dir, `${slug}.md`);
87965
+ const filePath = join26(dir, `${slug}.md`);
87304
87966
  let content;
87305
87967
  if (meta.template) {
87306
87968
  const rendered = loadTemplate(vaultTemplates(), meta.template, {
@@ -87334,9 +87996,9 @@ ${meta.body}
87334
87996
  }
87335
87997
  function appendToDaily(date, content) {
87336
87998
  const dir = vaultDailyDir();
87337
- const filePath = join24(dir, `${date}.md`);
87338
- if (existsSync26(filePath)) {
87339
- const existing = readFileSync25(filePath, "utf-8");
87999
+ const filePath = join26(dir, `${date}.md`);
88000
+ if (existsSync28(filePath)) {
88001
+ const existing = readFileSync26(filePath, "utf-8");
87340
88002
  const timestamp = new Date().toLocaleTimeString("en-US", {
87341
88003
  hour: "2-digit",
87342
88004
  minute: "2-digit",
@@ -87374,7 +88036,7 @@ ${content}
87374
88036
  return filePath;
87375
88037
  }
87376
88038
  function ingestFile(sourcePath, meta) {
87377
- const raw = readFileSync25(sourcePath, "utf-8");
88039
+ const raw = readFileSync26(sourcePath, "utf-8");
87378
88040
  const now = new Date().toISOString();
87379
88041
  const headingMatch = raw.match(/^#\s+(.+)$/m);
87380
88042
  const title = headingMatch?.[1] ?? sourcePath.split("/").pop().replace(/\.md$/, "");
@@ -87412,7 +88074,7 @@ ${raw}`;
87412
88074
  }
87413
88075
  const slug = slugifyTitle(title);
87414
88076
  const dir = categoryToDir(meta.category, meta.projectSlug);
87415
- const filePath = join24(dir, `${slug}.md`);
88077
+ const filePath = join26(dir, `${slug}.md`);
87416
88078
  atomicWriteText(filePath, content);
87417
88079
  return { filePath, content };
87418
88080
  }
@@ -87428,7 +88090,7 @@ __export(exports_note, {
87428
88090
  note: () => note
87429
88091
  });
87430
88092
  import { resolve as resolve12 } from "path";
87431
- import { existsSync as existsSync27, readFileSync as readFileSync26 } from "fs";
88093
+ import { existsSync as existsSync29, readFileSync as readFileSync27 } from "fs";
87432
88094
  async function note(cwd, args) {
87433
88095
  if (!isWikiEnabled()) {
87434
88096
  console.error("[mink] wiki feature is disabled");
@@ -87453,13 +88115,13 @@ async function note(cwd, args) {
87453
88115
  const date = new Date().toISOString().split("T")[0];
87454
88116
  const content = parsed.positional || parsed.body || "";
87455
88117
  const filePath = appendToDaily(date, content);
87456
- updateVaultIndexForFile(filePath, readFileSync26(filePath, "utf-8"));
88118
+ updateVaultIndexForFile(filePath, readFileSync27(filePath, "utf-8"));
87457
88119
  console.log(`[mink] daily note: ${filePath}`);
87458
88120
  return;
87459
88121
  }
87460
88122
  if (parsed.file) {
87461
88123
  const sourcePath = resolve12(cwd, parsed.file);
87462
- if (!existsSync27(sourcePath)) {
88124
+ if (!existsSync29(sourcePath)) {
87463
88125
  console.error(`[mink] file not found: ${sourcePath}`);
87464
88126
  process.exit(1);
87465
88127
  }
@@ -87620,29 +88282,29 @@ var exports_skill = {};
87620
88282
  __export(exports_skill, {
87621
88283
  skill: () => skill
87622
88284
  });
87623
- import { join as join25, resolve as resolve13, dirname as dirname12 } from "path";
88285
+ import { join as join27, resolve as resolve13, dirname as dirname13 } from "path";
87624
88286
  import { homedir as homedir5 } from "os";
87625
88287
  import {
87626
- existsSync as existsSync28,
87627
- mkdirSync as mkdirSync11,
88288
+ existsSync as existsSync30,
88289
+ mkdirSync as mkdirSync13,
87628
88290
  copyFileSync,
87629
- unlinkSync as unlinkSync3,
88291
+ unlinkSync as unlinkSync4,
87630
88292
  readdirSync as readdirSync8,
87631
88293
  rmSync,
87632
88294
  symlinkSync as symlinkSync2,
87633
88295
  lstatSync as lstatSync2
87634
88296
  } from "fs";
87635
88297
  function getSkillsSourceDir() {
87636
- return resolve13(dirname12(new URL(import.meta.url).pathname), "../../skills");
88298
+ return resolve13(dirname13(new URL(import.meta.url).pathname), "../../skills");
87637
88299
  }
87638
88300
  function getAvailableSkills() {
87639
88301
  const dir = getSkillsSourceDir();
87640
- if (!existsSync28(dir))
88302
+ if (!existsSync30(dir))
87641
88303
  return [];
87642
- return readdirSync8(dir, { withFileTypes: true }).filter((d) => d.isDirectory() && existsSync28(join25(dir, d.name, "SKILL.md"))).map((d) => d.name);
88304
+ return readdirSync8(dir, { withFileTypes: true }).filter((d) => d.isDirectory() && existsSync30(join27(dir, d.name, "SKILL.md"))).map((d) => d.name);
87643
88305
  }
87644
88306
  function isInstalled(skillName) {
87645
- return existsSync28(join25(AGENTS_SKILLS_DIR, skillName, "SKILL.md"));
88307
+ return existsSync30(join27(AGENTS_SKILLS_DIR, skillName, "SKILL.md"));
87646
88308
  }
87647
88309
  async function skill(args) {
87648
88310
  const sub = args[0];
@@ -87676,28 +88338,28 @@ function skillInstall(name) {
87676
88338
  console.error(" Expected skills at: " + sourceDir);
87677
88339
  return;
87678
88340
  }
87679
- mkdirSync11(AGENTS_SKILLS_DIR, { recursive: true });
88341
+ mkdirSync13(AGENTS_SKILLS_DIR, { recursive: true });
87680
88342
  for (const skillName of skills) {
87681
- const srcDir = join25(sourceDir, skillName);
87682
- const srcFile = join25(srcDir, "SKILL.md");
87683
- const destDir = join25(AGENTS_SKILLS_DIR, skillName);
87684
- if (!existsSync28(srcFile)) {
88343
+ const srcDir = join27(sourceDir, skillName);
88344
+ const srcFile = join27(srcDir, "SKILL.md");
88345
+ const destDir = join27(AGENTS_SKILLS_DIR, skillName);
88346
+ if (!existsSync30(srcFile)) {
87685
88347
  console.error(`[mink] skill not found: ${skillName}`);
87686
88348
  continue;
87687
88349
  }
87688
- mkdirSync11(destDir, { recursive: true });
88350
+ mkdirSync13(destDir, { recursive: true });
87689
88351
  copyDirRecursive(srcDir, destDir);
87690
- mkdirSync11(CLAUDE_SKILLS_DIR, { recursive: true });
87691
- const symlink = join25(CLAUDE_SKILLS_DIR, skillName);
88352
+ mkdirSync13(CLAUDE_SKILLS_DIR, { recursive: true });
88353
+ const symlink = join27(CLAUDE_SKILLS_DIR, skillName);
87692
88354
  try {
87693
- if (existsSync28(symlink)) {
88355
+ if (existsSync30(symlink)) {
87694
88356
  if (lstatSync2(symlink).isSymbolicLink() || lstatSync2(symlink).isFile()) {
87695
- unlinkSync3(symlink);
88357
+ unlinkSync4(symlink);
87696
88358
  } else {
87697
88359
  rmSync(symlink, { recursive: true, force: true });
87698
88360
  }
87699
88361
  }
87700
- const relativeTarget = join25("..", "..", ".agents", "skills", skillName);
88362
+ const relativeTarget = join27("..", "..", ".agents", "skills", skillName);
87701
88363
  symlinkSync2(relativeTarget, symlink);
87702
88364
  } catch {}
87703
88365
  console.log(`[mink] installed: ${skillName} -> ${destDir}`);
@@ -87708,16 +88370,16 @@ function skillInstall(name) {
87708
88370
  function skillUninstall(name) {
87709
88371
  const skills = name ? [name] : getAvailableSkills();
87710
88372
  for (const skillName of skills) {
87711
- const destDir = join25(AGENTS_SKILLS_DIR, skillName);
87712
- if (!existsSync28(destDir)) {
88373
+ const destDir = join27(AGENTS_SKILLS_DIR, skillName);
88374
+ if (!existsSync30(destDir)) {
87713
88375
  console.log(`[mink] not installed: ${skillName}`);
87714
88376
  continue;
87715
88377
  }
87716
88378
  rmSync(destDir, { recursive: true, force: true });
87717
- const symlink = join25(CLAUDE_SKILLS_DIR, skillName);
88379
+ const symlink = join27(CLAUDE_SKILLS_DIR, skillName);
87718
88380
  try {
87719
- if (existsSync28(symlink))
87720
- unlinkSync3(symlink);
88381
+ if (existsSync30(symlink))
88382
+ unlinkSync4(symlink);
87721
88383
  } catch {}
87722
88384
  console.log(`[mink] uninstalled: ${skillName}`);
87723
88385
  }
@@ -87731,7 +88393,7 @@ function skillList() {
87731
88393
  if (installed.length > 0) {
87732
88394
  console.log(" Installed:");
87733
88395
  for (const s of installed) {
87734
- console.log(` ${s} (${join25(AGENTS_SKILLS_DIR, s)})`);
88396
+ console.log(` ${s} (${join27(AGENTS_SKILLS_DIR, s)})`);
87735
88397
  }
87736
88398
  }
87737
88399
  if (notInstalled.length > 0) {
@@ -87750,10 +88412,10 @@ function skillList() {
87750
88412
  function copyDirRecursive(src, dest) {
87751
88413
  const entries = readdirSync8(src, { withFileTypes: true });
87752
88414
  for (const entry of entries) {
87753
- const srcPath = join25(src, entry.name);
87754
- const destPath = join25(dest, entry.name);
88415
+ const srcPath = join27(src, entry.name);
88416
+ const destPath = join27(dest, entry.name);
87755
88417
  if (entry.isDirectory()) {
87756
- mkdirSync11(destPath, { recursive: true });
88418
+ mkdirSync13(destPath, { recursive: true });
87757
88419
  copyDirRecursive(srcPath, destPath);
87758
88420
  } else {
87759
88421
  copyFileSync(srcPath, destPath);
@@ -87762,8 +88424,8 @@ function copyDirRecursive(src, dest) {
87762
88424
  }
87763
88425
  var AGENTS_SKILLS_DIR, CLAUDE_SKILLS_DIR;
87764
88426
  var init_skill = __esm(() => {
87765
- AGENTS_SKILLS_DIR = join25(homedir5(), ".agents", "skills");
87766
- CLAUDE_SKILLS_DIR = join25(homedir5(), ".claude", "skills");
88427
+ AGENTS_SKILLS_DIR = join27(homedir5(), ".agents", "skills");
88428
+ CLAUDE_SKILLS_DIR = join27(homedir5(), ".claude", "skills");
87767
88429
  });
87768
88430
 
87769
88431
  // src/commands/sync.ts
@@ -88218,6 +88880,11 @@ switch (command2) {
88218
88880
  await daemon2(cwd, process.argv.slice(3));
88219
88881
  break;
88220
88882
  }
88883
+ case "channel": {
88884
+ const { channel: channel2 } = await Promise.resolve().then(() => (init_channel(), exports_channel));
88885
+ await channel2(process.argv.slice(3));
88886
+ break;
88887
+ }
88221
88888
  case "config": {
88222
88889
  const { config: config3 } = await Promise.resolve().then(() => (init_config2(), exports_config));
88223
88890
  await config3(process.argv.slice(3));
@@ -88287,11 +88954,11 @@ switch (command2) {
88287
88954
  case "version":
88288
88955
  case "--version":
88289
88956
  case "-v": {
88290
- const { resolve: resolve14, dirname: dirname13 } = await import("path");
88291
- const cliPath = resolve14(dirname13(new URL(import.meta.url).pathname));
88292
- const { readFileSync: readFileSync27 } = await import("fs");
88957
+ const { resolve: resolve14, dirname: dirname14 } = await import("path");
88958
+ const cliPath = resolve14(dirname14(new URL(import.meta.url).pathname));
88959
+ const { readFileSync: readFileSync28 } = await import("fs");
88293
88960
  try {
88294
- const pkg = JSON.parse(readFileSync27(resolve14(cliPath, "../package.json"), "utf-8"));
88961
+ const pkg = JSON.parse(readFileSync28(resolve14(cliPath, "../package.json"), "utf-8"));
88295
88962
  console.log(`mink ${pkg.version}`);
88296
88963
  } catch {
88297
88964
  console.log("mink (unknown version)");
@@ -88332,6 +88999,13 @@ switch (command2) {
88332
88999
  console.log(" sync pause / resume Temporarily disable/enable auto-sync");
88333
89000
  console.log(" sync disconnect Remove git tracking (data preserved)");
88334
89001
  console.log();
89002
+ console.log("Channels (conversational companion):");
89003
+ console.log(" channel setup discord --token <t> Configure Discord bot token");
89004
+ console.log(" channel start [platform] Launch a Claude Code session with --channels in the vault");
89005
+ console.log(" channel stop Stop the channel session");
89006
+ console.log(" channel status Show channel status");
89007
+ console.log(" channel logs Tail channel log");
89008
+ console.log();
88335
89009
  console.log("Automation & Analysis:");
88336
89010
  console.log(" dashboard [--port=N] Open the real-time web dashboard");
88337
89011
  console.log(" daemon <cmd> Manage the background daemon (start|stop|restart|logs)");