@starlein/paperclip-plugin-company-wizard 0.3.23 → 0.3.24
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/CHANGELOG.md +12 -0
- package/README.md +3 -2
- package/dist/manifest.js +1 -1
- package/dist/manifest.js.map +1 -1
- package/dist/worker.js +53 -6
- package/dist/worker.js.map +2 -2
- package/package.json +1 -1
- package/templates/modules/pr-review/agents/code-reviewer/skills/code-review.md +16 -21
- package/templates/modules/pr-review/agents/qa/skills/qa-review.md +40 -19
- package/templates/modules/pr-review/agents/security-engineer/skills/pr-security-review.md +27 -0
- package/templates/modules/pr-review/docs/pr-conventions.md +32 -23
- package/templates/modules/pr-review/module.meta.json +4 -3
- package/templates/roles/code-reviewer/AGENTS.md +1 -1
- package/templates/roles/code-reviewer/HEARTBEAT.md +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,18 @@ All notable changes to the Company Wizard plugin are documented here.
|
|
|
5
5
|
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
6
|
|
|
7
7
|
---
|
|
8
|
+
## [0.3.24] - 2026-06-15
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- **PR review is now substantive instead of ceremonial.** The `pr-review` module previously gated merges on a `code-reviewer` reading a diff and recording a verdict — effectively self-approval, since all agents share one model and one GitHub account. The merge gate is now **executed verification**: when the `ci-cd` module is active, CI (lint/test/build) must be green before the Engineer merges; otherwise the Engineer must run the test suite/build and paste the real output into the merge-gate verdict. The hard gate sits on the Engineer's final merge-gate stage and holds regardless of which reviewers are present.
|
|
13
|
+
- **QA is the substantive review stage; the Code Reviewer is advisory.** The `pr-review` `reviewGate` reviewers changed from `["code-reviewer"]` to `["qa"]`. QA's skill (`qa-review.md`) was rewritten with two explicit modes (CI present vs. no CI) and a hard evidence requirement — a verdict that does not cite executed verification is invalid. The Code Reviewer's skill (`code-review.md`) and base role files (`roles/code-reviewer/AGENTS.md`, `HEARTBEAT.md`) were reframed as advisory, non-blocking; they no longer instruct GitHub-native `gh pr review --approve`/`--request-changes` (which cannot work with a shared GitHub account) and now post advisory feedback via `gh pr comment --body-file`.
|
|
14
|
+
- **`renderReviewGate` / BOOTSTRAP guardrail are CI-aware.** The generated `executionPolicy` sketch and the BOOTSTRAP PR-review guardrail now render the CI-green precondition (or the run-the-tests-and-paste-output fallback) on the merge-gate stage, plus an evidence-required note that rejects "looks good" verdicts (`assemble.js`).
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **PR-scoped security review.** `security-engineer` is now in `pr-review`'s `activatesWithRoles`, and a new skill `templates/modules/pr-review/agents/security-engineer/skills/pr-security-review.md` reviews a specific PR's diff for security-relevant changes (auth, secrets, input boundaries, crypto, dependencies, infra exposure). The stage is conditional — the Engineer adds it only when the change is security-relevant. Named `pr-security-review.md` (not `security-review.md`) to avoid clobbering the `security-audit` module's capability skill of the same name. `pr-conventions.md` (Review Workflow, Review Roles, Merge Rules) was rewritten to match the new model.
|
|
19
|
+
|
|
8
20
|
## [0.3.23] - 2026-06-10
|
|
9
21
|
|
|
10
22
|
### Changed
|
package/README.md
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="https://raw.githubusercontent.com/starlein/paperclip-plugin-company-wizard/main/public/favicon.svg" alt="Company Wizard" width="48" height="48">
|
|
3
2
|
<h1 align="center">Company Wizard</h1>
|
|
4
3
|
<p align="center">
|
|
5
4
|
<strong>Bootstrap AI agent teams from modular templates.</strong>
|
|
@@ -10,6 +9,8 @@
|
|
|
10
9
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="License"></a>
|
|
11
10
|
<a href="https://nodejs.org"><img src="https://img.shields.io/badge/node-%3E%3D20-brightgreen" alt="Node.js"></a>
|
|
12
11
|
</p>
|
|
12
|
+
<hr>
|
|
13
|
+
<img src="https://raw.githubusercontent.com/starlein/paperclip-plugin-company-wizard/main/docs/GIF-Screencast-Paperclip-Plugin-Company-Wizard.gif" alt="Screencast Paperclip Plugin Company Wizard" height="240">
|
|
13
14
|
</p>
|
|
14
15
|
|
|
15
16
|
---
|
|
@@ -160,7 +161,7 @@ Start with just a CEO. Everything works. Add roles and responsibilities shift au
|
|
|
160
161
|
| `tech-stack` | Engineer | CEO | tech-stack |
|
|
161
162
|
| `architecture-plan` | Engineer | CEO | architecture-plan |
|
|
162
163
|
| `design-system` | UI Designer | Engineer | architecture-plan |
|
|
163
|
-
| `pr-review` |
|
|
164
|
+
| `pr-review` | QA (gate) / Security Engineer (security-relevant) / Product Owner (approval) / Engineer (merge); Code Reviewer / UI / UX / DevOps advisory | — | pr-review |
|
|
164
165
|
| `threat-model` | Security Engineer → DevOps | Engineer | security-audit |
|
|
165
166
|
| `security-review` | Security Engineer → DevOps | Engineer | security-audit |
|
|
166
167
|
| `project-docs` | Technical Writer → Engineer | CEO | documentation |
|
package/dist/manifest.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
var manifest = {
|
|
3
3
|
id: "starlein.paperclip-plugin-company-wizard",
|
|
4
4
|
apiVersion: 1,
|
|
5
|
-
version: "0.3.
|
|
5
|
+
version: "0.3.24",
|
|
6
6
|
displayName: "Company Wizard",
|
|
7
7
|
description: "AI-powered wizard to bootstrap agent companies from composable templates",
|
|
8
8
|
author: "Sascha Pietrowski <sp@speednetwork.de>",
|
package/dist/manifest.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/manifest.ts"],
|
|
4
|
-
"sourcesContent": ["import type { PaperclipPluginManifestV1 } from '@paperclipai/plugin-sdk';\n\nconst manifest: PaperclipPluginManifestV1 = {\n id: 'starlein.paperclip-plugin-company-wizard',\n apiVersion: 1,\n version: '0.3.
|
|
4
|
+
"sourcesContent": ["import type { PaperclipPluginManifestV1 } from '@paperclipai/plugin-sdk';\n\nconst manifest: PaperclipPluginManifestV1 = {\n id: 'starlein.paperclip-plugin-company-wizard',\n apiVersion: 1,\n version: '0.3.24',\n displayName: 'Company Wizard',\n description: 'AI-powered wizard to bootstrap agent companies from composable templates',\n author: 'Sascha Pietrowski <sp@speednetwork.de>',\n categories: ['workspace', 'ui'],\n capabilities: [\n 'companies.read',\n 'issues.create',\n 'issues.read',\n 'issues.update',\n 'goals.create',\n 'goals.read',\n 'agents.read',\n 'projects.read',\n 'plugin.state.read',\n 'plugin.state.write',\n 'secrets.read-ref',\n 'events.subscribe',\n 'ui.page.register',\n 'ui.sidebar.register',\n ],\n instanceConfigSchema: {\n type: 'object',\n properties: {\n companiesDir: {\n type: 'string',\n description:\n 'Directory where assembled company workspaces are written. Defaults to ~/.paperclip/instances/default/companies. Override for Docker setups (e.g. /paperclip/instances/default/companies).',\n },\n templatesPath: {\n type: 'string',\n description:\n 'Path to the templates directory. Defaults to ~/.paperclip/plugin-templates (auto-downloaded from templatesRepoUrl if missing). Override for Docker setups (e.g. /paperclip/plugin-templates).',\n },\n templatesRepoUrl: {\n type: 'string',\n default: 'https://github.com/starlein/paperclip-plugin-company-wizard/tree/main/templates',\n description:\n 'GitHub tree URL to pull templates from when the templates directory does not exist.',\n },\n anthropicApiKey: {\n type: 'string',\n description:\n 'Anthropic API key for the AI wizard (e.g. sk-ant-...). Required to use the AI-powered company setup path.',\n },\n paperclipUrl: {\n type: 'string',\n description:\n 'Paperclip instance URL. Defaults to http://localhost:3100 or the PAPERCLIP_PUBLIC_URL env var.',\n },\n paperclipEmail: {\n type: 'string',\n description: 'Board login email (for authenticated instances).',\n },\n paperclipPassword: {\n type: 'string',\n description: 'Board login password (for authenticated instances).',\n },\n disableBoardApprovalOnNewCompanies: {\n type: 'boolean',\n default: false,\n description:\n 'Optional. If true, the wizard will PATCH new companies to set requireBoardApprovalForNewAgents=false during provisioning. Leave false to preserve approval-gated hiring policies.',\n },\n enableEnrichedPersonas: {\n type: 'boolean',\n default: false,\n description:\n 'Optional. If true, expert roles are enriched with domain lenses (named mental models), module skills gain concrete output/review bars with negative examples, and HEARTBEAT.md gains explicit done-criteria. Leave false (default) for the lean baseline personas.',\n },\n },\n },\n entrypoints: {\n worker: './dist/worker.js',\n ui: './dist/ui',\n },\n ui: {\n slots: [\n {\n type: 'page',\n id: 'company-wizard',\n displayName: 'Company Wizard',\n exportName: 'WizardPage',\n routePath: 'company-creator',\n },\n {\n type: 'sidebar',\n id: 'company-wizard-link',\n displayName: 'Create Company',\n exportName: 'SidebarLink',\n },\n ],\n },\n};\n\nexport default manifest;\n"],
|
|
5
5
|
"mappings": ";AAEA,IAAM,WAAsC;AAAA,EAC1C,IAAI;AAAA,EACJ,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,aAAa;AAAA,EACb,aAAa;AAAA,EACb,QAAQ;AAAA,EACR,YAAY,CAAC,aAAa,IAAI;AAAA,EAC9B,cAAc;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,sBAAsB;AAAA,IACpB,MAAM;AAAA,IACN,YAAY;AAAA,MACV,cAAc;AAAA,QACZ,MAAM;AAAA,QACN,aACE;AAAA,MACJ;AAAA,MACA,eAAe;AAAA,QACb,MAAM;AAAA,QACN,aACE;AAAA,MACJ;AAAA,MACA,kBAAkB;AAAA,QAChB,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aACE;AAAA,MACJ;AAAA,MACA,iBAAiB;AAAA,QACf,MAAM;AAAA,QACN,aACE;AAAA,MACJ;AAAA,MACA,cAAc;AAAA,QACZ,MAAM;AAAA,QACN,aACE;AAAA,MACJ;AAAA,MACA,gBAAgB;AAAA,QACd,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,MACA,mBAAmB;AAAA,QACjB,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,MACA,oCAAoC;AAAA,QAClC,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aACE;AAAA,MACJ;AAAA,MACA,wBAAwB;AAAA,QACtB,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aACE;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX,QAAQ;AAAA,IACR,IAAI;AAAA,EACN;AAAA,EACA,IAAI;AAAA,IACF,OAAO;AAAA,MACL;AAAA,QACE,MAAM;AAAA,QACN,IAAI;AAAA,QACJ,aAAa;AAAA,QACb,YAAY;AAAA,QACZ,WAAW;AAAA,MACb;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,IAAI;AAAA,QACJ,aAAa;AAAA,QACb,YAAY;AAAA,MACd;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAO,mBAAQ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/worker.js
CHANGED
|
@@ -9551,6 +9551,7 @@ async function assembleCompany({
|
|
|
9551
9551
|
if (reviewers.length === 0 && !approver && !mergeGate) return null;
|
|
9552
9552
|
return { reviewers, approver, mergeGate };
|
|
9553
9553
|
};
|
|
9554
|
+
const hasCi = moduleNames.includes("ci-cd");
|
|
9554
9555
|
const renderReviewGate = (gate) => {
|
|
9555
9556
|
const stages = [];
|
|
9556
9557
|
for (const role of gate.reviewers) {
|
|
@@ -9562,12 +9563,14 @@ async function assembleCompany({
|
|
|
9562
9563
|
);
|
|
9563
9564
|
}
|
|
9564
9565
|
if (gate.mergeGate) {
|
|
9566
|
+
const gatePrecondition = hasCi ? "CI must be green before merge" : "no CI configured \u2014 run the test suite/build and paste the output before merge";
|
|
9565
9567
|
stages.push(
|
|
9566
|
-
` - stage ${stages.length + 1} (approval) \u2192 assign ${JSON.stringify(gate.mergeGate)} \u2014 merge gate: merge the PR, then record approved to close`
|
|
9568
|
+
` - stage ${stages.length + 1} (approval) \u2192 assign ${JSON.stringify(gate.mergeGate)} \u2014 merge gate: ${gatePrecondition}; merge the PR, then record approved to close`
|
|
9567
9569
|
);
|
|
9568
9570
|
}
|
|
9569
9571
|
return `- **executionPolicy** (set when creating this issue; resolve each role to its agentId):
|
|
9570
9572
|
${stages.join("\n")}
|
|
9573
|
+
- every verdict must cite executed verification (commands + results); "looks good" without evidence is not a valid verdict
|
|
9571
9574
|
|
|
9572
9575
|
`;
|
|
9573
9576
|
};
|
|
@@ -10274,7 +10277,8 @@ Read: \`docs/${doc}\`
|
|
|
10274
10277
|
bootstrap += `- Do not reuse parent workspaces for subissues unless explicitly requested.
|
|
10275
10278
|
`;
|
|
10276
10279
|
if (moduleNames.includes("pr-review")) {
|
|
10277
|
-
|
|
10280
|
+
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.
|
|
10278
10282
|
`;
|
|
10279
10283
|
}
|
|
10280
10284
|
bootstrap += `
|
|
@@ -11090,6 +11094,49 @@ function resolveCompaniesDir(cfg) {
|
|
|
11090
11094
|
if (cfg.companiesDir) return cfg.companiesDir;
|
|
11091
11095
|
return path2.join(os.homedir(), ".paperclip", "instances", "default", "companies");
|
|
11092
11096
|
}
|
|
11097
|
+
function mkdirErrorMessage(err) {
|
|
11098
|
+
if (err instanceof Error) return err.message;
|
|
11099
|
+
return String(err);
|
|
11100
|
+
}
|
|
11101
|
+
function ensureWritableDir(dir) {
|
|
11102
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
11103
|
+
fs2.accessSync(dir, fs2.constants.W_OK);
|
|
11104
|
+
}
|
|
11105
|
+
function resolveWritableCompaniesDir(cfg, log) {
|
|
11106
|
+
const configuredDir = typeof cfg.companiesDir === "string" ? cfg.companiesDir.trim() : "";
|
|
11107
|
+
if (configuredDir) {
|
|
11108
|
+
try {
|
|
11109
|
+
ensureWritableDir(configuredDir);
|
|
11110
|
+
return configuredDir;
|
|
11111
|
+
} catch (err) {
|
|
11112
|
+
throw new Error(
|
|
11113
|
+
`Configured companiesDir is not writable (${configuredDir}): ${mkdirErrorMessage(err)}`
|
|
11114
|
+
);
|
|
11115
|
+
}
|
|
11116
|
+
}
|
|
11117
|
+
const candidates = [
|
|
11118
|
+
resolveCompaniesDir(cfg),
|
|
11119
|
+
path2.join("/paperclip", "instances", "default", "companies"),
|
|
11120
|
+
path2.join(os.tmpdir(), "paperclip-companies")
|
|
11121
|
+
];
|
|
11122
|
+
const attempted = /* @__PURE__ */ new Set();
|
|
11123
|
+
let lastError = "";
|
|
11124
|
+
for (const candidate of candidates) {
|
|
11125
|
+
if (attempted.has(candidate)) continue;
|
|
11126
|
+
attempted.add(candidate);
|
|
11127
|
+
try {
|
|
11128
|
+
ensureWritableDir(candidate);
|
|
11129
|
+
return candidate;
|
|
11130
|
+
} catch (err) {
|
|
11131
|
+
const message = mkdirErrorMessage(err);
|
|
11132
|
+
lastError = `${candidate}: ${message}`;
|
|
11133
|
+
if (log) log(`\u26A0 Companies dir unavailable: ${candidate} (${message})`);
|
|
11134
|
+
}
|
|
11135
|
+
}
|
|
11136
|
+
throw new Error(
|
|
11137
|
+
`Unable to prepare a writable companies directory. Last attempt failed at ${lastError}`
|
|
11138
|
+
);
|
|
11139
|
+
}
|
|
11093
11140
|
function formatRoleName(role) {
|
|
11094
11141
|
return role.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
11095
11142
|
}
|
|
@@ -11197,7 +11244,7 @@ var plugin = definePlugin({
|
|
|
11197
11244
|
const companyName = typeof params.companyName === "string" && params.companyName.trim() ? params.companyName.trim() : "Preview";
|
|
11198
11245
|
const templatesDir = await ensureTemplatesDir(cfg);
|
|
11199
11246
|
tmpDir = path2.join(os.tmpdir(), `company-wizard-preview-${Date.now()}`);
|
|
11200
|
-
const companiesDir =
|
|
11247
|
+
const companiesDir = resolveWritableCompaniesDir(cfg);
|
|
11201
11248
|
const [presets, allModules] = await Promise.all([
|
|
11202
11249
|
loadPresets(templatesDir),
|
|
11203
11250
|
loadModules(templatesDir)
|
|
@@ -11352,8 +11399,7 @@ var plugin = definePlugin({
|
|
|
11352
11399
|
);
|
|
11353
11400
|
const goals = collectGoals(selectedPreset, allModules, new Set(effectiveModules));
|
|
11354
11401
|
const presetBootstrapData = collectPresetBootstrapData(selectedPreset);
|
|
11355
|
-
const outputDir =
|
|
11356
|
-
fs2.mkdirSync(outputDir, { recursive: true });
|
|
11402
|
+
const outputDir = resolveWritableCompaniesDir(cfg, log);
|
|
11357
11403
|
log("Assembling company workspace...");
|
|
11358
11404
|
const companyDescription = typeof params.companyDescription === "string" ? params.companyDescription.trim() : "";
|
|
11359
11405
|
const userGoals = Array.isArray(params.goals) ? params.goals : params.goal ? [params.goal] : [];
|
|
@@ -11750,6 +11796,7 @@ var plugin = definePlugin({
|
|
|
11750
11796
|
var worker_default = plugin;
|
|
11751
11797
|
runWorker(plugin, import.meta.url);
|
|
11752
11798
|
export {
|
|
11753
|
-
worker_default as default
|
|
11799
|
+
worker_default as default,
|
|
11800
|
+
resolveWritableCompaniesDir
|
|
11754
11801
|
};
|
|
11755
11802
|
//# sourceMappingURL=worker.js.map
|