codebyplan 1.13.12 → 1.13.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/dist/cli.js CHANGED
@@ -14,7 +14,7 @@ var VERSION, PACKAGE_NAME;
14
14
  var init_version = __esm({
15
15
  "src/lib/version.ts"() {
16
16
  "use strict";
17
- VERSION = "1.13.12";
17
+ VERSION = "1.13.14";
18
18
  PACKAGE_NAME = "codebyplan";
19
19
  }
20
20
  });
@@ -1281,7 +1281,11 @@ var init_template_walker = __esm({
1281
1281
  "hooks/validate-structure-lengths.sh",
1282
1282
  "hooks/validate-structure-smoke.sh",
1283
1283
  "hooks/validate-context-usage.sh",
1284
- "hooks/validate-git-commit.sh"
1284
+ "hooks/validate-git-commit.sh",
1285
+ // Advisory GATE-6 sibling-identity nudge — fires ONLY in the templates source
1286
+ // repo (detects packages/codebyplan-package/templates/). A no-op for consumers,
1287
+ // so it ships neither in hooks.json nor as a copied file.
1288
+ "hooks/cbp-canonical-templates-nudge.sh"
1285
1289
  ]);
1286
1290
  }
1287
1291
  });
@@ -5897,6 +5901,310 @@ var init_resolve_worktree2 = __esm({
5897
5901
  }
5898
5902
  });
5899
5903
 
5904
+ // src/cli/create-org.ts
5905
+ var create_org_exports = {};
5906
+ __export(create_org_exports, {
5907
+ runCreateOrg: () => runCreateOrg
5908
+ });
5909
+ import { stdin as stdin3, stdout as stdout4 } from "node:process";
5910
+ import { createInterface as createInterface3 } from "node:readline/promises";
5911
+ function deriveSlug(name) {
5912
+ const trimmed = name.trim();
5913
+ if (trimmed === "") return "";
5914
+ const slug = trimmed.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
5915
+ return slug || "org";
5916
+ }
5917
+ async function runCreateOrg() {
5918
+ const rl = createInterface3({ input: stdin3, output: stdout4 });
5919
+ console.log("\n CodeByPlan \u2014 Create Organization\n");
5920
+ try {
5921
+ const rawName = (await rl.question(" Organization name: ")).trim();
5922
+ if (!rawName) {
5923
+ console.error("\n Error: Organization name cannot be empty.\n");
5924
+ process.exitCode = 1;
5925
+ return;
5926
+ }
5927
+ const slug = deriveSlug(rawName);
5928
+ if (slug) {
5929
+ console.log(` Slug preview: ${slug}
5930
+ `);
5931
+ }
5932
+ let response;
5933
+ try {
5934
+ response = await apiPost("/organizations", {
5935
+ name: rawName
5936
+ });
5937
+ } catch (err) {
5938
+ if (err instanceof ApiError) {
5939
+ console.error(`
5940
+ Error: ${err.message} (HTTP ${err.status})
5941
+ `);
5942
+ } else {
5943
+ const msg = err instanceof Error ? err.message : String(err);
5944
+ console.error(`
5945
+ Error: ${msg}
5946
+ `);
5947
+ }
5948
+ process.exitCode = 1;
5949
+ return;
5950
+ }
5951
+ const org = response.data;
5952
+ console.log("\n Organization created successfully.\n");
5953
+ console.log(` id: ${org.id}`);
5954
+ console.log(` name: ${org.name}`);
5955
+ console.log(` slug: ${org.slug}
5956
+ `);
5957
+ } finally {
5958
+ rl.close();
5959
+ }
5960
+ }
5961
+ var init_create_org = __esm({
5962
+ "src/cli/create-org.ts"() {
5963
+ "use strict";
5964
+ init_api();
5965
+ }
5966
+ });
5967
+
5968
+ // src/cli/create-project.ts
5969
+ var create_project_exports = {};
5970
+ __export(create_project_exports, {
5971
+ runCreateProject: () => runCreateProject
5972
+ });
5973
+ import { stdin as stdin4, stdout as stdout5 } from "node:process";
5974
+ import { createInterface as createInterface4 } from "node:readline/promises";
5975
+ function deriveSlug2(name) {
5976
+ const trimmed = name.trim();
5977
+ if (trimmed === "") return "";
5978
+ const slug = trimmed.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
5979
+ return slug || "project";
5980
+ }
5981
+ async function runCreateProject() {
5982
+ const rl = createInterface4({ input: stdin4, output: stdout5 });
5983
+ console.log("\n CodeByPlan \u2014 Create Project\n");
5984
+ try {
5985
+ const orgIdFlag = (() => {
5986
+ const idx = process.argv.indexOf("--org-id");
5987
+ return idx !== -1 ? process.argv[idx + 1] ?? "" : "";
5988
+ })();
5989
+ let organizationId;
5990
+ if (orgIdFlag) {
5991
+ organizationId = orgIdFlag.trim();
5992
+ } else {
5993
+ let orgs = null;
5994
+ try {
5995
+ const resp = await apiGet("/organizations");
5996
+ if (resp.data && resp.data.length > 0) {
5997
+ orgs = resp.data;
5998
+ }
5999
+ } catch {
6000
+ }
6001
+ if (orgs && orgs.length > 0) {
6002
+ console.log(" Available organizations:\n");
6003
+ orgs.forEach((org, i) => {
6004
+ console.log(` ${i + 1}. ${org.name} (${org.slug}) [${org.id}]`);
6005
+ });
6006
+ console.log("");
6007
+ const rawChoice = (await rl.question(
6008
+ ` Select organization (1\u2013${orgs.length}) or paste an org ID: `
6009
+ )).trim();
6010
+ const choiceNum = parseInt(rawChoice, 10);
6011
+ if (!isNaN(choiceNum) && choiceNum >= 1 && choiceNum <= orgs.length) {
6012
+ organizationId = orgs[choiceNum - 1].id;
6013
+ } else if (rawChoice) {
6014
+ organizationId = rawChoice;
6015
+ } else {
6016
+ console.error("\n Error: Organization selection cannot be empty.\n");
6017
+ process.exitCode = 1;
6018
+ return;
6019
+ }
6020
+ } else {
6021
+ const rawOrgId = (await rl.question(" Organization ID: ")).trim();
6022
+ if (!rawOrgId) {
6023
+ console.error("\n Error: Organization ID cannot be empty.\n");
6024
+ process.exitCode = 1;
6025
+ return;
6026
+ }
6027
+ organizationId = rawOrgId;
6028
+ }
6029
+ }
6030
+ const rawName = (await rl.question(" Project name: ")).trim();
6031
+ if (!rawName) {
6032
+ console.error("\n Error: Project name cannot be empty.\n");
6033
+ process.exitCode = 1;
6034
+ return;
6035
+ }
6036
+ const slug = deriveSlug2(rawName);
6037
+ if (slug) {
6038
+ console.log(` Slug preview: ${slug}
6039
+ `);
6040
+ }
6041
+ let response;
6042
+ try {
6043
+ response = await apiPost("/projects", {
6044
+ organization_id: organizationId,
6045
+ name: rawName
6046
+ });
6047
+ } catch (err) {
6048
+ if (err instanceof ApiError) {
6049
+ console.error(`
6050
+ Error: ${err.message} (HTTP ${err.status})
6051
+ `);
6052
+ } else {
6053
+ const msg = err instanceof Error ? err.message : String(err);
6054
+ console.error(`
6055
+ Error: ${msg}
6056
+ `);
6057
+ }
6058
+ process.exitCode = 1;
6059
+ return;
6060
+ }
6061
+ const project = response.data;
6062
+ console.log("\n Project created successfully.\n");
6063
+ console.log(` id: ${project.id}`);
6064
+ console.log(` name: ${project.name}`);
6065
+ console.log(` slug: ${project.slug}
6066
+ `);
6067
+ } finally {
6068
+ rl.close();
6069
+ }
6070
+ }
6071
+ var init_create_project = __esm({
6072
+ "src/cli/create-project.ts"() {
6073
+ "use strict";
6074
+ init_api();
6075
+ }
6076
+ });
6077
+
6078
+ // src/cli/create-repo.ts
6079
+ var create_repo_exports = {};
6080
+ __export(create_repo_exports, {
6081
+ runCreateRepo: () => runCreateRepo
6082
+ });
6083
+ import { stdin as stdin5, stdout as stdout6 } from "node:process";
6084
+ import { createInterface as createInterface5 } from "node:readline/promises";
6085
+ async function runCreateRepo() {
6086
+ const rl = createInterface5({ input: stdin5, output: stdout6 });
6087
+ console.log("\n CodeByPlan \u2014 Create Repository\n");
6088
+ try {
6089
+ const projectIdFlag = (() => {
6090
+ const idx = process.argv.indexOf("--project-id");
6091
+ return idx !== -1 ? process.argv[idx + 1] ?? "" : "";
6092
+ })();
6093
+ let projectId;
6094
+ if (projectIdFlag) {
6095
+ const trimmedFlag = projectIdFlag.trim();
6096
+ if (!UUID_RE.test(trimmedFlag)) {
6097
+ console.error("\n Error: Project ID must be a valid UUID.\n");
6098
+ process.exitCode = 1;
6099
+ return;
6100
+ }
6101
+ projectId = trimmedFlag;
6102
+ } else {
6103
+ let projects = null;
6104
+ try {
6105
+ const resp = await apiGet("/projects");
6106
+ if (resp.data && resp.data.length > 0) {
6107
+ projects = resp.data;
6108
+ }
6109
+ } catch {
6110
+ }
6111
+ if (projects && projects.length > 0) {
6112
+ console.log(" Available projects:\n");
6113
+ projects.forEach((proj, i) => {
6114
+ console.log(
6115
+ ` ${i + 1}. ${proj.name} (${proj.slug}) [${proj.id}]`
6116
+ );
6117
+ });
6118
+ console.log("");
6119
+ const rawChoice = (await rl.question(
6120
+ ` Select project (1\u2013${projects.length}) or paste a project ID: `
6121
+ )).trim();
6122
+ const choiceNum = parseInt(rawChoice, 10);
6123
+ if (!isNaN(choiceNum) && choiceNum >= 1 && choiceNum <= projects.length) {
6124
+ projectId = projects[choiceNum - 1].id;
6125
+ } else if (rawChoice) {
6126
+ if (!UUID_RE.test(rawChoice)) {
6127
+ console.error("\n Error: Project ID must be a valid UUID.\n");
6128
+ process.exitCode = 1;
6129
+ return;
6130
+ }
6131
+ projectId = rawChoice;
6132
+ } else {
6133
+ console.error("\n Error: Project selection cannot be empty.\n");
6134
+ process.exitCode = 1;
6135
+ return;
6136
+ }
6137
+ } else {
6138
+ const rawProjectId = (await rl.question(" Project ID: ")).trim();
6139
+ if (!rawProjectId) {
6140
+ console.error("\n Error: Project ID cannot be empty.\n");
6141
+ process.exitCode = 1;
6142
+ return;
6143
+ }
6144
+ if (!UUID_RE.test(rawProjectId)) {
6145
+ console.error("\n Error: Project ID must be a valid UUID.\n");
6146
+ process.exitCode = 1;
6147
+ return;
6148
+ }
6149
+ projectId = rawProjectId;
6150
+ }
6151
+ }
6152
+ const rawName = (await rl.question(" Repository name: ")).trim();
6153
+ if (!rawName) {
6154
+ console.error("\n Error: Repository name cannot be empty.\n");
6155
+ process.exitCode = 1;
6156
+ return;
6157
+ }
6158
+ const rawPath = (await rl.question(" Local path (optional, press Enter to skip): ")).trim();
6159
+ const rawBranch = (await rl.question(
6160
+ " Default git branch (optional, press Enter for 'main'): "
6161
+ )).trim();
6162
+ const git_branch = rawBranch || "main";
6163
+ let response;
6164
+ try {
6165
+ response = await apiPost("/repos", {
6166
+ project_id: projectId,
6167
+ name: rawName,
6168
+ ...rawPath ? { path: rawPath } : {},
6169
+ git_branch
6170
+ });
6171
+ } catch (err) {
6172
+ if (err instanceof ApiError) {
6173
+ console.error(`
6174
+ Error: ${err.message} (HTTP ${err.status})
6175
+ `);
6176
+ } else {
6177
+ const msg = err instanceof Error ? err.message : String(err);
6178
+ console.error(`
6179
+ Error: ${msg}
6180
+ `);
6181
+ }
6182
+ process.exitCode = 1;
6183
+ return;
6184
+ }
6185
+ const repo = response.data;
6186
+ console.log("\n Repository created successfully.\n");
6187
+ console.log(` id: ${repo.id}`);
6188
+ console.log(` name: ${repo.name}`);
6189
+ console.log(` git_branch: ${repo.git_branch ?? git_branch}`);
6190
+ console.log(
6191
+ `
6192
+ Tip: run \`codebyplan setup\` from the repo directory to link it.
6193
+ `
6194
+ );
6195
+ } finally {
6196
+ rl.close();
6197
+ }
6198
+ }
6199
+ var UUID_RE;
6200
+ var init_create_repo = __esm({
6201
+ "src/cli/create-repo.ts"() {
6202
+ "use strict";
6203
+ init_api();
6204
+ UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
6205
+ }
6206
+ });
6207
+
5900
6208
  // src/cli/version-status.ts
5901
6209
  var version_status_exports = {};
5902
6210
  __export(version_status_exports, {
@@ -7875,6 +8183,21 @@ void (async () => {
7875
8183
  await runResolveWorktree2();
7876
8184
  process.exit(0);
7877
8185
  }
8186
+ if (arg === "create-org") {
8187
+ const { runCreateOrg: runCreateOrg2 } = await Promise.resolve().then(() => (init_create_org(), create_org_exports));
8188
+ await runCreateOrg2();
8189
+ process.exit(0);
8190
+ }
8191
+ if (arg === "create-project") {
8192
+ const { runCreateProject: runCreateProject2 } = await Promise.resolve().then(() => (init_create_project(), create_project_exports));
8193
+ await runCreateProject2();
8194
+ process.exit(0);
8195
+ }
8196
+ if (arg === "create-repo") {
8197
+ const { runCreateRepo: runCreateRepo2 } = await Promise.resolve().then(() => (init_create_repo(), create_repo_exports));
8198
+ await runCreateRepo2();
8199
+ process.exit(0);
8200
+ }
7878
8201
  if (arg === "version-status") {
7879
8202
  const { runVersionStatus: runVersionStatus2 } = await Promise.resolve().then(() => (init_version_status(), version_status_exports));
7880
8203
  await runVersionStatus2();
@@ -7970,6 +8293,9 @@ void (async () => {
7970
8293
  codebyplan logout Clear cached OAuth tokens
7971
8294
  codebyplan whoami Show currently authenticated identity
7972
8295
  codebyplan upgrade-auth Migrate legacy x-api-key MCP config to OAuth
8296
+ codebyplan create-org Create a new organization (interactive prompt)
8297
+ codebyplan create-project Create a new project within an organization (interactive prompt)
8298
+ codebyplan create-repo Create a new repository within a project (interactive prompt)
7973
8299
  codebyplan config Sync repo config from DB to .codebyplan/ files
7974
8300
  codebyplan ports Verify port allocations against local package.json scripts
7975
8301
  codebyplan tech-stack Detect and sync tech stack dependencies
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codebyplan",
3
- "version": "1.13.12",
3
+ "version": "1.13.14",
4
4
  "description": "CLI for CodeByPlan — AI-powered development planning and tracking",
5
5
  "type": "module",
6
6
  "bin": {
@@ -61,6 +61,6 @@
61
61
  "prettier": "^3.8.1",
62
62
  "typescript": "^5",
63
63
  "typescript-eslint": "^8.20.0",
64
- "vitest": "^4.0.18"
64
+ "vitest": "^4.1.2"
65
65
  }
66
66
  }
@@ -18,10 +18,6 @@
18
18
  {
19
19
  "type": "command",
20
20
  "command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/cbp-maestro-yaml-validate.sh"
21
- },
22
- {
23
- "type": "command",
24
- "command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/cbp-canonical-templates-nudge.sh"
25
21
  }
26
22
  ]
27
23
  },
@@ -0,0 +1,51 @@
1
+ ---
2
+ name: task-routing-recommendation
3
+ scope: repo-only:codebyplan
4
+ description: Routing guide — when to use /cbp-task-* vs /cbp-standalone-task-*
5
+ ---
6
+
7
+ # Task Routing Recommendation
8
+
9
+ ## Two-Family Command Surface
10
+
11
+ CodeByPlan has two families of task commands since CHK-141:
12
+
13
+ | Family | Commands | When to use |
14
+ |--------|----------|-------------|
15
+ | Checkpoint-bound | `/cbp-task-create`, `/cbp-task-start {chk}-{task}`, `/cbp-task-check`, `/cbp-task-testing`, `/cbp-task-complete` | Work that belongs to a CHK-NNN checkpoint |
16
+ | Standalone | `/cbp-standalone-task-create`, `/cbp-standalone-task-start {task}`, `/cbp-standalone-task-check`, `/cbp-standalone-task-testing`, `/cbp-standalone-task-complete` | Independent work not tied to any checkpoint |
17
+
18
+ ## Round Commands (Both Families)
19
+
20
+ All `/cbp-round-*` commands work for both task families. The correct family is detected from the active task:
21
+ - Checkpoint-bound task in progress → round commands use checkpoint MCP tools
22
+ - Standalone task in progress → round commands use standalone MCP tools
23
+
24
+ ## Identifier Format
25
+
26
+ | Context | Correct format | Example |
27
+ |---------|----------------|---------|
28
+ | Checkpoint-bound task | `{chk}-{task}` | `141-3` = CHK-141 TASK-3 |
29
+ | Standalone task | `{task}` (bare number) | `45` = standalone TASK-45 |
30
+ | Round of checkpoint task | `{chk}-{task}-{round}` | `141-3-1` |
31
+ | Round of standalone task | `{task}-{round}` | `45-2` |
32
+
33
+ ## Bare-Number Rejection Rule
34
+
35
+ Since CHK-141, `/cbp-task-*` commands reject bare-number arguments. If you type `/cbp-task-start 45`, you will see:
36
+
37
+ ```
38
+ task-start: bare number `45` is no longer valid here.
39
+ Use /cbp-standalone-task-start 45 instead — bare numbers no longer route to standalone tasks.
40
+ ```
41
+
42
+ ## Close-Out Routing
43
+
44
+ After task completion, routes use single-directive form (never A/B/C menus):
45
+
46
+ **Checkpoint-bound task complete:**
47
+ - More tasks in checkpoint → auto-triggers next task (same context)
48
+ - Last task in checkpoint → `Next: /clear, then /cbp-checkpoint-check`
49
+
50
+ **Standalone task complete:**
51
+ - Always → `Next: /cbp-session-end` (or `/cbp-standalone-task-create` for new work)
@@ -58,6 +58,8 @@
58
58
  "mcp__codebyplan__create_launch",
59
59
  "mcp__codebyplan__update_launch",
60
60
  "mcp__codebyplan__delete_launch",
61
+ "mcp__codebyplan__create_organization",
62
+ "mcp__codebyplan__create_project",
61
63
  "mcp__codebyplan__create_repo",
62
64
  "mcp__codebyplan__delete_session_log",
63
65
  "mcp__codebyplan__delete_worktree",
@@ -67,6 +69,12 @@
67
69
  "mcp__codebyplan__release_assignment",
68
70
  "Bash(codebyplan setup:*)",
69
71
  "Bash(npx codebyplan setup:*)",
72
+ "Bash(codebyplan create-org:*)",
73
+ "Bash(npx codebyplan create-org:*)",
74
+ "Bash(codebyplan create-project:*)",
75
+ "Bash(npx codebyplan create-project:*)",
76
+ "Bash(codebyplan create-repo:*)",
77
+ "Bash(npx codebyplan create-repo:*)",
70
78
  "Bash(codebyplan login:*)",
71
79
  "Bash(npx codebyplan login:*)",
72
80
  "Bash(codebyplan logout:*)",
@@ -7,6 +7,27 @@ effort: low
7
7
 
8
8
  <!-- Re-read this file before executing. Do not rely on memory. -->
9
9
 
10
+ ## Kind Detection
11
+
12
+ Inspect the resolved identifier from argument parsing to determine the task kind:
13
+
14
+ | Identifier shape | KIND |
15
+ |-----------------|------|
16
+ | `{task}-{round}` (2-segment, e.g. `45-2`) | `standalone` |
17
+ | `{chk}-{task}-{round}` (3-segment, e.g. `141-3-1`) | `checkpoint` |
18
+ | _(empty / free-text)_ | Check `get_current_standalone_task` first; if found → `standalone`. Else → `checkpoint` via `get_current_task`. |
19
+
20
+ Set `KIND` for the rest of this skill. MCP tool names vary by KIND:
21
+
22
+ | Operation | `checkpoint` KIND | `standalone` KIND |
23
+ |-----------|------------------|-------------------|
24
+ | Get task | `get_current_task(repo_id)` | `get_current_standalone_task(repo_id)` |
25
+ | Get rounds | `get_rounds(task_id)` | `get_standalone_rounds(standalone_task_id)` |
26
+ | Add round | `add_round(task_id, ...)` | `add_standalone_round(standalone_task_id, ...)` |
27
+ | Update round | `update_round(round_id, ...)` | `update_standalone_round(standalone_round_id, ...)` |
28
+ | Complete round | `complete_round(round_id, duration_minutes?)` | `complete_standalone_round(standalone_round_id, duration_minutes?, caller_worktree_id)` ⚠️ `caller_worktree_id` is REQUIRED for standalone |
29
+ | Update task | `update_task(task_id, ...)` | `update_standalone_task(standalone_task_id, ...)` |
30
+
10
31
  # Round Check Command
11
32
 
12
33
  Run automated checks independently with mandatory execution. Updates round QA. Hard fails if mandatory checks (build/lint/types) fail.
@@ -15,7 +36,10 @@ Run automated checks independently with mandatory execution. Updates round QA. H
15
36
 
16
37
  ### Step 1: Get Current Round
17
38
 
18
- Use MCP `get_current_task` to find active task, then `get_rounds` to find the in-progress round.
39
+ Use Kind Detection above to set KIND. Then:
40
+
41
+ - **checkpoint KIND**: MCP `get_current_task(repo_id)` to find active task, then `get_rounds(task_id)` to find the in-progress round.
42
+ - **standalone KIND**: MCP `get_current_standalone_task(repo_id)` to find active task, then `get_standalone_rounds(standalone_task_id)` to find the in-progress round.
19
43
 
20
44
  ### Step 2: Determine Project Root
21
45
 
@@ -59,7 +83,7 @@ Scan all captured output for:
59
83
 
60
84
  ### Step 6: Save QA Results
61
85
 
62
- Update round QA via MCP `update_round(round_id, qa: ...)`:
86
+ Update round QA via MCP `update_round(round_id, qa: ...)` (checkpoint KIND) or `update_standalone_round(standalone_round_id, qa: ...)` (standalone KIND):
63
87
 
64
88
  ```json
65
89
  {
@@ -99,6 +123,6 @@ If soft failures only: `Run /cbp-round-start to trigger auto-fix, or fix manuall
99
123
 
100
124
  ## Integration
101
125
 
102
- - **Reads**: MCP `get_current_task`, `get_rounds`
103
- - **Writes**: MCP `update_round` (qa field)
126
+ - **Reads**: MCP `get_current_task` / `get_current_standalone_task`, `get_rounds` / `get_standalone_rounds` (per KIND)
127
+ - **Writes**: MCP `update_round` / `update_standalone_round` (qa field) — per KIND
104
128
  - **Standalone**: Can be run independently at any time
@@ -5,6 +5,27 @@ description: Summary wrap-up after testing phase completes
5
5
  effort: high
6
6
  ---
7
7
 
8
+ ## Kind Detection
9
+
10
+ Inspect the resolved identifier from argument parsing to determine the task kind:
11
+
12
+ | Identifier shape | KIND |
13
+ |-----------------|------|
14
+ | `{task}-{round}` (2-segment, e.g. `45-2`) | `standalone` |
15
+ | `{chk}-{task}-{round}` (3-segment, e.g. `141-3-1`) | `checkpoint` |
16
+ | _(empty / free-text)_ | Check `get_current_standalone_task` first; if found → `standalone`. Else → `checkpoint` via `get_current_task`. |
17
+
18
+ Set `KIND` for the rest of this skill. MCP tool names vary by KIND:
19
+
20
+ | Operation | `checkpoint` KIND | `standalone` KIND |
21
+ |-----------|------------------|-------------------|
22
+ | Get task | `get_current_task(repo_id)` | `get_current_standalone_task(repo_id)` |
23
+ | Get rounds | `get_rounds(task_id)` | `get_standalone_rounds(standalone_task_id)` |
24
+ | Add round | `add_round(task_id, ...)` | `add_standalone_round(standalone_task_id, ...)` |
25
+ | Update round | `update_round(round_id, ...)` | `update_standalone_round(standalone_round_id, ...)` |
26
+ | Complete round | `complete_round(round_id, duration_minutes?)` | `complete_standalone_round(standalone_round_id, duration_minutes?, caller_worktree_id)` ⚠️ `caller_worktree_id` is REQUIRED for standalone |
27
+ | Update task | `update_task(task_id, ...)` | `update_standalone_task(standalone_task_id, ...)` |
28
+
8
29
  # Round End Command
9
30
 
10
31
  Summary phase — presents what was done, then runs code quality review to catch bugs and logic errors that automated checks miss.
@@ -21,14 +42,16 @@ See `reference/inline-fallback.md` for full trigger table, procedure, and covera
21
42
 
22
43
  ## Identifier Notation
23
44
 
24
- This skill operates on the **active** task/round resolved via MCP `get_current_task` / `get_rounds` and does not accept a positional identifier argument. Canonical chk-task-round notation — used in prose, error messages, and cross-references — follows `.claude/rules/notation-consistency.md` "CHK / TASK / ROUND Identifier Notation": `108-1` (CHK-108 TASK-1), `45` (standalone TASK-45), `108-1-2` (round 2 of CHK-108 TASK-1), `45-2` (round 2 of standalone TASK-45).
45
+ This skill operates on the **active** task/round resolved via MCP and does not accept a positional identifier argument. Canonical chk-task-round notation — used in prose, error messages, and cross-references — follows `.claude/rules/notation-consistency.md` "CHK / TASK / ROUND Identifier Notation": `108-1` (CHK-108 TASK-1), `45` (standalone TASK-45), `108-1-2` (round 2 of CHK-108 TASK-1), `45-2` (round 2 of standalone TASK-45).
25
46
 
26
47
  ## Instructions
27
48
 
28
49
  ### Step 1: Get Current Task and Round
29
50
 
30
- Use MCP `get_current_task` with repo_id (pass `checkpoint_id` if known to avoid disambiguation) to find the active task.
31
- Use MCP `get_rounds` for the task to find the in-progress round.
51
+ Use Kind Detection above to set KIND. Then:
52
+
53
+ - **checkpoint KIND**: MCP `get_current_task(repo_id)` (pass `checkpoint_id` if known) to find the active task. MCP `get_rounds(task_id)` to find the in-progress round.
54
+ - **standalone KIND**: MCP `get_current_standalone_task(repo_id)` to find the active task. MCP `get_standalone_rounds(standalone_task_id)` to find the in-progress round.
32
55
 
33
56
  Load round context with all outputs (executor_output, testing_qa_output, reviewer_output).
34
57
 
@@ -70,11 +93,11 @@ Merge with previous rounds (supersede items for re-modified files, preserve veri
70
93
 
71
94
  ### Step 4: Update Task Files and QA
72
95
 
73
- Update via MCP:
96
+ Update via MCP using KIND-appropriate tools:
74
97
 
75
- - `update_task(task_id, files_changed: [...])` — merge with existing
76
- - `update_round(round_id, files_changed: [...], qa: {items: [auto_qa items + default_checklist items]})` — round-specific
77
- - `update_task(task_id, qa: {items: [auto_qa items + default_checklist items]})` — aggregated
98
+ - `update_task(task_id, files_changed: [...])` / `update_standalone_task(standalone_task_id, files_changed: [...])` — merge with existing
99
+ - `update_round(round_id, files_changed: [...], qa: {items: [auto_qa items + default_checklist items]})` / `update_standalone_round(standalone_round_id, ...)` — round-specific
100
+ - `update_task(task_id, qa: {items: [auto_qa items + default_checklist items]})` / `update_standalone_task(standalone_task_id, qa: {items: [auto_qa items + default_checklist items]})` — aggregated
78
101
 
79
102
  ### Step 5: Present Summary
80
103
 
@@ -137,8 +160,8 @@ Example tables and the `inline` option gating spec: see `reference/findings-pres
137
160
  - Auto-accept ALL findings into `improve_round_findings[]` regardless of severity (the user opted into the loop).
138
161
  - Skip the polish-spiral stop-gate (auto-loop has its own cap-exhausted termination).
139
162
  - Skip the user findings-decision prompt.
140
- - Save findings via `update_round` exactly as in manual mode.
141
- - Auto-trigger `/cbp-round-update` immediately. round-update Step 6 will decide whether to spawn another round or exit clean (see cbp-round-update SKILL.md Step 6).
163
+ - Save findings via `update_round` / `update_standalone_round` per KIND exactly as in manual mode.
164
+ - Auto-trigger `/cbp-round-update` immediately. round-update Step 4 will decide whether to spawn another round or exit clean (see cbp-round-update SKILL.md Step 4).
142
165
 
143
166
  **Else (manual mode — flag absent or false):**
144
167
 
@@ -146,7 +169,7 @@ Run the existing flow:
146
169
 
147
170
  1. After round 2+, surface the polish-spiral stop-gate per `polish-spiral-stop-gate.md` (defer-to-followups vs continue).
148
171
  2. Surface the findings-decision AskUserQuestion (with optional `inline` per the gating rules in `reference/findings-presentation.md`).
149
- 3. Save accepted/rejected findings to round context via MCP `update_round`:
172
+ 3. Save accepted/rejected findings to round context via MCP `update_round` / `update_standalone_round` per KIND:
150
173
  ```json
151
174
  {
152
175
  "context": {
@@ -167,7 +190,7 @@ Run the existing flow:
167
190
  ## Integration
168
191
 
169
192
  - **Triggered by**: `/cbp-round-execute` (auto, after all waves + testing complete)
170
- - **Reads**: MCP `get_current_task`, `get_rounds`, round context
171
- - **Writes**: MCP `update_round`, `update_task` (files_changed, qa, findings)
193
+ - **Reads**: MCP `get_current_task` / `get_current_standalone_task`, `get_rounds` / `get_standalone_rounds` (per KIND), round context
194
+ - **Writes**: MCP `update_round` / `update_standalone_round`, `update_task` / `update_standalone_task` (files_changed, qa, findings) — per KIND
172
195
  - **Spawns**: `cbp-improve-round` (code quality review)
173
196
  - **Triggers**: `/cbp-round-update` (auto, after findings handled)