From fea86a27ec9f355dd8d3ff7b3f40bd44596ea41c Mon Sep 17 00:00:00 2001 From: alphali <5236230+alphali@users.noreply.github.com> Date: Fri, 25 Sep 2026 00:21:22 +0800 Subject: [PATCH] fix(code-context): accept bound create-resume rounds in 0.2.8 --- CHANGELOG.md | 10 ++++++ README.md | 2 +- package.json | 2 +- .../.claude-plugin/plugin.json | 2 +- .../.codex-plugin/plugin.json | 2 +- .../.cursor-plugin/plugin.json | 2 +- .../scripts/doable-code-context.mjs | 9 +++-- scripts/verify-release.mjs | 2 +- tests/doable-code-context-helper.test.mjs | 34 +++++++++++++++++++ 9 files changed, 54 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a41ca3..23ee3ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ All notable changes to Doable Agent Plugins are documented here. +## [0.2.8] - 2026-09-25 + +### Fixed + +- Accept a server-bound pre-create successor when a TRD needs more context to + finish creation. Keep checking the original connection code and local workspace. +- Requires the matching TRD connection resolver fix; older servers retain their + existing behavior. Cross-repository contract: `getdoable/trd` + `docs/change-sets/pre-create-code-context-toggle.yaml`. + ## [0.2.7] - 2026-09-17 ### Fixed diff --git a/README.md b/README.md index d4ea8dc..3216c24 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Official agent plugins for [Doable](https://getdoable.ai), supporting Codex, Cla | Plugin | Version | Purpose | Network | | --- | --- | --- | --- | -| `doable-code-context` | `0.2.7` | Resolve context requests or start a managed feature-testing workflow | Doable MCP | +| `doable-code-context` | `0.2.8` | Resolve context requests or start a managed feature-testing workflow | Doable MCP | ## Workflow diff --git a/package.json b/package.json index de515b9..880f396 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doable-agent-plugins", - "version": "0.2.7", + "version": "0.2.8", "private": true, "description": "Official installable agent plugins for Doable.", "license": "MIT", diff --git a/plugins/doable-code-context/.claude-plugin/plugin.json b/plugins/doable-code-context/.claude-plugin/plugin.json index c59d5a6..4ee0d27 100644 --- a/plugins/doable-code-context/.claude-plugin/plugin.json +++ b/plugins/doable-code-context/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "doable-code-context", - "version": "0.2.7", + "version": "0.2.8", "description": "Connect private code to Doable through MCP, resolve grounded context requests, and start managed feature-testing workflows.", "author": { "name": "Doable AI", diff --git a/plugins/doable-code-context/.codex-plugin/plugin.json b/plugins/doable-code-context/.codex-plugin/plugin.json index 46e9cd9..9368ee2 100644 --- a/plugins/doable-code-context/.codex-plugin/plugin.json +++ b/plugins/doable-code-context/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "doable-code-context", - "version": "0.2.7", + "version": "0.2.8", "description": "Connect private code to Doable through MCP, resolve grounded context requests, and start managed feature-testing workflows.", "author": { "name": "Doable AI", diff --git a/plugins/doable-code-context/.cursor-plugin/plugin.json b/plugins/doable-code-context/.cursor-plugin/plugin.json index 32e5bbc..0d1bd79 100644 --- a/plugins/doable-code-context/.cursor-plugin/plugin.json +++ b/plugins/doable-code-context/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "doable-code-context", "displayName": "Doable Code Context", - "version": "0.2.7", + "version": "0.2.8", "description": "Connect private code to Doable through MCP, resolve grounded context requests, and start managed feature-testing workflows.", "author": { "name": "Doable AI" diff --git a/plugins/doable-code-context/scripts/doable-code-context.mjs b/plugins/doable-code-context/scripts/doable-code-context.mjs index 9e6619f..addda5f 100644 --- a/plugins/doable-code-context/scripts/doable-code-context.mjs +++ b/plugins/doable-code-context/scripts/doable-code-context.mjs @@ -18,7 +18,7 @@ import { import { basename, dirname, isAbsolute, join, resolve, sep } from "node:path"; import { execFileSync } from "node:child_process"; -const CLIENT = Object.freeze({ name: "doable-code-context", version: "0.2.7" }); +const CLIENT = Object.freeze({ name: "doable-code-context", version: "0.2.8" }); const STATE_SCHEMA_VERSION = "1"; const SUBMISSION_SCHEMA_VERSION = "1"; @@ -854,10 +854,9 @@ function normalizeRound(data, state, requestedCode) { roundUse === "pre_create" || roundUse === "follow_up", "round use must be pre_create or follow_up", ); - assert( - code.toLowerCase() === requestedCode.toLowerCase() || roundUse === "follow_up", - "Doable returned a different pre-create round code", - ); + // The server may resolve the connection to a create-resume pre-create Round. + // The original connection code was checked above; workspace checks below still + // reject a successor from another local workspace. const rawTestSuitePublicId = round.test_suite_public_id || round.testSuitePublicId || ""; const testSuitePublicId = rawTestSuitePublicId ? string(rawTestSuitePublicId, "test suite public id", { max: 160 }) diff --git a/scripts/verify-release.mjs b/scripts/verify-release.mjs index 7428313..b9f7fab 100644 --- a/scripts/verify-release.mjs +++ b/scripts/verify-release.mjs @@ -11,7 +11,7 @@ const semver = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?(?: const plugins = [ { name: "doable-code-context", - version: "0.2.7", + version: "0.2.8", skillNames: ["doable-connect", "doable-answer-questions", "doable-test-feature"], network: "bundled-doable-mcp-config", }, diff --git a/tests/doable-code-context-helper.test.mjs b/tests/doable-code-context-helper.test.mjs index 8ff03de..8934870 100644 --- a/tests/doable-code-context-helper.test.mjs +++ b/tests/doable-code-context-helper.test.mjs @@ -945,3 +945,37 @@ test("agent-origin helper records the exact MCP round and finalize result", asyn ), /Next action: wait/); }); + +test("a pre-create successor requires the original connection and matching workspace", async (t) => { + const testRoot = mkdtempSync(join(tmpdir(), "doable-resume-connection-")); + t.after(() => rmSync(testRoot, { recursive: true, force: true })); + mkdirSync(join(testRoot, ".doable")); + const statePath = join(testRoot, ".doable", "workspace-private.json"); + writeFileSync(statePath, JSON.stringify({ + schemaVersion: "1", workspace: { localId: "local-fixture", serverId: "workspace-safe" }, + organization: { id: "org-safe" }, repositories: [], + privateFingerprintKey: "local-test-only", + sync: { profileFingerprint: "fixture" }, profile: { profileFingerprint: "fixture" }, + })); + const responsePath = join(testRoot, "resume-round.json"); + const round = { + round_id: "resume-round", round_code: "DQ-RESUME1", connection_round_code: "DQ-ORIGIN1", + round_use: "pre_create", workspace_id: "workspace-safe", status: "open_for_agent", + next_action: "answer", revision: 1, feature_scope: "Account recovery", + questions: [{ id: "base-question", purpose: "base_context", question: "Ground account recovery.", why: "Resume creation." }], + }; + const environment = { TEST_WORKSPACE: testRoot }; + const args = ["record-round", "--code", "DQ-ORIGIN1", "--response", responsePath, "--state", statePath]; + writeFileSync(responsePath, JSON.stringify(round)); + assert.match(await runHelper(args, environment), /Next action: answer/); + const candidate = JSON.parse(readFileSync(join(testRoot, ".doable", "requests", "DQ-RESUME1", "submission-r1.json"), "utf8")); + assert.equal(candidate.round.id, "resume-round"); + assert.deepEqual(candidate.answers.map(answer => answer.questionId), ["base-question"]); + + for (const changes of [{ connection_round_code: undefined }, { connection_round_code: "DQ-OTHER1" }]) { + writeFileSync(responsePath, JSON.stringify({ ...round, ...changes })); + await assert.rejects(runHelper(args, environment), /different context connection/); + } + writeFileSync(responsePath, JSON.stringify({ ...round, workspace_id: "workspace-other" })); + await assert.rejects(runHelper(args, environment), /different workspace/); +});