@starlein/paperclip-plugin-company-wizard 0.3.19 → 0.3.20
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/README.md +4 -0
- package/dist/manifest.js +6 -1
- package/dist/manifest.js.map +2 -2
- package/dist/worker.js +44 -3
- package/dist/worker.js.map +2 -2
- package/package.json +13 -15
- package/templates/modules/accessibility/skills/accessibility-audit.bar.md +11 -0
- package/templates/modules/architecture-plan/agents/ui-designer/skills/design-system.bar.md +11 -0
- package/templates/modules/architecture-plan/skills/architecture-plan.bar.md +11 -0
- package/templates/modules/backlog/skills/backlog-health.bar.md +11 -0
- package/templates/modules/brand-identity/skills/brand-identity.bar.md +11 -0
- package/templates/modules/build-api/skills/api-design.bar.md +11 -0
- package/templates/modules/ci-cd/skills/ci-cd.bar.md +11 -0
- package/templates/modules/codebase-onboarding/skills/codebase-audit.bar.md +11 -0
- package/templates/modules/market-analysis/skills/market-analysis.bar.md +11 -0
- package/templates/modules/monitoring/skills/monitoring.bar.md +11 -0
- package/templates/modules/security-audit/skills/security-review.bar.md +11 -0
- package/templates/modules/security-audit/skills/threat-model.bar.md +11 -0
- package/templates/modules/tech-stack/skills/tech-stack.bar.md +11 -0
- package/templates/modules/user-testing/skills/user-testing.bar.md +11 -0
- package/templates/roles/code-reviewer/DONE.md +10 -0
- package/templates/roles/code-reviewer/LENSES.md +11 -0
- package/templates/roles/devops/DONE.md +10 -0
- package/templates/roles/devops/LENSES.md +12 -0
- package/templates/roles/engineer/DONE.md +10 -0
- package/templates/roles/product-owner/DONE.md +10 -0
- package/templates/roles/product-owner/LENSES.md +11 -0
- package/templates/roles/qa/DONE.md +10 -0
- package/templates/roles/security-engineer/DONE.md +10 -0
- package/templates/roles/security-engineer/LENSES.md +16 -0
- package/templates/roles/ui-designer/DONE.md +10 -0
- package/templates/roles/ui-designer/LENSES.md +13 -0
- package/templates/roles/ux-researcher/DONE.md +10 -0
- package/templates/roles/ux-researcher/LENSES.md +14 -0
package/README.md
CHANGED
|
@@ -139,6 +139,8 @@ Every company starts with just the **CEO** — and that's already a functional t
|
|
|
139
139
|
|
|
140
140
|
No role is ever truly missing. When a specialist isn't present, the next best available person steps in. The CEO is always the final fallback.
|
|
141
141
|
|
|
142
|
+
> **Enriched personas (opt-in):** set `enableEnrichedPersonas` to give expert roles named **domain lenses** (e.g. STRIDE, Nielsen's 10, RICE) in their `SOUL.md`, add **output/review bars** to module skills, and append **done-criteria** to `HEARTBEAT.md`. Off by default — the baseline personas stay lean.
|
|
143
|
+
|
|
142
144
|
<details>
|
|
143
145
|
<summary><strong>Full capability ownership table</strong></summary>
|
|
144
146
|
|
|
@@ -587,6 +589,8 @@ Configure the plugin via **Settings → Plugins → Company Wizard** in the Pape
|
|
|
587
589
|
| `paperclipPassword` | No | Board login password. Stored as a secret ref. |
|
|
588
590
|
| `anthropicApiKey` | No | Anthropic API key for AI wizard mode. Stored as a secret ref. Required to use the AI-powered setup path. |
|
|
589
591
|
| `disableBoardApprovalOnNewCompanies` | No | If `true`, the wizard PATCHes new companies to set `requireBoardApprovalForNewAgents=false` during provisioning. Leave `false` to preserve approval-gated hiring. Defaults to `false`. |
|
|
592
|
+
| `enableEnrichedPersonas` | No | If `true`, expert roles get domain lenses (named mental models) in `SOUL.md`, module skills get concrete output/review bars, and `HEARTBEAT.md` gets explicit done-criteria. Leave `false` (default) for the lean baseline personas. |
|
|
593
|
+
|
|
590
594
|
For isolated worktrees: there is no plugin setting. The policy is controlled by Paperclip instance settings under **Settings → Instance → Experimental → enableIsolatedWorkspaces** and is consumed by the plugin during provisioning.
|
|
591
595
|
|
|
592
596
|
<br>
|
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.20",
|
|
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>",
|
|
@@ -59,6 +59,11 @@ var manifest = {
|
|
|
59
59
|
type: "boolean",
|
|
60
60
|
default: false,
|
|
61
61
|
description: "Optional. If true, the wizard will PATCH new companies to set requireBoardApprovalForNewAgents=false during provisioning. Leave false to preserve approval-gated hiring policies."
|
|
62
|
+
},
|
|
63
|
+
enableEnrichedPersonas: {
|
|
64
|
+
type: "boolean",
|
|
65
|
+
default: false,
|
|
66
|
+
description: "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."
|
|
62
67
|
}
|
|
63
68
|
}
|
|
64
69
|
},
|
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.
|
|
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,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;",
|
|
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.20',\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
|
+
"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
|
@@ -9366,6 +9366,9 @@ async function appendToFile(filePath, content) {
|
|
|
9366
9366
|
await appendFile(filePath, content);
|
|
9367
9367
|
}
|
|
9368
9368
|
}
|
|
9369
|
+
function isEnrichmentFragment(name) {
|
|
9370
|
+
return name === "LENSES.md" || name === "DONE.md" || name.endsWith(".bar.md");
|
|
9371
|
+
}
|
|
9369
9372
|
async function readJson(p) {
|
|
9370
9373
|
if (!await exists(p)) return null;
|
|
9371
9374
|
return JSON.parse(await readFile(p, "utf-8"));
|
|
@@ -9397,6 +9400,7 @@ async function assembleCompany({
|
|
|
9397
9400
|
presetRoutines = [],
|
|
9398
9401
|
presetLabels = [],
|
|
9399
9402
|
enableIsolatedWorktrees = false,
|
|
9403
|
+
enableEnrichedPersonas = false,
|
|
9400
9404
|
outputDir,
|
|
9401
9405
|
templatesDir,
|
|
9402
9406
|
onProgress = () => {
|
|
@@ -9480,7 +9484,7 @@ async function assembleCompany({
|
|
|
9480
9484
|
await copyDir(join(roleSrc, entry.name), join(roleDest, entry.name), {
|
|
9481
9485
|
skipExt: ".meta.json"
|
|
9482
9486
|
});
|
|
9483
|
-
} else if (!entry.name.endsWith(".meta.json")) {
|
|
9487
|
+
} else if (!entry.name.endsWith(".meta.json") && !isEnrichmentFragment(entry.name)) {
|
|
9484
9488
|
await copyFile(join(roleSrc, entry.name), join(roleDest, entry.name));
|
|
9485
9489
|
}
|
|
9486
9490
|
}
|
|
@@ -9497,6 +9501,7 @@ async function assembleCompany({
|
|
|
9497
9501
|
const entries = await readdir(roleDir, { withFileTypes: true });
|
|
9498
9502
|
for (const entry of entries) {
|
|
9499
9503
|
if (entry.isDirectory() || !entry.name.endsWith(".md")) continue;
|
|
9504
|
+
if (isEnrichmentFragment(entry.name)) continue;
|
|
9500
9505
|
await copyFile(join(roleDir, entry.name), join(destDir, entry.name));
|
|
9501
9506
|
}
|
|
9502
9507
|
onProgress(`+ agents/${roleName}/ (role)`);
|
|
@@ -9671,7 +9676,18 @@ ${stages.join("\n")}
|
|
|
9671
9676
|
if (!resolved) return false;
|
|
9672
9677
|
const destSkillsDir = join(companyDir, "agents", roleName, "skills");
|
|
9673
9678
|
await mkdir(destSkillsDir, { recursive: true });
|
|
9674
|
-
|
|
9679
|
+
const destFile = join(destSkillsDir, fileName);
|
|
9680
|
+
await copyFile(resolved.path, destFile);
|
|
9681
|
+
let barApplied = false;
|
|
9682
|
+
if (enableEnrichedPersonas && label === "primary") {
|
|
9683
|
+
const barFileName = fileName.replace(/\.md$/, ".bar.md");
|
|
9684
|
+
const bar = await resolveSkillFile(roleName, barFileName);
|
|
9685
|
+
if (bar) {
|
|
9686
|
+
const barContent = await readFile(bar.path, "utf-8");
|
|
9687
|
+
await appendToFile(destFile, "\n" + barContent.trim() + "\n");
|
|
9688
|
+
barApplied = true;
|
|
9689
|
+
}
|
|
9690
|
+
}
|
|
9675
9691
|
await appendToFile(
|
|
9676
9692
|
join(companyDir, "agents", roleName, "AGENTS.md"),
|
|
9677
9693
|
`
|
|
@@ -9679,7 +9695,10 @@ Read and follow: \`$AGENT_HOME/skills/${fileName}\`
|
|
|
9679
9695
|
`
|
|
9680
9696
|
);
|
|
9681
9697
|
const sourceTag = resolved.source === "shared" ? ", shared" : "";
|
|
9682
|
-
|
|
9698
|
+
const barTag = barApplied ? ", output bar" : "";
|
|
9699
|
+
onProgress(
|
|
9700
|
+
`+ agents/${roleName}/skills/${fileName} (${moduleName}, ${label}${sourceTag}${barTag})`
|
|
9701
|
+
);
|
|
9683
9702
|
return true;
|
|
9684
9703
|
}
|
|
9685
9704
|
for (const [skillName, { primary, cap }] of capabilityOwners) {
|
|
@@ -9701,6 +9720,7 @@ Read and follow: \`$AGENT_HOME/skills/${fileName}\`
|
|
|
9701
9720
|
if (!await exists(skillsDir)) continue;
|
|
9702
9721
|
const skills = await readdir(skillsDir);
|
|
9703
9722
|
for (const skillFile of skills) {
|
|
9723
|
+
if (skillFile.endsWith(".bar.md")) continue;
|
|
9704
9724
|
const skillName = skillFile.replace(/\.md$/, "");
|
|
9705
9725
|
const skillBaseName = skillName.replace(/\.fallback$/, "");
|
|
9706
9726
|
if (capabilityOwners.has(skillBaseName)) continue;
|
|
@@ -9744,6 +9764,24 @@ Read and follow: \`$AGENT_HOME/skills/${skillFile}\`
|
|
|
9744
9764
|
onProgress(`+ agents/${modRole.name}/HEARTBEAT.md (${moduleName}, heartbeat section)`);
|
|
9745
9765
|
}
|
|
9746
9766
|
}
|
|
9767
|
+
if (enableEnrichedPersonas) {
|
|
9768
|
+
for (const roleName of allRoles) {
|
|
9769
|
+
const lensesSrc = join(rolesDir, roleName, "LENSES.md");
|
|
9770
|
+
const soulPath = join(companyDir, "agents", roleName, "SOUL.md");
|
|
9771
|
+
if (await exists(lensesSrc) && await exists(soulPath)) {
|
|
9772
|
+
const lenses = await readFile(lensesSrc, "utf-8");
|
|
9773
|
+
await appendToFile(soulPath, "\n" + lenses.trim() + "\n");
|
|
9774
|
+
onProgress(`+ agents/${roleName}/SOUL.md (domain lenses)`);
|
|
9775
|
+
}
|
|
9776
|
+
const doneSrc = join(rolesDir, roleName, "DONE.md");
|
|
9777
|
+
const heartbeatPath = join(companyDir, "agents", roleName, "HEARTBEAT.md");
|
|
9778
|
+
if (await exists(doneSrc) && await exists(heartbeatPath)) {
|
|
9779
|
+
const done = await readFile(doneSrc, "utf-8");
|
|
9780
|
+
await appendToFile(heartbeatPath, "\n" + done.trim() + "\n");
|
|
9781
|
+
onProgress(`+ agents/${roleName}/HEARTBEAT.md (done criteria)`);
|
|
9782
|
+
}
|
|
9783
|
+
}
|
|
9784
|
+
}
|
|
9747
9785
|
const finalDocsDir = join(companyDir, "docs");
|
|
9748
9786
|
if (await exists(finalDocsDir)) {
|
|
9749
9787
|
const docs = (await readdir(finalDocsDir)).sort();
|
|
@@ -11150,6 +11188,7 @@ var plugin = definePlugin({
|
|
|
11150
11188
|
presetRoutines: presetBootstrapData.routines,
|
|
11151
11189
|
presetLabels: presetBootstrapData.labels,
|
|
11152
11190
|
enableIsolatedWorktrees: await resolveEnableIsolatedWorkspacesFromInstance(cfg),
|
|
11191
|
+
enableEnrichedPersonas: cfgBool(cfg, "enableEnrichedPersonas"),
|
|
11153
11192
|
outputDir: tmpDir,
|
|
11154
11193
|
templatesDir
|
|
11155
11194
|
});
|
|
@@ -11255,6 +11294,7 @@ var plugin = definePlugin({
|
|
|
11255
11294
|
"disableBoardApprovalOnNewCompanies"
|
|
11256
11295
|
);
|
|
11257
11296
|
const enableIsolatedWorktrees = await resolveEnableIsolatedWorkspacesFromInstance(cfg, log);
|
|
11297
|
+
const enableEnrichedPersonas = cfgBool(cfg, "enableEnrichedPersonas");
|
|
11258
11298
|
const companyName = typeof params.companyName === "string" ? params.companyName.trim() : "";
|
|
11259
11299
|
const existingCompanyId = typeof params.existingCompanyId === "string" && params.existingCompanyId.trim() ? params.existingCompanyId.trim() : "";
|
|
11260
11300
|
if (!companyName) return { error: "companyName is required", logs };
|
|
@@ -11295,6 +11335,7 @@ var plugin = definePlugin({
|
|
|
11295
11335
|
presetRoutines: presetBootstrapData.routines,
|
|
11296
11336
|
presetLabels: presetBootstrapData.labels,
|
|
11297
11337
|
enableIsolatedWorktrees,
|
|
11338
|
+
enableEnrichedPersonas,
|
|
11298
11339
|
outputDir,
|
|
11299
11340
|
templatesDir,
|
|
11300
11341
|
onProgress: log
|