opencode-acp 1.14.17-pr.304.12 → 1.14.17-pr.305.14

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
@@ -492,13 +492,13 @@ For the complete list with root cause analysis, see the [bug tracker](https://gi
492
492
 
493
493
  ## Changelog
494
494
 
495
- ### v1.14.17 — Eliminate compress retry dead-ends (#301)
495
+ ### v1.14.17 — CI release: dist/ artifact on every PR, npm version in artifact comment
496
496
 
497
- **Problem**: Two compress arguments hard-failed on first use and produced confusing error loops instead of actionable feedback. (1) The model learned "add `acknowledgeRisk: true` to retry" from quality-gate rejection templates, then carried the flag into *every* retry — including retries after non-quality errors (e.g. a missing topic), where no quality-gate rejection was pending, hitting `Parameter "acknowledgeRisk": true was provided, but no quality gate rejection is pending` (issue #301). (2) `content[0] needs a topic — provide content[0].topic or the top-level topic` hard-failed compress calls whose entries had no topic and no top-level fallback.
497
+ **Problem**: `dist/` was only built during release publishing, so PR reviews couldn't verify the bundled output, and after publishing there was no quick way to confirm which npm version a merged PR actually landed in.
498
498
 
499
- **Fix**: Both parameters are now tolerant. `acknowledgeRisk` without a pending rejection is a no-op — quality checks still run (the gate's protection is unchanged: bypass is only armed by a real quality-gate rejection), and a successful result carries an `⚠️ acknowledgeRisk was ignored: ...` note teaching correct usage. Topics are fully optional: an entry without its own topic falls back to the top-level topic, then to one derived from the summary's first line (markdown headings stripped, capped at 80 chars), so `search_context` always has something searchable.
499
+ **Fix**: CI now builds `dist/` and uploads it as a workflow artifact on every PR (#298), and the PR artifact comment displays the published npm version (#299). No plugin runtime behavior changes in this release — CI/workflow only.
500
500
 
501
- Files: `lib/compress/range.ts`, `lib/compress/range-utils.ts` (new `deriveFallbackTopic`), `lib/compress/quality-gate/rejection.ts` (removed `buildPreemptiveAcknowledgeError`), `lib/compress/types.ts`, `lib/prompts/compress-range.ts`, `lib/prompts/extensions/tool.ts`, `lib/state/types.ts`. Tests: 976 pass.
501
+ Files: `.github/workflows/`. Tests: 976 pass.
502
502
 
503
503
  **Install**: `opencode plugin opencode-acp@latest --global`
504
504
 
package/README.zh-CN.md CHANGED
@@ -446,13 +446,13 @@ ACP 是 DCP 的直接替代品。迁移步骤:
446
446
 
447
447
  ## 更新日志
448
448
 
449
- ### v1.14.17 — 消除 compress 重试死循环(#301)
449
+ ### v1.14.17 — CI 版本:每个 PR 构建 dist/ 产物并在评论中显示 npm 版本
450
450
 
451
- **问题**:两个 compress 参数在首次使用时硬报错,产生令人困惑的错误循环而非可执行的反馈。(1) 模型从质量门拒绝模板学到「重试要加 `acknowledgeRisk: true`」,于是把它带进了所有重试——包括非质量错误(如缺 topic)之后的重试,此时没有 pending 的质量门拒绝,撞上 `Parameter "acknowledgeRisk": true was provided, but no quality gate rejection is pending`(issue #301)。(2) `content[0] needs a topic — provide content[0].topic or the top-level topic` 在 entry 无 topic 且无顶层 fallback 时硬报错。
451
+ **问题**:\`dist/\` 只在发版发布时构建,PR review 无法核对打包产物;发布后也没有快速途径确认某个已合并 PR 实际落在哪个 npm 版本。
452
452
 
453
- **修复**:两个参数均改为宽容处理。无 pending 拒绝时的 `acknowledgeRisk` 为 no-op——质量检查照常运行(质量门保护不变:bypass 只由真实的质量门拒绝解锁),成功结果附带 `⚠️ acknowledgeRisk was ignored: ...` 提示教模型正确用法。topic 完全可选:entry 无自有 topic 时依次回退到顶层 topic、再到从 summary 首行派生的 topic(去 markdown 标题符、截断 80 字符),保证 `search_context` 始终有可检索内容。
453
+ **修复**:CI 现在在每个 PR 上构建 \`dist/\` 并上传为 workflow artifact(#298),PR artifact 评论会显示已发布的 npm 版本(#299)。本版本**不含插件运行时行为变更**——仅 CI/workflow 改动。
454
454
 
455
- 文件:`lib/compress/range.ts`、`lib/compress/range-utils.ts`(新增 `deriveFallbackTopic`)、`lib/compress/quality-gate/rejection.ts`(移除 `buildPreemptiveAcknowledgeError`)、`lib/compress/types.ts`、`lib/prompts/compress-range.ts`、`lib/prompts/extensions/tool.ts`、`lib/state/types.ts`。测试:976 通过。
455
+ 文件:\`.github/workflows/\`。测试:976 通过。
456
456
 
457
457
  **安装**:`opencode plugin opencode-acp@latest --global`
458
458
 
package/dist/index.js CHANGED
@@ -2075,7 +2075,7 @@ THE FORMAT OF COMPRESS
2075
2075
  ]
2076
2076
  }
2077
2077
  \`\`\`
2078
- Each entry MAY have a topic. Missing topics fall back to the top-level topic, then to an automatic one derived from the summary.`;
2078
+ Each entry needs a topic \u2014 either its own or the top-level fallback.`;
2079
2079
 
2080
2080
  // lib/state/persistence.ts
2081
2081
  import * as fs from "fs/promises";
@@ -3756,11 +3756,8 @@ function filterProtectedRecentMessages(selection, searchContext, state, compress
3756
3756
 
3757
3757
  // lib/compress/range-utils.ts
3758
3758
  var BLOCK_PLACEHOLDER_REGEX = /\(b(\d+)\)|\{block_(\d+)\}/gi;
3759
- function deriveFallbackTopic(summary) {
3760
- const firstLine = summary.split("\n").map((line) => line.replace(/^#{1,6}\s*/, "").trim()).find((line) => line.length > 0) ?? "compressed range";
3761
- return firstLine.length > 80 ? `${firstLine.slice(0, 77)}...` : firstLine;
3762
- }
3763
3759
  function validateArgs(args) {
3760
+ const hasTopLevelTopic = typeof args.topic === "string" && args.topic.trim().length > 0;
3764
3761
  if (!Array.isArray(args.content) || args.content.length === 0) {
3765
3762
  throw new Error("content is required and must be a non-empty array");
3766
3763
  }
@@ -3776,12 +3773,18 @@ function validateArgs(args) {
3776
3773
  if (typeof entry?.summary !== "string" || entry.summary.trim().length === 0) {
3777
3774
  throw new Error(`${prefix}.summary is required and must be a non-empty string`);
3778
3775
  }
3776
+ const hasEntryTopic = typeof entry?.topic === "string" && entry.topic.trim().length > 0;
3777
+ if (!hasEntryTopic && !hasTopLevelTopic) {
3778
+ throw new Error(
3779
+ `${prefix} needs a topic \u2014 provide ${prefix}.topic or the top-level topic`
3780
+ );
3781
+ }
3779
3782
  }
3780
3783
  }
3781
3784
  function resolveRanges(args, searchContext, state, logger) {
3782
3785
  return args.content.map((entry, index) => {
3783
3786
  const normalizedEntry = {
3784
- topic: typeof entry.topic === "string" && entry.topic.trim().length > 0 ? entry.topic.trim() : typeof args.topic === "string" && args.topic.trim().length > 0 ? void 0 : deriveFallbackTopic(entry.summary),
3787
+ topic: typeof entry.topic === "string" && entry.topic.trim().length > 0 ? entry.topic.trim() : void 0,
3785
3788
  startId: entry.startId.trim(),
3786
3789
  endId: entry.endId.trim(),
3787
3790
  summary: entry.summary
@@ -5669,6 +5672,11 @@ exact values, errors). Then add "acknowledgeRisk": true to the compress tool cal
5669
5672
  Without acknowledgeRisk: true, the compression will be rejected again.`;
5670
5673
  return new Error(message);
5671
5674
  }
5675
+ function buildPreemptiveAcknowledgeError() {
5676
+ return new Error(
5677
+ 'Parameter "acknowledgeRisk": true was provided, but no quality gate rejection is pending. This parameter is only valid immediately after a compression was rejected by the quality gate. Remove it and try again.'
5678
+ );
5679
+ }
5672
5680
 
5673
5681
  // lib/compress/pipeline.ts
5674
5682
  function snapshotCompressionState(state) {
@@ -6142,13 +6150,13 @@ function createCompressRangeTool(factoryCtx) {
6142
6150
  }
6143
6151
  const acknowledgeRisk = args.acknowledgeRisk === true;
6144
6152
  const qualityGateRetryPendingBefore = ctx.state.qualityGateRetryPending;
6145
- const bypassQuality = acknowledgeRisk && ctx.state.qualityGateRetryPending;
6146
- const ignoredAcknowledgeRisk = acknowledgeRisk && !ctx.state.qualityGateRetryPending;
6147
- if (ignoredAcknowledgeRisk) {
6148
- ctx.logger.warn("compress: acknowledgeRisk ignored \u2014 no quality gate rejection pending");
6153
+ if (acknowledgeRisk && !ctx.state.qualityGateRetryPending) {
6154
+ throw buildPreemptiveAcknowledgeError();
6149
6155
  }
6150
- ctx.state.qualityGateRetryPending = false;
6151
- if (!bypassQuality) {
6156
+ if (acknowledgeRisk) {
6157
+ ctx.state.qualityGateRetryPending = false;
6158
+ } else {
6159
+ ctx.state.qualityGateRetryPending = false;
6152
6160
  for (const plan of preparedPlans) {
6153
6161
  const result = evaluatePreCommitQuality(
6154
6162
  rawMessages,
@@ -6224,10 +6232,7 @@ function createCompressRangeTool(factoryCtx) {
6224
6232
  const skippedNote = phantomSkipNotice !== null ? `
6225
6233
  \u26A0\uFE0F ${phantomSkipNotice}
6226
6234
  ` : "";
6227
- const ackNote = ignoredAcknowledgeRisk ? `
6228
- \u26A0\uFE0F acknowledgeRisk was ignored: no quality gate rejection was pending, so quality checks ran normally. Only pass it when retrying immediately after a quality gate rejection.
6229
- ` : "";
6230
- return `Compressed ${totalCompressedMessages} messages into ${COMPRESSED_BLOCK_HEADER}.${skippedNote}${ackNote}
6235
+ return `Compressed ${totalCompressedMessages} messages into ${COMPRESSED_BLOCK_HEADER}.${skippedNote}
6231
6236
  IMPORTANT: This was an automatic context compression. You MUST continue your previous task exactly where you left off. Do NOT ask the user what to do next.
6232
6237
  \u{1F4A1} Tip: Use search_context('keyword') to find compressed content when you need it later.`;
6233
6238
  }
@@ -8944,7 +8949,7 @@ import { writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
8944
8949
  import { join as join3 } from "path";
8945
8950
  import { existsSync as existsSync3 } from "fs";
8946
8951
  import { homedir as homedir3 } from "os";
8947
- var LOG_VERSION = true ? "1.14.17-pr.304.12" : "dev";
8952
+ var LOG_VERSION = true ? "1.14.17-pr.305.14" : "dev";
8948
8953
  var Logger = class {
8949
8954
  logDir;
8950
8955
  enabled;
@@ -9272,7 +9277,7 @@ Rules:
9272
9277
  BATCHING
9273
9278
  When multiple independent ranges are ready and their boundaries do not overlap, include all of them as separate entries in the \`content\` array of a single tool call. Each entry should have its own \`startId\`, \`endId\`, and \`summary\`.
9274
9279
 
9275
- When the ranges cover unrelated topics, give each entry its own \`topic\` for better summary quality \u2014 do not force unrelated content under a single shared topic. The top-level \`topic\` is an optional fallback; when no topic is provided at all, one is derived from the summary's first line automatically.
9280
+ When the ranges cover unrelated topics, give each entry its own \`topic\` for better summary quality \u2014 do not force unrelated content under a single shared topic. Omit the top-level \`topic\` when every entry has its own. Use the top-level \`topic\` only as a fallback when entries don't specify one.
9276
9281
 
9277
9282
  \`\`\`
9278
9283
  compress({ content: [