openmates 0.15.0-alpha.32 → 0.15.0-alpha.34

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.
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-AXNRPVLE.js";
5
5
 
6
6
  // src/client.ts
7
- import { createHash as createHash7, randomBytes as randomBytes3, randomUUID as randomUUID5 } from "crypto";
7
+ import { createHash as createHash8, randomBytes as randomBytes3, randomUUID as randomUUID5 } from "crypto";
8
8
  import { arch, platform as platform2, release } from "os";
9
9
  import { createInterface as createInterface2 } from "readline/promises";
10
10
  import { stdin as stdin2, stdout } from "process";
@@ -2484,6 +2484,464 @@ async function encryptEmbed(embed, masterKey, chatKey, chatId, messageId, userId
2484
2484
  }
2485
2485
  }
2486
2486
 
2487
+ // src/fileEmbed.ts
2488
+ import { readFileSync as readFileSync4, statSync, existsSync as existsSync4 } from "fs";
2489
+ import { basename, extname, resolve as resolve2 } from "path";
2490
+ import { homedir as homedir4 } from "os";
2491
+ import { createHash as createHash5 } from "crypto";
2492
+ var MAX_PER_FILE_SIZE = 100 * 1024 * 1024;
2493
+ var BLOCKED_EXTENSIONS = /* @__PURE__ */ new Set([
2494
+ ".pem",
2495
+ ".key",
2496
+ ".p12",
2497
+ ".pfx",
2498
+ ".keystore",
2499
+ ".kdbx",
2500
+ ".credentials"
2501
+ ]);
2502
+ var BLOCKED_NAMES = /* @__PURE__ */ new Set([
2503
+ "id_rsa",
2504
+ "id_ed25519",
2505
+ "id_dsa",
2506
+ "id_ecdsa",
2507
+ "authorized_keys",
2508
+ "known_hosts",
2509
+ ".git-credentials",
2510
+ ".netrc",
2511
+ ".pgpass",
2512
+ ".my.cnf"
2513
+ ]);
2514
+ var CODE_EXTENSIONS = /* @__PURE__ */ new Set([
2515
+ "py",
2516
+ "js",
2517
+ "ts",
2518
+ "html",
2519
+ "css",
2520
+ "json",
2521
+ "svelte",
2522
+ "java",
2523
+ "cpp",
2524
+ "c",
2525
+ "h",
2526
+ "hpp",
2527
+ "rs",
2528
+ "go",
2529
+ "rb",
2530
+ "php",
2531
+ "swift",
2532
+ "kt",
2533
+ "txt",
2534
+ "md",
2535
+ "xml",
2536
+ "yaml",
2537
+ "yml",
2538
+ "sh",
2539
+ "bash",
2540
+ "sql",
2541
+ "vue",
2542
+ "jsx",
2543
+ "tsx",
2544
+ "scss",
2545
+ "less",
2546
+ "sass",
2547
+ "dockerfile",
2548
+ "toml",
2549
+ "ini",
2550
+ "cfg",
2551
+ "conf",
2552
+ "env",
2553
+ "envrc",
2554
+ "graphql",
2555
+ "gql",
2556
+ "r",
2557
+ "m",
2558
+ "pl",
2559
+ "lua",
2560
+ "ex",
2561
+ "exs",
2562
+ "erl",
2563
+ "hs",
2564
+ "scala",
2565
+ "dart",
2566
+ "tf"
2567
+ ]);
2568
+ var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
2569
+ "jpg",
2570
+ "jpeg",
2571
+ "png",
2572
+ "webp",
2573
+ "gif",
2574
+ "heic",
2575
+ "heif",
2576
+ "bmp",
2577
+ "tiff",
2578
+ "tif",
2579
+ "svg"
2580
+ ]);
2581
+ var AUDIO_EXTENSIONS = /* @__PURE__ */ new Set([
2582
+ "mp3",
2583
+ "m4a",
2584
+ "mp4",
2585
+ "wav",
2586
+ "webm",
2587
+ "ogg",
2588
+ "oga",
2589
+ "aac"
2590
+ ]);
2591
+ function isEnvFile(filename) {
2592
+ const lower = filename.toLowerCase();
2593
+ return lower === ".env" || lower.startsWith(".env.") || lower === ".envrc";
2594
+ }
2595
+ function getExt(filename) {
2596
+ const ext = extname(filename).toLowerCase();
2597
+ return ext.startsWith(".") ? ext.slice(1) : ext;
2598
+ }
2599
+ function isCodeOrTextFile(filename) {
2600
+ const lower = filename.toLowerCase();
2601
+ if (lower === "dockerfile") return true;
2602
+ if (isEnvFile(lower)) return true;
2603
+ return CODE_EXTENSIONS.has(getExt(filename));
2604
+ }
2605
+ function isImageFile(filename) {
2606
+ return IMAGE_EXTENSIONS.has(getExt(filename));
2607
+ }
2608
+ function isPDFFile(filename) {
2609
+ return getExt(filename) === "pdf";
2610
+ }
2611
+ function isAudioFile(filename) {
2612
+ return AUDIO_EXTENSIONS.has(getExt(filename));
2613
+ }
2614
+ var LANGUAGE_MAP = {
2615
+ ts: "typescript",
2616
+ tsx: "typescript",
2617
+ js: "javascript",
2618
+ jsx: "javascript",
2619
+ py: "python",
2620
+ rb: "ruby",
2621
+ rs: "rust",
2622
+ go: "go",
2623
+ java: "java",
2624
+ kt: "kotlin",
2625
+ swift: "swift",
2626
+ c: "c",
2627
+ cpp: "cpp",
2628
+ h: "c",
2629
+ hpp: "cpp",
2630
+ cs: "csharp",
2631
+ php: "php",
2632
+ sql: "sql",
2633
+ sh: "bash",
2634
+ bash: "bash",
2635
+ zsh: "bash",
2636
+ yml: "yaml",
2637
+ yaml: "yaml",
2638
+ json: "json",
2639
+ xml: "xml",
2640
+ html: "html",
2641
+ css: "css",
2642
+ scss: "scss",
2643
+ less: "less",
2644
+ md: "markdown",
2645
+ toml: "toml",
2646
+ ini: "ini",
2647
+ cfg: "ini",
2648
+ env: "bash",
2649
+ envrc: "bash",
2650
+ svelte: "svelte",
2651
+ vue: "vue",
2652
+ graphql: "graphql",
2653
+ gql: "graphql",
2654
+ tf: "hcl",
2655
+ dart: "dart",
2656
+ dockerfile: "dockerfile",
2657
+ txt: "text"
2658
+ };
2659
+ function detectLanguage(filename) {
2660
+ if (filename.toLowerCase() === "dockerfile") return "dockerfile";
2661
+ return LANGUAGE_MAP[getExt(filename)] || "text";
2662
+ }
2663
+ function processEnvFileZeroKnowledge(content) {
2664
+ const lines = content.split("\n");
2665
+ const processed = [];
2666
+ for (const rawLine of lines) {
2667
+ const line = rawLine.trim();
2668
+ if (!line || line.startsWith("#")) {
2669
+ processed.push(line);
2670
+ continue;
2671
+ }
2672
+ const cleanLine = line.startsWith("export ") ? line.slice(7).trim() : line;
2673
+ const eqIndex = cleanLine.indexOf("=");
2674
+ if (eqIndex === -1) {
2675
+ processed.push(line);
2676
+ continue;
2677
+ }
2678
+ const key = cleanLine.slice(0, eqIndex).trim();
2679
+ let value = cleanLine.slice(eqIndex + 1).trim();
2680
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
2681
+ value = value.slice(1, -1);
2682
+ }
2683
+ if (value.length > 3) {
2684
+ processed.push(`${key}=***${value.slice(-3)}`);
2685
+ } else if (value.length > 0) {
2686
+ processed.push(`${key}=***`);
2687
+ } else {
2688
+ processed.push(`${key}=`);
2689
+ }
2690
+ }
2691
+ return processed.join("\n");
2692
+ }
2693
+ function resolvePath(filePath) {
2694
+ if (filePath.startsWith("~/")) {
2695
+ return resolve2(homedir4(), filePath.slice(2));
2696
+ }
2697
+ return resolve2(filePath);
2698
+ }
2699
+ function processFiles(filePaths, redactor) {
2700
+ const embeds = [];
2701
+ const errors = [];
2702
+ const blocked = [];
2703
+ for (const rawPath of filePaths) {
2704
+ const resolvedPath = resolvePath(rawPath);
2705
+ const filename = basename(resolvedPath);
2706
+ const ext = getExt(filename);
2707
+ if (!existsSync4(resolvedPath)) {
2708
+ errors.push({ path: rawPath, error: "File not found" });
2709
+ continue;
2710
+ }
2711
+ let stats;
2712
+ try {
2713
+ stats = statSync(resolvedPath);
2714
+ } catch (e) {
2715
+ errors.push({
2716
+ path: rawPath,
2717
+ error: `Cannot read: ${e instanceof Error ? e.message : String(e)}`
2718
+ });
2719
+ continue;
2720
+ }
2721
+ if (stats.isDirectory()) {
2722
+ errors.push({ path: rawPath, error: "Is a directory, not a file" });
2723
+ continue;
2724
+ }
2725
+ if (stats.size > MAX_PER_FILE_SIZE) {
2726
+ errors.push({
2727
+ path: rawPath,
2728
+ error: `File too large (${Math.round(stats.size / 1024 / 1024)}MB > 100MB limit)`
2729
+ });
2730
+ continue;
2731
+ }
2732
+ if (BLOCKED_EXTENSIONS.has(`.${ext}`)) {
2733
+ blocked.push({
2734
+ path: rawPath,
2735
+ error: `Blocked: .${ext} files may contain private keys. Use --allow-sensitive to override.`
2736
+ });
2737
+ continue;
2738
+ }
2739
+ if (BLOCKED_NAMES.has(filename)) {
2740
+ blocked.push({
2741
+ path: rawPath,
2742
+ error: `Blocked: '${filename}' typically contains credentials. Use --allow-sensitive to override.`
2743
+ });
2744
+ continue;
2745
+ }
2746
+ if (isCodeOrTextFile(filename)) {
2747
+ const result = processCodeFile(resolvedPath, filename, redactor);
2748
+ if (result) embeds.push(result);
2749
+ else errors.push({ path: rawPath, error: "Failed to process file" });
2750
+ } else if (isImageFile(filename)) {
2751
+ const result = processImageFile(resolvedPath, filename);
2752
+ if (result) embeds.push(result);
2753
+ else errors.push({ path: rawPath, error: "Failed to process image" });
2754
+ } else if (isPDFFile(filename)) {
2755
+ const result = processPDFFile(resolvedPath, filename);
2756
+ if (result) embeds.push(result);
2757
+ else errors.push({ path: rawPath, error: "Failed to process PDF" });
2758
+ } else if (isAudioFile(filename)) {
2759
+ const result = processAudioFile(resolvedPath, filename);
2760
+ if (result) embeds.push(result);
2761
+ else errors.push({ path: rawPath, error: "Failed to process audio" });
2762
+ } else {
2763
+ errors.push({
2764
+ path: rawPath,
2765
+ error: `Unsupported file type: .${ext}. Supported: code/text, images, PDFs, audio.`
2766
+ });
2767
+ }
2768
+ }
2769
+ return { embeds, errors, blocked };
2770
+ }
2771
+ function processCodeFile(filePath, filename, redactor) {
2772
+ try {
2773
+ let content = readFileSync4(filePath, "utf-8");
2774
+ let secretsRedacted = false;
2775
+ let zeroKnowledge = false;
2776
+ if (isEnvFile(filename)) {
2777
+ content = processEnvFileZeroKnowledge(content);
2778
+ secretsRedacted = true;
2779
+ zeroKnowledge = true;
2780
+ } else if (redactor?.isInitialized) {
2781
+ const result = redactor.redactWithMappings(content);
2782
+ if (result.mappings.length > 0) {
2783
+ content = result.redacted;
2784
+ secretsRedacted = true;
2785
+ }
2786
+ }
2787
+ const language = detectLanguage(filename);
2788
+ const lineCount = content.split("\n").length;
2789
+ const embedId = generateEmbedId();
2790
+ const embedRef = createEmbedRef("code", `${filename}:${embedId}`);
2791
+ const embedContent = toonEncodeContent({
2792
+ type: "code",
2793
+ language,
2794
+ code: content,
2795
+ filename,
2796
+ embed_ref: embedRef,
2797
+ status: "finished",
2798
+ line_count: lineCount
2799
+ });
2800
+ const textPreview = `${filename} (${language}, ${lineCount} lines)`;
2801
+ const contentHash = createHash5("sha256").update(content).digest("hex");
2802
+ const embed = {
2803
+ embedId,
2804
+ embedRef,
2805
+ type: "code-code",
2806
+ content: embedContent,
2807
+ textPreview,
2808
+ status: "finished",
2809
+ filePath: filename,
2810
+ contentHash,
2811
+ textLengthChars: content.length
2812
+ };
2813
+ return {
2814
+ embed,
2815
+ referenceBlock: createEmbedReferenceBlock(embedRef),
2816
+ displayName: filename,
2817
+ secretsRedacted,
2818
+ zeroKnowledge,
2819
+ requiresUpload: false
2820
+ };
2821
+ } catch (e) {
2822
+ process.stderr.write(
2823
+ `\x1B[31mError:\x1B[0m Failed to read ${filename}: ${e instanceof Error ? e.message : String(e)}
2824
+ `
2825
+ );
2826
+ return null;
2827
+ }
2828
+ }
2829
+ function processImageFile(filePath, filename) {
2830
+ try {
2831
+ const embedId = generateEmbedId();
2832
+ const embedRef = createEmbedRef("image", `${filename}:${embedId}`);
2833
+ const embedContent = toonEncodeContent({
2834
+ type: "image",
2835
+ app_id: "images",
2836
+ skill_id: "upload",
2837
+ status: "uploading",
2838
+ filename,
2839
+ embed_ref: embedRef
2840
+ });
2841
+ const embed = {
2842
+ embedId,
2843
+ embedRef,
2844
+ type: "image",
2845
+ content: embedContent,
2846
+ textPreview: filename,
2847
+ status: "finished"
2848
+ // Will be set to "finished" after upload
2849
+ };
2850
+ return {
2851
+ embed,
2852
+ referenceBlock: createEmbedReferenceBlock(embedRef),
2853
+ displayName: filename,
2854
+ secretsRedacted: false,
2855
+ zeroKnowledge: false,
2856
+ requiresUpload: true,
2857
+ localPath: filePath
2858
+ };
2859
+ } catch (e) {
2860
+ process.stderr.write(
2861
+ `\x1B[31mError:\x1B[0m Failed to process ${filename}: ${e instanceof Error ? e.message : String(e)}
2862
+ `
2863
+ );
2864
+ return null;
2865
+ }
2866
+ }
2867
+ function processPDFFile(filePath, filename) {
2868
+ try {
2869
+ const embedId = generateEmbedId();
2870
+ const embedRef = createEmbedRef("pdf", `${filename}:${embedId}`);
2871
+ const embedContent = toonEncodeContent({
2872
+ type: "pdf",
2873
+ status: "uploading",
2874
+ filename,
2875
+ embed_ref: embedRef
2876
+ });
2877
+ const embed = {
2878
+ embedId,
2879
+ embedRef,
2880
+ type: "pdf",
2881
+ content: embedContent,
2882
+ textPreview: filename,
2883
+ status: "processing"
2884
+ // PDFs start as "processing" for background OCR
2885
+ };
2886
+ return {
2887
+ embed,
2888
+ referenceBlock: createEmbedReferenceBlock(embedRef),
2889
+ displayName: filename,
2890
+ secretsRedacted: false,
2891
+ zeroKnowledge: false,
2892
+ requiresUpload: true,
2893
+ localPath: filePath
2894
+ };
2895
+ } catch (e) {
2896
+ process.stderr.write(
2897
+ `\x1B[31mError:\x1B[0m Failed to process ${filename}: ${e instanceof Error ? e.message : String(e)}
2898
+ `
2899
+ );
2900
+ return null;
2901
+ }
2902
+ }
2903
+ function processAudioFile(filePath, filename) {
2904
+ try {
2905
+ const embedId = generateEmbedId();
2906
+ const embedRef = createEmbedRef("audio-recording", `${filename}:${embedId}`);
2907
+ const embedContent = toonEncodeContent({
2908
+ app_id: "audio",
2909
+ skill_id: "transcribe",
2910
+ type: "audio-recording",
2911
+ status: "uploading",
2912
+ filename,
2913
+ embed_ref: embedRef
2914
+ });
2915
+ const embed = {
2916
+ embedId,
2917
+ embedRef,
2918
+ type: "audio-recording",
2919
+ content: embedContent,
2920
+ textPreview: filename,
2921
+ status: "processing"
2922
+ };
2923
+ return {
2924
+ embed,
2925
+ referenceBlock: createEmbedReferenceBlock(embedRef),
2926
+ displayName: filename,
2927
+ secretsRedacted: false,
2928
+ zeroKnowledge: false,
2929
+ requiresUpload: true,
2930
+ localPath: filePath
2931
+ };
2932
+ } catch (e) {
2933
+ process.stderr.write(
2934
+ `\x1B[31mError:\x1B[0m Failed to process ${filename}: ${e instanceof Error ? e.message : String(e)}
2935
+ `
2936
+ );
2937
+ return null;
2938
+ }
2939
+ }
2940
+ function formatEmbedsForMessage(embeds) {
2941
+ if (embeds.length === 0) return "";
2942
+ return "\n" + embeds.map((e) => e.referenceBlock).join("\n");
2943
+ }
2944
+
2487
2945
  // src/shareEncryption.ts
2488
2946
  import { webcrypto as webcrypto4 } from "crypto";
2489
2947
  var crypto = webcrypto4;
@@ -2603,7 +3061,7 @@ function buildEmbedShareUrl(origin, embedId, blob) {
2603
3061
  }
2604
3062
 
2605
3063
  // src/connectedAccountImport.ts
2606
- import { createHash as createHash5, randomUUID as randomUUID2, webcrypto as webcrypto5 } from "crypto";
3064
+ import { createHash as createHash6, randomUUID as randomUUID2, webcrypto as webcrypto5 } from "crypto";
2607
3065
  var TRANSFER_PREFIX = "OMCA1.";
2608
3066
  var SUPPORTED_KDF_ITERATIONS = 1e5;
2609
3067
  async function decryptConnectedAccountCliTransferPayload(encryptedPayload, passcode) {
@@ -2748,7 +3206,7 @@ function defaultProviderLabel(providerId) {
2748
3206
  return providerId === "google_calendar" ? "Google Calendar" : "Connected account";
2749
3207
  }
2750
3208
  function sha256Hex2(value) {
2751
- return createHash5("sha256").update(value).digest("hex");
3209
+ return createHash6("sha256").update(value).digest("hex");
2752
3210
  }
2753
3211
  function base64UrlToBytes2(value) {
2754
3212
  return base64ToBytes(value.replace(/-/g, "+").replace(/_/g, "/"));
@@ -2761,7 +3219,7 @@ function toArrayBuffer3(input) {
2761
3219
 
2762
3220
  // src/protonBridgeConnector.ts
2763
3221
  import { spawn } from "child_process";
2764
- import { existsSync as existsSync4 } from "fs";
3222
+ import { existsSync as existsSync5 } from "fs";
2765
3223
  import { connect as connectTcp } from "net";
2766
3224
  import { arch as nodeArch, platform as nodePlatform } from "os";
2767
3225
  import { stdin, stderr } from "process";
@@ -2796,7 +3254,7 @@ function containsCredentialLikeField(value) {
2796
3254
  function resolveProtonBridgeCommand(deps = {}) {
2797
3255
  const platform3 = deps.platform ?? normalizePlatform(nodePlatform());
2798
3256
  const architecture = deps.architecture ?? nodeArch();
2799
- const exists = deps.exists ?? existsSync4;
3257
+ const exists = deps.exists ?? existsSync5;
2800
3258
  const findExecutable = deps.findExecutable ?? defaultFindExecutable;
2801
3259
  if (platform3 === "darwin") {
2802
3260
  if (exists(MACOS_BRIDGE_BINARY)) {
@@ -3496,7 +3954,7 @@ function defaultFindExecutable(name) {
3496
3954
  const paths = (process.env.PATH ?? "").split(process.platform === "win32" ? ";" : ":");
3497
3955
  for (const directory of paths) {
3498
3956
  const candidate = `${directory}/${name}`;
3499
- if (candidate !== `/${name}` && existsSync4(candidate)) return candidate;
3957
+ if (candidate !== `/${name}` && existsSync5(candidate)) return candidate;
3500
3958
  }
3501
3959
  return null;
3502
3960
  }
@@ -3597,7 +4055,7 @@ function stripTimer(job) {
3597
4055
  }
3598
4056
 
3599
4057
  // src/tasksCli.ts
3600
- import { createHash as createHash6, createHmac, hkdfSync, randomBytes as randomBytes2, randomUUID as randomUUID4 } from "crypto";
4058
+ import { createHash as createHash7, createHmac, hkdfSync, randomBytes as randomBytes2, randomUUID as randomUUID4 } from "crypto";
3601
4059
  var TASK_STATUSES2 = ["backlog", "todo", "in_progress", "blocked", "done"];
3602
4060
  var DEFAULT_STANDALONE_PREFIX = "TASK";
3603
4061
  var PRIORITY_LEVELS = ["none", "low", "medium", "high", "urgent"];
@@ -3779,7 +4237,7 @@ function workflowProjectionToTask(record) {
3779
4237
  }
3780
4238
  function workflowProjectionShortId(record) {
3781
4239
  const stableId = record.workflow_run_id || record.task_id;
3782
- return `WF-${createHash6("sha256").update(stableId).digest("hex").slice(0, 6).toUpperCase()}`;
4240
+ return `WF-${createHash7("sha256").update(stableId).digest("hex").slice(0, 6).toUpperCase()}`;
3783
4241
  }
3784
4242
  async function decryptUserTasks(records, masterKey) {
3785
4243
  const output = [];
@@ -3885,7 +4343,7 @@ function parseStringArray(value) {
3885
4343
  function deriveShortId(record) {
3886
4344
  const prefix = record.short_id_prefix || DEFAULT_STANDALONE_PREFIX;
3887
4345
  const source = record.task_id || `${record.created_at ?? ""}-${record.position ?? ""}`;
3888
- const digest = createHash6("sha256").update(source).digest("hex").slice(0, 4).toUpperCase();
4346
+ const digest = createHash7("sha256").update(source).digest("hex").slice(0, 4).toUpperCase();
3889
4347
  return `${prefix}-${parseInt(digest, 16) % 1e4}`;
3890
4348
  }
3891
4349
  function nowSeconds() {
@@ -5701,8 +6159,8 @@ var OpenMatesClient = class _OpenMatesClient {
5701
6159
  return decryptBytesWithAesGcm(encryptedChatKey, masterKey);
5702
6160
  }
5703
6161
  getContextWrapperEncryptedChatKey(cache, chatId, teamId = null) {
5704
- const hashedChatId = createHash7("sha256").update(chatId).digest("hex");
5705
- const hashedTeamId = teamId ? createHash7("sha256").update(teamId).digest("hex") : null;
6162
+ const hashedChatId = createHash8("sha256").update(chatId).digest("hex");
6163
+ const hashedTeamId = teamId ? createHash8("sha256").update(teamId).digest("hex") : null;
5706
6164
  const wrapper = (cache?.chatKeyWrappers ?? []).find(
5707
6165
  (entry) => entry.key_type === (teamId ? "team" : "master") && entry.hashed_chat_id === hashedChatId && (!hashedTeamId || entry.hashed_team_id === hashedTeamId) && typeof entry.encrypted_chat_key === "string"
5708
6166
  );
@@ -5808,6 +6266,94 @@ var OpenMatesClient = class _OpenMatesClient {
5808
6266
  async addIdeaBucketText(params) {
5809
6267
  const ideaText = params.text.trim();
5810
6268
  if (!ideaText) throw new Error("IdeaBucket text capture requires non-empty text.");
6269
+ return await this.addIdeaBucketPreparedIdeas({
6270
+ ...params,
6271
+ ideas: [{
6272
+ content: ideaText,
6273
+ preview: ideaText,
6274
+ payload: { type: "text", text: ideaText }
6275
+ }]
6276
+ });
6277
+ }
6278
+ async addIdeaBucketAudio(params) {
6279
+ const now = Math.floor(Date.now() / 1e3);
6280
+ const chatId = params.chatId ?? randomUUID5();
6281
+ const fileResult = processFiles([params.filePath], null);
6282
+ if (fileResult.blocked.length > 0) {
6283
+ throw new Error(fileResult.blocked.map((entry) => `${entry.path}: ${entry.error}`).join("; "));
6284
+ }
6285
+ if (fileResult.errors.length > 0) {
6286
+ throw new Error(fileResult.errors.map((entry) => `${entry.path}: ${entry.error}`).join("; "));
6287
+ }
6288
+ const audioEmbed = fileResult.embeds[0];
6289
+ if (!audioEmbed || audioEmbed.embed.type !== "audio-recording" || !audioEmbed.requiresUpload || !audioEmbed.localPath) {
6290
+ throw new Error("IdeaBucket audio requires one supported local audio file.");
6291
+ }
6292
+ const session = this.getSession();
6293
+ const uploadResult = await uploadFile(audioEmbed.localPath, session);
6294
+ const embedRef = audioEmbed.embed.embedRef ?? createEmbedRef("audio-recording", `${audioEmbed.displayName}:${audioEmbed.embed.embedId}`);
6295
+ audioEmbed.embed.embedRef = embedRef;
6296
+ const transcription = await transcribeUploadedAudio(
6297
+ uploadResult,
6298
+ audioEmbed.displayName,
6299
+ session,
6300
+ { chatId, requestId: audioEmbed.embed.embedId }
6301
+ );
6302
+ const transcript = transcription.transcript_corrected ?? transcription.transcript ?? transcription.transcript_original ?? "";
6303
+ audioEmbed.embed.content = toonEncodeContent({
6304
+ app_id: "audio",
6305
+ skill_id: "transcribe",
6306
+ type: "audio-recording",
6307
+ status: "finished",
6308
+ filename: audioEmbed.displayName,
6309
+ embed_ref: embedRef,
6310
+ mime_type: uploadResult.content_type,
6311
+ transcript: transcription.transcript ?? null,
6312
+ transcript_original: transcription.transcript_original ?? null,
6313
+ transcript_corrected: transcription.transcript_corrected ?? null,
6314
+ use_corrected: transcription.use_corrected ?? null,
6315
+ correction_model: transcription.correction_model ?? null,
6316
+ model: transcription.model ?? null,
6317
+ s3_base_url: uploadResult.s3_base_url,
6318
+ files: uploadResult.files,
6319
+ aes_key: uploadResult.aes_key,
6320
+ aes_nonce: uploadResult.aes_nonce,
6321
+ vault_wrapped_aes_key: uploadResult.vault_wrapped_aes_key
6322
+ });
6323
+ audioEmbed.embed.status = "finished";
6324
+ audioEmbed.embed.contentHash = uploadResult.content_hash;
6325
+ const referenceBlock = createEmbedReferenceBlock(embedRef);
6326
+ const audioMarkdown = [
6327
+ `Audio: ${audioEmbed.displayName}`,
6328
+ referenceBlock,
6329
+ transcript ? `Transcript: ${transcript}` : null
6330
+ ].filter((line) => Boolean(line)).join("\n");
6331
+ return await this.addIdeaBucketPreparedIdeas({
6332
+ chatId,
6333
+ bucketId: params.bucketId,
6334
+ scheduledSendAt: params.scheduledSendAt,
6335
+ prompt: params.prompt,
6336
+ version: params.version ?? now,
6337
+ preparedEmbeds: [audioEmbed.embed],
6338
+ ideas: [{
6339
+ content: audioMarkdown,
6340
+ preview: transcript || audioEmbed.displayName,
6341
+ payload: {
6342
+ type: "audio",
6343
+ filename: audioEmbed.displayName,
6344
+ embed_ref: embedRef,
6345
+ transcript,
6346
+ transcript_original: transcription.transcript_original,
6347
+ transcript_corrected: transcription.transcript_corrected,
6348
+ use_corrected: transcription.use_corrected,
6349
+ correction_model: transcription.correction_model,
6350
+ model: transcription.model
6351
+ }
6352
+ }]
6353
+ });
6354
+ }
6355
+ async addIdeaBucketPreparedIdeas(params) {
6356
+ if (params.ideas.length === 0) throw new Error("IdeaBucket add requires at least one idea.");
5811
6357
  const now = Math.floor(Date.now() / 1e3);
5812
6358
  const chatId = params.chatId ?? randomUUID5();
5813
6359
  const bucketId = params.bucketId ?? defaultIdeaBucketProcessingWindowId();
@@ -5815,14 +6361,18 @@ var OpenMatesClient = class _OpenMatesClient {
5815
6361
  const scheduledSendAt = params.scheduledSendAt ?? defaultIdeaBucketScheduledSendAt(now);
5816
6362
  const version = params.version ?? now;
5817
6363
  const prompt = params.prompt ?? IDEABUCKET_DEFAULT_PROCESSING_PROMPT;
5818
- const markdown = buildIdeaBucketMarkdown(prompt, [{ index: 1, content: ideaText }]);
5819
- const preview = `IdeaBucket ${processingWindowId}: ${ideaText.slice(0, 120)}`;
6364
+ const markdown = buildIdeaBucketMarkdown(
6365
+ prompt,
6366
+ params.ideas.map((idea, index) => ({ index: index + 1, content: idea.content }))
6367
+ );
6368
+ const previewText = params.ideas.map((idea) => idea.preview).join(" ").trim();
6369
+ const preview = `IdeaBucket ${processingWindowId}: ${previewText.slice(0, 120)}`;
5820
6370
  const serverProcessablePayload = JSON.stringify({
5821
6371
  prompt,
5822
6372
  processing_window_id: processingWindowId,
5823
- ideas: [{ index: 1, type: "text", text: ideaText }]
6373
+ ideas: params.ideas.map((idea, index) => ({ index: index + 1, ...idea.payload }))
5824
6374
  });
5825
- const payloadHash = createHash7("sha256").update(serverProcessablePayload).digest("hex");
6375
+ const payloadHash = createHash8("sha256").update(serverProcessablePayload).digest("hex");
5826
6376
  const masterKey = this.getMasterKeyBytes();
5827
6377
  const encryptedDraftMd = await encryptWithAesGcmCombined(markdown, masterKey);
5828
6378
  const encryptedPreview = await encryptWithAesGcmCombined(preview, masterKey);
@@ -5833,6 +6383,9 @@ var OpenMatesClient = class _OpenMatesClient {
5833
6383
  source: "openmates_cli"
5834
6384
  }), masterKey);
5835
6385
  const serverCacheCiphertext = await encryptWithAesGcmCombined(serverProcessablePayload, masterKey);
6386
+ if (params.preparedEmbeds && params.preparedEmbeds.length > 0) {
6387
+ await this.storeDraftEmbeds({ chatId, preparedEmbeds: params.preparedEmbeds });
6388
+ }
5836
6389
  const encrypted = await this.saveEncryptedDraft({
5837
6390
  chatId,
5838
6391
  encryptedDraftMd,
@@ -5860,6 +6413,65 @@ var OpenMatesClient = class _OpenMatesClient {
5860
6413
  preview
5861
6414
  };
5862
6415
  }
6416
+ async storeDraftEmbeds(params) {
6417
+ const { ws, ownerId } = await this.openWsClient();
6418
+ try {
6419
+ if (!ownerId) throw new Error("Authenticated user identity is required to store IdeaBucket embeds.");
6420
+ const masterKey = this.getMasterKeyBytes();
6421
+ const messageId = randomUUID5();
6422
+ for (const embed of params.preparedEmbeds) {
6423
+ const encrypted = await encryptEmbed(
6424
+ embed,
6425
+ masterKey,
6426
+ null,
6427
+ params.chatId,
6428
+ messageId,
6429
+ ownerId
6430
+ );
6431
+ if (!encrypted) continue;
6432
+ const storeRequestId = randomUUID5();
6433
+ const stored = ws.waitForMessage(
6434
+ "store_embed_confirmed",
6435
+ (payload) => {
6436
+ const p = payload;
6437
+ return p.request_id === storeRequestId && p.embed_id === encrypted.embed_id;
6438
+ },
6439
+ 3e4
6440
+ );
6441
+ await ws.sendAsync("store_embed", {
6442
+ request_id: storeRequestId,
6443
+ embed_id: encrypted.embed_id,
6444
+ encrypted_type: encrypted.encrypted_type,
6445
+ encrypted_content: encrypted.encrypted_content,
6446
+ encrypted_text_preview: encrypted.encrypted_text_preview,
6447
+ status: encrypted.status,
6448
+ hashed_chat_id: encrypted.hashed_chat_id,
6449
+ hashed_message_id: encrypted.hashed_message_id,
6450
+ hashed_user_id: encrypted.hashed_user_id,
6451
+ embed_ids: encrypted.embed_ids,
6452
+ file_path: encrypted.file_path,
6453
+ content_hash: encrypted.content_hash,
6454
+ text_length_chars: encrypted.text_length_chars,
6455
+ created_at: encrypted.created_at,
6456
+ updated_at: encrypted.updated_at
6457
+ });
6458
+ await stored;
6459
+ const keysRequestId = randomUUID5();
6460
+ const keysStored = ws.waitForMessage(
6461
+ "store_embed_keys_confirmed",
6462
+ (payload) => payload.request_id === keysRequestId,
6463
+ 3e4
6464
+ );
6465
+ await ws.sendAsync("store_embed_keys", {
6466
+ request_id: keysRequestId,
6467
+ keys: encrypted.embed_keys
6468
+ });
6469
+ await keysStored;
6470
+ }
6471
+ } finally {
6472
+ ws.close();
6473
+ }
6474
+ }
5863
6475
  async getIdeaBucketStatus(bucketId) {
5864
6476
  this.requireSession();
5865
6477
  const path = bucketId ? `/v1/ideabucket/buckets/${encodeURIComponent(bucketId)}` : "/v1/ideabucket/buckets";
@@ -14290,14 +14902,14 @@ var GeneratedAppSkills = class {
14290
14902
 
14291
14903
  // src/sdk.ts
14292
14904
  import { decode as toonDecode } from "@toon-format/toon";
14293
- import { createHash as createHash8, randomBytes as randomBytes4, randomUUID as randomUUID6 } from "crypto";
14294
- import { chmodSync as chmodSync2, existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
14295
- import { homedir as homedir4 } from "os";
14905
+ import { createHash as createHash9, randomBytes as randomBytes4, randomUUID as randomUUID6 } from "crypto";
14906
+ import { chmodSync as chmodSync2, existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
14907
+ import { homedir as homedir5 } from "os";
14296
14908
  import { dirname as dirname2, join as join3 } from "path";
14297
14909
 
14298
14910
  // src/designIcons.ts
14299
14911
  import { mkdir, writeFile } from "fs/promises";
14300
- import { dirname, extname } from "path";
14912
+ import { dirname, extname as extname2 } from "path";
14301
14913
  import { Resvg } from "@resvg/resvg-js";
14302
14914
  var ICON_SEGMENT_PATTERN = /^[a-z0-9][a-z0-9._-]*$/i;
14303
14915
  var ICON_PATH_PATTERN = /^\/v1\/apps\/design\/icons\/iconify\/([a-z0-9][a-z0-9._-]*)\/([a-z0-9][a-z0-9._-]*)\.svg$/i;
@@ -14365,7 +14977,7 @@ function applyDesignIconColor(svg, color) {
14365
14977
  }
14366
14978
  function resolveDesignIconFormat(format, outputPath) {
14367
14979
  if (format) return format;
14368
- const extension = outputPath ? extname(outputPath).toLowerCase() : ".svg";
14980
+ const extension = outputPath ? extname2(outputPath).toLowerCase() : ".svg";
14369
14981
  return extension === ".png" ? "png" : "svg";
14370
14982
  }
14371
14983
  function decodeFetchedSvg(value) {
@@ -14538,7 +15150,7 @@ var OpenMates = class {
14538
15150
  }
14539
15151
  async resolveEmbedKeyForShare(embedKeys, embedId) {
14540
15152
  const masterKey = await this.getMasterKey();
14541
- const hashedEmbedId = createHash8("sha256").update(embedId).digest("hex");
15153
+ const hashedEmbedId = createHash9("sha256").update(embedId).digest("hex");
14542
15154
  return this.resolveLoadedEmbedKey(embedKeys, hashedEmbedId, masterKey, masterKey);
14543
15155
  }
14544
15156
  async decryptChatMetadata(chat, chatKeyWrappers) {
@@ -14595,7 +15207,7 @@ var OpenMates = class {
14595
15207
  }
14596
15208
  async resolveLoadedChatKey(chat, chatKeyWrappers) {
14597
15209
  const masterKey = await this.getMasterKey();
14598
- const hashedChatId = createHash8("sha256").update(chat.id).digest("hex");
15210
+ const hashedChatId = createHash9("sha256").update(chat.id).digest("hex");
14599
15211
  const wrapper = (chatKeyWrappers ?? []).find(
14600
15212
  (entry) => entry.key_type === "master" && entry.hashed_chat_id === hashedChatId && typeof entry.encrypted_chat_key === "string"
14601
15213
  );
@@ -14609,7 +15221,7 @@ var OpenMates = class {
14609
15221
  if (!embedId) {
14610
15222
  return { ...embed };
14611
15223
  }
14612
- const hashedEmbedId = createHash8("sha256").update(embedId).digest("hex");
15224
+ const hashedEmbedId = createHash9("sha256").update(embedId).digest("hex");
14613
15225
  const embedKey = await this.resolveLoadedEmbedKey(embedKeys, hashedEmbedId, masterKey, chatKey);
14614
15226
  if (!embedKey) {
14615
15227
  return { ...embed };
@@ -14717,9 +15329,9 @@ var OpenMates = class {
14717
15329
  }
14718
15330
  };
14719
15331
  function loadOrCreateDeviceId(customPath) {
14720
- const path = customPath ?? join3(homedir4(), ".openmates", "sdk-device-id");
14721
- if (existsSync5(path)) {
14722
- const stored = readFileSync4(path, "utf8").trim();
15332
+ const path = customPath ?? join3(homedir5(), ".openmates", "sdk-device-id");
15333
+ if (existsSync6(path)) {
15334
+ const stored = readFileSync5(path, "utf8").trim();
14723
15335
  if (stored) return stored;
14724
15336
  }
14725
15337
  const deviceId = randomUUID6();
@@ -15085,7 +15697,7 @@ var OpenMatesIdeaBucket = class {
15085
15697
  processing_window_id: bucketId,
15086
15698
  ideas: [{ index: 1, type: "text", text: ideaText }]
15087
15699
  });
15088
- const payloadHash = createHash8("sha256").update(serverProcessablePayload).digest("hex");
15700
+ const payloadHash = createHash9("sha256").update(serverProcessablePayload).digest("hex");
15089
15701
  const masterKey = await this.client.masterKey();
15090
15702
  return {
15091
15703
  chat_id: chatId,
@@ -16866,464 +17478,6 @@ var OutputRedactor = class {
16866
17478
  }
16867
17479
  };
16868
17480
 
16869
- // src/fileEmbed.ts
16870
- import { readFileSync as readFileSync5, statSync, existsSync as existsSync6 } from "fs";
16871
- import { basename, extname as extname2, resolve as resolve2 } from "path";
16872
- import { homedir as homedir5 } from "os";
16873
- import { createHash as createHash9 } from "crypto";
16874
- var MAX_PER_FILE_SIZE = 100 * 1024 * 1024;
16875
- var BLOCKED_EXTENSIONS = /* @__PURE__ */ new Set([
16876
- ".pem",
16877
- ".key",
16878
- ".p12",
16879
- ".pfx",
16880
- ".keystore",
16881
- ".kdbx",
16882
- ".credentials"
16883
- ]);
16884
- var BLOCKED_NAMES = /* @__PURE__ */ new Set([
16885
- "id_rsa",
16886
- "id_ed25519",
16887
- "id_dsa",
16888
- "id_ecdsa",
16889
- "authorized_keys",
16890
- "known_hosts",
16891
- ".git-credentials",
16892
- ".netrc",
16893
- ".pgpass",
16894
- ".my.cnf"
16895
- ]);
16896
- var CODE_EXTENSIONS = /* @__PURE__ */ new Set([
16897
- "py",
16898
- "js",
16899
- "ts",
16900
- "html",
16901
- "css",
16902
- "json",
16903
- "svelte",
16904
- "java",
16905
- "cpp",
16906
- "c",
16907
- "h",
16908
- "hpp",
16909
- "rs",
16910
- "go",
16911
- "rb",
16912
- "php",
16913
- "swift",
16914
- "kt",
16915
- "txt",
16916
- "md",
16917
- "xml",
16918
- "yaml",
16919
- "yml",
16920
- "sh",
16921
- "bash",
16922
- "sql",
16923
- "vue",
16924
- "jsx",
16925
- "tsx",
16926
- "scss",
16927
- "less",
16928
- "sass",
16929
- "dockerfile",
16930
- "toml",
16931
- "ini",
16932
- "cfg",
16933
- "conf",
16934
- "env",
16935
- "envrc",
16936
- "graphql",
16937
- "gql",
16938
- "r",
16939
- "m",
16940
- "pl",
16941
- "lua",
16942
- "ex",
16943
- "exs",
16944
- "erl",
16945
- "hs",
16946
- "scala",
16947
- "dart",
16948
- "tf"
16949
- ]);
16950
- var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
16951
- "jpg",
16952
- "jpeg",
16953
- "png",
16954
- "webp",
16955
- "gif",
16956
- "heic",
16957
- "heif",
16958
- "bmp",
16959
- "tiff",
16960
- "tif",
16961
- "svg"
16962
- ]);
16963
- var AUDIO_EXTENSIONS = /* @__PURE__ */ new Set([
16964
- "mp3",
16965
- "m4a",
16966
- "mp4",
16967
- "wav",
16968
- "webm",
16969
- "ogg",
16970
- "oga",
16971
- "aac"
16972
- ]);
16973
- function isEnvFile(filename) {
16974
- const lower = filename.toLowerCase();
16975
- return lower === ".env" || lower.startsWith(".env.") || lower === ".envrc";
16976
- }
16977
- function getExt(filename) {
16978
- const ext = extname2(filename).toLowerCase();
16979
- return ext.startsWith(".") ? ext.slice(1) : ext;
16980
- }
16981
- function isCodeOrTextFile(filename) {
16982
- const lower = filename.toLowerCase();
16983
- if (lower === "dockerfile") return true;
16984
- if (isEnvFile(lower)) return true;
16985
- return CODE_EXTENSIONS.has(getExt(filename));
16986
- }
16987
- function isImageFile(filename) {
16988
- return IMAGE_EXTENSIONS.has(getExt(filename));
16989
- }
16990
- function isPDFFile(filename) {
16991
- return getExt(filename) === "pdf";
16992
- }
16993
- function isAudioFile(filename) {
16994
- return AUDIO_EXTENSIONS.has(getExt(filename));
16995
- }
16996
- var LANGUAGE_MAP = {
16997
- ts: "typescript",
16998
- tsx: "typescript",
16999
- js: "javascript",
17000
- jsx: "javascript",
17001
- py: "python",
17002
- rb: "ruby",
17003
- rs: "rust",
17004
- go: "go",
17005
- java: "java",
17006
- kt: "kotlin",
17007
- swift: "swift",
17008
- c: "c",
17009
- cpp: "cpp",
17010
- h: "c",
17011
- hpp: "cpp",
17012
- cs: "csharp",
17013
- php: "php",
17014
- sql: "sql",
17015
- sh: "bash",
17016
- bash: "bash",
17017
- zsh: "bash",
17018
- yml: "yaml",
17019
- yaml: "yaml",
17020
- json: "json",
17021
- xml: "xml",
17022
- html: "html",
17023
- css: "css",
17024
- scss: "scss",
17025
- less: "less",
17026
- md: "markdown",
17027
- toml: "toml",
17028
- ini: "ini",
17029
- cfg: "ini",
17030
- env: "bash",
17031
- envrc: "bash",
17032
- svelte: "svelte",
17033
- vue: "vue",
17034
- graphql: "graphql",
17035
- gql: "graphql",
17036
- tf: "hcl",
17037
- dart: "dart",
17038
- dockerfile: "dockerfile",
17039
- txt: "text"
17040
- };
17041
- function detectLanguage(filename) {
17042
- if (filename.toLowerCase() === "dockerfile") return "dockerfile";
17043
- return LANGUAGE_MAP[getExt(filename)] || "text";
17044
- }
17045
- function processEnvFileZeroKnowledge(content) {
17046
- const lines = content.split("\n");
17047
- const processed = [];
17048
- for (const rawLine of lines) {
17049
- const line = rawLine.trim();
17050
- if (!line || line.startsWith("#")) {
17051
- processed.push(line);
17052
- continue;
17053
- }
17054
- const cleanLine = line.startsWith("export ") ? line.slice(7).trim() : line;
17055
- const eqIndex = cleanLine.indexOf("=");
17056
- if (eqIndex === -1) {
17057
- processed.push(line);
17058
- continue;
17059
- }
17060
- const key = cleanLine.slice(0, eqIndex).trim();
17061
- let value = cleanLine.slice(eqIndex + 1).trim();
17062
- if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
17063
- value = value.slice(1, -1);
17064
- }
17065
- if (value.length > 3) {
17066
- processed.push(`${key}=***${value.slice(-3)}`);
17067
- } else if (value.length > 0) {
17068
- processed.push(`${key}=***`);
17069
- } else {
17070
- processed.push(`${key}=`);
17071
- }
17072
- }
17073
- return processed.join("\n");
17074
- }
17075
- function resolvePath(filePath) {
17076
- if (filePath.startsWith("~/")) {
17077
- return resolve2(homedir5(), filePath.slice(2));
17078
- }
17079
- return resolve2(filePath);
17080
- }
17081
- function processFiles(filePaths, redactor) {
17082
- const embeds = [];
17083
- const errors = [];
17084
- const blocked = [];
17085
- for (const rawPath of filePaths) {
17086
- const resolvedPath = resolvePath(rawPath);
17087
- const filename = basename(resolvedPath);
17088
- const ext = getExt(filename);
17089
- if (!existsSync6(resolvedPath)) {
17090
- errors.push({ path: rawPath, error: "File not found" });
17091
- continue;
17092
- }
17093
- let stats;
17094
- try {
17095
- stats = statSync(resolvedPath);
17096
- } catch (e) {
17097
- errors.push({
17098
- path: rawPath,
17099
- error: `Cannot read: ${e instanceof Error ? e.message : String(e)}`
17100
- });
17101
- continue;
17102
- }
17103
- if (stats.isDirectory()) {
17104
- errors.push({ path: rawPath, error: "Is a directory, not a file" });
17105
- continue;
17106
- }
17107
- if (stats.size > MAX_PER_FILE_SIZE) {
17108
- errors.push({
17109
- path: rawPath,
17110
- error: `File too large (${Math.round(stats.size / 1024 / 1024)}MB > 100MB limit)`
17111
- });
17112
- continue;
17113
- }
17114
- if (BLOCKED_EXTENSIONS.has(`.${ext}`)) {
17115
- blocked.push({
17116
- path: rawPath,
17117
- error: `Blocked: .${ext} files may contain private keys. Use --allow-sensitive to override.`
17118
- });
17119
- continue;
17120
- }
17121
- if (BLOCKED_NAMES.has(filename)) {
17122
- blocked.push({
17123
- path: rawPath,
17124
- error: `Blocked: '${filename}' typically contains credentials. Use --allow-sensitive to override.`
17125
- });
17126
- continue;
17127
- }
17128
- if (isCodeOrTextFile(filename)) {
17129
- const result = processCodeFile(resolvedPath, filename, redactor);
17130
- if (result) embeds.push(result);
17131
- else errors.push({ path: rawPath, error: "Failed to process file" });
17132
- } else if (isImageFile(filename)) {
17133
- const result = processImageFile(resolvedPath, filename);
17134
- if (result) embeds.push(result);
17135
- else errors.push({ path: rawPath, error: "Failed to process image" });
17136
- } else if (isPDFFile(filename)) {
17137
- const result = processPDFFile(resolvedPath, filename);
17138
- if (result) embeds.push(result);
17139
- else errors.push({ path: rawPath, error: "Failed to process PDF" });
17140
- } else if (isAudioFile(filename)) {
17141
- const result = processAudioFile(resolvedPath, filename);
17142
- if (result) embeds.push(result);
17143
- else errors.push({ path: rawPath, error: "Failed to process audio" });
17144
- } else {
17145
- errors.push({
17146
- path: rawPath,
17147
- error: `Unsupported file type: .${ext}. Supported: code/text, images, PDFs, audio.`
17148
- });
17149
- }
17150
- }
17151
- return { embeds, errors, blocked };
17152
- }
17153
- function processCodeFile(filePath, filename, redactor) {
17154
- try {
17155
- let content = readFileSync5(filePath, "utf-8");
17156
- let secretsRedacted = false;
17157
- let zeroKnowledge = false;
17158
- if (isEnvFile(filename)) {
17159
- content = processEnvFileZeroKnowledge(content);
17160
- secretsRedacted = true;
17161
- zeroKnowledge = true;
17162
- } else if (redactor?.isInitialized) {
17163
- const result = redactor.redactWithMappings(content);
17164
- if (result.mappings.length > 0) {
17165
- content = result.redacted;
17166
- secretsRedacted = true;
17167
- }
17168
- }
17169
- const language = detectLanguage(filename);
17170
- const lineCount = content.split("\n").length;
17171
- const embedId = generateEmbedId();
17172
- const embedRef = createEmbedRef("code", `${filename}:${embedId}`);
17173
- const embedContent = toonEncodeContent({
17174
- type: "code",
17175
- language,
17176
- code: content,
17177
- filename,
17178
- embed_ref: embedRef,
17179
- status: "finished",
17180
- line_count: lineCount
17181
- });
17182
- const textPreview = `${filename} (${language}, ${lineCount} lines)`;
17183
- const contentHash = createHash9("sha256").update(content).digest("hex");
17184
- const embed = {
17185
- embedId,
17186
- embedRef,
17187
- type: "code-code",
17188
- content: embedContent,
17189
- textPreview,
17190
- status: "finished",
17191
- filePath: filename,
17192
- contentHash,
17193
- textLengthChars: content.length
17194
- };
17195
- return {
17196
- embed,
17197
- referenceBlock: createEmbedReferenceBlock(embedRef),
17198
- displayName: filename,
17199
- secretsRedacted,
17200
- zeroKnowledge,
17201
- requiresUpload: false
17202
- };
17203
- } catch (e) {
17204
- process.stderr.write(
17205
- `\x1B[31mError:\x1B[0m Failed to read ${filename}: ${e instanceof Error ? e.message : String(e)}
17206
- `
17207
- );
17208
- return null;
17209
- }
17210
- }
17211
- function processImageFile(filePath, filename) {
17212
- try {
17213
- const embedId = generateEmbedId();
17214
- const embedRef = createEmbedRef("image", `${filename}:${embedId}`);
17215
- const embedContent = toonEncodeContent({
17216
- type: "image",
17217
- app_id: "images",
17218
- skill_id: "upload",
17219
- status: "uploading",
17220
- filename,
17221
- embed_ref: embedRef
17222
- });
17223
- const embed = {
17224
- embedId,
17225
- embedRef,
17226
- type: "image",
17227
- content: embedContent,
17228
- textPreview: filename,
17229
- status: "finished"
17230
- // Will be set to "finished" after upload
17231
- };
17232
- return {
17233
- embed,
17234
- referenceBlock: createEmbedReferenceBlock(embedRef),
17235
- displayName: filename,
17236
- secretsRedacted: false,
17237
- zeroKnowledge: false,
17238
- requiresUpload: true,
17239
- localPath: filePath
17240
- };
17241
- } catch (e) {
17242
- process.stderr.write(
17243
- `\x1B[31mError:\x1B[0m Failed to process ${filename}: ${e instanceof Error ? e.message : String(e)}
17244
- `
17245
- );
17246
- return null;
17247
- }
17248
- }
17249
- function processPDFFile(filePath, filename) {
17250
- try {
17251
- const embedId = generateEmbedId();
17252
- const embedRef = createEmbedRef("pdf", `${filename}:${embedId}`);
17253
- const embedContent = toonEncodeContent({
17254
- type: "pdf",
17255
- status: "uploading",
17256
- filename,
17257
- embed_ref: embedRef
17258
- });
17259
- const embed = {
17260
- embedId,
17261
- embedRef,
17262
- type: "pdf",
17263
- content: embedContent,
17264
- textPreview: filename,
17265
- status: "processing"
17266
- // PDFs start as "processing" for background OCR
17267
- };
17268
- return {
17269
- embed,
17270
- referenceBlock: createEmbedReferenceBlock(embedRef),
17271
- displayName: filename,
17272
- secretsRedacted: false,
17273
- zeroKnowledge: false,
17274
- requiresUpload: true,
17275
- localPath: filePath
17276
- };
17277
- } catch (e) {
17278
- process.stderr.write(
17279
- `\x1B[31mError:\x1B[0m Failed to process ${filename}: ${e instanceof Error ? e.message : String(e)}
17280
- `
17281
- );
17282
- return null;
17283
- }
17284
- }
17285
- function processAudioFile(filePath, filename) {
17286
- try {
17287
- const embedId = generateEmbedId();
17288
- const embedRef = createEmbedRef("audio-recording", `${filename}:${embedId}`);
17289
- const embedContent = toonEncodeContent({
17290
- app_id: "audio",
17291
- skill_id: "transcribe",
17292
- type: "audio-recording",
17293
- status: "uploading",
17294
- filename,
17295
- embed_ref: embedRef
17296
- });
17297
- const embed = {
17298
- embedId,
17299
- embedRef,
17300
- type: "audio-recording",
17301
- content: embedContent,
17302
- textPreview: filename,
17303
- status: "processing"
17304
- };
17305
- return {
17306
- embed,
17307
- referenceBlock: createEmbedReferenceBlock(embedRef),
17308
- displayName: filename,
17309
- secretsRedacted: false,
17310
- zeroKnowledge: false,
17311
- requiresUpload: true,
17312
- localPath: filePath
17313
- };
17314
- } catch (e) {
17315
- process.stderr.write(
17316
- `\x1B[31mError:\x1B[0m Failed to process ${filename}: ${e instanceof Error ? e.message : String(e)}
17317
- `
17318
- );
17319
- return null;
17320
- }
17321
- }
17322
- function formatEmbedsForMessage(embeds) {
17323
- if (embeds.length === 0) return "";
17324
- return "\n" + embeds.map((e) => e.referenceBlock).join("\n");
17325
- }
17326
-
17327
17481
  // src/urlEmbed.ts
17328
17482
  var URL_PATTERN = /\bhttps?:\/\/[^\s<>()`"']+/gi;
17329
17483
  var FENCED_BLOCK_PATTERN = /(```[\s\S]*?```)/g;
@@ -39358,6 +39512,12 @@ Only output the final Markdown table. Do NOT include explanations, notes, or any
39358
39512
  text: "Create flowcharts, sequences, timelines & more."
39359
39513
  }
39360
39514
  },
39515
+ design: {
39516
+ text: "Design",
39517
+ description: {
39518
+ text: "Find icons and visual assets for product design."
39519
+ }
39520
+ },
39361
39521
  docs: {
39362
39522
  text: "Docs",
39363
39523
  description: {
@@ -60269,6 +60429,19 @@ async function handleIdeaBucket(client, subcommand, rest, flags) {
60269
60429
  }));
60270
60430
  return;
60271
60431
  }
60432
+ if (subcommand === "audio") {
60433
+ const filePath = rest[0];
60434
+ if (!filePath) throw new Error("Missing audio file path for IdeaBucket audio.");
60435
+ const scheduledSendAt = typeof flags["scheduled-at"] === "string" ? parseUnixSecondsFlag(flags["scheduled-at"], "--scheduled-at") : void 0;
60436
+ printJson2(await client.addIdeaBucketAudio({
60437
+ filePath,
60438
+ chatId: typeof flags.chat === "string" ? flags.chat : void 0,
60439
+ bucketId: typeof flags.bucket === "string" ? flags.bucket : void 0,
60440
+ scheduledSendAt,
60441
+ prompt: typeof flags.prompt === "string" ? flags.prompt : void 0
60442
+ }));
60443
+ return;
60444
+ }
60272
60445
  if (subcommand === "status") {
60273
60446
  const bucketId = rest[0] ?? (typeof flags.bucket === "string" ? flags.bucket : void 0);
60274
60447
  printJson2(await client.getIdeaBucketStatus(bucketId));
@@ -65957,7 +66130,7 @@ Commands:
65957
66130
  openmates tasks [--help] Task commands (list, create, board, ...)
65958
66131
  openmates teams [--help] Team lifecycle, membership, billing, and move commands
65959
66132
  openmates drafts [--help] Encrypted draft lifecycle commands
65960
- openmates ideabucket [--help] IdeaBucket capture, draft/status, and process commands
66133
+ openmates ideabucket [--help] IdeaBucket add, audio, status, and process commands
65961
66134
  openmates apps [--help] App skill commands (list, run, ...)
65962
66135
  openmates workflows [--help] Server-side workflow commands
65963
66136
  openmates mentions [--help] List available @mentions
@@ -66315,11 +66488,14 @@ ciphertext and version metadata are sent to the server or written to CLI cache.`
66315
66488
  function printIdeaBucketHelp() {
66316
66489
  console.log(`IdeaBucket commands:
66317
66490
  openmates ideabucket add <text> [--chat <uuid>] [--bucket <id>] [--scheduled-at <unix>] [--prompt <text>] [--json]
66491
+ openmates ideabucket audio <file> [--chat <uuid>] [--bucket <id>] [--scheduled-at <unix>] [--prompt <text>] [--json]
66318
66492
  openmates ideabucket status [bucket-id] [--json]
66319
66493
  openmates ideabucket process <bucket-id> [--now] [--json]
66320
66494
 
66321
- Adding text updates the encrypted OpenMates IdeaBucket draft for the processing
66322
- bucket and sends only ciphertext plus sparse non-content metadata to the server.`);
66495
+ Adding text or audio updates the encrypted OpenMates IdeaBucket draft for the
66496
+ processing bucket and sends only ciphertext plus sparse non-content metadata to
66497
+ the server. Audio reuses OpenMates upload and audio.transcribe before encrypting
66498
+ the bucket draft.`);
66323
66499
  }
66324
66500
  function printAppsHelp() {
66325
66501
  console.log(`Apps commands:
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  getExtForLang,
4
4
  serializeToYaml
5
- } from "./chunk-4UXNJ2I6.js";
5
+ } from "./chunk-ASTZUBZU.js";
6
6
  import "./chunk-AXNRPVLE.js";
7
7
  export {
8
8
  getExtForLang,
package/dist/index.d.ts CHANGED
@@ -1421,6 +1421,16 @@ declare class OpenMatesClient {
1421
1421
  prompt?: string;
1422
1422
  version?: number;
1423
1423
  }): Promise<IdeaBucketAddResult>;
1424
+ addIdeaBucketAudio(params: {
1425
+ filePath: string;
1426
+ chatId?: string;
1427
+ bucketId?: string;
1428
+ scheduledSendAt?: number;
1429
+ prompt?: string;
1430
+ version?: number;
1431
+ }): Promise<IdeaBucketAddResult>;
1432
+ private addIdeaBucketPreparedIdeas;
1433
+ private storeDraftEmbeds;
1424
1434
  getIdeaBucketStatus(bucketId?: string): Promise<IdeaBucketStatusResult>;
1425
1435
  processIdeaBucketBucket(bucketId: string, options?: {
1426
1436
  now?: boolean;
@@ -5707,4 +5717,4 @@ type AssistantFeedbackDecision = {
5707
5717
  };
5708
5718
  declare function buildAssistantFeedbackDecision(rating: number): AssistantFeedbackDecision;
5709
5719
 
5710
- export { APP_SKILL_METADATA, ASSISTANT_FEEDBACK_REPORT_TITLE, ASSISTANT_FEEDBACK_THANKS, type ApiKeyCreateOptions, type ApiKeyCreateResult, type ApiKeyRecord, type AssistantFeedbackDecision, type AuthMethodsStatus, type AuthoritativeChatReconciliation, type BackupCodesResult, type BankTransferOrderDetails, type BankTransferStatus, type CachedChat, type CachedNewChatSuggestion, type ChatCreateOptions, type ChatListOptions, type ChatListPage, type ChatResponse, type CliSignupResult, type DecryptedDraft, type DecryptedEmbed, type DecryptedMemoryEntry, type DecryptedMessage, type DecryptedNewChatSuggestion, type DecryptedUserTask, type DesignIconExportFormat, type DesignIconExportOptions, type DesignIconExportResult, type DocsFile, type DocsFolder, type DocsSearchResult, type DocsTree, type DraftRecord, type EncryptedChatMetadata, type EncryptedDraft, type EncryptedDraftRecord, type FocusModeSelection, type GiftCardBankTransferStatus, INTEREST_TAG_IDS, type InterestTagId, MATE_NAMES, MEMORY_TYPE_REGISTRY, type MemoryFieldDef, type MemoryTypeDef, OpenMates, OpenMatesApiError, OpenMatesClient, type OpenMatesClientOptions, OpenMatesConfigError, type OpenMatesOptions, type OpenMatesSession, type ProjectSourceCapability, type ProjectSourceCreateInput, type ProjectSourceRecord, type ProjectSourceStatus, type ProjectSourceType, SUPPORT_URL, type SyncCache, type TaskListFilters, type TaskPlainCreateOptions, type TaskPlainUpdateOptions, type TaskRecord, type TopicPreferencesPayload, type TotpSetupStartResult, type WorkflowCapability, type WorkflowDetail, type WorkflowEdge, type WorkflowGraph, type WorkflowNode, type WorkflowNodeRun, type WorkflowNodeType, type WorkflowRunContentRetention, type WorkflowRunContentStorage, type WorkflowRunDetail, type WorkflowSummary, buildAssistantFeedbackDecision, defaultCloneBranchForVersion, deriveAppUrl, normalizeInterestTagIds, reconcileAuthoritativeChats, renderSupportInfo };
5720
+ export { APP_SKILL_METADATA, ASSISTANT_FEEDBACK_REPORT_TITLE, ASSISTANT_FEEDBACK_THANKS, type ApiKeyCreateOptions, type ApiKeyCreateResult, type ApiKeyRecord, type AssistantFeedbackDecision, type AuthMethodsStatus, type AuthoritativeChatReconciliation, type BackupCodesResult, type BankTransferOrderDetails, type BankTransferStatus, type CachedChat, type CachedNewChatSuggestion, type ChatCreateOptions, type ChatListOptions, type ChatListPage, type ChatResponse, type CliSignupResult, type DecryptedDraft, type DecryptedEmbed, type DecryptedMemoryEntry, type DecryptedMessage, type DecryptedNewChatSuggestion, type DecryptedUserTask, type DesignIconExportFormat, type DesignIconExportOptions, type DesignIconExportResult, type DocsFile, type DocsFolder, type DocsSearchResult, type DocsTree, type DraftRecord, type EncryptedChatMetadata, type EncryptedDraft, type EncryptedDraftRecord, type FocusModeSelection, type GiftCardBankTransferStatus, INTEREST_TAG_IDS, type IdeaBucketAddInput, type IdeaBucketProcessOptions, type IdeaBucketResult, type InterestTagId, MATE_NAMES, MEMORY_TYPE_REGISTRY, type MemoryFieldDef, type MemoryTypeDef, OpenMates, OpenMatesApiError, OpenMatesClient, type OpenMatesClientOptions, OpenMatesConfigError, type OpenMatesOptions, type OpenMatesSession, type ProjectSourceCapability, type ProjectSourceCreateInput, type ProjectSourceRecord, type ProjectSourceStatus, type ProjectSourceType, SUPPORT_URL, type SyncCache, type TaskListFilters, type TaskPlainCreateOptions, type TaskPlainUpdateOptions, type TaskRecord, type TopicPreferencesPayload, type TotpSetupStartResult, type WorkflowCapability, type WorkflowDetail, type WorkflowEdge, type WorkflowGraph, type WorkflowNode, type WorkflowNodeRun, type WorkflowNodeType, type WorkflowRunContentRetention, type WorkflowRunContentStorage, type WorkflowRunDetail, type WorkflowSummary, buildAssistantFeedbackDecision, defaultCloneBranchForVersion, deriveAppUrl, normalizeInterestTagIds, reconcileAuthoritativeChats, renderSupportInfo };
package/dist/index.js CHANGED
@@ -18,7 +18,7 @@ import {
18
18
  reconcileAuthoritativeChats,
19
19
  renderSupportInfo,
20
20
  serializeToYaml
21
- } from "./chunk-4UXNJ2I6.js";
21
+ } from "./chunk-ASTZUBZU.js";
22
22
  import "./chunk-AXNRPVLE.js";
23
23
  export {
24
24
  APP_SKILL_METADATA,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openmates",
3
- "version": "0.15.0-alpha.32",
3
+ "version": "0.15.0-alpha.34",
4
4
  "description": "OpenMates CLI and SDK",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",