opencode-reviewer 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/tui.js +243 -158
  2. package/package.json +1 -1
package/dist/tui.js CHANGED
@@ -550,10 +550,10 @@ var require_shell_quote = __commonJS({
550
550
  // src/tui.tsx
551
551
  init_define_REVIEW_PROMPTS();
552
552
  init_define_REVIEW_SOUNDS();
553
- import { createTextNode as _$createTextNode } from "@opentui/solid";
554
- import { insertNode as _$insertNode } from "@opentui/solid";
555
553
  import { use as _$use } from "@opentui/solid";
556
554
  import { effect as _$effect } from "@opentui/solid";
555
+ import { createTextNode as _$createTextNode } from "@opentui/solid";
556
+ import { insertNode as _$insertNode } from "@opentui/solid";
557
557
  import { insert as _$insert } from "@opentui/solid";
558
558
  import { memo as _$memo2 } from "@opentui/solid";
559
559
  import { createComponent as _$createComponent2 } from "@opentui/solid";
@@ -1128,6 +1128,77 @@ async function override(directory, name, signal) {
1128
1128
  // src/usage.ts
1129
1129
  init_define_REVIEW_PROMPTS();
1130
1130
  init_define_REVIEW_SOUNDS();
1131
+
1132
+ // src/ui-text.ts
1133
+ init_define_REVIEW_PROMPTS();
1134
+ init_define_REVIEW_SOUNDS();
1135
+ var uiText = {
1136
+ review: {
1137
+ heading: "Permission analysis",
1138
+ safe: "\u2713 Safe",
1139
+ unsafe: "\u2717 Unsafe",
1140
+ unavailable: "! Analysis unavailable",
1141
+ evaluating: "Evaluating",
1142
+ retrying: "Retrying",
1143
+ staticIndicator: "[\u22EF]",
1144
+ failed: "Review failed",
1145
+ invalidConfiguration: "Invalid configuration"
1146
+ },
1147
+ autoApproval: {
1148
+ countdown: (seconds) => `Allowed in ${seconds}s`,
1149
+ checking: "Checking\u2026",
1150
+ cancel: "Cancel",
1151
+ allowing: "Allowing\u2026",
1152
+ cancelled: "Auto-approval canceled",
1153
+ unavailable: "! Auto-approval unavailable. Use native controls."
1154
+ },
1155
+ commands: {
1156
+ category: "Reviewer",
1157
+ enable: "Reviewer: Enable for conversation",
1158
+ disable: "Reviewer: Disable for conversation",
1159
+ lifetime: "Reviewer: Lifetime usage"
1160
+ },
1161
+ sessionMode: {
1162
+ saved: (enabled) => enabled ? "Reviewer enabled for this conversation." : "Reviewer disabled for this conversation.",
1163
+ saveFailed: (enabled) => enabled ? "Reviewer enabled locally, but saving failed. Resume may use the previous setting." : "Reviewer disabled locally, but saving failed. Resume may use the previous setting.",
1164
+ unavailable: "Reviewer setting unavailable. Session ancestry or saved mode could not be read."
1165
+ },
1166
+ usage: {
1167
+ tokens: (input, output) => `token: ${input} in ${output} out`,
1168
+ cost: (amount2) => `cost: $${amount2}`
1169
+ },
1170
+ lifetime: {
1171
+ title: "Reviewer lifetime usage",
1172
+ loading: "Loading recorded usage\u2026",
1173
+ unavailable: "Lifetime usage unavailable. Recorded totals have not been reset.",
1174
+ inlineUnavailable: "lifetime: usage unavailable",
1175
+ empty: "lifetime: no recorded usage",
1176
+ costUnavailable: "lifetime: cost unavailable",
1177
+ cost: (amount2, partial) => `lifetime: $${amount2}${partial ? " (partial pricing)" : ""}`,
1178
+ requests: (count3) => `${count3} requests with recorded usage`,
1179
+ tokens: (input, output, partial) => `token: ${input} in ${output} out${partial ? " (partial coverage)" : ""}`,
1180
+ tokensUnavailable: "tokens unavailable",
1181
+ tokenCoverage: (available, total) => `Token counts available: ${available}/${total} requests`,
1182
+ pricingCoverage: (available, total) => `Pricing available: ${available}/${total} requests`,
1183
+ since: (date) => `Recorded since: ${date}`,
1184
+ explanation: "Received usage only, including interrupted or unsuccessful reviews. Unreported charges remain unknown. Costs combine endpoint-reported amounts and catalog estimates; legacy history retains its original estimates. Earlier unrecorded usage cannot be recovered."
1185
+ },
1186
+ notifications: {
1187
+ application: "Opencode",
1188
+ heading: (session) => `Opencode (${session})`,
1189
+ openSession: "Open session",
1190
+ fallbackSession: "OpenCode session",
1191
+ attention: "Session needs attention",
1192
+ countdown: (seconds) => `Reviewer will approve permission in ${seconds} s`,
1193
+ approved: "Reviewer approved a permission",
1194
+ error: "Session error",
1195
+ ended: "Session ended",
1196
+ // Arguments are escaped by the desktop adapter before formatting.
1197
+ body: (event) => event
1198
+ }
1199
+ };
1200
+
1201
+ // src/usage.ts
1131
1202
  var record = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
1132
1203
  var count = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
1133
1204
  var rate = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0;
@@ -1217,8 +1288,8 @@ function sumUsage(previous, next) {
1217
1288
  }
1218
1289
  function usageText(usage) {
1219
1290
  return [
1220
- ...count(usage.input) && count(usage.output) ? [`token: ${usage.input} in ${usage.output} out`] : [],
1221
- ...usage.cost === void 0 ? [] : [`cost: $${usage.cost.toFixed(4)}`]
1291
+ ...count(usage.input) && count(usage.output) ? [uiText.usage.tokens(usage.input, usage.output)] : [],
1292
+ ...usage.cost === void 0 ? [] : [uiText.usage.cost(usage.cost.toFixed(4))]
1222
1293
  ].join("\n");
1223
1294
  }
1224
1295
 
@@ -2222,7 +2293,7 @@ var Controller = class {
2222
2293
  }, (error) => {
2223
2294
  this.clearProgress(entry);
2224
2295
  if (active()) {
2225
- entry.view = { ...entry.view, status: entry.view.status === "identifying" ? "unidentified" : "unavailable", progress: void 0, error: error instanceof Error ? error.message : "Review failed" };
2296
+ entry.view = { ...entry.view, status: entry.view.status === "identifying" ? "unidentified" : "unavailable", progress: void 0, error: error instanceof Error ? error.message : uiText.review.failed };
2226
2297
  this.publish();
2227
2298
  }
2228
2299
  });
@@ -3344,7 +3415,7 @@ async function evaluateEvidence(request, reader2, options, config, configError,
3344
3415
  if (!classified) return null;
3345
3416
  if (!enabledKind(classified.kind, options)) return null;
3346
3417
  onIdentified();
3347
- if (!config) throw new Error(configError || "Invalid configuration");
3418
+ if (!config) throw new Error(configError || uiText.review.invalidConfiguration);
3348
3419
  const scope = files.scope(signal);
3349
3420
  if (classified.kind === "shell") {
3350
3421
  const context = await loadContext(request, reader2, signal, scope, invocation);
@@ -3601,20 +3672,20 @@ var LifetimeUsage = class {
3601
3672
  }
3602
3673
  };
3603
3674
  function lifetimeCost(totals) {
3604
- if (!totals.requests) return "lifetime: no recorded usage";
3605
- if (!totals.priced) return "lifetime: cost unavailable";
3606
- return `lifetime: $${totals.cost.toFixed(4)}${totals.priced < totals.requests ? " (partial pricing)" : ""}`;
3675
+ if (!totals.requests) return uiText.lifetime.empty;
3676
+ if (!totals.priced) return uiText.lifetime.costUnavailable;
3677
+ return uiText.lifetime.cost(totals.cost.toFixed(4), totals.priced < totals.requests);
3607
3678
  }
3608
3679
  function lifetimeReport(totals) {
3609
3680
  return [
3610
3681
  lifetimeCost(totals),
3611
- `${totals.requests} requests with recorded usage`,
3612
- totals.tokenRequests ? `token: ${totals.input} in ${totals.output} out${totals.tokenRequests < totals.requests ? " (partial coverage)" : ""}` : "tokens unavailable",
3613
- `Token counts available: ${totals.tokenRequests}/${totals.requests} requests`,
3614
- `Pricing available: ${totals.priced}/${totals.requests} requests`,
3615
- ...totals.since === null ? [] : [`Recorded since: ${new Date(totals.since).toISOString().slice(0, 10)}`],
3682
+ uiText.lifetime.requests(totals.requests),
3683
+ totals.tokenRequests ? uiText.lifetime.tokens(totals.input, totals.output, totals.tokenRequests < totals.requests) : uiText.lifetime.tokensUnavailable,
3684
+ uiText.lifetime.tokenCoverage(totals.tokenRequests, totals.requests),
3685
+ uiText.lifetime.pricingCoverage(totals.priced, totals.requests),
3686
+ ...totals.since === null ? [] : [uiText.lifetime.since(new Date(totals.since).toISOString().slice(0, 10))],
3616
3687
  "",
3617
- "Received usage only, including interrupted or unsuccessful reviews. Unreported charges remain unknown. Costs combine endpoint-reported amounts and catalog estimates; legacy history retains its original estimates. Earlier unrecorded usage cannot be recovered."
3688
+ uiText.lifetime.explanation
3618
3689
  ].join("\n");
3619
3690
  }
3620
3691
 
@@ -3713,14 +3784,16 @@ function lifetimeTracker(api) {
3713
3784
  commands: [{
3714
3785
  name: "opencode-reviewer.lifetime",
3715
3786
  namespace: "palette",
3716
- title: "Reviewer: Lifetime usage",
3717
- category: "Reviewer",
3787
+ title: uiText.commands.lifetime,
3788
+ category: uiText.commands.category,
3718
3789
  run: () => {
3719
3790
  refresh.refresh();
3720
3791
  api.ui.dialog.replace(() => _$createComponent(api.ui.DialogAlert, {
3721
- title: "Reviewer lifetime usage",
3792
+ get title() {
3793
+ return uiText.lifetime.title;
3794
+ },
3722
3795
  get message() {
3723
- return _$memo(() => !!unavailable())() ? "Lifetime usage unavailable. Recorded totals have not been reset." : _$memo(() => !!totals())() ? lifetimeReport(totals()) : "Loading recorded usage\u2026";
3796
+ return _$memo(() => !!unavailable())() ? uiText.lifetime.unavailable : _$memo(() => !!totals())() ? lifetimeReport(totals()) : uiText.lifetime.loading;
3724
3797
  }
3725
3798
  }));
3726
3799
  }
@@ -3735,7 +3808,7 @@ function lifetimeTracker(api) {
3735
3808
  // The controller must settle aborted review workers before this final queue drain.
3736
3809
  flush: () => store.flush().catch(() => {
3737
3810
  }),
3738
- text: () => unavailable() ? "lifetime: usage unavailable" : totals()?.requests ? lifetimeCost(totals()) : void 0,
3811
+ text: () => unavailable() ? uiText.lifetime.inlineUnavailable : totals()?.requests ? lifetimeCost(totals()) : void 0,
3739
3812
  record: (usage) => {
3740
3813
  void store.record(usage).then(() => refresh.refresh(), () => refresh.failed());
3741
3814
  }
@@ -3939,8 +4012,8 @@ function sessionModeCommands(api, modes, changed) {
3939
4012
  name: `opencode-reviewer.${enabled ? "enable" : "disable"}`,
3940
4013
  namespace: "palette",
3941
4014
  slashName: `reviewer-${enabled ? "enable" : "disable"}`,
3942
- title: `Reviewer: ${enabled ? "Enable" : "Disable"} for conversation`,
3943
- category: "Reviewer",
4015
+ title: enabled ? uiText.commands.enable : uiText.commands.disable,
4016
+ category: uiText.commands.category,
3944
4017
  enabled: () => selected() !== void 0,
3945
4018
  run: async () => {
3946
4019
  const sessionID = selected();
@@ -3961,10 +4034,10 @@ function sessionModeCommands(api, modes, changed) {
3961
4034
  await persisted;
3962
4035
  if (!api.lifecycle.signal.aborted && latest.get(root) === order) api.ui.toast({
3963
4036
  variant: "success",
3964
- message: `Reviewer ${enabled ? "enabled" : "disabled"} for this conversation and descendants. Saved for resume.`
4037
+ message: uiText.sessionMode.saved(enabled)
3965
4038
  });
3966
4039
  } catch {
3967
- if (!api.lifecycle.signal.aborted && (root === void 0 || latest.get(root) === order)) api.ui.toast({ variant: "error", message: applied ? `Reviewer ${enabled ? "enabled" : "disabled"} locally, but saving failed. Resume may use the previous setting.` : "Reviewer setting unavailable. Session ancestry or saved mode could not be read." });
4040
+ if (!api.lifecycle.signal.aborted && (root === void 0 || latest.get(root) === order)) api.ui.toast({ variant: "error", message: applied ? uiText.sessionMode.saveFailed(enabled) : uiText.sessionMode.unavailable });
3968
4041
  }
3969
4042
  }
3970
4043
  })) });
@@ -3985,7 +4058,7 @@ var notificationClock = {
3985
4058
  }
3986
4059
  };
3987
4060
  function notificationText(value) {
3988
- return Array.from(value.replace(/[\u0000-\u001f\u007f-\u009f\u202a-\u202e\u2066-\u2069]/g, " ")).slice(0, 256).join("").trim() || "OpenCode session";
4061
+ return Array.from(value.replace(/[\u0000-\u001f\u007f-\u009f\u202a-\u202e\u2066-\u2069]/g, " ")).slice(0, 256).join("").trim() || uiText.notifications.fallbackSession;
3989
4062
  }
3990
4063
  function notificationMarkup(value) {
3991
4064
  return notificationText(value).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
@@ -4082,7 +4155,7 @@ var NotificationPolicy = class {
4082
4155
  if (entry.phase === "attention") return;
4083
4156
  this.withdraw(entry.banner);
4084
4157
  entry.phase = "attention";
4085
- entry.banner = this.show("attention", "Session needs attention", entry.target);
4158
+ entry.banner = this.show("attention", uiText.notifications.attention, entry.target);
4086
4159
  }
4087
4160
  snapshot(views) {
4088
4161
  if (this.stopped) return;
@@ -4103,7 +4176,7 @@ var NotificationPolicy = class {
4103
4176
  if (entry.phase !== "automatic") {
4104
4177
  this.withdraw(entry.banner);
4105
4178
  entry.phase = "automatic";
4106
- entry.banner = state === "countdown" && this.delay > 0 ? this.show("attention", `Reviewer will approve permission in ${view.autoApproval.status === "countdown" ? view.autoApproval.seconds : this.delay} s`, entry.target) : void 0;
4179
+ entry.banner = state === "countdown" && this.delay > 0 ? this.show("attention", uiText.notifications.countdown(view.autoApproval.status === "countdown" ? view.autoApproval.seconds : this.delay), entry.target) : void 0;
4107
4180
  }
4108
4181
  return;
4109
4182
  }
@@ -4135,7 +4208,7 @@ var NotificationPolicy = class {
4135
4208
  approved(request, target) {
4136
4209
  if (!this.remember(`approved:${request.id}`)) return;
4137
4210
  const current = this.permissions.get(request.id);
4138
- if (current || target) this.show("approved", "Reviewer approved a permission", current?.target ?? target);
4211
+ if (current || target) this.show("approved", uiText.notifications.approved, current?.target ?? target);
4139
4212
  }
4140
4213
  resolved(kind, id) {
4141
4214
  const entries = kind === "permission" ? this.permissions : this.questions;
@@ -4146,7 +4219,7 @@ var NotificationPolicy = class {
4146
4219
  this.remember(`${kind}:${id}`);
4147
4220
  }
4148
4221
  turn(kind, id, target) {
4149
- if (this.remember(`turn:${target.root}:${id}`)) this.show(kind, kind === "error" ? "Session error" : "Session ended", target);
4222
+ if (this.remember(`turn:${target.root}:${id}`)) this.show(kind, uiText.notifications[kind], target);
4150
4223
  }
4151
4224
  deleted(sessionID) {
4152
4225
  for (const banner of this.banners) if (banner.target.root === sessionID || banner.target.sessionID === sessionID) this.withdraw(banner);
@@ -4313,7 +4386,7 @@ var NotificationHost = class {
4313
4386
  }
4314
4387
  const root = this.roots.get(rootID);
4315
4388
  if (!root || request.received < root.since) return;
4316
- const target = { root: rootID, sessionID: rootID, title: this.api.state.session.get(rootID)?.title ?? "OpenCode session" };
4389
+ const target = { root: rootID, sessionID: rootID, title: this.api.state.session.get(rootID)?.title ?? uiText.notifications.fallbackSession };
4317
4390
  request.target = target;
4318
4391
  if (kind === "question") this.policy.question(id, target, true);
4319
4392
  else {
@@ -4327,7 +4400,7 @@ var NotificationHost = class {
4327
4400
  if (this.stopped) return;
4328
4401
  this.views = views;
4329
4402
  for (const request of this.permissions.values()) if (request.target) {
4330
- request.target.title = this.api.state.session.get(request.target.root)?.title ?? "OpenCode session";
4403
+ request.target.title = this.api.state.session.get(request.target.root)?.title ?? uiText.notifications.fallbackSession;
4331
4404
  }
4332
4405
  this.policy.snapshot(views);
4333
4406
  for (const [id, request] of this.permissions) this.admit("permission", id, request);
@@ -4343,7 +4416,7 @@ var NotificationHost = class {
4343
4416
  const dispatched = this.dispatched.get(fact.request.id);
4344
4417
  this.dispatched.delete(fact.request.id);
4345
4418
  if (dispatched?.automatic) {
4346
- dispatched.target.title = this.api.state.session.get(dispatched.target.root)?.title ?? "OpenCode session";
4419
+ dispatched.target.title = this.api.state.session.get(dispatched.target.root)?.title ?? uiText.notifications.fallbackSession;
4347
4420
  this.policy.approved(fact.request, dispatched.target);
4348
4421
  }
4349
4422
  } else this.dispatched.delete(fact.request.id);
@@ -4392,7 +4465,7 @@ var NotificationHost = class {
4392
4465
  if (assistant?.role === "assistant") root.assistant = assistant;
4393
4466
  if (root.assistant?.error?.name === "MessageAbortedError" || root.error?.name === "MessageAbortedError") return;
4394
4467
  if (this.views.some((v) => this.rootOf(v.request.sessionID) === id) || [...this.questions.values()].some((q) => this.rootOf(q.sessionID) === id) || this.api.state.session.question(id).length || this.api.state.session.permission(id).length) return;
4395
- const target = { root: id, sessionID: id, title: this.api.state.session.get(id)?.title ?? "OpenCode session" };
4468
+ const target = { root: id, sessionID: id, title: this.api.state.session.get(id)?.title ?? uiText.notifications.fallbackSession };
4396
4469
  const message = root.assistant;
4397
4470
  if (message?.error || root.error && (!message?.time.completed || !message.finish || message.finish === "error")) {
4398
4471
  this.policy.turn("error", root.user ?? root.error.id, target);
@@ -5712,7 +5785,7 @@ var LinuxNotifications = class {
5712
5785
  const process2 = this.start(
5713
5786
  "notify-send",
5714
5787
  [
5715
- "--app-name=Opencode",
5788
+ `--app-name=${uiText.notifications.application}`,
5716
5789
  ...icon ? [`--icon=${icon}`] : [],
5717
5790
  // GNOME uses the desktop-entry's source icon, ignoring --icon there.
5718
5791
  // image-path supplies the separate image beside the notification heading.
@@ -5724,13 +5797,12 @@ var LinuxNotifications = class {
5724
5797
  "--print-id",
5725
5798
  // GNOME emits an activation token only for a recognized application.
5726
5799
  ...this.identity ? ["--hint=string:desktop-entry:org.gnome.Terminal"] : [],
5727
- ...this.identity ? ["--action=default=Open session"] : [],
5800
+ ...this.identity ? [`--action=default=${uiText.notifications.openSession}`] : [],
5728
5801
  "--wait",
5729
5802
  "--",
5730
- "Opencode",
5731
- // GNOME flattens newlines in collapsed banners. Keep an explicit separator
5732
- // so the session title cannot run into the event message.
5733
- `${notificationMarkup(message.title)} \xB7 ${notificationMarkup(message.body)}`.replaceAll("\\", "\\\\")
5803
+ // Summaries are plain text; only the body supports desktop markup.
5804
+ uiText.notifications.heading(notificationText(message.body)).replaceAll("\\", "\\\\"),
5805
+ uiText.notifications.body(notificationMarkup(message.title)).replaceAll("\\", "\\\\")
5734
5806
  ],
5735
5807
  12e4,
5736
5808
  AbortSignal.any([local.signal, this.abort.signal]),
@@ -5795,13 +5867,16 @@ function ReviewLoading(props) {
5795
5867
  onCleanup(() => clearInterval(timer));
5796
5868
  });
5797
5869
  return (() => {
5798
- var _el$ = _$createElement("text");
5870
+ var _el$ = _$createElement("text"), _el$2 = _$createTextNode(` `);
5871
+ _$insertNode(_el$, _el$2);
5799
5872
  _$setProp(_el$, "height", 1);
5800
5873
  _$insert(_el$, _$createComponent2(Show, {
5801
5874
  get when() {
5802
5875
  return animated();
5803
5876
  },
5804
- fallback: "[\u22EF]",
5877
+ get fallback() {
5878
+ return uiText.review.staticIndicator;
5879
+ },
5805
5880
  get children() {
5806
5881
  return _$createComponent2(Index, {
5807
5882
  get each() {
@@ -5817,18 +5892,21 @@ function ReviewLoading(props) {
5817
5892
  return RGBA.fromValues(Math.min(1, base.r * brightness), Math.min(1, base.g * brightness), Math.min(1, base.b * brightness), alpha);
5818
5893
  });
5819
5894
  return (() => {
5820
- var _el$2 = _$createElement("span");
5821
- _$insert(_el$2, () => cell().character);
5822
- _$effect((_$p) => _$setProp(_el$2, "style", {
5895
+ var _el$3 = _$createElement("span");
5896
+ _$insert(_el$3, () => cell().character);
5897
+ _$effect((_$p) => _$setProp(_el$3, "style", {
5823
5898
  fg: color()
5824
5899
  }, _$p));
5825
- return _el$2;
5900
+ return _el$3;
5826
5901
  })();
5827
5902
  }
5828
5903
  });
5829
5904
  }
5830
- }), null);
5831
- _$insert(_el$, () => props.retrying ? " Retrying" : " Evaluating", null);
5905
+ }), _el$2);
5906
+ _$insert(_el$, (() => {
5907
+ var _c$ = _$memo2(() => !!props.retrying);
5908
+ return () => _c$() ? uiText.review.retrying : uiText.review.evaluating;
5909
+ })(), null);
5832
5910
  _$effect((_$p) => _$setProp(_el$, "fg", props.api.theme.current.textMuted, _$p));
5833
5911
  return _el$;
5834
5912
  })();
@@ -5843,21 +5921,21 @@ function ReviewDescription(props) {
5843
5921
  return syntax;
5844
5922
  });
5845
5923
  return (() => {
5846
- var _el$3 = _$createElement("markdown");
5924
+ var _el$4 = _$createElement("markdown");
5847
5925
  var _ref$ = props.ref;
5848
- typeof _ref$ === "function" ? _$use(_ref$, _el$3) : props.ref = _el$3;
5849
- _$setProp(_el$3, "conceal", true);
5850
- _$setProp(_el$3, "tableOptions", {
5926
+ typeof _ref$ === "function" ? _$use(_ref$, _el$4) : props.ref = _el$4;
5927
+ _$setProp(_el$4, "conceal", true);
5928
+ _$setProp(_el$4, "tableOptions", {
5851
5929
  style: "grid"
5852
5930
  });
5853
- _$setProp(_el$3, "width", "100%");
5854
- _$setProp(_el$3, "flexShrink", 0);
5931
+ _$setProp(_el$4, "width", "100%");
5932
+ _$setProp(_el$4, "flexShrink", 0);
5855
5933
  _$effect((_p$) => {
5856
5934
  var _v$ = displayText(props.text), _v$2 = style(), _v$3 = props.api.theme.current.markdownText, _v$4 = props.streaming;
5857
- _v$ !== _p$.e && (_p$.e = _$setProp(_el$3, "content", _v$, _p$.e));
5858
- _v$2 !== _p$.t && (_p$.t = _$setProp(_el$3, "syntaxStyle", _v$2, _p$.t));
5859
- _v$3 !== _p$.a && (_p$.a = _$setProp(_el$3, "fg", _v$3, _p$.a));
5860
- _v$4 !== _p$.o && (_p$.o = _$setProp(_el$3, "streaming", _v$4, _p$.o));
5935
+ _v$ !== _p$.e && (_p$.e = _$setProp(_el$4, "content", _v$, _p$.e));
5936
+ _v$2 !== _p$.t && (_p$.t = _$setProp(_el$4, "syntaxStyle", _v$2, _p$.t));
5937
+ _v$3 !== _p$.a && (_p$.a = _$setProp(_el$4, "fg", _v$3, _p$.a));
5938
+ _v$4 !== _p$.o && (_p$.o = _$setProp(_el$4, "streaming", _v$4, _p$.o));
5861
5939
  return _p$;
5862
5940
  }, {
5863
5941
  e: void 0,
@@ -5865,7 +5943,7 @@ function ReviewDescription(props) {
5865
5943
  a: void 0,
5866
5944
  o: void 0
5867
5945
  });
5868
- return _el$3;
5946
+ return _el$4;
5869
5947
  })();
5870
5948
  }
5871
5949
  function highlightingComplete(node) {
@@ -5888,28 +5966,28 @@ function ReviewButton(props) {
5888
5966
  return 0.299 * r + 0.587 * g + 0.114 * b > 0.5 ? RGBA.fromInts(0, 0, 0) : RGBA.fromInts(255, 255, 255);
5889
5967
  };
5890
5968
  return (() => {
5891
- var _el$4 = _$createElement("box"), _el$5 = _$createElement("text");
5892
- _$insertNode(_el$4, _el$5);
5893
- _$setProp(_el$4, "paddingLeft", 1);
5894
- _$setProp(_el$4, "paddingRight", 1);
5895
- _$setProp(_el$4, "onMouseOver", () => {
5969
+ var _el$5 = _$createElement("box"), _el$6 = _$createElement("text");
5970
+ _$insertNode(_el$5, _el$6);
5971
+ _$setProp(_el$5, "paddingLeft", 1);
5972
+ _$setProp(_el$5, "paddingRight", 1);
5973
+ _$setProp(_el$5, "onMouseOver", () => {
5896
5974
  if (!props.disabled) props.onHover?.();
5897
5975
  });
5898
- _$setProp(_el$4, "onMouseUp", (event) => {
5976
+ _$setProp(_el$5, "onMouseUp", (event) => {
5899
5977
  event.stopPropagation();
5900
5978
  if (event.button === 0 && !props.disabled) props.onClick();
5901
5979
  });
5902
- _$insert(_el$5, () => props.label);
5980
+ _$insert(_el$6, () => props.label);
5903
5981
  _$effect((_p$) => {
5904
5982
  var _v$5 = selected() ? props.api.theme.current.warning : props.api.theme.current.backgroundMenu, _v$6 = foreground();
5905
- _v$5 !== _p$.e && (_p$.e = _$setProp(_el$4, "backgroundColor", _v$5, _p$.e));
5906
- _v$6 !== _p$.t && (_p$.t = _$setProp(_el$5, "fg", _v$6, _p$.t));
5983
+ _v$5 !== _p$.e && (_p$.e = _$setProp(_el$5, "backgroundColor", _v$5, _p$.e));
5984
+ _v$6 !== _p$.t && (_p$.t = _$setProp(_el$6, "fg", _v$6, _p$.t));
5907
5985
  return _p$;
5908
5986
  }, {
5909
5987
  e: void 0,
5910
5988
  t: void 0
5911
5989
  });
5912
- return _el$4;
5990
+ return _el$5;
5913
5991
  })();
5914
5992
  }
5915
5993
  function ReviewFooter(props) {
@@ -5917,30 +5995,30 @@ function ReviewFooter(props) {
5917
5995
  const state = () => props.view.autoApproval;
5918
5996
  const label = () => {
5919
5997
  const current = state();
5920
- return current?.status === "countdown" ? `Allowed in ${current.seconds}s` : "Checking\u2026";
5998
+ return current?.status === "countdown" ? uiText.autoApproval.countdown(current.seconds) : uiText.autoApproval.checking;
5921
5999
  };
5922
6000
  return _$createComponent2(Show, {
5923
6001
  get when() {
5924
6002
  return _$memo2(() => !!props.enabled)() && props.view.assessment?.safe;
5925
6003
  },
5926
6004
  get children() {
5927
- var _el$6 = _$createElement("box");
5928
- _$setProp(_el$6, "marginTop", 1);
5929
- _$setProp(_el$6, "paddingTop", 1);
5930
- _$setProp(_el$6, "minHeight", 3);
5931
- _$setProp(_el$6, "flexShrink", 0);
5932
- _$setProp(_el$6, "border", ["top"]);
5933
- _$insert(_el$6, _$createComponent2(Switch, {
6005
+ var _el$7 = _$createElement("box");
6006
+ _$setProp(_el$7, "marginTop", 1);
6007
+ _$setProp(_el$7, "paddingTop", 1);
6008
+ _$setProp(_el$7, "minHeight", 3);
6009
+ _$setProp(_el$7, "flexShrink", 0);
6010
+ _$setProp(_el$7, "border", ["top"]);
6011
+ _$insert(_el$7, _$createComponent2(Switch, {
5934
6012
  get children() {
5935
6013
  return [_$createComponent2(Match, {
5936
6014
  get when() {
5937
6015
  return state()?.status === "countdown" || state()?.status === "checking";
5938
6016
  },
5939
6017
  get children() {
5940
- var _el$7 = _$createElement("box");
5941
- _$setProp(_el$7, "flexDirection", "row");
5942
- _$setProp(_el$7, "gap", 1);
5943
- _$insert(_el$7, _$createComponent2(ReviewButton, {
6018
+ var _el$8 = _$createElement("box");
6019
+ _$setProp(_el$8, "flexDirection", "row");
6020
+ _$setProp(_el$8, "gap", 1);
6021
+ _$insert(_el$8, _$createComponent2(ReviewButton, {
5944
6022
  get api() {
5945
6023
  return props.api;
5946
6024
  },
@@ -5958,18 +6036,20 @@ function ReviewFooter(props) {
5958
6036
  void props.controller.approveNow(props.view.request.id);
5959
6037
  }
5960
6038
  }), null);
5961
- _$insert(_el$7, _$createComponent2(ReviewButton, {
6039
+ _$insert(_el$8, _$createComponent2(ReviewButton, {
5962
6040
  get api() {
5963
6041
  return props.api;
5964
6042
  },
5965
- label: "Cancel",
6043
+ get label() {
6044
+ return uiText.autoApproval.cancel;
6045
+ },
5966
6046
  get selected() {
5967
6047
  return selected() === "cancel";
5968
6048
  },
5969
6049
  onHover: () => setSelected("cancel"),
5970
6050
  onClick: () => props.controller.cancelAutoApproval(props.view.request.id)
5971
6051
  }), null);
5972
- return _el$7;
6052
+ return _el$8;
5973
6053
  }
5974
6054
  }), _$createComponent2(Match, {
5975
6055
  get when() {
@@ -5980,7 +6060,9 @@ function ReviewFooter(props) {
5980
6060
  get api() {
5981
6061
  return props.api;
5982
6062
  },
5983
- label: "Allowing\u2026",
6063
+ get label() {
6064
+ return uiText.autoApproval.allowing;
6065
+ },
5984
6066
  disabled: true,
5985
6067
  onClick: () => {
5986
6068
  }
@@ -5991,10 +6073,10 @@ function ReviewFooter(props) {
5991
6073
  return state()?.status === "cancelled";
5992
6074
  },
5993
6075
  get children() {
5994
- var _el$8 = _$createElement("text");
5995
- _$insertNode(_el$8, _$createTextNode(`Auto-approval canceled`));
5996
- _$effect((_$p) => _$setProp(_el$8, "fg", props.api.theme.current.textMuted, _$p));
5997
- return _el$8;
6076
+ var _el$9 = _$createElement("text");
6077
+ _$insert(_el$9, () => uiText.autoApproval.cancelled);
6078
+ _$effect((_$p) => _$setProp(_el$9, "fg", props.api.theme.current.textMuted, _$p));
6079
+ return _el$9;
5998
6080
  }
5999
6081
  }), _$createComponent2(Match, {
6000
6082
  get when() {
@@ -6002,15 +6084,15 @@ function ReviewFooter(props) {
6002
6084
  },
6003
6085
  get children() {
6004
6086
  var _el$0 = _$createElement("text");
6005
- _$insertNode(_el$0, _$createTextNode(`! Auto-approval unavailable. Use native controls.`));
6087
+ _$insert(_el$0, () => uiText.autoApproval.unavailable);
6006
6088
  _$effect((_$p) => _$setProp(_el$0, "fg", props.api.theme.current.warning, _$p));
6007
6089
  return _el$0;
6008
6090
  }
6009
6091
  })];
6010
6092
  }
6011
6093
  }));
6012
- _$effect((_$p) => _$setProp(_el$6, "borderColor", props.api.theme.current.borderSubtle, _$p));
6013
- return _el$6;
6094
+ _$effect((_$p) => _$setProp(_el$7, "borderColor", props.api.theme.current.borderSubtle, _$p));
6095
+ return _el$7;
6014
6096
  }
6015
6097
  });
6016
6098
  }
@@ -6090,7 +6172,7 @@ async function reviewTui(api, options, fileIO, observer, notificationBackend) {
6090
6172
  prompts = await withDeadline(api.lifecycle.signal, parsed.timeoutMs, (signal) => loadPrompts(parsed.instructions, signal), "Prompt loading");
6091
6173
  config = parsed;
6092
6174
  } catch (error) {
6093
- configError = error instanceof Error ? error.message : "Invalid configuration";
6175
+ configError = error instanceof Error ? error.message : uiText.review.invalidConfiguration;
6094
6176
  }
6095
6177
  api.lifecycle.signal.throwIfAborted();
6096
6178
  const lifetime = lifetimeTracker(api);
@@ -6265,45 +6347,48 @@ async function reviewTui(api, options, fileIO, observer, notificationBackend) {
6265
6347
  // The app slot lets this cover its title, sections, and footer while
6266
6348
  // the original sidebar remains mounted beneath it.
6267
6349
  (() => {
6268
- var _el$10 = _$createElement("box"), _el$11 = _$createElement("text"), _el$12 = _$createElement("b"), _el$14 = _$createElement("box"), _el$20 = _$createElement("scrollbox");
6269
- _$insertNode(_el$10, _el$11);
6270
- _$insertNode(_el$10, _el$14);
6271
- _$insertNode(_el$10, _el$20);
6350
+ var _el$1 = _$createElement("box"), _el$10 = _$createElement("text"), _el$11 = _$createElement("b"), _el$12 = _$createElement("box"), _el$17 = _$createElement("scrollbox");
6351
+ _$insertNode(_el$1, _el$10);
6352
+ _$insertNode(_el$1, _el$12);
6353
+ _$insertNode(_el$1, _el$17);
6272
6354
  _$use((value) => {
6273
6355
  panel = value;
6274
- }, _el$10);
6275
- _$setProp(_el$10, "renderAfter", () => {
6356
+ }, _el$1);
6357
+ _$setProp(_el$1, "renderAfter", () => {
6276
6358
  const assessment = view().assessment;
6277
6359
  if (assessment && paintedAssessment !== assessment && description && !description.isDestroyed && !description.streaming && description.content === displayText(assessment.desc) && description.getChildrenCount() && highlightingComplete(description)) paintedAssessment = assessment;
6278
6360
  });
6279
- _$setProp(_el$10, "position", "absolute");
6280
- _$setProp(_el$10, "top", 0);
6281
- _$setProp(_el$10, "right", 0);
6282
- _$setProp(_el$10, "bottom", 0);
6283
- _$setProp(_el$10, "width", 42);
6284
- _$setProp(_el$10, "zIndex", 1);
6285
- _$setProp(_el$10, "paddingTop", 1);
6286
- _$setProp(_el$10, "paddingBottom", 1);
6287
- _$setProp(_el$10, "paddingLeft", 2);
6288
- _$setProp(_el$10, "paddingRight", 2);
6289
- _$insertNode(_el$11, _el$12);
6290
- _$setProp(_el$11, "flexShrink", 0);
6291
- _$insertNode(_el$12, _$createTextNode(`Permission analysis`));
6292
- _$setProp(_el$14, "marginTop", 1);
6293
- _$setProp(_el$14, "flexShrink", 0);
6294
- _$insert(_el$14, _$createComponent2(Show, {
6361
+ _$setProp(_el$1, "position", "absolute");
6362
+ _$setProp(_el$1, "top", 0);
6363
+ _$setProp(_el$1, "right", 0);
6364
+ _$setProp(_el$1, "bottom", 0);
6365
+ _$setProp(_el$1, "width", 42);
6366
+ _$setProp(_el$1, "zIndex", 1);
6367
+ _$setProp(_el$1, "paddingTop", 1);
6368
+ _$setProp(_el$1, "paddingBottom", 1);
6369
+ _$setProp(_el$1, "paddingLeft", 2);
6370
+ _$setProp(_el$1, "paddingRight", 2);
6371
+ _$insertNode(_el$10, _el$11);
6372
+ _$setProp(_el$10, "flexShrink", 0);
6373
+ _$insert(_el$11, () => uiText.review.heading);
6374
+ _$setProp(_el$12, "marginTop", 1);
6375
+ _$setProp(_el$12, "flexShrink", 0);
6376
+ _$insert(_el$12, _$createComponent2(Show, {
6295
6377
  get when() {
6296
6378
  return rating() !== void 0;
6297
6379
  },
6298
6380
  get children() {
6299
- var _el$15 = _$createElement("text"), _el$16 = _$createElement("b");
6300
- _$insertNode(_el$15, _el$16);
6301
- _$insert(_el$16, () => rating() ? "\u2713 Safe" : "\u2717 Unsafe");
6302
- _$effect((_$p) => _$setProp(_el$15, "fg", rating() ? api.theme.current.success : api.theme.current.error, _$p));
6303
- return _el$15;
6381
+ var _el$13 = _$createElement("text"), _el$14 = _$createElement("b");
6382
+ _$insertNode(_el$13, _el$14);
6383
+ _$insert(_el$14, (() => {
6384
+ var _c$2 = _$memo2(() => !!rating());
6385
+ return () => _c$2() ? uiText.review.safe : uiText.review.unsafe;
6386
+ })());
6387
+ _$effect((_$p) => _$setProp(_el$13, "fg", rating() ? api.theme.current.success : api.theme.current.error, _$p));
6388
+ return _el$13;
6304
6389
  }
6305
6390
  }), null);
6306
- _$insert(_el$14, _$createComponent2(Show, {
6391
+ _$insert(_el$12, _$createComponent2(Show, {
6307
6392
  get when() {
6308
6393
  return _$memo2(() => view().status === "analyzing")() && rating() === void 0;
6309
6394
  },
@@ -6316,28 +6401,28 @@ async function reviewTui(api, options, fileIO, observer, notificationBackend) {
6316
6401
  });
6317
6402
  }
6318
6403
  }), null);
6319
- _$insert(_el$14, _$createComponent2(Show, {
6404
+ _$insert(_el$12, _$createComponent2(Show, {
6320
6405
  get when() {
6321
6406
  return view().status === "unavailable";
6322
6407
  },
6323
6408
  get children() {
6324
- var _el$17 = _$createElement("text"), _el$18 = _$createElement("b");
6325
- _$insertNode(_el$17, _el$18);
6326
- _$insertNode(_el$18, _$createTextNode(`! Analysis unavailable`));
6327
- _$effect((_$p) => _$setProp(_el$17, "fg", api.theme.current.warning, _$p));
6328
- return _el$17;
6409
+ var _el$15 = _$createElement("text"), _el$16 = _$createElement("b");
6410
+ _$insertNode(_el$15, _el$16);
6411
+ _$insert(_el$16, () => uiText.review.unavailable);
6412
+ _$effect((_$p) => _$setProp(_el$15, "fg", api.theme.current.warning, _$p));
6413
+ return _el$15;
6329
6414
  }
6330
6415
  }), null);
6331
6416
  _$use((value) => {
6332
6417
  scroll = value;
6333
- }, _el$20);
6334
- _$setProp(_el$20, "marginTop", 1);
6335
- _$setProp(_el$20, "flexGrow", 1);
6336
- _$setProp(_el$20, "minHeight", 0);
6337
- _$setProp(_el$20, "contentOptions", {
6418
+ }, _el$17);
6419
+ _$setProp(_el$17, "marginTop", 1);
6420
+ _$setProp(_el$17, "flexGrow", 1);
6421
+ _$setProp(_el$17, "minHeight", 0);
6422
+ _$setProp(_el$17, "contentOptions", {
6338
6423
  minHeight: 0
6339
6424
  });
6340
- _$insert(_el$20, _$createComponent2(ReviewDescription, {
6425
+ _$insert(_el$17, _$createComponent2(ReviewDescription, {
6341
6426
  api,
6342
6427
  get text() {
6343
6428
  return report();
@@ -6349,46 +6434,46 @@ async function reviewTui(api, options, fileIO, observer, notificationBackend) {
6349
6434
  description = value;
6350
6435
  }
6351
6436
  }), null);
6352
- _$insert(_el$20, _$createComponent2(Show, {
6437
+ _$insert(_el$17, _$createComponent2(Show, {
6353
6438
  get when() {
6354
6439
  return view().status === "unavailable";
6355
6440
  },
6356
6441
  get children() {
6357
- var _el$21 = _$createElement("text");
6358
- _$setProp(_el$21, "width", "100%");
6359
- _$setProp(_el$21, "flexShrink", 0);
6360
- _$insert(_el$21, () => displayText(view().error ?? "Review failed"));
6361
- _$effect((_$p) => _$setProp(_el$21, "fg", api.theme.current.text, _$p));
6362
- return _el$21;
6442
+ var _el$18 = _$createElement("text");
6443
+ _$setProp(_el$18, "width", "100%");
6444
+ _$setProp(_el$18, "flexShrink", 0);
6445
+ _$insert(_el$18, () => displayText(view().error ?? uiText.review.failed));
6446
+ _$effect((_$p) => _$setProp(_el$18, "fg", api.theme.current.text, _$p));
6447
+ return _el$18;
6363
6448
  }
6364
6449
  }), null);
6365
- _$insert(_el$20, _$createComponent2(Show, {
6450
+ _$insert(_el$17, _$createComponent2(Show, {
6366
6451
  get when() {
6367
6452
  return view().assessment?.usage;
6368
6453
  },
6369
6454
  children: (usage) => [(() => {
6370
- var _el$22 = _$createElement("text");
6371
- _$setProp(_el$22, "marginTop", 1);
6372
- _$setProp(_el$22, "width", "100%");
6373
- _$setProp(_el$22, "flexShrink", 0);
6374
- _$insert(_el$22, () => usageText(usage()));
6375
- _$effect((_$p) => _$setProp(_el$22, "fg", api.theme.current.textMuted, _$p));
6376
- return _el$22;
6455
+ var _el$19 = _$createElement("text");
6456
+ _$setProp(_el$19, "marginTop", 1);
6457
+ _$setProp(_el$19, "width", "100%");
6458
+ _$setProp(_el$19, "flexShrink", 0);
6459
+ _$insert(_el$19, () => usageText(usage()));
6460
+ _$effect((_$p) => _$setProp(_el$19, "fg", api.theme.current.textMuted, _$p));
6461
+ return _el$19;
6377
6462
  })(), _$createComponent2(Show, {
6378
6463
  get when() {
6379
6464
  return lifetime.text();
6380
6465
  },
6381
6466
  children: (text) => (() => {
6382
- var _el$23 = _$createElement("text");
6383
- _$setProp(_el$23, "width", "100%");
6384
- _$setProp(_el$23, "flexShrink", 0);
6385
- _$insert(_el$23, text);
6386
- _$effect((_$p) => _$setProp(_el$23, "fg", api.theme.current.textMuted, _$p));
6387
- return _el$23;
6467
+ var _el$20 = _$createElement("text");
6468
+ _$setProp(_el$20, "width", "100%");
6469
+ _$setProp(_el$20, "flexShrink", 0);
6470
+ _$insert(_el$20, text);
6471
+ _$effect((_$p) => _$setProp(_el$20, "fg", api.theme.current.textMuted, _$p));
6472
+ return _el$20;
6388
6473
  })()
6389
6474
  })]
6390
6475
  }), null);
6391
- _$insert(_el$10, _$createComponent2(ReviewFooter, {
6476
+ _$insert(_el$1, _$createComponent2(ReviewFooter, {
6392
6477
  api,
6393
6478
  get view() {
6394
6479
  return view();
@@ -6405,16 +6490,16 @@ async function reviewTui(api, options, fileIO, observer, notificationBackend) {
6405
6490
  foregroundColor: api.theme.current.textMuted
6406
6491
  }
6407
6492
  };
6408
- _v$7 !== _p$.e && (_p$.e = _$setProp(_el$10, "backgroundColor", _v$7, _p$.e));
6409
- _v$8 !== _p$.t && (_p$.t = _$setProp(_el$11, "fg", _v$8, _p$.t));
6410
- _v$9 !== _p$.a && (_p$.a = _$setProp(_el$20, "scrollbarOptions", _v$9, _p$.a));
6493
+ _v$7 !== _p$.e && (_p$.e = _$setProp(_el$1, "backgroundColor", _v$7, _p$.e));
6494
+ _v$8 !== _p$.t && (_p$.t = _$setProp(_el$10, "fg", _v$8, _p$.t));
6495
+ _v$9 !== _p$.a && (_p$.a = _$setProp(_el$17, "scrollbarOptions", _v$9, _p$.a));
6411
6496
  return _p$;
6412
6497
  }, {
6413
6498
  e: void 0,
6414
6499
  t: void 0,
6415
6500
  a: void 0
6416
6501
  });
6417
- return _el$10;
6502
+ return _el$1;
6418
6503
  })()
6419
6504
  );
6420
6505
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-reviewer",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public",