@starlein/paperclip-plugin-company-wizard 0.3.24 → 0.4.1

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 (65) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +15 -11
  3. package/dist/manifest.js +1 -6
  4. package/dist/manifest.js.map +2 -2
  5. package/dist/ui/index.css +3 -0
  6. package/dist/ui/index.css.map +2 -2
  7. package/dist/ui/index.js +59 -30
  8. package/dist/ui/index.js.map +3 -3
  9. package/dist/worker.js +263 -81
  10. package/dist/worker.js.map +3 -3
  11. package/package.json +1 -1
  12. package/templates/ai-wizard/config-format.md +4 -4
  13. package/templates/ai-wizard/interview-system.md +3 -3
  14. package/templates/ai-wizard/single-shot-system.md +3 -3
  15. package/templates/bootstrap-instructions.md +3 -3
  16. package/templates/modules/architecture-plan/agents/ui-designer/skills/design-system.md +1 -1
  17. package/templates/modules/auto-assign/agents/ceo/heartbeat-section.md +2 -8
  18. package/templates/modules/auto-assign/agents/product-owner/heartbeat-section.md +2 -9
  19. package/templates/modules/auto-assign/module.meta.json +1 -1
  20. package/templates/modules/auto-assign/skills/auto-assign.md +18 -15
  21. package/templates/modules/backlog/agents/ceo/heartbeat-section.md +2 -9
  22. package/templates/modules/backlog/agents/product-owner/heartbeat-section.md +2 -14
  23. package/templates/modules/backlog/module.meta.json +1 -1
  24. package/templates/modules/backlog/skills/backlog-health.md +20 -21
  25. package/templates/modules/codebase-onboarding/skills/codebase-audit.md +29 -30
  26. package/templates/modules/github-repo/agents/engineer/skills/git-workflow.md +11 -7
  27. package/templates/modules/github-repo/docs/git-workflow.md +10 -6
  28. package/templates/modules/hiring-review/skills/hiring-review.md +40 -16
  29. package/templates/modules/market-analysis/agents/ux-researcher/skills/market-analysis.md +1 -1
  30. package/templates/modules/pr-review/README.md +13 -13
  31. package/templates/modules/pr-review/agents/devops/skills/infra-review.md +1 -1
  32. package/templates/modules/pr-review/agents/engineer/skills/pr-workflow.md +17 -11
  33. package/templates/modules/pr-review/agents/product-owner/skills/product-review.md +1 -1
  34. package/templates/modules/pr-review/agents/qa/skills/qa-review.md +1 -1
  35. package/templates/modules/pr-review/agents/security-engineer/skills/pr-security-review.md +1 -1
  36. package/templates/modules/pr-review/agents/ui-designer/skills/design-review.md +1 -1
  37. package/templates/modules/pr-review/agents/ux-researcher/skills/ux-review.md +1 -1
  38. package/templates/modules/pr-review/docs/pr-conventions.md +11 -8
  39. package/templates/modules/stall-detection/README.md +8 -8
  40. package/templates/modules/stall-detection/agents/ceo/heartbeat-section.md +2 -11
  41. package/templates/modules/stall-detection/agents/ceo/skills/stall-detection.md +22 -13
  42. package/templates/modules/stall-detection/module.meta.json +1 -1
  43. package/templates/modules/triage/skills/issue-triage.md +20 -33
  44. package/templates/roles/audio-designer/HEARTBEAT.md +37 -21
  45. package/templates/roles/ceo/HEARTBEAT.md +34 -56
  46. package/templates/roles/cmo/HEARTBEAT.md +37 -21
  47. package/templates/roles/code-reviewer/HEARTBEAT.md +39 -19
  48. package/templates/roles/cto/HEARTBEAT.md +33 -25
  49. package/templates/roles/customer-success/HEARTBEAT.md +39 -19
  50. package/templates/roles/devops/HEARTBEAT.md +36 -25
  51. package/templates/roles/engineer/AGENTS.md +27 -9
  52. package/templates/roles/engineer/HEARTBEAT.md +35 -21
  53. package/templates/roles/game-artist/HEARTBEAT.md +37 -21
  54. package/templates/roles/game-designer/HEARTBEAT.md +37 -21
  55. package/templates/roles/level-designer/HEARTBEAT.md +37 -21
  56. package/templates/roles/product-owner/AGENTS.md +24 -8
  57. package/templates/roles/product-owner/HEARTBEAT.md +37 -19
  58. package/templates/roles/qa/AGENTS.md +26 -11
  59. package/templates/roles/qa/HEARTBEAT.md +37 -21
  60. package/templates/roles/security-engineer/AGENTS.md +21 -23
  61. package/templates/roles/security-engineer/HEARTBEAT.md +39 -19
  62. package/templates/roles/technical-writer/HEARTBEAT.md +39 -18
  63. package/templates/roles/ui-designer/AGENTS.md +26 -9
  64. package/templates/roles/ui-designer/HEARTBEAT.md +37 -21
  65. package/templates/roles/ux-researcher/HEARTBEAT.md +37 -21
package/dist/worker.js CHANGED
@@ -9381,11 +9381,7 @@ function normalizeExecutionBaseRef(ref, fallbackRef) {
9381
9381
  (value) => typeof value === "string" && value.trim()
9382
9382
  );
9383
9383
  const selected = candidates.length > 0 ? String(candidates[0]).trim() : "";
9384
- if (!selected) return "origin/main";
9385
- if (selected.startsWith("origin/") || selected.startsWith("refs/")) {
9386
- return selected;
9387
- }
9388
- return `origin/${selected}`;
9384
+ return selected || null;
9389
9385
  }
9390
9386
  async function assembleCompany({
9391
9387
  companyName,
@@ -9400,7 +9396,7 @@ async function assembleCompany({
9400
9396
  presetRoutines = [],
9401
9397
  presetLabels = [],
9402
9398
  enableIsolatedWorktrees = false,
9403
- enableEnrichedPersonas = false,
9399
+ enableEnrichedPersonas = true,
9404
9400
  outputDir,
9405
9401
  templatesDir,
9406
9402
  onProgress = () => {
@@ -10013,6 +10009,9 @@ Read: \`docs/${doc}\`
10013
10009
  if (allGoals.length > 0) {
10014
10010
  bootstrap += `## Goals
10015
10011
 
10012
+ `;
10013
+ bootstrap += `> **Goal focus:** keep the top-level goal outcome-first and product-first. Secondary constraints (compliance, security, accessibility, performance, tech stack) are quality bars unless the user explicitly made one of them the primary project. Seed issues should lead with core product capabilities and include constraints as acceptance criteria/risk notes, not let one side constraint dominate the backlog.
10014
+
10016
10015
  `;
10017
10016
  for (const g of allGoals) {
10018
10017
  bootstrap += `### ${g.title}
@@ -10079,21 +10078,34 @@ Read: \`docs/${doc}\`
10079
10078
  const isFreshLocalRepo = (workspace) => workspace?.sourceType !== "git_repo";
10080
10079
  const effectiveExecutionPolicy = (proj, workspace) => {
10081
10080
  const policy = proj?.executionWorkspacePolicy;
10082
- if (!policy || typeof policy !== "object") return null;
10081
+ const canUseIsolatedWorktrees = enableIsolatedWorktrees && !isFreshLocalRepo(workspace);
10082
+ if (!policy || typeof policy !== "object") {
10083
+ if (!canUseIsolatedWorktrees) return null;
10084
+ const baseRef = normalizeExecutionBaseRef(null, workspace?.defaultRef || workspace?.repoRef);
10085
+ return {
10086
+ enabled: true,
10087
+ defaultMode: "isolated_workspace",
10088
+ workspaceStrategy: {
10089
+ type: "git_worktree",
10090
+ ...baseRef ? { baseRef } : {}
10091
+ }
10092
+ };
10093
+ }
10083
10094
  if (policy.defaultMode === "isolated_workspace") {
10084
- if (!enableIsolatedWorktrees || isFreshLocalRepo(workspace)) return null;
10095
+ if (!canUseIsolatedWorktrees) return null;
10085
10096
  const strategy = policy.workspaceStrategy;
10086
- if (!strategy || typeof strategy !== "object") return policy;
10087
- if (strategy.type !== "git_worktree") return policy;
10097
+ if (!strategy || typeof strategy !== "object")
10098
+ return { ...policy, enabled: policy.enabled ?? true };
10099
+ if (strategy.type !== "git_worktree") return { ...policy, enabled: policy.enabled ?? true };
10088
10100
  const workspaceStrategy = { ...strategy };
10089
- const normalizedBaseRef = normalizeExecutionBaseRef(
10101
+ const resolvedBaseRef = normalizeExecutionBaseRef(
10090
10102
  workspaceStrategy.baseRef,
10091
- workspace?.repoRef || workspace?.defaultRef
10103
+ workspace?.defaultRef || workspace?.repoRef
10092
10104
  );
10093
- if (normalizedBaseRef) {
10094
- workspaceStrategy.baseRef = normalizedBaseRef;
10105
+ if (resolvedBaseRef) {
10106
+ workspaceStrategy.baseRef = resolvedBaseRef;
10095
10107
  }
10096
- return { ...policy, workspaceStrategy };
10108
+ return { ...policy, enabled: policy.enabled ?? true, workspaceStrategy };
10097
10109
  }
10098
10110
  return policy;
10099
10111
  };
@@ -10113,24 +10125,34 @@ Read: \`docs/${doc}\`
10113
10125
  };
10114
10126
  const renderDeferredIsolationNote = (workspace) => {
10115
10127
  if (!enableIsolatedWorktrees || !isFreshLocalRepo(workspace)) return "";
10116
- return `> **Enable isolated worktrees once the repo exists.** This instance has isolated worktrees enabled, but this project starts as a fresh local repository, so the \`executionWorkspacePolicy\` is intentionally omitted now \u2014 worktrees need an existing base ref and would fail on the first run. As the final step of **"Prepare GitHub repository"**, after the initial commit is pushed to \`main\`, switch this project to isolated worktrees (Project settings \u2192 isolated workspaces, or set \`executionWorkspacePolicy: { defaultMode: "isolated_workspace", workspaceStrategy: { type: "git_worktree", baseRef: "main" } }\` on the project). Until then agents share the project workspace; do not flip it before the repo has its first commit.
10128
+ const configuredRef = normalizeExecutionBaseRef(
10129
+ null,
10130
+ workspace?.defaultRef || workspace?.repoRef
10131
+ );
10132
+ const refHint = configuredRef ? `When you later enable the project policy, use that configured ref (currently \`${configuredRef}\`) as the worktree \`baseRef\`.` : `When you later enable the project policy, first set the project/worktree base ref to the branch Paperclip should branch from.`;
10133
+ return `> **Enable isolated worktrees once the repo exists.** This instance has isolated worktrees enabled, but this project starts as a fresh local repository, so the \`executionWorkspacePolicy\` is intentionally omitted now \u2014 worktrees need an existing base ref and would fail on the first run. After the initial commit exists on the configured base branch, switch this project to isolated worktrees in Project settings. ${refHint} Until then agents share the project workspace; do not flip it before the repo has its first commit.
10117
10134
 
10118
10135
  `;
10119
10136
  };
10120
10137
  const mainProject = resolvedProjects[0];
10121
10138
  const mainProjectName = mainProject?.name || companyName;
10122
- const mainProjectInfo = mainProject ? {
10123
- name: mainProjectName,
10124
- description: mainProject.description || "",
10125
- workspace: normalizeProjectWorkspace(mainProject)
10126
- } : null;
10139
+ const mainProjectInfo = mainProject ? (() => {
10140
+ const workspace = normalizeProjectWorkspace(mainProject);
10141
+ const executionWorkspacePolicy = effectiveExecutionPolicy(mainProject, workspace);
10142
+ return {
10143
+ name: mainProjectName,
10144
+ description: mainProject.description || "",
10145
+ workspace,
10146
+ ...executionWorkspacePolicy ? { executionWorkspacePolicy } : {}
10147
+ };
10148
+ })() : null;
10127
10149
  const mainProjectPreCreated = initialRoutines.length > 0 && mainProjectInfo !== null;
10128
10150
  if (resolvedProjects.length > 0) {
10129
10151
  bootstrap += `## Projects
10130
10152
 
10131
10153
  `;
10132
10154
  if (mainProjectPreCreated) {
10133
- bootstrap += `> **The Company Wizard has already created the main project "${mainProjectName}"** (with board authority) so the scheduled routines could be linked to it. Do NOT recreate it \u2014 create issues against it, and link the goals above to it.
10155
+ bootstrap += `> **The Company Wizard has already created the main project "${mainProjectName}"** (with board authority) so the scheduled routines could be linked to it. Do NOT recreate it \u2014 create issues against it. After creating the goals above, resolve their real ids and link them with \`PATCH /api/projects/{projectId}\` using \`{ "goalIds": [...] }\`.
10134
10156
 
10135
10157
  `;
10136
10158
  }
@@ -10278,7 +10300,7 @@ Read: \`docs/${doc}\`
10278
10300
  `;
10279
10301
  if (moduleNames.includes("pr-review")) {
10280
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";
10281
- 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. Do not create separate child review issues and do not use @-mentions.
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.
10282
10304
  `;
10283
10305
  }
10284
10306
  bootstrap += `
@@ -10312,7 +10334,7 @@ Read: \`docs/${doc}\`
10312
10334
  bootstrap += `## Provisioning Steps
10313
10335
 
10314
10336
  `;
10315
- bootstrap += `The Company Wizard "Provision" step creates the company, the CEO, and this bootstrap issue. The CEO heartbeat creates the remaining Paperclip objects below by following this task.
10337
+ bootstrap += `The Company Wizard "Provision" step creates the company, board-operations issue, hiring-plan issue, agent hire requests, routines, and this bootstrap issue. Approve any pending hires before running dependent team workflows. The CEO heartbeat completes the remaining setup below by following this task.
10316
10338
 
10317
10339
  `;
10318
10340
  bootstrap += `Manual setup order (respects Paperclip object dependencies):
@@ -10333,7 +10355,7 @@ Read: \`docs/${doc}\`
10333
10355
  const activePolicy = effectiveExecutionPolicy(proj, workspace);
10334
10356
  const policy = activePolicy?.defaultMode ? `, executionWorkspacePolicy.defaultMode: "${activePolicy.defaultMode}"` : "";
10335
10357
  if (idx === 0 && mainProjectPreCreated) {
10336
- const goalLinkInstruction = goalLinks ? ` After creating the goals above, link them to it (${goalLinks.replace(/^, /, "")}).` : "";
10358
+ const goalLinkInstruction = goalLinks ? ` After creating the goals above, resolve their real ids and link them with PATCH /api/projects/{projectId} (${goalLinks.replace(/^, /, "")}).` : "";
10337
10359
  bootstrap += `${stepN++}. **Main project already created** \u2014 the Company Wizard provisioned project "${proj.name}" (with board authority) so the scheduled routines could be linked to it. Do NOT recreate it.${goalLinkInstruction}
10338
10360
  `;
10339
10361
  } else {
@@ -10369,6 +10391,22 @@ Read: \`docs/${doc}\`
10369
10391
  };
10370
10392
  }
10371
10393
 
10394
+ // src/logic/version.js
10395
+ function compareSemver(a, b) {
10396
+ const parse = (value) => String(value || "").trim().replace(/^v/i, "").split("-", 1)[0].split(".").map((part) => Number.parseInt(part, 10) || 0);
10397
+ const left = parse(a);
10398
+ const right = parse(b);
10399
+ const max = Math.max(left.length, right.length, 3);
10400
+ for (let i = 0; i < max; i += 1) {
10401
+ const diff = (left[i] || 0) - (right[i] || 0);
10402
+ if (diff !== 0) return diff > 0 ? 1 : -1;
10403
+ }
10404
+ return 0;
10405
+ }
10406
+ function isNewerVersion(candidate, current) {
10407
+ return compareSemver(candidate, current) > 0;
10408
+ }
10409
+
10372
10410
  // src/api/client.js
10373
10411
  var BASE_ROLE_MAP = {
10374
10412
  ceo: "ceo",
@@ -10551,7 +10589,9 @@ var PaperclipClient = class {
10551
10589
  budgetMonthlyCents,
10552
10590
  permissions,
10553
10591
  metadata,
10554
- instructionsBundle
10592
+ instructionsBundle,
10593
+ sourceIssueId,
10594
+ sourceIssueIds
10555
10595
  } = agent || {};
10556
10596
  const payload = {
10557
10597
  name,
@@ -10568,49 +10608,28 @@ var PaperclipClient = class {
10568
10608
  ...budgetMonthlyCents !== void 0 ? { budgetMonthlyCents } : {},
10569
10609
  ...permissions ? { permissions } : {},
10570
10610
  ...metadata !== void 0 ? { metadata } : {},
10571
- ...instructionsBundle !== void 0 ? { instructionsBundle } : {}
10611
+ ...instructionsBundle !== void 0 ? { instructionsBundle } : {},
10612
+ ...sourceIssueId !== void 0 ? { sourceIssueId } : {},
10613
+ ...sourceIssueIds !== void 0 ? { sourceIssueIds } : {}
10572
10614
  };
10573
- try {
10574
- return await this._fetch(`/api/companies/${companyId}/agents`, {
10575
- method: "POST",
10576
- body: JSON.stringify(payload)
10577
- });
10578
- } catch (err) {
10579
- const message = err instanceof Error ? err.message : String(err);
10580
- const requiresApproval = message.includes("Direct agent creation requires board approval") || message.includes("/agent-hires");
10581
- if (!requiresApproval) throw err;
10582
- const hireResult = await this._fetch(`/api/companies/${companyId}/agent-hires`, {
10583
- method: "POST",
10584
- body: JSON.stringify(payload)
10585
- });
10586
- const hiredAgent = hireResult?.agent || null;
10587
- const approvalId = hireResult?.approval?.id || null;
10588
- if (!hiredAgent) {
10589
- throw new Error("Agent hire endpoint returned no agent.");
10590
- }
10591
- if (approvalId) {
10592
- try {
10593
- await this._fetch(`/api/approvals/${approvalId}/approve`, {
10594
- method: "POST",
10595
- body: JSON.stringify({ decisionNote: "Auto-approved by Company Wizard provisioning" })
10596
- });
10597
- try {
10598
- return await this._fetch(`/api/agents/${hiredAgent.id}`, { method: "GET" });
10599
- } catch {
10600
- return hiredAgent;
10601
- }
10602
- } catch (approveErr) {
10603
- return {
10604
- ...hiredAgent,
10605
- _pendingApprovalId: approvalId,
10606
- _approvalAutoApproveError: approveErr instanceof Error ? approveErr.message : String(approveErr)
10607
- };
10608
- }
10609
- }
10610
- return hiredAgent;
10615
+ const hireResult = await this._fetch(`/api/companies/${companyId}/agent-hires`, {
10616
+ method: "POST",
10617
+ body: JSON.stringify(payload)
10618
+ });
10619
+ const hiredAgent = hireResult?.agent || null;
10620
+ const approvalId = hireResult?.approval?.id || null;
10621
+ if (!hiredAgent) {
10622
+ throw new Error("Agent hire endpoint returned no agent.");
10611
10623
  }
10624
+ if (approvalId) {
10625
+ return {
10626
+ ...hiredAgent,
10627
+ _pendingApprovalId: approvalId
10628
+ };
10629
+ }
10630
+ return hiredAgent;
10612
10631
  }
10613
- async createProject(companyId, { name, description, goalIds, workspace }) {
10632
+ async createProject(companyId, { name, description, goalIds, workspace, executionWorkspacePolicy }) {
10614
10633
  const workspacePayload = typeof workspace === "string" ? { sourceType: "local_path", cwd: workspace, isPrimary: true } : workspace || void 0;
10615
10634
  return this._fetch(`/api/companies/${companyId}/projects`, {
10616
10635
  method: "POST",
@@ -10618,10 +10637,17 @@ var PaperclipClient = class {
10618
10637
  name,
10619
10638
  description: description || null,
10620
10639
  ...goalIds?.length ? { goalIds } : {},
10621
- workspace: workspacePayload
10640
+ workspace: workspacePayload,
10641
+ ...executionWorkspacePolicy ? { executionWorkspacePolicy } : {}
10622
10642
  })
10623
10643
  });
10624
10644
  }
10645
+ async updateProject(projectId, updates = {}) {
10646
+ return this._fetch(`/api/projects/${projectId}`, {
10647
+ method: "PATCH",
10648
+ body: JSON.stringify(updates || {})
10649
+ });
10650
+ }
10625
10651
  async createGoal(companyId, { title, description, level, parentId, status, ownerAgentId }) {
10626
10652
  return this._fetch(`/api/companies/${companyId}/goals`, {
10627
10653
  method: "POST",
@@ -10681,6 +10707,17 @@ var PaperclipClient = class {
10681
10707
  body: JSON.stringify(updates || {})
10682
10708
  });
10683
10709
  }
10710
+ async putIssueDocument(issueId, key, { title, format, body, baseRevisionId }) {
10711
+ return this._fetch(`/api/issues/${issueId}/documents/${encodeURIComponent(key)}`, {
10712
+ method: "PUT",
10713
+ body: JSON.stringify({
10714
+ title,
10715
+ format: format || "markdown",
10716
+ body: body || "",
10717
+ ...baseRevisionId !== void 0 ? { baseRevisionId } : {}
10718
+ })
10719
+ });
10720
+ }
10684
10721
  async createRoutine(companyId, {
10685
10722
  title,
10686
10723
  description,
@@ -10901,6 +10938,9 @@ function collectPresetBootstrapData(preset) {
10901
10938
  var __dirname = path2.dirname(fileURLToPath2(import.meta.url));
10902
10939
  var DEFAULT_TEMPLATES_REPO_URL = "https://github.com/starlein/paperclip-plugin-company-wizard/tree/main/templates";
10903
10940
  var BUNDLED_TEMPLATES_DIR = path2.resolve(__dirname, "..", "templates");
10941
+ var PLUGIN_PACKAGE_NAME = "@starlein/paperclip-plugin-company-wizard";
10942
+ var CURRENT_PLUGIN_VERSION = "0.4.1";
10943
+ var NPM_LATEST_URL = "https://registry.npmjs.org/@starlein%2Fpaperclip-plugin-company-wizard/latest";
10904
10944
  function copyDirSync(src, dest) {
10905
10945
  fs2.mkdirSync(dest, { recursive: true });
10906
10946
  for (const entry of fs2.readdirSync(src, { withFileTypes: true })) {
@@ -11194,6 +11234,57 @@ async function syncAgentInstructionsIntoManagedBundle({
11194
11234
  );
11195
11235
  }
11196
11236
  }
11237
+ function buildDecisionLogBody({
11238
+ companyName,
11239
+ companyDescription,
11240
+ preset,
11241
+ moduleNames,
11242
+ roles,
11243
+ repositoryMode,
11244
+ approvalMode
11245
+ }) {
11246
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
11247
+ return `# Decision Log \u2014 ${companyName}
11248
+
11249
+ ## ${today}
11250
+ - Created or selected company "${companyName}"${companyDescription ? ` with mission: ${companyDescription}` : ""}.
11251
+ - Selected preset: ${preset || "custom/manual"}.
11252
+ - Selected modules: ${moduleNames.length > 0 ? moduleNames.join(", ") : "none"}.
11253
+ - Initial roles: ${roles.join(", ")}.
11254
+ - Repository setup: ${repositoryMode}.
11255
+ - Hiring governance: ${approvalMode}.
11256
+ - Company Wizard generated the initial bootstrap package, agent instruction bundles, routines, and backlog seed from templates.
11257
+ `;
11258
+ }
11259
+ function buildHiringPlanBody({
11260
+ companyName,
11261
+ roles,
11262
+ moduleNames
11263
+ }) {
11264
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
11265
+ return `# Hiring Plan \u2014 ${companyName}
11266
+
11267
+ Generated by Company Wizard on ${today}.
11268
+
11269
+ ## Instruction Source
11270
+
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.
11272
+
11273
+ ## Initial Roles
11274
+
11275
+ ${roles.map((role) => `- ${formatRoleName(role)}`).join("\n")}
11276
+
11277
+ ## Selected Modules
11278
+
11279
+ ${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
+ `;
11287
+ }
11197
11288
  var plugin = definePlugin({
11198
11289
  async setup(ctx) {
11199
11290
  ctx.data.register("templates", async () => {
@@ -11220,6 +11311,46 @@ var plugin = definePlugin({
11220
11311
  return { ok: false, error: err instanceof Error ? err.message : String(err) };
11221
11312
  }
11222
11313
  });
11314
+ ctx.actions.register("check-update", async () => {
11315
+ try {
11316
+ const response = await fetch(NPM_LATEST_URL, {
11317
+ headers: { accept: "application/json" }
11318
+ });
11319
+ if (!response.ok) {
11320
+ return {
11321
+ ok: false,
11322
+ currentVersion: CURRENT_PLUGIN_VERSION,
11323
+ packageName: PLUGIN_PACKAGE_NAME,
11324
+ error: `npm registry returned ${response.status}`
11325
+ };
11326
+ }
11327
+ const data = await response.json();
11328
+ const latestVersion = typeof data.version === "string" ? data.version.trim() : "";
11329
+ if (!latestVersion) {
11330
+ return {
11331
+ ok: false,
11332
+ currentVersion: CURRENT_PLUGIN_VERSION,
11333
+ packageName: PLUGIN_PACKAGE_NAME,
11334
+ error: "npm registry response did not include a version"
11335
+ };
11336
+ }
11337
+ return {
11338
+ ok: true,
11339
+ packageName: PLUGIN_PACKAGE_NAME,
11340
+ currentVersion: CURRENT_PLUGIN_VERSION,
11341
+ latestVersion,
11342
+ updateAvailable: isNewerVersion(latestVersion, CURRENT_PLUGIN_VERSION),
11343
+ url: "https://www.npmjs.com/package/@starlein/paperclip-plugin-company-wizard"
11344
+ };
11345
+ } catch (err) {
11346
+ return {
11347
+ ok: false,
11348
+ currentVersion: CURRENT_PLUGIN_VERSION,
11349
+ packageName: PLUGIN_PACKAGE_NAME,
11350
+ error: err instanceof Error ? err.message : String(err)
11351
+ };
11352
+ }
11353
+ });
11223
11354
  ctx.actions.register("preview-files", async (params) => {
11224
11355
  let tmpDir;
11225
11356
  try {
@@ -11272,7 +11403,7 @@ var plugin = definePlugin({
11272
11403
  presetRoutines: presetBootstrapData.routines,
11273
11404
  presetLabels: presetBootstrapData.labels,
11274
11405
  enableIsolatedWorktrees: await resolveEnableIsolatedWorkspacesFromInstance(cfg),
11275
- enableEnrichedPersonas: cfgBool(cfg, "enableEnrichedPersonas"),
11406
+ enableEnrichedPersonas: true,
11276
11407
  outputDir: tmpDir,
11277
11408
  templatesDir
11278
11409
  });
@@ -11378,7 +11509,7 @@ var plugin = definePlugin({
11378
11509
  "disableBoardApprovalOnNewCompanies"
11379
11510
  );
11380
11511
  const enableIsolatedWorktrees = await resolveEnableIsolatedWorkspacesFromInstance(cfg, log);
11381
- const enableEnrichedPersonas = cfgBool(cfg, "enableEnrichedPersonas");
11512
+ const enableEnrichedPersonas = true;
11382
11513
  const companyName = typeof params.companyName === "string" ? params.companyName.trim() : "";
11383
11514
  const existingCompanyId = typeof params.existingCompanyId === "string" && params.existingCompanyId.trim() ? params.existingCompanyId.trim() : "";
11384
11515
  if (!companyName) return { error: "companyName is required", logs };
@@ -11484,8 +11615,58 @@ var plugin = definePlugin({
11484
11615
  }
11485
11616
  let ceoAgentId;
11486
11617
  const teamAgentIds = {};
11618
+ let boardOperationsIssue = null;
11619
+ let hiringPlanIssue = null;
11487
11620
  let bootstrapIssue;
11488
11621
  try {
11622
+ const allRoleNames = [...assembleResult.allRoles ?? []].filter(Boolean).sort();
11623
+ const repositoryMode = userProjects.some(
11624
+ (project) => project?.repoUrl || project?.workspace?.sourceType === "git_repo"
11625
+ ) ? "existing git repository" : "fresh local repository";
11626
+ const approvalMode = disableBoardApprovalOnNewCompanies ? "board approval disabled for this new company by plugin setting" : "board approval preserved; /agent-hires may create pending approvals";
11627
+ log("Creating board operations and hiring plan records...");
11628
+ const createdBoardOperationsIssue = await client.createIssue(companyId, {
11629
+ title: "Board Operations",
11630
+ description: "Standing issue for board decision log and operations tracking.",
11631
+ status: "in_progress",
11632
+ priority: "medium"
11633
+ });
11634
+ boardOperationsIssue = createdBoardOperationsIssue;
11635
+ await client.putIssueDocument(createdBoardOperationsIssue.id, "decision-log", {
11636
+ title: "Decision Log",
11637
+ format: "markdown",
11638
+ body: buildDecisionLogBody({
11639
+ companyName,
11640
+ companyDescription,
11641
+ preset: selectedPreset?.name,
11642
+ moduleNames: effectiveModules,
11643
+ roles: allRoleNames,
11644
+ repositoryMode,
11645
+ approvalMode
11646
+ })
11647
+ });
11648
+ log(
11649
+ `\u2713 Board Operations issue created${createdBoardOperationsIssue.identifier ? `: ${createdBoardOperationsIssue.identifier}` : ""}`
11650
+ );
11651
+ const createdHiringPlanIssue = await client.createIssue(companyId, {
11652
+ title: "Hiring Plan",
11653
+ description: "Develop and execute the governed team hiring plan.",
11654
+ status: "in_progress",
11655
+ priority: "high"
11656
+ });
11657
+ hiringPlanIssue = createdHiringPlanIssue;
11658
+ await client.putIssueDocument(createdHiringPlanIssue.id, "hiring-plan", {
11659
+ title: "Hiring Plan",
11660
+ format: "markdown",
11661
+ body: buildHiringPlanBody({
11662
+ companyName,
11663
+ roles: allRoleNames,
11664
+ moduleNames: effectiveModules
11665
+ })
11666
+ });
11667
+ log(
11668
+ `\u2713 Hiring Plan issue created${createdHiringPlanIssue.identifier ? `: ${createdHiringPlanIssue.identifier}` : ""}`
11669
+ );
11489
11670
  const userCeoAdapter = params.ceoAdapter || {};
11490
11671
  const adapterType = normalizeCeoAdapterType(userCeoAdapter);
11491
11672
  const ceoTemplate = roleTemplateByName.get("ceo") || {};
@@ -11511,9 +11692,6 @@ var plugin = definePlugin({
11511
11692
  log(
11512
11693
  `\u26A0 CEO hire is pending approval: ${agent._pendingApprovalId}. Approve it in the board before the bootstrap heartbeat can run.`
11513
11694
  );
11514
- if (agent._approvalAutoApproveError) {
11515
- log(` Auto-approve failed: ${agent._approvalAutoApproveError}`);
11516
- }
11517
11695
  };
11518
11696
  if (existingCompanyId) {
11519
11697
  log("Looking for an existing CEO agent...");
@@ -11558,7 +11736,8 @@ var plugin = definePlugin({
11558
11736
  adapterConfig,
11559
11737
  instructionsBundle: ceoInstructionsBundle,
11560
11738
  runtimeConfig: ceoRuntimeConfig,
11561
- permissions: { canCreateAgents: true }
11739
+ permissions: { canCreateAgents: true },
11740
+ ...boardOperationsIssue?.id ? { sourceIssueId: boardOperationsIssue.id } : {}
11562
11741
  });
11563
11742
  ceoAgentId = ceoAgent.id;
11564
11743
  log(`\u2713 CEO agent created (${ceoAgentId})`);
@@ -11577,7 +11756,8 @@ var plugin = definePlugin({
11577
11756
  adapterConfig,
11578
11757
  instructionsBundle: ceoInstructionsBundle,
11579
11758
  runtimeConfig: ceoRuntimeConfig,
11580
- permissions: { canCreateAgents: true }
11759
+ permissions: { canCreateAgents: true },
11760
+ ...boardOperationsIssue?.id ? { sourceIssueId: boardOperationsIssue.id } : {}
11581
11761
  });
11582
11762
  ceoAgentId = ceoAgent.id;
11583
11763
  log(`\u2713 CEO agent created (${ceoAgentId})`);
@@ -11654,7 +11834,8 @@ var plugin = definePlugin({
11654
11834
  adapterType,
11655
11835
  adapterConfig: roleAdapterConfig,
11656
11836
  instructionsBundle: roleInstructionsBundle,
11657
- runtimeConfig: roleRuntimeConfig
11837
+ runtimeConfig: roleRuntimeConfig,
11838
+ ...hiringPlanIssue?.id ? { sourceIssueId: hiringPlanIssue.id } : {}
11658
11839
  });
11659
11840
  teamAgentIds[roleName] = roleAgent.id;
11660
11841
  log(`\u2713 ${roleTitle} created (${roleAgent.id})`);
@@ -11662,9 +11843,6 @@ var plugin = definePlugin({
11662
11843
  log(
11663
11844
  `\u26A0 ${roleTitle} hire pending approval: ${roleAgent._pendingApprovalId}. Approve it in the board.`
11664
11845
  );
11665
- if (roleAgent._approvalAutoApproveError) {
11666
- log(` Auto-approve failed: ${roleAgent._approvalAutoApproveError}`);
11667
- }
11668
11846
  }
11669
11847
  }
11670
11848
  if (!existingCompanyId) {
@@ -11676,7 +11854,8 @@ var plugin = definePlugin({
11676
11854
  const createdProject = await client.createProject(companyId, {
11677
11855
  name: mainProject.name,
11678
11856
  description: mainProject.description,
11679
- workspace: mainProject.workspace
11857
+ workspace: mainProject.workspace,
11858
+ executionWorkspacePolicy: mainProject.executionWorkspacePolicy
11680
11859
  });
11681
11860
  mainProjectId = createdProject?.id;
11682
11861
  log(
@@ -11753,14 +11932,17 @@ var plugin = definePlugin({
11753
11932
  log("");
11754
11933
  log("Provisioning complete!");
11755
11934
  log(
11756
- existingCompanyId ? "Bootstrap task created in existing company. Trigger the CEO heartbeat to continue setup." : "The CEO agent is ready. Trigger its first heartbeat to hire the rest of the team and create the initial backlog."
11935
+ existingCompanyId ? "Bootstrap task created in existing company. Trigger the CEO heartbeat to continue setup." : "The CEO agent and initial team hire requests are ready. Approve any pending hires, then trigger the CEO heartbeat to continue setup."
11936
+ );
11937
+ const issueIds = [boardOperationsIssue?.id, hiringPlanIssue?.id, bootstrapIssue.id].filter(
11938
+ Boolean
11757
11939
  );
11758
11940
  return {
11759
11941
  companyId,
11760
11942
  issuePrefix: company.issuePrefix,
11761
11943
  paperclipUrl,
11762
11944
  agentIds: { ceo: ceoAgentId, ...teamAgentIds },
11763
- issueIds: [bootstrapIssue.id],
11945
+ issueIds,
11764
11946
  logs
11765
11947
  };
11766
11948
  } catch (err) {