opencode-reviewer 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +13 -5
  2. package/dist/tui.js +128 -36
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -116,11 +116,19 @@ costs use reported charges; other endpoints use available catalog estimates.
116
116
  Received usage counts even if a review fails or is interrupted. Unreported charges
117
117
  are missing from the totals.
118
118
 
119
- Lifetime statistics also show **Safe** and **Unsafe** review counts. Each completed,
120
- validated review counts once, even without usage data. Previews, retries and failed
121
- or interrupted analyses do not count. Re-enabling a conversation can produce a new
122
- review, which counts again. The totals persist across restarts; earlier ratings
123
- were not recorded and cannot be reconstructed.
119
+ The lifetime dialog shows completed reviews, retries, tokens, cost, Safe/Unsafe
120
+ percentages, confirmed auto-approvals, and average time to a rating and full report.
121
+ Percentages use recorded completed reviews as their denominator. Each validated
122
+ review counts once, even without usage data; a fresh review after re-enabling counts
123
+ again. Retries count extra API attempts actually dispatched, including format
124
+ corrections and transport recovery. Manual approvals are not auto-approvals.
125
+ Timings run from evaluation start, including evidence and retries, to the accepted
126
+ attempt's first rating and final validated response, excluding rendering/countdown
127
+ time. Non-streaming reviews use the final response time for both measurements.
128
+ Only running averages and sample counts are stored, not individual timings.
129
+ Totals persist across restarts. New metrics show partial history when older records
130
+ lack them; averages include measured reviews only. Earlier unrecorded values cannot
131
+ be reconstructed.
124
132
 
125
133
  Reviews send the pending request, latest user prompt, project context, and relevant
126
134
  file snapshots, diffs, or tool arguments to your endpoint before approval. Shell
package/dist/tui.js CHANGED
@@ -1181,7 +1181,17 @@ var uiText = {
1181
1181
  tokenCoverage: (available, total) => `Token counts available: ${available}/${total} requests`,
1182
1182
  pricingCoverage: (available, total) => `Pricing available: ${available}/${total} requests`,
1183
1183
  since: (date) => `Recorded since: ${date}`,
1184
- ratings: (safe, unsafe) => `Safe: ${safe} \xB7 Unsafe: ${unsafe}`,
1184
+ ratings: (safe, unsafe) => `${safe} \u2713 ${unsafe} \u2717`,
1185
+ dialogReviews: (count3) => `Reviews: ${count3}`,
1186
+ dialogRetries: (count3, partial) => `Retries: ${count3}${partial ? " (partial history)" : ""}`,
1187
+ dialogTokens: (input, output, partial) => `Tokens: ${input} in ${output} out${partial ? " (partial coverage)" : ""}`,
1188
+ dialogTokensUnavailable: "Tokens: unavailable",
1189
+ dialogCost: (amount2, partial) => amount2 === void 0 ? "Cost: unavailable" : `Cost: $${amount2}${partial ? " (partial pricing)" : ""}`,
1190
+ dialogSafe: (count3, percentage) => `Safe: ${count3} (${percentage === void 0 ? "n/a" : `${percentage}%`})`,
1191
+ dialogUnsafe: (count3, percentage) => `Unsafe: ${count3} (${percentage === void 0 ? "n/a" : `${percentage}%`})`,
1192
+ dialogAutoApproved: (count3, percentage, partial) => `Auto-approved: ${count3} (${percentage === void 0 ? "n/a" : `${percentage}%`})${partial ? " (partial history)" : ""}`,
1193
+ averageFullReport: (seconds) => `Average time to full report: ${seconds === void 0 ? "unavailable" : `${seconds}s`}`,
1194
+ averageRating: (seconds) => `Average time to rating: ${seconds === void 0 ? "unavailable" : `${seconds}s`}`,
1185
1195
  ratingsSince: (date) => `Ratings recorded since: ${date}`,
1186
1196
  ratingsExplanation: "Ratings count completed, validated reviews, including those without usage data. Previews, retries and failed or interrupted analyses do not count. A fresh review after re-enabling counts again. Earlier ratings were not recorded and cannot be recovered.",
1187
1197
  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."
@@ -1817,11 +1827,11 @@ async function streamedAssessment(response, signal, accounting, progress, firstC
1817
1827
  if (!done || !stopped) throw new Error("Reviewer stream ended without stop and DONE");
1818
1828
  return assessment;
1819
1829
  }
1820
- async function review(evidence, config, signal, fetcher = fetch, environment = process.env, prompts = BUILTIN_PROMPTS, pricing, onUsage, onProgress, onDiagnostics) {
1830
+ async function review(evidence, config, signal, fetcher = fetch, environment = process.env, prompts = BUILTIN_PROMPTS, pricing, onUsage, onProgress, onDiagnostics, onRetry) {
1821
1831
  if (remainingTime(signal) === Infinity) {
1822
1832
  let worker;
1823
1833
  try {
1824
- return await withDeadline(signal, config.timeoutMs, (bounded) => worker = review(evidence, config, bounded, fetcher, environment, prompts, pricing, onUsage, onProgress, onDiagnostics));
1834
+ return await withDeadline(signal, config.timeoutMs, (bounded) => worker = review(evidence, config, bounded, fetcher, environment, prompts, pricing, onUsage, onProgress, onDiagnostics, onRetry));
1825
1835
  } finally {
1826
1836
  await worker?.catch(() => {
1827
1837
  });
@@ -1861,18 +1871,32 @@ async function review(evidence, config, signal, fetcher = fetch, environment = p
1861
1871
  const body = JSON.stringify({
1862
1872
  model: config.model,
1863
1873
  messages,
1874
+ max_tokens: 2e3,
1864
1875
  stream: config.stream,
1865
1876
  ...config.stream ? { stream_options: { include_usage: true } } : {}
1866
1877
  });
1867
1878
  reviewStage(signal, "Reviewer response");
1868
1879
  diagnose = onDiagnostics ? diagnosticAttempt(onDiagnostics, attempt) : void 0;
1869
- response = await abortable(fetcher(`${config.baseURL}/chat/completions`, {
1870
- method: "POST",
1871
- redirect: "error",
1872
- signal: AbortSignal.any([signal, requestAbort.signal]),
1873
- headers: { "Content-Type": "application/json", ...key ? { Authorization: `Bearer ${key}` } : {} },
1874
- body
1875
- }), signal, cancelBody);
1880
+ signal.throwIfAborted();
1881
+ let pending;
1882
+ try {
1883
+ pending = fetcher(`${config.baseURL}/chat/completions`, {
1884
+ method: "POST",
1885
+ redirect: "error",
1886
+ signal: AbortSignal.any([signal, requestAbort.signal]),
1887
+ headers: { "Content-Type": "application/json", ...key ? { Authorization: `Bearer ${key}` } : {} },
1888
+ body
1889
+ });
1890
+ } finally {
1891
+ if (attempt > 0) {
1892
+ try {
1893
+ void Promise.resolve(onRetry?.()).catch(() => {
1894
+ });
1895
+ } catch {
1896
+ }
1897
+ }
1898
+ }
1899
+ response = await abortable(pending, signal, cancelBody);
1876
1900
  diagnose?.("headers");
1877
1901
  } catch (error) {
1878
1902
  signal.throwIfAborted();
@@ -2184,6 +2208,7 @@ var Controller = class {
2184
2208
  if (value.attempt !== entry.attempt + 1 || value.phase !== (value.attempt ? "retrying" : "evaluating")) return;
2185
2209
  this.clearProgress(entry);
2186
2210
  entry.attempt = value.attempt;
2211
+ entry.ratingAt = void 0;
2187
2212
  entry.view = { ...entry.view, progress: { attempt: value.attempt, phase: value.phase } };
2188
2213
  this.publish();
2189
2214
  return;
@@ -2199,6 +2224,7 @@ var Controller = class {
2199
2224
  ...typeof value.preview.safe === "boolean" ? { safe: value.preview.safe } : {},
2200
2225
  ...typeof value.preview.desc === "string" ? { desc: value.preview.desc } : {}
2201
2226
  };
2227
+ if (typeof preview.safe === "boolean" && entry.ratingAt === void 0) entry.ratingAt = this.time.now();
2202
2228
  entry.pendingProgress = { attempt: value.attempt, phase: "streaming", preview };
2203
2229
  if (preview.safe !== entry.view.progress?.preview?.safe) {
2204
2230
  const desc = entry.view.progress?.preview?.desc;
@@ -2378,6 +2404,7 @@ var Controller = class {
2378
2404
  return null;
2379
2405
  }
2380
2406
  }
2407
+ entry.startedAt = this.time.now();
2381
2408
  return this.evaluate(request, entry.abort.signal, () => {
2382
2409
  if (active() && (entry.view.status === "identifying" || entry.view.status === "analyzing")) {
2383
2410
  entry.view = { ...entry.view, status: "analyzing" };
@@ -2390,7 +2417,9 @@ var Controller = class {
2390
2417
  entry.view = assessment ? { ...entry.view, status: "complete", assessment, progress: void 0 } : { ...entry.view, status: "unrelated", progress: void 0 };
2391
2418
  if (assessment) {
2392
2419
  try {
2393
- void Promise.resolve(this.ratingObserver?.(assessment.safe)).catch(() => {
2420
+ const fullReportMs = Math.max(0, this.time.now() - entry.startedAt);
2421
+ const ratingMs = entry.ratingAt === void 0 ? fullReportMs : Math.max(0, entry.ratingAt - entry.startedAt);
2422
+ void Promise.resolve(this.ratingObserver?.(assessment.safe, { fullReportMs, ratingMs })).catch(() => {
2394
2423
  });
2395
2424
  } catch {
2396
2425
  }
@@ -3645,6 +3674,16 @@ import { constants as constants3 } from "node:fs";
3645
3674
  import { mkdir, open as open3, readdir as readdir2, rename, unlink } from "node:fs/promises";
3646
3675
  import { randomUUID } from "node:crypto";
3647
3676
  import path8 from "node:path";
3677
+ var emptyActivity = () => ({
3678
+ reviews: 0,
3679
+ usageRequests: 0,
3680
+ retries: 0,
3681
+ autoApproved: 0,
3682
+ timedReviews: 0,
3683
+ meanFullReportMs: 0,
3684
+ meanRatingMs: 0,
3685
+ since: null
3686
+ });
3648
3687
  var empty = () => ({
3649
3688
  requests: 0,
3650
3689
  tokenRequests: 0,
@@ -3655,7 +3694,8 @@ var empty = () => ({
3655
3694
  since: null,
3656
3695
  safe: 0,
3657
3696
  unsafe: 0,
3658
- ratingsSince: null
3697
+ ratingsSince: null,
3698
+ activity: emptyActivity()
3659
3699
  });
3660
3700
  var count2 = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
3661
3701
  var amount = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0;
@@ -3664,8 +3704,15 @@ function validate(value) {
3664
3704
  if (!value || ![value.requests, value.tokenRequests, value.input, value.output, value.priced, value.safe, value.unsafe, value.safe + value.unsafe].every(count2) || !amount(value.cost) || value.priced > value.requests || value.tokenRequests > value.requests || value.requests > value.tokenRequests + value.priced || !value.tokenRequests && (value.input !== 0 || value.output !== 0) || (value.requests > 0 ? !count2(value.since) || value.since > 864e13 : value.since !== null || value.input !== 0 || value.output !== 0) || !value.priced && value.cost !== 0 || (value.safe + value.unsafe > 0 ? !count2(value.ratingsSince) || value.ratingsSince > 864e13 : value.ratingsSince !== null)) {
3665
3705
  throw new Error("Invalid lifetime usage totals");
3666
3706
  }
3707
+ const activity = value.activity;
3708
+ if (!activity || ![activity.reviews, activity.usageRequests, activity.retries, activity.autoApproved, activity.timedReviews].every(count2) || activity.reviews > value.safe + value.unsafe || activity.usageRequests > value.requests || activity.timedReviews > activity.reviews || ![activity.meanFullReportMs, activity.meanRatingMs].every(amount) || activity.meanRatingMs > activity.meanFullReportMs || !activity.timedReviews && (activity.meanFullReportMs !== 0 || activity.meanRatingMs !== 0) || (activity.reviews || activity.usageRequests || activity.retries || activity.autoApproved ? !count2(activity.since) || activity.since > 864e13 : activity.since !== null)) throw new Error("Invalid lifetime activity totals");
3667
3709
  return value;
3668
3710
  }
3711
+ function mean(left, leftCount, right, rightCount) {
3712
+ if (!leftCount) return right;
3713
+ if (!rightCount) return left;
3714
+ return left + (right - left) * (rightCount / (leftCount + rightCount));
3715
+ }
3669
3716
  function add(left, right) {
3670
3717
  return validate({
3671
3718
  requests: left.requests + right.requests,
@@ -3677,7 +3724,17 @@ function add(left, right) {
3677
3724
  since: left.since === null ? right.since : right.since === null ? left.since : Math.min(left.since, right.since),
3678
3725
  safe: left.safe + right.safe,
3679
3726
  unsafe: left.unsafe + right.unsafe,
3680
- ratingsSince: left.ratingsSince === null ? right.ratingsSince : right.ratingsSince === null ? left.ratingsSince : Math.min(left.ratingsSince, right.ratingsSince)
3727
+ ratingsSince: left.ratingsSince === null ? right.ratingsSince : right.ratingsSince === null ? left.ratingsSince : Math.min(left.ratingsSince, right.ratingsSince),
3728
+ activity: {
3729
+ reviews: left.activity.reviews + right.activity.reviews,
3730
+ usageRequests: left.activity.usageRequests + right.activity.usageRequests,
3731
+ retries: left.activity.retries + right.activity.retries,
3732
+ autoApproved: left.activity.autoApproved + right.activity.autoApproved,
3733
+ timedReviews: left.activity.timedReviews + right.activity.timedReviews,
3734
+ meanFullReportMs: mean(left.activity.meanFullReportMs, left.activity.timedReviews, right.activity.meanFullReportMs, right.activity.timedReviews),
3735
+ meanRatingMs: mean(left.activity.meanRatingMs, left.activity.timedReviews, right.activity.meanRatingMs, right.activity.timedReviews),
3736
+ since: left.activity.since === null ? right.activity.since : right.activity.since === null ? left.activity.since : Math.min(left.activity.since, right.activity.since)
3737
+ }
3681
3738
  });
3682
3739
  }
3683
3740
  var LifetimeUsage = class {
@@ -3706,13 +3763,36 @@ var LifetimeUsage = class {
3706
3763
  output: usage.output ?? 0,
3707
3764
  priced: usage.cost === void 0 ? 0 : 1,
3708
3765
  cost: usage.cost ?? 0,
3709
- since: Date.now()
3766
+ since: Date.now(),
3767
+ activity: { ...emptyActivity(), usageRequests: 1, since: Date.now() }
3710
3768
  });
3711
3769
  }
3712
3770
  /** One accepted final review, independent of POST count or received usage. */
3713
- recordRating(safe) {
3771
+ recordRating(safe, timing) {
3714
3772
  if (typeof safe !== "boolean") return Promise.reject(new Error("Invalid review rating"));
3715
- return this.increment({ ...empty(), safe: safe ? 1 : 0, unsafe: safe ? 0 : 1, ratingsSince: Date.now() });
3773
+ if (timing && (![timing.fullReportMs, timing.ratingMs].every(amount) || timing.ratingMs > timing.fullReportMs)) {
3774
+ return Promise.reject(new Error("Invalid review timing"));
3775
+ }
3776
+ return this.increment({
3777
+ ...empty(),
3778
+ safe: safe ? 1 : 0,
3779
+ unsafe: safe ? 0 : 1,
3780
+ ratingsSince: Date.now(),
3781
+ activity: {
3782
+ ...emptyActivity(),
3783
+ reviews: 1,
3784
+ since: Date.now(),
3785
+ timedReviews: timing ? 1 : 0,
3786
+ meanFullReportMs: timing?.fullReportMs ?? 0,
3787
+ meanRatingMs: timing?.ratingMs ?? 0
3788
+ }
3789
+ });
3790
+ }
3791
+ recordRetry() {
3792
+ return this.increment({ ...empty(), activity: { ...emptyActivity(), retries: 1, since: Date.now() } });
3793
+ }
3794
+ recordAutoApproval() {
3795
+ return this.increment({ ...empty(), activity: { ...emptyActivity(), autoApproved: 1, since: Date.now() } });
3716
3796
  }
3717
3797
  increment(increment) {
3718
3798
  this.pending = this.pending.catch(() => {
@@ -3723,7 +3803,7 @@ var LifetimeUsage = class {
3723
3803
  try {
3724
3804
  const file = await open3(temporary, "wx", 384);
3725
3805
  try {
3726
- await file.writeFile(JSON.stringify({ version: 3, ...this.local }));
3806
+ await file.writeFile(JSON.stringify({ version: 4, ...this.local }));
3727
3807
  await file.sync();
3728
3808
  } finally {
3729
3809
  await file.close();
@@ -3783,7 +3863,7 @@ var LifetimeUsage = class {
3783
3863
  }
3784
3864
  if (size > 1024) throw new Error("Invalid lifetime usage snapshot");
3785
3865
  const value = JSON.parse(bytes.subarray(0, size).toString("utf8"));
3786
- if (value?.version !== 1 && value?.version !== 2 && value?.version !== 3) throw new Error("Unsupported lifetime usage snapshot");
3866
+ if (![1, 2, 3, 4].includes(value?.version)) throw new Error("Unsupported lifetime usage snapshot");
3787
3867
  total = add(total, validate({
3788
3868
  requests: value.requests,
3789
3869
  input: value.input,
@@ -3792,9 +3872,10 @@ var LifetimeUsage = class {
3792
3872
  priced: value.priced,
3793
3873
  cost: value.cost,
3794
3874
  since: value.since,
3795
- safe: value.version === 3 ? value.safe : 0,
3796
- unsafe: value.version === 3 ? value.unsafe : 0,
3797
- ratingsSince: value.version === 3 ? value.ratingsSince : null
3875
+ safe: value.version >= 3 ? value.safe : 0,
3876
+ unsafe: value.version >= 3 ? value.unsafe : 0,
3877
+ ratingsSince: value.version >= 3 ? value.ratingsSince : null,
3878
+ activity: value.version === 4 ? value.activity : emptyActivity()
3798
3879
  }));
3799
3880
  } finally {
3800
3881
  await file.close();
@@ -3811,19 +3892,21 @@ function lifetimeCost(totals) {
3811
3892
  return uiText.lifetime.cost(totals.cost.toFixed(4), totals.priced < totals.requests);
3812
3893
  }
3813
3894
  function lifetimeReport(totals) {
3895
+ const reviews = totals.safe + totals.unsafe, activity = totals.activity;
3896
+ const percentage = (count3) => reviews ? (count3 / reviews * 100).toFixed(1) : void 0;
3897
+ const partial = activity.reviews < reviews || activity.usageRequests < totals.requests;
3814
3898
  return [
3815
- lifetimeCost(totals),
3816
- uiText.lifetime.ratings(totals.safe, totals.unsafe),
3817
- uiText.lifetime.requests(totals.requests),
3818
- totals.tokenRequests ? uiText.lifetime.tokens(totals.input, totals.output, totals.tokenRequests < totals.requests) : uiText.lifetime.tokensUnavailable,
3819
- uiText.lifetime.tokenCoverage(totals.tokenRequests, totals.requests),
3820
- uiText.lifetime.pricingCoverage(totals.priced, totals.requests),
3821
- ...totals.since === null ? [] : [uiText.lifetime.since(new Date(totals.since).toISOString().slice(0, 10))],
3822
- ...totals.ratingsSince === null ? [] : [uiText.lifetime.ratingsSince(new Date(totals.ratingsSince).toISOString().slice(0, 10))],
3899
+ uiText.lifetime.dialogReviews(reviews),
3900
+ uiText.lifetime.dialogRetries(activity.retries, partial),
3901
+ totals.tokenRequests ? uiText.lifetime.dialogTokens(totals.input, totals.output, totals.tokenRequests < totals.requests) : uiText.lifetime.dialogTokensUnavailable,
3902
+ uiText.lifetime.dialogCost(totals.priced ? totals.cost.toFixed(4) : void 0, totals.priced < totals.requests),
3823
3903
  "",
3824
- uiText.lifetime.explanation,
3904
+ uiText.lifetime.dialogSafe(totals.safe, percentage(totals.safe)),
3905
+ uiText.lifetime.dialogUnsafe(totals.unsafe, percentage(totals.unsafe)),
3906
+ uiText.lifetime.dialogAutoApproved(activity.autoApproved, percentage(activity.autoApproved), partial),
3825
3907
  "",
3826
- uiText.lifetime.ratingsExplanation
3908
+ uiText.lifetime.averageFullReport(activity.timedReviews ? (activity.meanFullReportMs / 1e3).toFixed(2) : void 0),
3909
+ uiText.lifetime.averageRating(activity.timedReviews ? (activity.meanRatingMs / 1e3).toFixed(2) : void 0)
3827
3910
  ].join("\n");
3828
3911
  }
3829
3912
 
@@ -3909,7 +3992,7 @@ var LifetimeRefresh = class {
3909
3992
  // src/lifetime-view.tsx
3910
3993
  function lifetimeTracker(api) {
3911
3994
  const directory = path9.join(api.state.path.state, "opencode-reviewer");
3912
- const store = new LifetimeUsage(path9.join(directory, "usage-v3"), path9.join(directory, "usage-v2"), path9.join(directory, "usage-v1"));
3995
+ const store = new LifetimeUsage(path9.join(directory, "usage-v4"), path9.join(directory, "usage-v3"), path9.join(directory, "usage-v2"), path9.join(directory, "usage-v1"));
3913
3996
  const [totals, setTotals] = createSignal();
3914
3997
  const [unavailable, setUnavailable] = createSignal(false);
3915
3998
  const refresh = new LifetimeRefresh((signal) => store.totals(signal), (value) => {
@@ -3950,8 +4033,14 @@ function lifetimeTracker(api) {
3950
4033
  record: (usage) => {
3951
4034
  void store.record(usage).then(() => refresh.refresh(), () => refresh.failed());
3952
4035
  },
3953
- recordRating: (safe) => {
3954
- void store.recordRating(safe).then(() => refresh.refresh(), () => refresh.failed());
4036
+ recordRating: (safe, timing) => {
4037
+ void store.recordRating(safe, timing).then(() => refresh.refresh(), () => refresh.failed());
4038
+ },
4039
+ recordRetry: () => {
4040
+ void store.recordRetry().then(() => refresh.refresh(), () => refresh.failed());
4041
+ },
4042
+ recordAutoApproval: () => {
4043
+ void store.recordAutoApproval().then(() => refresh.refresh(), () => refresh.failed());
3955
4044
  }
3956
4045
  };
3957
4046
  }
@@ -6347,7 +6436,7 @@ async function reviewTui(api, options, fileIO, observer, notificationBackend) {
6347
6436
  }, config, configError, signal, onIdentified, files);
6348
6437
  if (!evidence) return null;
6349
6438
  signal.throwIfAborted();
6350
- const result = review(evidence, config, signal, void 0, void 0, prompts, (model) => modelPricing(api.state.provider, config.baseURL, model), lifetime.record, onProgress, trace?.forward);
6439
+ const result = review(evidence, config, signal, void 0, void 0, prompts, (model) => modelPricing(api.state.provider, config.baseURL, model), lifetime.record, onProgress, trace?.forward, lifetime.recordRetry);
6351
6440
  worker = result;
6352
6441
  return result;
6353
6442
  });
@@ -6368,7 +6457,10 @@ async function reviewTui(api, options, fileIO, observer, notificationBackend) {
6368
6457
  once: (request, signal) => measured(traces?.get(request), "approval-reply", () => approval.once(request, signal))
6369
6458
  } : approval,
6370
6459
  visibleID: () => visibleApproval()
6371
- }, void 0, modes, (fact) => notifications?.fact(fact), lifetime.recordRating);
6460
+ }, void 0, modes, (fact) => {
6461
+ if (fact.type === "confirmed" && fact.automatic) lifetime.recordAutoApproval();
6462
+ notifications?.fact(fact);
6463
+ }, lifetime.recordRating);
6372
6464
  api.event.on("permission.asked", (event) => controller.asked(event.properties));
6373
6465
  api.event.on("permission.replied", (event) => controller.replied(event.properties.requestID));
6374
6466
  api.event.on("session.deleted", (event) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-reviewer",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public",