@starlein/paperclip-plugin-company-wizard 0.3.22 → 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 +566 -0
- package/CONTRIBUTING.md +90 -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 +4 -2
- 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/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Contributing to Company Wizard
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in contributing! Company Wizard is a [Paperclip](https://github.com/paperclipai/paperclip) plugin that bootstraps agent company workspaces from composable templates.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
git clone <repo-url>
|
|
9
|
+
cd paperclip-plugin-company-wizard
|
|
10
|
+
pnpm install
|
|
11
|
+
pnpm build
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Development
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
pnpm build # esbuild: worker + manifest + UI → dist/
|
|
18
|
+
pnpm dev # watch mode (rebuilds on change)
|
|
19
|
+
pnpm test # vitest: tests/**/*.spec.ts
|
|
20
|
+
pnpm test:logic # node --test: src/logic/*.test.js
|
|
21
|
+
pnpm typecheck # tsc --noEmit
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Load the plugin in Paperclip by pointing to this directory (the `paperclipPlugin` field in `package.json` tells Paperclip where to find the built artifacts). After `pnpm build`, reload the plugin in the Paperclip UI — no reinstall required.
|
|
25
|
+
|
|
26
|
+
## Project Structure
|
|
27
|
+
|
|
28
|
+
```text
|
|
29
|
+
src/
|
|
30
|
+
├── worker.ts # Plugin worker: actions (preview-files, start-provision, check-auth)
|
|
31
|
+
├── manifest.ts # Plugin manifest (id, displayName, slots)
|
|
32
|
+
├── logic/ # Pure functions (assembly, resolution, template loading)
|
|
33
|
+
├── api/ # Paperclip REST API client and provisioning
|
|
34
|
+
└── ui/
|
|
35
|
+
├── main.tsx # UI entry point
|
|
36
|
+
├── context/ # WizardContext (state machine + reducer)
|
|
37
|
+
└── components/ # React components (WizardShell, step components, ConfigReview)
|
|
38
|
+
|
|
39
|
+
templates/
|
|
40
|
+
├── roles/ # All roles with role.meta.json (base: true for always-present)
|
|
41
|
+
├── modules/ # Composable capabilities with module.meta.json
|
|
42
|
+
└── presets/ # Curated module+role combinations with preset.meta.json
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Adding Templates
|
|
46
|
+
|
|
47
|
+
### New module
|
|
48
|
+
|
|
49
|
+
See [docs/TEMPLATES.md](docs/TEMPLATES.md) for the full module schema. Key points:
|
|
50
|
+
|
|
51
|
+
- Every capability needs a shared skill in `skills/<skill>.md`
|
|
52
|
+
- Role-specific overrides go in `agents/<role>/skills/<skill>.md` (only when genuinely different)
|
|
53
|
+
- Fallback variants are always role-specific (`.fallback.md`)
|
|
54
|
+
- Add `node --test` tests in `src/logic/` if the module has non-trivial resolution logic
|
|
55
|
+
|
|
56
|
+
### New role
|
|
57
|
+
|
|
58
|
+
See [docs/TEMPLATES.md](docs/TEMPLATES.md). Map `paperclipRole` to a valid Paperclip enum value. Set `base: true` only for roles that belong in every company (only the CEO currently has `base: true`).
|
|
59
|
+
|
|
60
|
+
### New preset
|
|
61
|
+
|
|
62
|
+
See [docs/TEMPLATES.md](docs/TEMPLATES.md). Test that the module combination resolves correctly. Presets can include inline `goals[]` arrays with milestones and issues.
|
|
63
|
+
|
|
64
|
+
## Pull Requests
|
|
65
|
+
|
|
66
|
+
- Keep PRs focused — one feature or fix per PR
|
|
67
|
+
- Add or update tests for logic changes
|
|
68
|
+
- Run `pnpm test && pnpm test:logic` before submitting
|
|
69
|
+
- Update `docs/TEMPLATES.md` if you add modules, roles, or presets
|
|
70
|
+
- Update `CHANGELOG.md` with your changes
|
|
71
|
+
|
|
72
|
+
## Code Style
|
|
73
|
+
|
|
74
|
+
- TypeScript for plugin infrastructure (`src/worker.ts`, `src/manifest.ts`, `src/ui/`)
|
|
75
|
+
- ESM only (`type: "module"`)
|
|
76
|
+
- Plain JS for logic/API modules (`src/logic/`, `src/api/`) — JSDoc where helpful
|
|
77
|
+
- Prettier via pre-commit hook (lint-staged)
|
|
78
|
+
|
|
79
|
+
## Reporting Issues
|
|
80
|
+
|
|
81
|
+
Use GitHub Issues. Include:
|
|
82
|
+
|
|
83
|
+
- What you expected vs what happened
|
|
84
|
+
- Plugin version (from `package.json`)
|
|
85
|
+
- Node.js version (`node --version`)
|
|
86
|
+
- OS
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
|
|
90
|
+
By contributing, you agree that your contributions will be licensed under the [MIT License](LICENSE).
|
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
|