@dualityinstitute/blink 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,7 +24,7 @@ credentials on the Mac.
24
24
  ## Install
25
25
 
26
26
  ```bash
27
- bunx @dualityinstitute/blink install
27
+ bunx @dualityinstitute/blink@latest install
28
28
  ```
29
29
 
30
30
  The terminal UI asks for the access token, writes `~/.blink/config.json`, and
@@ -34,7 +34,7 @@ at its default URL, so only the token is needed.
34
34
  For non-interactive installation:
35
35
 
36
36
  ```bash
37
- bunx @dualityinstitute/blink install --token blink_customer_token
37
+ bunx @dualityinstitute/blink@latest install --token blink_customer_token
38
38
  ```
39
39
 
40
40
  Pass `--api-url` as well to point the app at a different gateway, such as a
@@ -72,7 +72,9 @@ the signed **Blink** app identity.
72
72
 
73
73
  Enable **Meeting** in the tray or popup. Blink starts a new identity-scoped
74
74
  Meeting conversation, captures system audio as `Them` and microphone audio as
75
- `You`, and keeps a rolling two-minute transcript locally. Captures made with the
75
+ `You`, and keeps a rolling two-minute transcript for the model. The popup widens
76
+ to show the full running transcript beside the answer; scroll back at any point
77
+ and it stops following new speech until you return to the bottom. Captures made with the
76
78
  global shortcuts are retained in a private staging directory. The popup shows
77
79
  which transcript and screenshot context is ready.
78
80
 
@@ -89,15 +91,18 @@ Run `blink ungrant` to clear both permission records and make macOS ask again.
89
91
 
90
92
  ### Saving transcripts
91
93
 
92
- **Save transcript** is off by default. When enabled, the entire Meeting is
93
- appended to a Markdown file under:
94
+ Every Meeting is appended to a Markdown file on your Mac, one per session:
94
95
 
95
96
  ```text
96
97
  ~/.blink/transcripts/2026-08-30-143022.md
97
98
  ```
98
99
 
99
- This local setting is independent from submission: Ask always sends the current
100
- two-minute transcript snapshot when one is available.
100
+ Saving is local only and independent from submission: Ask always sends the
101
+ current two-minute transcript snapshot when one is available, no more.
102
+
103
+ Open **Meeting Transcripts…** from the tray to read, search, and filter past
104
+ sessions by date. Search runs across every saved transcript and reports how many
105
+ times each session matched.
101
106
 
102
107
  ## Answer lifecycle and cancellation
103
108
 
@@ -110,7 +115,7 @@ two-minute transcript snapshot when one is available.
110
115
 
111
116
  Subscribe at [duality.institute/blink](https://duality.institute/blink). After
112
117
  Stripe Checkout the claim page shows your access token exactly once; paste it
113
- into `bunx @dualityinstitute/blink install`.
118
+ into `bunx @dualityinstitute/blink@latest install`.
114
119
 
115
120
  Every Monitor screenshot and every Meeting Ask counts as one answer against
116
121
  your monthly limit. The popup shows `used / limit` for the current period, and
@@ -136,7 +141,8 @@ Blink Cloud receives:
136
141
  - The bearer access token needed to authorize and isolate the request
137
142
 
138
143
  The desktop stores the access token in `~/.blink/config.json`. Answer metadata
139
- and text are appended locally to `~/.blink/answers.jsonl`. Presenter Notes stay
144
+ and text are appended locally to `~/.blink/answers.jsonl`, and meeting
145
+ transcripts to `~/.blink/transcripts/`. Presenter Notes stay
140
146
  local in `~/.blink/presenter.md` and are never submitted. Meeting captures are
141
147
  staged under `~/.blink/meeting-captures/` and cleared when Meeting ends.
142
148
 
@@ -153,8 +159,7 @@ and token totals are kept for billing.
153
159
  | `accessToken` | Empty | Bearer token issued for Blink Cloud |
154
160
  | `screenshotDir` | `~/blinkDir/` | Watched PNG directory |
155
161
  | `hideFromCapture` | `true` | Enables privacy mode |
156
- | `showTranscript` | `true` | Shows the live transcript strip |
157
- | `saveTranscript` | `false` | Saves full meeting transcripts locally |
162
+ | `showTranscript` | `true` | Shows the live transcript panel during a meeting |
158
163
 
159
164
  Blink materializes new defaults without deleting unrelated settings from an
160
165
  existing config file. The obsolete `sessionMode` and `hotkeyPreset` keys are
package/dist/cli.js CHANGED
@@ -1146,30 +1146,6 @@ var u$1 = class u2 extends V {
1146
1146
  });
1147
1147
  }
1148
1148
  };
1149
- class n extends V {
1150
- get userInputWithCursor() {
1151
- if (this.state === "submit")
1152
- return this.userInput;
1153
- const t2 = this.userInput;
1154
- if (this.cursor >= t2.length)
1155
- return `${this.userInput}\u2588`;
1156
- const r = t2.slice(0, this.cursor), s = t2.slice(this.cursor, this.cursor + 1), e = t2.slice(this.cursor + 1);
1157
- return `${r}${styleText("inverse", s)}${e}`;
1158
- }
1159
- get cursor() {
1160
- return this._cursor;
1161
- }
1162
- constructor(t2) {
1163
- super({
1164
- ...t2,
1165
- initialUserInput: t2.initialUserInput ?? t2.initialValue
1166
- }), this.on("userInput", (r) => {
1167
- this._setValue(r);
1168
- }), this.on("finalize", () => {
1169
- this.value || (this.value = t2.defaultValue), this.value === undefined && (this.value = "");
1170
- });
1171
- }
1172
- }
1173
1149
 
1174
1150
  // node_modules/@clack/prompts/dist/index.mjs
1175
1151
  import { styleText as styleText2, stripVTControlCharacters } from "util";
@@ -1290,44 +1266,6 @@ var SELECT_INSTRUCTIONS = [
1290
1266
  `${styleText2("dim", "Enter:")} confirm`
1291
1267
  ];
1292
1268
  var i = `${styleText2("gray", S_BAR)} `;
1293
- var text = (e) => new n({
1294
- validate: e.validate,
1295
- placeholder: e.placeholder,
1296
- defaultValue: e.defaultValue,
1297
- initialValue: e.initialValue,
1298
- output: e.output,
1299
- signal: e.signal,
1300
- input: e.input,
1301
- render() {
1302
- const i2 = e?.withGuide ?? settings.withGuide, s = `${`${i2 ? `${styleText2("gray", S_BAR)}
1303
- ` : ""}${symbol(this.state)} `}${e.message}
1304
- `, c2 = e.placeholder && e.placeholder.length > 0 ? styleText2("inverse", e.placeholder[0]) + styleText2("dim", e.placeholder.slice(1)) : styleText2(["inverse", "hidden"], "_"), o2 = this.userInput ? this.userInputWithCursor : c2, l = this.value ?? "";
1305
- switch (this.state) {
1306
- case "error": {
1307
- const n2 = this.error ? ` ${styleText2("yellow", this.error)}` : "", r2 = i2 ? `${styleText2("yellow", S_BAR)} ` : "", d = i2 ? styleText2("yellow", S_BAR_END) : "";
1308
- return `${s.trim()}
1309
- ${r2}${o2}
1310
- ${d}${n2}
1311
- `;
1312
- }
1313
- case "submit": {
1314
- const n2 = l ? ` ${styleText2("dim", l)}` : "", r2 = i2 ? styleText2("gray", S_BAR) : "";
1315
- return `${s}${r2}${n2}`;
1316
- }
1317
- case "cancel": {
1318
- const n2 = l ? ` ${styleText2(["strikethrough", "dim"], l)}` : "", r2 = i2 ? styleText2("gray", S_BAR) : "";
1319
- return `${s}${r2}${n2}${l.trim() ? `
1320
- ${r2}` : ""}`;
1321
- }
1322
- default: {
1323
- const n2 = i2 ? `${styleText2("cyan", S_BAR)} ` : "", r2 = i2 ? styleText2("cyan", S_BAR_END) : "";
1324
- return `${s}${n2}${o2}
1325
- ${r2}
1326
- `;
1327
- }
1328
- }
1329
- }
1330
- }).prompt();
1331
1269
 
1332
1270
  // src/cli.ts
1333
1271
  import * as fs3 from "fs";
@@ -10356,8 +10294,8 @@ function ko_default() {
10356
10294
  };
10357
10295
  }
10358
10296
  // node_modules/zod/v4/locales/lt.js
10359
- var capitalizeFirstCharacter = (text2) => {
10360
- return text2.charAt(0).toUpperCase() + text2.slice(1);
10297
+ var capitalizeFirstCharacter = (text) => {
10298
+ return text.charAt(0).toUpperCase() + text.slice(1);
10361
10299
  };
10362
10300
  function getUnitTypeFromNumber(number2) {
10363
10301
  const abs = Math.abs(number2);
@@ -19924,14 +19862,17 @@ function date4(params) {
19924
19862
  return _coercedDate(ZodDate, params);
19925
19863
  }
19926
19864
  // src/core/cloud-protocol.ts
19865
+ var OptionalPrompt = exports_external.preprocess((value) => value === null || value === "" ? undefined : value, exports_external.string().trim().min(1).max(4000).optional());
19927
19866
  var MonitorRequestSchema = exports_external.object({
19928
19867
  kind: exports_external.literal("monitor"),
19929
- image: exports_external.instanceof(File)
19868
+ image: exports_external.instanceof(File),
19869
+ prompt: OptionalPrompt
19930
19870
  });
19931
19871
  var MeetingRequestSchema = exports_external.object({
19932
19872
  kind: exports_external.literal("meeting"),
19933
19873
  text: exports_external.preprocess((value) => value === null ? undefined : value, exports_external.string().trim().min(1).optional()),
19934
- images: exports_external.array(exports_external.instanceof(File)).readonly()
19874
+ images: exports_external.array(exports_external.instanceof(File)).readonly(),
19875
+ prompt: OptionalPrompt
19935
19876
  });
19936
19877
  var CloudAnswerRequestSchema = exports_external.discriminatedUnion("kind", [MonitorRequestSchema, MeetingRequestSchema]).superRefine((request, context) => {
19937
19878
  if (request.kind === "meeting" && request.text === undefined && request.images.length === 0) {
@@ -20024,9 +19965,10 @@ var DEFAULTS = {
20024
19965
  accessToken: "",
20025
19966
  hideFromCapture: true,
20026
19967
  showTranscript: true,
20027
- saveTranscript: false
19968
+ monitorPrompt: "",
19969
+ meetingPrompt: ""
20028
19970
  };
20029
- var OBSOLETE_KEYS = ["sessionMode", "hotkeyPreset"];
19971
+ var OBSOLETE_KEYS = ["sessionMode", "hotkeyPreset", "saveTranscript"];
20030
19972
  var RawConfigSchema = exports_external.record(exports_external.string(), exports_external.unknown());
20031
19973
  var HttpUrlSchema = exports_external.url().refine((value) => {
20032
19974
  const protocol = new URL(value).protocol;
@@ -20110,8 +20052,13 @@ function loadConfig() {
20110
20052
  if (user["showTranscript"] !== undefined) {
20111
20053
  merged.showTranscript = user["showTranscript"] === true;
20112
20054
  }
20113
- if (user["saveTranscript"] !== undefined) {
20114
- merged.saveTranscript = user["saveTranscript"] === true;
20055
+ for (const key of ["monitorPrompt", "meetingPrompt"]) {
20056
+ if (user[key] === undefined)
20057
+ continue;
20058
+ const prompt = exports_external.string().safeParse(user[key]);
20059
+ if (!prompt.success)
20060
+ throw new ConfigFileError(`${key} must be a string`);
20061
+ merged[key] = prompt.data.trim();
20115
20062
  }
20116
20063
  const missing = Object.keys(merged).filter((key) => !(key in persisted));
20117
20064
  if (missing.length > 0 || hadObsolete) {
@@ -20361,17 +20308,7 @@ async function selectCredentials(args, current) {
20361
20308
  };
20362
20309
  }
20363
20310
  intro("Blink Cloud setup");
20364
- let apiUrl = explicitUrl;
20365
- if (apiUrl === undefined) {
20366
- const result = await text({
20367
- message: "Blink Cloud URL",
20368
- initialValue: current.apiUrl,
20369
- validate: (value) => validationMessage(() => normalizeApiUrl(value ?? ""))
20370
- });
20371
- if (isCancel(result) || typeof result !== "string")
20372
- return cancelSetup();
20373
- apiUrl = result;
20374
- }
20311
+ const apiUrl = explicitUrl ?? current.apiUrl;
20375
20312
  let accessToken = explicitToken;
20376
20313
  if (accessToken === undefined) {
20377
20314
  const result = await password({