@starlein/paperclip-plugin-company-wizard 0.4.2 → 0.4.5-a

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 (30) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.md +1 -1
  3. package/dist/manifest.js +1 -1
  4. package/dist/manifest.js.map +1 -1
  5. package/dist/ui/index.css +6 -3
  6. package/dist/ui/index.css.map +2 -2
  7. package/dist/ui/index.js +69 -74
  8. package/dist/ui/index.js.map +3 -3
  9. package/dist/worker.js +120 -18
  10. package/dist/worker.js.map +2 -2
  11. package/package.json +1 -1
  12. package/templates/bootstrap-instructions.md +1 -1
  13. package/templates/modules/ci-cd/agents/devops/skills/ci-cd.md +4 -4
  14. package/templates/modules/ci-cd/agents/engineer/skills/ci-cd.fallback.md +1 -1
  15. package/templates/modules/ci-cd/module.meta.json +3 -3
  16. package/templates/modules/ci-cd/skills/ci-cd.bar.md +2 -2
  17. package/templates/modules/ci-cd/skills/ci-cd.md +4 -4
  18. package/templates/modules/github-repo/README.md +2 -2
  19. package/templates/modules/github-repo/agents/engineer/skills/git-workflow.md +2 -2
  20. package/templates/modules/github-repo/docs/git-workflow.md +27 -2
  21. package/templates/modules/github-repo/module.meta.json +1 -1
  22. package/templates/modules/launch-mvp/module.meta.json +1 -1
  23. package/templates/modules/pr-review/README.md +7 -7
  24. package/templates/modules/pr-review/agents/code-reviewer/skills/code-review.md +32 -16
  25. package/templates/modules/pr-review/agents/engineer/skills/pr-workflow.md +12 -11
  26. package/templates/modules/pr-review/docs/pr-conventions.md +13 -13
  27. package/templates/modules/pr-review/module.meta.json +3 -3
  28. package/templates/presets/fast/preset.meta.json +2 -2
  29. package/templates/presets/repo-maintenance/preset.meta.json +1 -1
  30. package/templates/roles/engineer/SOUL.md +1 -1
package/dist/worker.js CHANGED
@@ -9282,6 +9282,7 @@ import { join } from "node:path";
9282
9282
  var DEFAULT_CEO_ADAPTER_TYPE = "codex_local";
9283
9283
  var DEFAULT_CEO_MODEL = "gpt-5.5";
9284
9284
  var DEFAULT_CEO_THINKING_LEVEL = "high";
9285
+ var DEFAULT_WORKER_THINKING_LEVEL = "medium";
9285
9286
  var DEFAULT_CEO_MAX_CONCURRENT_RUNS = 1;
9286
9287
  var DEFAULT_CEO_HEARTBEAT_INTERVAL_SEC = 3600;
9287
9288
  var DEFAULT_CLAUDE_CEO_MODEL = "claude-opus-4-6";
@@ -9291,10 +9292,12 @@ function asTrimmedString(value) {
9291
9292
  function normalizeCeoAdapterType(userCeoAdapter = {}) {
9292
9293
  return asTrimmedString(userCeoAdapter.type) || DEFAULT_CEO_ADAPTER_TYPE;
9293
9294
  }
9294
- function buildCeoAdapterConfig({
9295
+ function buildAdapterConfig({
9295
9296
  userCeoAdapter = {},
9296
9297
  companyDir,
9297
- roleAdapterOverrides = {}
9298
+ roleAdapterOverrides = {},
9299
+ defaultThinkingLevel = DEFAULT_CEO_THINKING_LEVEL,
9300
+ inheritUserThinking = true
9298
9301
  } = {}) {
9299
9302
  const adapterType = normalizeCeoAdapterType(userCeoAdapter);
9300
9303
  const userCwd = asTrimmedString(userCeoAdapter.cwd);
@@ -9302,7 +9305,8 @@ function buildCeoAdapterConfig({
9302
9305
  const overrideModel = asTrimmedString(roleAdapterOverrides.model);
9303
9306
  const defaultModel = adapterType === "claude_local" ? DEFAULT_CLAUDE_CEO_MODEL : DEFAULT_CEO_MODEL;
9304
9307
  const model = userModel || overrideModel || defaultModel;
9305
- const thinkingLevel = asTrimmedString(userCeoAdapter.thinkingLevel) || asTrimmedString(userCeoAdapter.modelReasoningEffort) || asTrimmedString(userCeoAdapter.reasoningEffort) || asTrimmedString(roleAdapterOverrides.thinkingLevel) || asTrimmedString(roleAdapterOverrides.modelReasoningEffort) || asTrimmedString(roleAdapterOverrides.reasoningEffort) || DEFAULT_CEO_THINKING_LEVEL;
9308
+ const userThinking = inheritUserThinking ? asTrimmedString(userCeoAdapter.thinkingLevel) || asTrimmedString(userCeoAdapter.modelReasoningEffort) || asTrimmedString(userCeoAdapter.reasoningEffort) : "";
9309
+ const thinkingLevel = userThinking || asTrimmedString(roleAdapterOverrides.thinkingLevel) || asTrimmedString(roleAdapterOverrides.modelReasoningEffort) || asTrimmedString(roleAdapterOverrides.reasoningEffort) || defaultThinkingLevel;
9306
9310
  const adapterConfig = {
9307
9311
  ...roleAdapterOverrides,
9308
9312
  cwd: userCwd || companyDir,
@@ -9319,6 +9323,20 @@ function buildCeoAdapterConfig({
9319
9323
  }
9320
9324
  return adapterConfig;
9321
9325
  }
9326
+ function buildCeoAdapterConfig(opts = {}) {
9327
+ return buildAdapterConfig({
9328
+ ...opts,
9329
+ defaultThinkingLevel: DEFAULT_CEO_THINKING_LEVEL,
9330
+ inheritUserThinking: true
9331
+ });
9332
+ }
9333
+ function buildWorkerAdapterConfig(opts = {}) {
9334
+ return buildAdapterConfig({
9335
+ ...opts,
9336
+ defaultThinkingLevel: DEFAULT_WORKER_THINKING_LEVEL,
9337
+ inheritUserThinking: false
9338
+ });
9339
+ }
9322
9340
  function buildCeoAgentRuntimeConfig() {
9323
9341
  return {
9324
9342
  heartbeat: {
@@ -9539,7 +9557,18 @@ async function assembleCompany({
9539
9557
  reviewers.push(role);
9540
9558
  }
9541
9559
  const approver = typeof reviewGate.approver === "string" && allRoles.has(reviewGate.approver) ? reviewGate.approver : void 0;
9542
- const mergeGate = typeof reviewGate.mergeGate === "string" && allRoles.has(reviewGate.mergeGate) ? reviewGate.mergeGate : void 0;
9560
+ let mergeGate = typeof reviewGate.mergeGate === "string" && allRoles.has(reviewGate.mergeGate) ? reviewGate.mergeGate : void 0;
9561
+ if (!mergeGate) {
9562
+ const mergeGateFallbacks = [
9563
+ "code-reviewer",
9564
+ "devops",
9565
+ "ui-designer",
9566
+ "ux-researcher",
9567
+ "security-engineer",
9568
+ "qa"
9569
+ ];
9570
+ mergeGate = mergeGateFallbacks.find((role) => allRoles.has(role) && role !== approver);
9571
+ }
9543
9572
  if (approver) {
9544
9573
  const idx = reviewers.indexOf(approver);
9545
9574
  if (idx !== -1) reviewers.splice(idx, 1);
@@ -9561,11 +9590,12 @@ async function assembleCompany({
9561
9590
  if (gate.mergeGate) {
9562
9591
  const gatePrecondition = hasCi ? "CI must be green before merge" : "no CI configured \u2014 run the test suite/build and paste the output before merge";
9563
9592
  stages.push(
9564
- ` - stage ${stages.length + 1} (approval) \u2192 assign ${JSON.stringify(gate.mergeGate)} \u2014 merge gate: ${gatePrecondition}; merge the PR, then record approved to close`
9593
+ ` - stage ${stages.length + 1} (approval) \u2192 assign ${JSON.stringify(gate.mergeGate)} \u2014 merge gate (non-author): ${gatePrecondition}; merge the PR, then record approved to close`
9565
9594
  );
9566
9595
  }
9567
9596
  return `- **executionPolicy** (set when creating this issue; resolve each role to its agentId):
9568
9597
  ${stages.join("\n")}
9598
+ - never assign the issue's executor/author to any stage \u2014 Paperclip excludes the original executor, so a self-stage has no eligible participant and the issue stalls (422); the merge gate must be a non-author
9569
9599
  - every verdict must cite executed verification (commands + results); "looks good" without evidence is not a valid verdict
9570
9600
 
9571
9601
  `;
@@ -10299,8 +10329,8 @@ Read: \`docs/${doc}\`
10299
10329
  bootstrap += `- Do not reuse parent workspaces for subissues unless explicitly requested.
10300
10330
  `;
10301
10331
  if (moduleNames.includes("pr-review")) {
10302
- const ciClause = hasCi ? "CI (lint/test/build) must be green before the Engineer merges \u2014 this is the hard gate and cannot be skipped" : "no CI is configured, so the Engineer must run the test suite/build and paste the real output into the merge-gate verdict before merging \u2014 this is the hard gate";
10303
- bootstrap += `- Required PR reviews use the issue's \`executionPolicy\`. The substantive gate is execution, not opinion: ${ciClause}. Stages, in order: a \`review\` stage for QA when present (test adequacy / running the tests), a \`review\` stage for the Security Engineer **only when the change is security-relevant** (auth, secrets, input boundaries, crypto, dependencies, infra exposure), an \`approval\` stage for the Product Owner (intent/scope), then a final \`approval\` merge-gate stage for the Engineer (who satisfies the hard gate above, merges the PR, then records approval to close the issue). The merge gate must be last so the Product Owner's approval does not auto-close the issue with the PR still open. The Code Reviewer and other domain reviewers may add advisory, non-blocking comments but do not gate the merge. Every verdict must cite executed verification. Resolve each role to its agentId. Model review stages in executionPolicy rather than child issues or @-mentions.
10332
+ const ciClause = hasCi ? "CI (lint/test/build) must be green before the merge gate merges \u2014 this is the hard gate and cannot be skipped" : "no CI is configured, so the merge-gate agent must run the test suite/build and paste the real output into the merge-gate verdict before merging \u2014 this is the hard gate";
10333
+ bootstrap += `- Required PR reviews use the issue's \`executionPolicy\`. The substantive gate is execution, not opinion: ${ciClause}. Stages, in order: a \`review\` stage for QA when present (test adequacy / running the tests), a \`review\` stage for the Security Engineer **only when the change is security-relevant** (auth, secrets, input boundaries, crypto, dependencies, infra exposure), an \`approval\` stage for the Product Owner (intent/scope), then a final \`approval\` merge-gate stage for the **Code Reviewer** (a non-author who satisfies the hard gate above, merges the PR, then records approval to close the issue). **Never list the issue's executor/author as a participant in any stage** \u2014 Paperclip excludes the original executor from review/approval, so a stage whose only participant is the author has no eligible participant and the issue stalls in \`in_review\` (422 No eligible approval participant); this is why the merge gate is the Code Reviewer (or another present non-author), not the engineer who wrote the code. The merge gate must be last so the Product Owner's approval does not auto-close the issue with the PR still open. Other domain reviewers may add advisory, non-blocking comments but do not gate the merge. Every verdict must cite executed verification. Resolve each role to its agentId. Model review stages in executionPolicy rather than child issues or @-mentions.
10304
10334
  `;
10305
10335
  }
10306
10336
  bootstrap += `
@@ -10939,7 +10969,7 @@ var __dirname = path2.dirname(fileURLToPath2(import.meta.url));
10939
10969
  var DEFAULT_TEMPLATES_REPO_URL = "https://github.com/starlein/paperclip-plugin-company-wizard/tree/main/templates";
10940
10970
  var BUNDLED_TEMPLATES_DIR = path2.resolve(__dirname, "..", "templates");
10941
10971
  var PLUGIN_PACKAGE_NAME = "@starlein/paperclip-plugin-company-wizard";
10942
- var CURRENT_PLUGIN_VERSION = "0.4.2";
10972
+ var CURRENT_PLUGIN_VERSION = "0.4.5";
10943
10973
  var NPM_LATEST_URL = "https://registry.npmjs.org/@starlein%2Fpaperclip-plugin-company-wizard/latest";
10944
10974
  function copyDirSync(src, dest) {
10945
10975
  fs2.mkdirSync(dest, { recursive: true });
@@ -11177,6 +11207,49 @@ function resolveWritableCompaniesDir(cfg, log) {
11177
11207
  `Unable to prepare a writable companies directory. Last attempt failed at ${lastError}`
11178
11208
  );
11179
11209
  }
11210
+ function isPathInside(parent, child) {
11211
+ const relative = path2.relative(parent, child);
11212
+ return relative === "" || !!relative && !relative.startsWith("..") && !path2.isAbsolute(relative);
11213
+ }
11214
+ function normalizeGitBranch(value) {
11215
+ const branch = typeof value === "string" && value.trim() ? value.trim() : "main";
11216
+ return /^[A-Za-z0-9._/-]+$/.test(branch) ? branch.replace(/^origin\//, "") : "main";
11217
+ }
11218
+ function prepareLocalProjectWorkspace(mainProject, companyDir, log) {
11219
+ const workspace = mainProject?.workspace;
11220
+ if (!workspace || workspace.sourceType !== "local_path") return;
11221
+ const cwd = typeof workspace.cwd === "string" ? workspace.cwd.trim() : "";
11222
+ if (!cwd) return;
11223
+ const resolvedCompanyDir = path2.resolve(companyDir);
11224
+ const resolvedCwd = path2.resolve(cwd);
11225
+ if (!isPathInside(resolvedCompanyDir, resolvedCwd)) {
11226
+ log?.(`\u26A0 Skipped project workspace preparation outside company dir: ${resolvedCwd}`);
11227
+ return;
11228
+ }
11229
+ fs2.mkdirSync(resolvedCwd, { recursive: true });
11230
+ const gitDir = path2.join(resolvedCwd, ".git");
11231
+ if (fs2.existsSync(gitDir)) {
11232
+ log?.(`\u2713 Project workspace ready: ${resolvedCwd}`);
11233
+ return;
11234
+ }
11235
+ const branch = normalizeGitBranch(workspace.defaultRef);
11236
+ execFileSync("git", ["init", "-b", branch], { cwd: resolvedCwd, stdio: "pipe" });
11237
+ execFileSync(
11238
+ "git",
11239
+ [
11240
+ "-c",
11241
+ "user.email=bootstrap@paperclip.local",
11242
+ "-c",
11243
+ "user.name=Paperclip Bootstrap",
11244
+ "commit",
11245
+ "--allow-empty",
11246
+ "-m",
11247
+ "chore: initialize repository"
11248
+ ],
11249
+ { cwd: resolvedCwd, stdio: "pipe" }
11250
+ );
11251
+ log?.(`\u2713 Project workspace initialized: ${resolvedCwd}`);
11252
+ }
11180
11253
  function formatRoleName(role) {
11181
11254
  return role.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
11182
11255
  }
@@ -11266,23 +11339,36 @@ function buildHiringPlanBody({
11266
11339
 
11267
11340
  Generated by Company Wizard on ${today}.
11268
11341
 
11269
- ## Instruction Source
11342
+ ## Status: initial team already provisioned
11343
+
11344
+ Company Wizard has already submitted the initial team below as **governed hires**
11345
+ via \`/agent-hires\` (each with a full instruction bundle assembled from curated role
11346
+ templates). Where the board requires approval, those hires are pending your approval \u2014
11347
+ they were **not** auto-approved.
11348
+
11349
+ **This issue is your review checkpoint \u2014 not a re-hiring task.** Do not create the
11350
+ roles below again.
11270
11351
 
11271
- Company Wizard uses curated role templates from its template library. When proposing additional hires after bootstrap, follow the Paperclip \`paperclip-create-agent\` workflow: choose an exact, adjacent, or generic template; run the draft-review checklist; submit via \`/agent-hires\`; link this issue as \`sourceIssueId\`; and wait for board approval when required.
11352
+ ## Your tasks
11272
11353
 
11273
- ## Initial Roles
11354
+ 1. **Review each provisioned agent against the draft-review checklist** (Paperclip
11355
+ \`paperclip-create-agent\` \u2192 \`references/draft-review-checklist.md\`): instruction
11356
+ quality, correct adapter/model/thinking level, escalation/reportsTo path, and
11357
+ desiredSkills justification. Note any corrections in the decision log.
11358
+ 2. **Approve or reject** the pending hires accordingly.
11359
+ 3. **Only hire for genuine gaps.** If a capability is missing after the first
11360
+ roadmap/backlog pass, follow the \`paperclip-create-agent\` workflow: pick an exact,
11361
+ adjacent, or generic template, run the draft-review checklist, submit via
11362
+ \`/agent-hires\` with a concrete AGENTS.md draft + adapter config + desiredSkills
11363
+ justification, and set \`sourceIssueId\` to this issue.
11364
+
11365
+ ## Initial Roles (already provisioned)
11274
11366
 
11275
11367
  ${roles.map((role) => `- ${formatRoleName(role)}`).join("\n")}
11276
11368
 
11277
11369
  ## Selected Modules
11278
11370
 
11279
11371
  ${moduleNames.length > 0 ? moduleNames.map((mod) => `- ${mod}`).join("\n") : "- none"}
11280
-
11281
- ## Follow-up Review
11282
-
11283
- - Reassess capacity after the first roadmap/backlog pass.
11284
- - Do not hire for capabilities already covered by existing roles.
11285
- - If a gap remains, submit a governed hire request with a concrete AGENTS.md draft, adapter config, desiredSkills justification, and sourceIssueId pointing to this hiring plan issue.
11286
11372
  `;
11287
11373
  }
11288
11374
  var plugin = definePlugin({
@@ -11567,6 +11653,7 @@ var plugin = definePlugin({
11567
11653
  log(`\u270E Override: ${relPath}`);
11568
11654
  }
11569
11655
  }
11656
+ prepareLocalProjectWorkspace(assembleResult.mainProject, companyDir, log);
11570
11657
  const ceoInstructionsDir = path2.join(companyDir, "agents", "ceo");
11571
11658
  const ceoEntryFile = "AGENTS.md";
11572
11659
  const ceoEntryPath = path2.join(ceoInstructionsDir, ceoEntryFile);
@@ -11774,6 +11861,20 @@ var plugin = definePlugin({
11774
11861
  fallbackEntryContent: ceoPromptTemplate,
11775
11862
  log
11776
11863
  });
11864
+ for (const govIssue of [
11865
+ { issue: boardOperationsIssue, label: "Board Operations" },
11866
+ { issue: hiringPlanIssue, label: "Hiring Plan" }
11867
+ ]) {
11868
+ if (!govIssue.issue?.id) continue;
11869
+ try {
11870
+ await client.updateIssue(govIssue.issue.id, { assigneeAgentId: ceoAgentId });
11871
+ log(`\u2713 Assigned ${govIssue.label} issue to CEO`);
11872
+ } catch (assignErr) {
11873
+ log(
11874
+ `\u26A0 Could not assign ${govIssue.label} issue to CEO: ${assignErr instanceof Error ? assignErr.message : String(assignErr)}`
11875
+ );
11876
+ }
11877
+ }
11777
11878
  const teamRoles = [...assembleResult.allRoles ?? []].filter(
11778
11879
  (r) => r && r !== "ceo"
11779
11880
  );
@@ -11799,7 +11900,7 @@ var plugin = definePlugin({
11799
11900
  ...roleDescription ? { description: roleDescription } : {}
11800
11901
  };
11801
11902
  const roleRuntimeConfig = buildWorkerAgentRuntimeConfig();
11802
- const roleAdapterConfig = buildCeoAdapterConfig({
11903
+ const roleAdapterConfig = buildWorkerAdapterConfig({
11803
11904
  userCeoAdapter,
11804
11905
  companyDir,
11805
11906
  roleAdapterOverrides: assembleResult.roleAdapterOverrides?.get(roleName) ?? {}
@@ -11982,6 +12083,7 @@ var worker_default = plugin;
11982
12083
  runWorker(plugin, import.meta.url);
11983
12084
  export {
11984
12085
  worker_default as default,
12086
+ prepareLocalProjectWorkspace,
11985
12087
  resolveWritableCompaniesDir
11986
12088
  };
11987
12089
  //# sourceMappingURL=worker.js.map