codebyplan 1.13.12 → 1.13.13

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.13";
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.13",
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
  },
@@ -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:*)",