@starlein/paperclip-plugin-company-wizard 0.3.21 → 0.3.23
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 +554 -0
- package/CONTRIBUTING.md +90 -0
- package/README.md +2 -1
- package/dist/manifest.js +1 -1
- package/dist/manifest.js.map +1 -1
- package/dist/worker.js +48 -4
- package/dist/worker.js.map +2 -2
- package/package.json +4 -2
- package/templates/modules/pr-review/agents/code-reviewer/skills/code-review.md +1 -1
- package/templates/modules/pr-review/agents/devops/skills/infra-review.md +1 -1
- package/templates/modules/pr-review/agents/engineer/skills/pr-workflow.md +1 -1
- package/templates/modules/pr-review/agents/product-owner/skills/product-review.md +1 -1
- package/templates/modules/pr-review/agents/qa/skills/qa-review.md +1 -1
- package/templates/modules/pr-review/agents/ui-designer/skills/design-review.md +1 -1
- package/templates/modules/pr-review/agents/ux-researcher/skills/ux-review.md +1 -1
- package/templates/modules/pr-review/docs/pr-conventions.md +19 -1
- package/templates/roles/code-reviewer/AGENTS.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
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
#### Bootstrap reliability
|
|
30
30
|
|
|
31
31
|
- **Agents provisioned with complete instructions** — every non-CEO agent is now created by the plugin directly with its full `instructionsBundle` (AGENTS.md + HEARTBEAT/SOUL/TOOLS + skills). Previously the CEO created these agents during bootstrap with only an `instructionsFilePath`, leaving each agent with a bare AGENTS.md and fragile external path references
|
|
32
|
-
- **Routines created directly during provisioning** — Paperclip only allows an agent to create routines assigned to itself, so the CEO could not create routines owned by the Product Owner. The plugin now creates all routines with board authority at provisioning time; BOOTSTRAP.md tells the CEO they already exist
|
|
32
|
+
- **Routines created directly during provisioning** — Paperclip only allows an agent to create routines assigned to itself, so the CEO could not create routines owned by the Product Owner. The plugin now creates all routines with board authority at provisioning time and pre-creates the main project so every routine — including those owned by non-CEO agents — is linked to it; BOOTSTRAP.md tells the CEO they already exist
|
|
33
33
|
- **Worker agents no longer run always-on heartbeats** — enabling heartbeats on every provisioned agent caused bursts of concurrent runs that crashed the dev server. Only the CEO keeps an always-on heartbeat; all other agents are woken on assignment
|
|
34
34
|
- **Fresh local repos no longer bootstrap with isolated git worktrees** — provisioning a brand-new `local_path` project with an `isolated_workspace` / `git_worktree` policy made worker agents try to branch off `main` before the repo existed, so early runs failed and agents flipped to `error`. The isolated policy is now suppressed for fresh local repos (agents work in the shared project workspace during bootstrap); existing external repos keep it. Guarded in `assemble.js` and removed at the source in `StepRepository` and the AI wizard prompts
|
|
35
35
|
- **Workspace isolation follows Paperclip instance settings** — `enableIsolatedWorktrees` is no longer a plugin setting. The wizard reads `enableIsolatedWorkspaces` from the Paperclip instance experimental settings and only applies `isolated_workspace` / `git_worktree` for external repositories when that setting is enabled.
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
- **Doc references use relative paths** (`docs/<file>`) instead of absolute paths that baked in the collision-suffixed company directory name
|
|
43
43
|
- Duplicate bootstrap issues (same title from module + preset) are now deduplicated; preset issue wins
|
|
44
44
|
- CFO role removed — was orphaned (no preset, no capability, never activated)
|
|
45
|
+
- **PR bodies and comments use `--body-file`** — review skills posted GitHub PR bodies and comments with inline `gh pr … --body "..."`, where a double-quoted shell string keeps `\n` literal, so multi-line Markdown rendered as literal `text\ntext`. All PR-review guidance now writes Markdown to a file and uses `--body-file`, with a verdict-heading comment template documented in `pr-conventions.md`
|
|
45
46
|
|
|
46
47
|
#### AI wizard
|
|
47
48
|
|
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.23",
|
|
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.23',\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
|
@@ -10116,10 +10116,21 @@ Read: \`docs/${doc}\`
|
|
|
10116
10116
|
};
|
|
10117
10117
|
const mainProject = resolvedProjects[0];
|
|
10118
10118
|
const mainProjectName = mainProject?.name || companyName;
|
|
10119
|
+
const mainProjectInfo = mainProject ? {
|
|
10120
|
+
name: mainProjectName,
|
|
10121
|
+
description: mainProject.description || "",
|
|
10122
|
+
workspace: normalizeProjectWorkspace(mainProject)
|
|
10123
|
+
} : null;
|
|
10124
|
+
const mainProjectPreCreated = initialRoutines.length > 0 && mainProjectInfo !== null;
|
|
10119
10125
|
if (resolvedProjects.length > 0) {
|
|
10120
10126
|
bootstrap += `## Projects
|
|
10121
10127
|
|
|
10122
10128
|
`;
|
|
10129
|
+
if (mainProjectPreCreated) {
|
|
10130
|
+
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.
|
|
10131
|
+
|
|
10132
|
+
`;
|
|
10133
|
+
}
|
|
10123
10134
|
for (const proj of resolvedProjects) {
|
|
10124
10135
|
const workspace = normalizeProjectWorkspace(proj);
|
|
10125
10136
|
bootstrap += `### ${proj.name}
|
|
@@ -10312,14 +10323,20 @@ Read: \`docs/${doc}\`
|
|
|
10312
10323
|
bootstrap += `${stepN++}. **Create goal** "${g.title}" (level: ${level}${parentNote})
|
|
10313
10324
|
`;
|
|
10314
10325
|
}
|
|
10315
|
-
|
|
10326
|
+
resolvedProjects.forEach((proj, idx) => {
|
|
10316
10327
|
const workspace = normalizeProjectWorkspace(proj);
|
|
10317
10328
|
const goalLinks = proj.goals?.length > 0 ? `, goalIds \u2192 [${proj.goals.map((g) => `"${g}"`).join(", ")}]` : "";
|
|
10318
10329
|
const activePolicy = effectiveExecutionPolicy(proj, workspace);
|
|
10319
10330
|
const policy = activePolicy?.defaultMode ? `, executionWorkspacePolicy.defaultMode: "${activePolicy.defaultMode}"` : "";
|
|
10320
|
-
|
|
10331
|
+
if (idx === 0 && mainProjectPreCreated) {
|
|
10332
|
+
const goalLinkInstruction = goalLinks ? ` After creating the goals above, link them to it (${goalLinks.replace(/^, /, "")}).` : "";
|
|
10333
|
+
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}
|
|
10321
10334
|
`;
|
|
10322
|
-
|
|
10335
|
+
} else {
|
|
10336
|
+
bootstrap += `${stepN++}. **Create project** "${proj.name}" (workspace: ${formatWorkspaceObject(workspace)}${policy}${goalLinks})
|
|
10337
|
+
`;
|
|
10338
|
+
}
|
|
10339
|
+
});
|
|
10323
10340
|
if (bootstrapLabels.length > 0) {
|
|
10324
10341
|
bootstrap += `${stepN++}. **Create labels** \u2014 create each label exactly as listed in the Labels section before creating issues
|
|
10325
10342
|
`;
|
|
@@ -10338,7 +10355,14 @@ Read: \`docs/${doc}\`
|
|
|
10338
10355
|
`;
|
|
10339
10356
|
await writeFile(join(companyDir, "BOOTSTRAP.md"), bootstrap);
|
|
10340
10357
|
onProgress("+ BOOTSTRAP.md");
|
|
10341
|
-
return {
|
|
10358
|
+
return {
|
|
10359
|
+
companyDir,
|
|
10360
|
+
allRoles,
|
|
10361
|
+
initialIssues,
|
|
10362
|
+
initialRoutines,
|
|
10363
|
+
roleAdapterOverrides,
|
|
10364
|
+
mainProject: mainProjectInfo
|
|
10365
|
+
};
|
|
10342
10366
|
}
|
|
10343
10367
|
|
|
10344
10368
|
// src/api/client.js
|
|
@@ -11599,6 +11623,25 @@ var plugin = definePlugin({
|
|
|
11599
11623
|
}
|
|
11600
11624
|
if (!existingCompanyId) {
|
|
11601
11625
|
const routines = Array.isArray(assembleResult.initialRoutines) ? assembleResult.initialRoutines : [];
|
|
11626
|
+
let mainProjectId;
|
|
11627
|
+
const mainProject = assembleResult.mainProject;
|
|
11628
|
+
if (routines.length > 0 && mainProject?.name) {
|
|
11629
|
+
try {
|
|
11630
|
+
const createdProject = await client.createProject(companyId, {
|
|
11631
|
+
name: mainProject.name,
|
|
11632
|
+
description: mainProject.description,
|
|
11633
|
+
workspace: mainProject.workspace
|
|
11634
|
+
});
|
|
11635
|
+
mainProjectId = createdProject?.id;
|
|
11636
|
+
log(
|
|
11637
|
+
`\u2713 Main project "${mainProject.name}" created${mainProjectId ? ` (${mainProjectId})` : " (no id returned)"}`
|
|
11638
|
+
);
|
|
11639
|
+
} catch (err) {
|
|
11640
|
+
log(
|
|
11641
|
+
`\u26A0 Could not create main project "${mainProject.name}": ${err instanceof Error ? err.message : String(err)}. Routines will be created without a project.`
|
|
11642
|
+
);
|
|
11643
|
+
}
|
|
11644
|
+
}
|
|
11602
11645
|
for (const routine of routines) {
|
|
11603
11646
|
const title = typeof routine.title === "string" && routine.title.trim() ? routine.title.trim() : typeof routine.name === "string" ? routine.name.trim() : "";
|
|
11604
11647
|
if (!title) continue;
|
|
@@ -11609,6 +11652,7 @@ var plugin = definePlugin({
|
|
|
11609
11652
|
title,
|
|
11610
11653
|
description: routine.description,
|
|
11611
11654
|
assigneeAgentId,
|
|
11655
|
+
projectId: mainProjectId,
|
|
11612
11656
|
priority: routine.priority || "medium",
|
|
11613
11657
|
concurrencyPolicy: routine.concurrencyPolicy || "skip_if_active"
|
|
11614
11658
|
});
|