@starlein/paperclip-plugin-company-wizard 0.4.6 → 0.4.7
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 +29 -0
- package/README.md +6 -4
- package/dist/manifest.js +1 -1
- package/dist/manifest.js.map +1 -1
- package/dist/ui/index.css +82 -0
- package/dist/ui/index.css.map +2 -2
- package/dist/ui/index.js +422 -137
- package/dist/ui/index.js.map +4 -4
- package/dist/worker.js +352 -21
- package/dist/worker.js.map +3 -3
- package/package.json +1 -1
- package/templates/bootstrap-instructions.md +2 -2
- package/templates/modules/architecture-plan/agents/ui-designer/skills/design-system.md +1 -1
- package/templates/modules/architecture-plan/skills/architecture-plan.md +1 -1
- package/templates/modules/auto-assign/agents/ceo/heartbeat-section.md +1 -1
- package/templates/modules/auto-assign/agents/product-owner/heartbeat-section.md +1 -1
- package/templates/modules/backlog/agents/ceo/heartbeat-section.md +1 -1
- package/templates/modules/backlog/agents/ceo/skills/backlog-health.fallback.md +2 -0
- package/templates/modules/backlog/agents/product-owner/heartbeat-section.md +1 -1
- package/templates/modules/backlog/docs/backlog-process.md +38 -1
- package/templates/modules/backlog/docs/backlog-template.md +1 -1
- package/templates/modules/backlog/module.meta.json +1 -1
- package/templates/modules/backlog/skills/backlog-health.bar.md +2 -0
- package/templates/modules/backlog/skills/backlog-health.md +7 -4
- package/templates/modules/competitive-intel/skills/competitive-tracking.md +1 -1
- package/templates/modules/github-repo/agents/engineer/skills/git-workflow.md +63 -16
- package/templates/modules/github-repo/docs/git-workflow.md +18 -16
- package/templates/modules/market-analysis/agents/ux-researcher/skills/market-analysis.md +1 -1
- package/templates/modules/market-analysis/skills/market-analysis.md +1 -1
- package/templates/modules/pr-review/agents/devops/skills/infra-review.md +6 -8
- package/templates/modules/pr-review/agents/engineer/skills/pr-workflow.md +31 -12
- package/templates/modules/pr-review/agents/product-owner/skills/product-review.md +3 -2
- package/templates/modules/pr-review/agents/ui-designer/skills/design-review.md +4 -6
- package/templates/modules/pr-review/agents/ux-researcher/skills/ux-review.md +4 -6
- package/templates/modules/pr-review/docs/pr-conventions.md +4 -4
- package/templates/modules/pr-review/module.meta.json +1 -1
- package/templates/modules/security-audit/skills/threat-model.md +1 -1
- package/templates/modules/stall-detection/agents/ceo/heartbeat-section.md +1 -1
- package/templates/modules/tech-stack/skills/tech-stack.md +1 -1
- package/templates/modules/triage/skills/issue-triage.md +1 -1
- package/templates/modules/user-testing/agents/qa/skills/user-testing.md +1 -1
- package/templates/modules/user-testing/skills/user-testing.md +1 -1
- package/templates/modules/vision-workshop/agents/ceo/skills/vision-workshop.md +1 -1
- package/templates/presets/repo-maintenance/preset.meta.json +3 -3
- package/templates/roles/audio-designer/role.meta.json +5 -2
- package/templates/roles/cmo/role.meta.json +2 -1
- package/templates/roles/code-reviewer/AGENTS.md +3 -3
- package/templates/roles/code-reviewer/role.meta.json +4 -1
- package/templates/roles/cto/role.meta.json +2 -1
- package/templates/roles/customer-success/role.meta.json +2 -1
- package/templates/roles/devops/role.meta.json +2 -1
- package/templates/roles/engineer/role.meta.json +2 -1
- package/templates/roles/game-artist/role.meta.json +5 -2
- package/templates/roles/game-designer/role.meta.json +4 -1
- package/templates/roles/level-designer/role.meta.json +4 -1
- package/templates/roles/product-owner/role.meta.json +4 -1
- package/templates/roles/qa/role.meta.json +2 -1
- package/templates/roles/security-engineer/role.meta.json +2 -1
- package/templates/roles/technical-writer/role.meta.json +2 -1
- package/templates/roles/ui-designer/role.meta.json +2 -1
- package/templates/roles/ux-researcher/role.meta.json +4 -1
package/dist/worker.js
CHANGED
|
@@ -9546,7 +9546,7 @@ async function assembleCompany({
|
|
|
9546
9546
|
}
|
|
9547
9547
|
return assignee;
|
|
9548
9548
|
};
|
|
9549
|
-
const resolveReviewGate = (reviewGate) => {
|
|
9549
|
+
const resolveReviewGate = (reviewGate, assignTo) => {
|
|
9550
9550
|
if (!reviewGate || typeof reviewGate !== "object") return null;
|
|
9551
9551
|
const reviewersRaw = Array.isArray(reviewGate.reviewers) ? reviewGate.reviewers : [];
|
|
9552
9552
|
const reviewers = [];
|
|
@@ -9560,22 +9560,12 @@ async function assembleCompany({
|
|
|
9560
9560
|
}
|
|
9561
9561
|
const approver = typeof reviewGate.approver === "string" && allRoles.has(reviewGate.approver) ? reviewGate.approver : void 0;
|
|
9562
9562
|
let mergeGate = typeof reviewGate.mergeGate === "string" && allRoles.has(reviewGate.mergeGate) ? reviewGate.mergeGate : void 0;
|
|
9563
|
-
if (
|
|
9564
|
-
const mergeGateFallbacks = [
|
|
9565
|
-
"code-reviewer",
|
|
9566
|
-
"devops",
|
|
9567
|
-
"ui-designer",
|
|
9568
|
-
"ux-researcher",
|
|
9569
|
-
"security-engineer",
|
|
9570
|
-
"qa"
|
|
9571
|
-
];
|
|
9572
|
-
mergeGate = mergeGateFallbacks.find((role) => allRoles.has(role) && role !== approver);
|
|
9573
|
-
}
|
|
9563
|
+
if (mergeGate === assignTo) mergeGate = void 0;
|
|
9574
9564
|
if (approver) {
|
|
9575
9565
|
const idx = reviewers.indexOf(approver);
|
|
9576
9566
|
if (idx !== -1) reviewers.splice(idx, 1);
|
|
9577
9567
|
}
|
|
9578
|
-
if (
|
|
9568
|
+
if (!mergeGate) return null;
|
|
9579
9569
|
return { reviewers, approver, mergeGate };
|
|
9580
9570
|
};
|
|
9581
9571
|
const hasCi = moduleNames.includes("ci-cd");
|
|
@@ -10309,7 +10299,7 @@ Read: \`docs/${doc}\`
|
|
|
10309
10299
|
["goalId", goalRef ? `\u2192 "${goalRef}"` : void 0],
|
|
10310
10300
|
["labelIds", `\u2192 [${issueLabelNames.map((name) => `"${name}"`).join(", ")}]`]
|
|
10311
10301
|
]);
|
|
10312
|
-
const issueReviewGate = resolveReviewGate(issue.reviewGate);
|
|
10302
|
+
const issueReviewGate = resolveReviewGate(issue.reviewGate, issue.assignTo);
|
|
10313
10303
|
if (issueReviewGate) {
|
|
10314
10304
|
bootstrap += renderReviewGate(issueReviewGate);
|
|
10315
10305
|
}
|
|
@@ -10334,7 +10324,7 @@ Read: \`docs/${doc}\`
|
|
|
10334
10324
|
`;
|
|
10335
10325
|
if (moduleNames.includes("pr-review")) {
|
|
10336
10326
|
const ciClause = hasCi ? "CI (lint/test/build) must be green before the merge gate merges \u2014 this is the hard gate and cannot be skipped" : "no CI is configured, so the merge-gate agent must run the test suite/build and paste the real output into the merge-gate verdict before merging \u2014 this is the hard gate";
|
|
10337
|
-
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 **Code Reviewer** (a non-author who satisfies the hard gate above, merges the PR, then records approval to close the issue). **Never list the issue's executor/author as a participant in any stage** \u2014 Paperclip excludes the original executor from review/approval, so a stage whose only participant is the author has no eligible participant and the issue stalls in \`in_review\` (422 No eligible approval participant); this is why the merge gate is the Code Reviewer (
|
|
10327
|
+
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 when present (intent/scope), then a final \`approval\` merge-gate stage for the **Code Reviewer** (a non-author who satisfies the hard gate above, merges the PR, then records approval to close the issue). **Never list the issue's executor/author as a participant in any stage** \u2014 Paperclip excludes the original executor from review/approval, so a stage whose only participant is the author has no eligible participant and the issue stalls in \`in_review\` (422 No eligible approval participant); this is why the merge gate is the Code Reviewer (a non-author), not the engineer who wrote the code. The merge gate must be last so the Product Owner's approval does not auto-close the issue with the PR still open. When no Code Reviewer is on the team, do not set executionPolicy stages at all \u2014 use the PR-Self-Merge path (the engineer opens the PR and merges via \`gh pr merge <N> --merge\`); other review roles may leave advisory comments but do not block. 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.
|
|
10338
10328
|
`;
|
|
10339
10329
|
}
|
|
10340
10330
|
bootstrap += `
|
|
@@ -10613,6 +10603,17 @@ var PaperclipClient = class {
|
|
|
10613
10603
|
})
|
|
10614
10604
|
});
|
|
10615
10605
|
}
|
|
10606
|
+
async getInstructionsBundle(agentId) {
|
|
10607
|
+
return this._fetch(`/api/agents/${agentId}/instructions-bundle`, {
|
|
10608
|
+
method: "GET"
|
|
10609
|
+
});
|
|
10610
|
+
}
|
|
10611
|
+
async deleteInstructionsBundleFile(agentId, { path: path3 }) {
|
|
10612
|
+
return this._fetch(`/api/agents/${agentId}/instructions-bundle/file`, {
|
|
10613
|
+
method: "DELETE",
|
|
10614
|
+
body: JSON.stringify({ path: path3 })
|
|
10615
|
+
});
|
|
10616
|
+
}
|
|
10616
10617
|
async createAgent(companyId, agent) {
|
|
10617
10618
|
const {
|
|
10618
10619
|
name,
|
|
@@ -11002,7 +11003,7 @@ var __dirname = path2.dirname(fileURLToPath2(import.meta.url));
|
|
|
11002
11003
|
var DEFAULT_TEMPLATES_REPO_URL = "https://github.com/starlein/paperclip-plugin-company-wizard/tree/main/templates";
|
|
11003
11004
|
var BUNDLED_TEMPLATES_DIR = path2.resolve(__dirname, "..", "templates");
|
|
11004
11005
|
var PLUGIN_PACKAGE_NAME = "@starlein/paperclip-plugin-company-wizard";
|
|
11005
|
-
var CURRENT_PLUGIN_VERSION = "0.4.
|
|
11006
|
+
var CURRENT_PLUGIN_VERSION = "0.4.7";
|
|
11006
11007
|
var NPM_LATEST_URL = "https://registry.npmjs.org/@starlein%2Fpaperclip-plugin-company-wizard/latest";
|
|
11007
11008
|
function copyDirSync(src, dest) {
|
|
11008
11009
|
fs2.mkdirSync(dest, { recursive: true });
|
|
@@ -11351,11 +11352,57 @@ async function syncAgentInstructionsIntoManagedBundle({
|
|
|
11351
11352
|
);
|
|
11352
11353
|
}
|
|
11353
11354
|
}
|
|
11355
|
+
function preserveExistingSkillSync(existingAgent, nextAdapterConfig) {
|
|
11356
|
+
const existingSync = existingAgent?.adapterConfig && typeof existingAgent.adapterConfig === "object" && "paperclipSkillSync" in existingAgent.adapterConfig ? existingAgent.adapterConfig.paperclipSkillSync : void 0;
|
|
11357
|
+
if (!existingSync) {
|
|
11358
|
+
return nextAdapterConfig;
|
|
11359
|
+
}
|
|
11360
|
+
return {
|
|
11361
|
+
...nextAdapterConfig,
|
|
11362
|
+
paperclipSkillSync: existingSync
|
|
11363
|
+
};
|
|
11364
|
+
}
|
|
11354
11365
|
function routineTemplateTitle(routine) {
|
|
11355
11366
|
if (typeof routine?.title === "string" && routine.title.trim()) return routine.title.trim();
|
|
11356
11367
|
if (typeof routine?.name === "string" && routine.name.trim()) return routine.name.trim();
|
|
11357
11368
|
return "";
|
|
11358
11369
|
}
|
|
11370
|
+
function buildWizardManifest(params) {
|
|
11371
|
+
const routineTitles = params.initialRoutines.map((r) => routineTemplateTitle(r)).filter(Boolean);
|
|
11372
|
+
const generatedFilePaths = {};
|
|
11373
|
+
if (params.assembleResult?.allFiles && typeof params.assembleResult.allFiles === "object") {
|
|
11374
|
+
for (const relativePath of Object.keys(params.assembleResult.allFiles)) {
|
|
11375
|
+
const match = relativePath.match(/^agents\/([^/]+)\//);
|
|
11376
|
+
if (match) {
|
|
11377
|
+
const agentRole = match[1];
|
|
11378
|
+
if (!generatedFilePaths[agentRole]) generatedFilePaths[agentRole] = [];
|
|
11379
|
+
generatedFilePaths[agentRole].push(relativePath);
|
|
11380
|
+
} else if (relativePath.startsWith("docs/")) {
|
|
11381
|
+
if (!generatedFilePaths["docs"]) generatedFilePaths["docs"] = [];
|
|
11382
|
+
generatedFilePaths["docs"].push(relativePath);
|
|
11383
|
+
}
|
|
11384
|
+
}
|
|
11385
|
+
}
|
|
11386
|
+
return {
|
|
11387
|
+
pluginVersion: CURRENT_PLUGIN_VERSION,
|
|
11388
|
+
preset: params.presetName,
|
|
11389
|
+
modules: params.selectedModules,
|
|
11390
|
+
roles: params.selectedRoleNames,
|
|
11391
|
+
generatedFilePaths,
|
|
11392
|
+
routineTitles,
|
|
11393
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
11394
|
+
};
|
|
11395
|
+
}
|
|
11396
|
+
var WIZARD_PLUGIN_KEY = "starlein.paperclip-plugin-company-wizard";
|
|
11397
|
+
async function findPluginId(client) {
|
|
11398
|
+
try {
|
|
11399
|
+
const plugins = await client._fetch("/api/plugins");
|
|
11400
|
+
const match = Array.isArray(plugins) ? plugins.find((p) => p.pluginKey === WIZARD_PLUGIN_KEY) : null;
|
|
11401
|
+
return match?.id ?? null;
|
|
11402
|
+
} catch {
|
|
11403
|
+
return null;
|
|
11404
|
+
}
|
|
11405
|
+
}
|
|
11359
11406
|
async function syncRoutineTrigger({
|
|
11360
11407
|
client,
|
|
11361
11408
|
routineId,
|
|
@@ -11656,6 +11703,204 @@ var plugin = definePlugin({
|
|
|
11656
11703
|
}
|
|
11657
11704
|
}
|
|
11658
11705
|
});
|
|
11706
|
+
ctx.actions.register("preview-company-update", async (params) => {
|
|
11707
|
+
let tmpDir;
|
|
11708
|
+
try {
|
|
11709
|
+
let countFiles2 = function(dir) {
|
|
11710
|
+
if (!fs2.existsSync(dir)) return;
|
|
11711
|
+
for (const entry of fs2.readdirSync(dir, { withFileTypes: true })) {
|
|
11712
|
+
const full = path2.join(dir, entry.name);
|
|
11713
|
+
if (entry.isDirectory()) countFiles2(full);
|
|
11714
|
+
else if (entry.isFile()) plannedFiles++;
|
|
11715
|
+
}
|
|
11716
|
+
};
|
|
11717
|
+
var countFiles = countFiles2;
|
|
11718
|
+
const existingCompanyId = typeof params.existingCompanyId === "string" && params.existingCompanyId.trim() ? params.existingCompanyId.trim() : "";
|
|
11719
|
+
if (!existingCompanyId) {
|
|
11720
|
+
return { error: "existingCompanyId is required for preview." };
|
|
11721
|
+
}
|
|
11722
|
+
const cfg = await ctx.config.get() ?? {};
|
|
11723
|
+
const paperclipUrl = cfg.paperclipUrl || process.env.PAPERCLIP_PUBLIC_URL || "http://localhost:3100";
|
|
11724
|
+
const paperclipEmail = cfg.paperclipEmail || "";
|
|
11725
|
+
const paperclipPassword = cfg.paperclipPassword || "";
|
|
11726
|
+
const companyName = typeof params.companyName === "string" && params.companyName.trim() ? params.companyName.trim() : "Preview";
|
|
11727
|
+
const templatesDir = await ensureTemplatesDir(cfg);
|
|
11728
|
+
tmpDir = path2.join(os.tmpdir(), `company-wizard-preview-update-${Date.now()}`);
|
|
11729
|
+
const [presets, allModules, roleTemplates] = await Promise.all([
|
|
11730
|
+
loadPresets(templatesDir),
|
|
11731
|
+
loadModules(templatesDir),
|
|
11732
|
+
loadRoles(templatesDir)
|
|
11733
|
+
]);
|
|
11734
|
+
const roleTemplateByName = new Map(
|
|
11735
|
+
(Array.isArray(roleTemplates) ? roleTemplates : []).filter((role) => role && typeof role.name === "string").map((role) => [role.name, role])
|
|
11736
|
+
);
|
|
11737
|
+
const selectedPreset = presets.find((p) => p.name === params.presetName) || null;
|
|
11738
|
+
const effectiveModules = resolveEffectiveModules(
|
|
11739
|
+
selectedPreset,
|
|
11740
|
+
allModules,
|
|
11741
|
+
params.selectedModules ?? []
|
|
11742
|
+
);
|
|
11743
|
+
const goals = collectGoals(selectedPreset, allModules, new Set(effectiveModules));
|
|
11744
|
+
const presetBootstrapData = collectPresetBootstrapData(selectedPreset);
|
|
11745
|
+
const previewGoals = Array.isArray(params.goals) ? params.goals : params.goal ? [params.goal] : [];
|
|
11746
|
+
const previewProjects = Array.isArray(params.projects) ? params.projects : [];
|
|
11747
|
+
const previewIssues = Array.isArray(params.issues) ? params.issues : [];
|
|
11748
|
+
const assembleResult = await assembleCompany({
|
|
11749
|
+
companyName,
|
|
11750
|
+
userGoals: previewGoals,
|
|
11751
|
+
userProjects: previewProjects,
|
|
11752
|
+
moduleNames: effectiveModules,
|
|
11753
|
+
extraRoleNames: params.selectedRoles ?? [],
|
|
11754
|
+
inlineGoals: goals,
|
|
11755
|
+
userIssues: previewIssues,
|
|
11756
|
+
presetIssues: presetBootstrapData.issues,
|
|
11757
|
+
presetRoutines: presetBootstrapData.routines,
|
|
11758
|
+
presetLabels: presetBootstrapData.labels,
|
|
11759
|
+
enableIsolatedWorktrees: await resolveEnableIsolatedWorkspacesFromInstance(cfg),
|
|
11760
|
+
enableEnrichedPersonas: true,
|
|
11761
|
+
outputDir: tmpDir,
|
|
11762
|
+
templatesDir
|
|
11763
|
+
});
|
|
11764
|
+
const allRoles = Array.isArray(params.allRoles) ? params.allRoles : [...assembleResult.allRoles ?? []].filter(Boolean);
|
|
11765
|
+
const teamRoles = allRoles.filter((r) => r && r !== "ceo");
|
|
11766
|
+
let plannedFiles = 0;
|
|
11767
|
+
countFiles2(assembleResult.companyDir);
|
|
11768
|
+
const client = new PaperclipClient(paperclipUrl, {
|
|
11769
|
+
email: paperclipEmail,
|
|
11770
|
+
password: paperclipPassword
|
|
11771
|
+
});
|
|
11772
|
+
await client.connect();
|
|
11773
|
+
const company = await client.getCompany(existingCompanyId);
|
|
11774
|
+
const existingAgents = await client.listAgents(existingCompanyId);
|
|
11775
|
+
const existingRoutines = await client.listRoutines(existingCompanyId);
|
|
11776
|
+
let existingManifest = null;
|
|
11777
|
+
try {
|
|
11778
|
+
const pluginId = await findPluginId(client);
|
|
11779
|
+
if (pluginId) {
|
|
11780
|
+
const settings = await client._fetch(
|
|
11781
|
+
`/api/plugins/${pluginId}/company-settings/${existingCompanyId}`
|
|
11782
|
+
);
|
|
11783
|
+
const manifestData = settings?.settingsJson?.wizardManifest ?? settings?.settings_json?.wizardManifest;
|
|
11784
|
+
if (manifestData && typeof manifestData === "object") {
|
|
11785
|
+
existingManifest = manifestData;
|
|
11786
|
+
}
|
|
11787
|
+
}
|
|
11788
|
+
} catch {
|
|
11789
|
+
}
|
|
11790
|
+
const existingCeo = Array.isArray(existingAgents) ? existingAgents.find((a) => a?.role === "ceo" && a?.status !== "terminated") : null;
|
|
11791
|
+
const existingByTemplateRole = /* @__PURE__ */ new Map();
|
|
11792
|
+
if (Array.isArray(existingAgents)) {
|
|
11793
|
+
for (const a of existingAgents) {
|
|
11794
|
+
const tr = a?.metadata?.templateRole;
|
|
11795
|
+
if (tr && a?.status !== "terminated" && a?.role !== "ceo") {
|
|
11796
|
+
existingByTemplateRole.set(tr, a);
|
|
11797
|
+
}
|
|
11798
|
+
}
|
|
11799
|
+
}
|
|
11800
|
+
const agents = [];
|
|
11801
|
+
const ceoTemplate = roleTemplateByName.get("ceo") || {};
|
|
11802
|
+
const ceoTitle = typeof ceoTemplate.title === "string" && ceoTemplate.title.trim() ? ceoTemplate.title.trim() : "CEO";
|
|
11803
|
+
agents.push({
|
|
11804
|
+
role: "ceo",
|
|
11805
|
+
title: existingCeo?.title || ceoTitle,
|
|
11806
|
+
action: existingCeo ? "update" : "hire"
|
|
11807
|
+
});
|
|
11808
|
+
for (const roleName of teamRoles) {
|
|
11809
|
+
const roleTemplate = roleTemplateByName.get(roleName) || {};
|
|
11810
|
+
const roleTitle = typeof roleTemplate.title === "string" && roleTemplate.title.trim() ? roleTemplate.title.trim() : formatRoleName(roleName);
|
|
11811
|
+
const existing = existingByTemplateRole.get(roleName);
|
|
11812
|
+
agents.push({
|
|
11813
|
+
role: roleName,
|
|
11814
|
+
title: roleTitle,
|
|
11815
|
+
action: existing ? "update" : "hire"
|
|
11816
|
+
});
|
|
11817
|
+
}
|
|
11818
|
+
const selectedRoleSet = new Set(allRoles);
|
|
11819
|
+
const manifestRoleSet = existingManifest?.roles ? new Set(existingManifest.roles) : null;
|
|
11820
|
+
for (const [tr, agent] of existingByTemplateRole.entries()) {
|
|
11821
|
+
if (!selectedRoleSet.has(tr)) {
|
|
11822
|
+
if (manifestRoleSet && !manifestRoleSet.has(tr)) {
|
|
11823
|
+
continue;
|
|
11824
|
+
}
|
|
11825
|
+
const roleTemplate = roleTemplateByName.get(tr) || {};
|
|
11826
|
+
const roleTitle = typeof roleTemplate.title === "string" && roleTemplate.title.trim() ? roleTemplate.title.trim() : formatRoleName(tr);
|
|
11827
|
+
agents.push({
|
|
11828
|
+
role: tr,
|
|
11829
|
+
title: agent?.title || roleTitle,
|
|
11830
|
+
action: "retire"
|
|
11831
|
+
});
|
|
11832
|
+
}
|
|
11833
|
+
}
|
|
11834
|
+
const existingRoutineByTitle = /* @__PURE__ */ new Map();
|
|
11835
|
+
if (Array.isArray(existingRoutines)) {
|
|
11836
|
+
for (const r of existingRoutines) {
|
|
11837
|
+
const title = routineTemplateTitle(r);
|
|
11838
|
+
if (title) existingRoutineByTitle.set(title.toLowerCase(), r);
|
|
11839
|
+
}
|
|
11840
|
+
}
|
|
11841
|
+
const plannedRoutines = [
|
|
11842
|
+
...assembleResult.initialRoutines ?? [],
|
|
11843
|
+
...presetBootstrapData.routines ?? []
|
|
11844
|
+
];
|
|
11845
|
+
const seenRoutineTitles = /* @__PURE__ */ new Set();
|
|
11846
|
+
const routines = [];
|
|
11847
|
+
for (const routine of plannedRoutines) {
|
|
11848
|
+
const title = routineTemplateTitle(routine);
|
|
11849
|
+
if (!title) continue;
|
|
11850
|
+
const key = title.toLowerCase();
|
|
11851
|
+
if (seenRoutineTitles.has(key)) continue;
|
|
11852
|
+
seenRoutineTitles.add(key);
|
|
11853
|
+
const existing = existingRoutineByTitle.get(key);
|
|
11854
|
+
routines.push({
|
|
11855
|
+
title,
|
|
11856
|
+
action: existing ? "update" : "create",
|
|
11857
|
+
assignTo: routine.assignTo || void 0
|
|
11858
|
+
});
|
|
11859
|
+
}
|
|
11860
|
+
const desiredSkillsPreserved = [];
|
|
11861
|
+
if (Array.isArray(existingAgents)) {
|
|
11862
|
+
for (const a of existingAgents) {
|
|
11863
|
+
if (a?.adapterConfig && typeof a.adapterConfig === "object" && "paperclipSkillSync" in a.adapterConfig) {
|
|
11864
|
+
const sync = a.adapterConfig.paperclipSkillSync;
|
|
11865
|
+
if (sync && typeof sync === "object" && "desiredSkills" in sync) {
|
|
11866
|
+
const skills = sync.desiredSkills;
|
|
11867
|
+
if (Array.isArray(skills) && skills.length > 0) {
|
|
11868
|
+
desiredSkillsPreserved.push({
|
|
11869
|
+
agentId: a.id,
|
|
11870
|
+
agentName: a.title || a.name || a.id,
|
|
11871
|
+
skills
|
|
11872
|
+
});
|
|
11873
|
+
}
|
|
11874
|
+
}
|
|
11875
|
+
}
|
|
11876
|
+
}
|
|
11877
|
+
}
|
|
11878
|
+
try {
|
|
11879
|
+
fs2.rmSync(tmpDir, { recursive: true, force: true });
|
|
11880
|
+
} catch {
|
|
11881
|
+
}
|
|
11882
|
+
tmpDir = void 0;
|
|
11883
|
+
return {
|
|
11884
|
+
diff: {
|
|
11885
|
+
companyId: existingCompanyId,
|
|
11886
|
+
companyName: company?.name || companyName,
|
|
11887
|
+
agents,
|
|
11888
|
+
routines,
|
|
11889
|
+
desiredSkillsPreserved,
|
|
11890
|
+
plannedFiles,
|
|
11891
|
+
existingManifest
|
|
11892
|
+
}
|
|
11893
|
+
};
|
|
11894
|
+
} catch (err) {
|
|
11895
|
+
if (tmpDir) {
|
|
11896
|
+
try {
|
|
11897
|
+
fs2.rmSync(tmpDir, { recursive: true, force: true });
|
|
11898
|
+
} catch {
|
|
11899
|
+
}
|
|
11900
|
+
}
|
|
11901
|
+
return { error: err instanceof Error ? err.message : String(err) };
|
|
11902
|
+
}
|
|
11903
|
+
});
|
|
11659
11904
|
ctx.actions.register("check-auth", async () => {
|
|
11660
11905
|
const cfg = await ctx.config.get() ?? {};
|
|
11661
11906
|
const paperclipUrl = cfg.paperclipUrl || process.env.PAPERCLIP_PUBLIC_URL || "http://localhost:3100";
|
|
@@ -11842,8 +12087,27 @@ var plugin = definePlugin({
|
|
|
11842
12087
|
let boardOperationsIssue = null;
|
|
11843
12088
|
let hiringPlanIssue = null;
|
|
11844
12089
|
let bootstrapIssue;
|
|
12090
|
+
let allRoleNames = [];
|
|
12091
|
+
let existingManifest = null;
|
|
12092
|
+
let existingByTemplateRole = /* @__PURE__ */ new Map();
|
|
12093
|
+
let routines = [];
|
|
11845
12094
|
try {
|
|
11846
|
-
|
|
12095
|
+
allRoleNames = [...assembleResult.allRoles ?? []].filter(Boolean).sort();
|
|
12096
|
+
if (existingCompanyId) {
|
|
12097
|
+
try {
|
|
12098
|
+
const pluginId = await findPluginId(client);
|
|
12099
|
+
if (pluginId) {
|
|
12100
|
+
const settings = await client._fetch(
|
|
12101
|
+
`/api/plugins/${pluginId}/company-settings/${companyId}`
|
|
12102
|
+
);
|
|
12103
|
+
const manifestData = settings?.settingsJson?.wizardManifest ?? settings?.settings_json?.wizardManifest;
|
|
12104
|
+
if (manifestData && typeof manifestData === "object") {
|
|
12105
|
+
existingManifest = manifestData;
|
|
12106
|
+
}
|
|
12107
|
+
}
|
|
12108
|
+
} catch {
|
|
12109
|
+
}
|
|
12110
|
+
}
|
|
11847
12111
|
const repositoryMode = userProjects.some(
|
|
11848
12112
|
(project) => project?.repoUrl || project?.workspace?.sourceType === "git_repo"
|
|
11849
12113
|
) ? "existing git repository" : "fresh local repository";
|
|
@@ -11930,7 +12194,7 @@ var plugin = definePlugin({
|
|
|
11930
12194
|
try {
|
|
11931
12195
|
const ceoPatch = {
|
|
11932
12196
|
adapterType,
|
|
11933
|
-
adapterConfig,
|
|
12197
|
+
adapterConfig: preserveExistingSkillSync(existingCeo, adapterConfig),
|
|
11934
12198
|
runtimeConfig: ceoRuntimeConfig,
|
|
11935
12199
|
...ceoMetadata ? { metadata: { ...existingCeo.metadata ?? {}, ...ceoMetadata } } : {}
|
|
11936
12200
|
};
|
|
@@ -12015,7 +12279,7 @@ var plugin = definePlugin({
|
|
|
12015
12279
|
const teamRoles = [...assembleResult.allRoles ?? []].filter(
|
|
12016
12280
|
(r) => r && r !== "ceo"
|
|
12017
12281
|
);
|
|
12018
|
-
|
|
12282
|
+
existingByTemplateRole = /* @__PURE__ */ new Map();
|
|
12019
12283
|
if (existingCompanyId && teamRoles.length > 0) {
|
|
12020
12284
|
const agents = await client.listAgents(companyId);
|
|
12021
12285
|
if (Array.isArray(agents)) {
|
|
@@ -12050,7 +12314,7 @@ var plugin = definePlugin({
|
|
|
12050
12314
|
try {
|
|
12051
12315
|
await client.updateAgent(existingAgent.id, {
|
|
12052
12316
|
adapterType,
|
|
12053
|
-
adapterConfig: roleAdapterConfig,
|
|
12317
|
+
adapterConfig: preserveExistingSkillSync(existingAgent, roleAdapterConfig),
|
|
12054
12318
|
runtimeConfig: roleRuntimeConfig,
|
|
12055
12319
|
metadata: { ...existingAgent.metadata ?? {}, ...roleMetadata },
|
|
12056
12320
|
...!existingAgent.title && roleTitle ? { title: roleTitle } : {},
|
|
@@ -12094,7 +12358,7 @@ var plugin = definePlugin({
|
|
|
12094
12358
|
);
|
|
12095
12359
|
}
|
|
12096
12360
|
}
|
|
12097
|
-
|
|
12361
|
+
routines = Array.isArray(assembleResult.initialRoutines) ? assembleResult.initialRoutines : [];
|
|
12098
12362
|
if (!existingCompanyId) {
|
|
12099
12363
|
let mainProjectId;
|
|
12100
12364
|
const mainProject = assembleResult.mainProject;
|
|
@@ -12196,6 +12460,73 @@ var plugin = definePlugin({
|
|
|
12196
12460
|
const issueIds = [boardOperationsIssue?.id, hiringPlanIssue?.id, bootstrapIssue.id].filter(
|
|
12197
12461
|
Boolean
|
|
12198
12462
|
);
|
|
12463
|
+
try {
|
|
12464
|
+
const pluginId = await findPluginId(client);
|
|
12465
|
+
if (pluginId) {
|
|
12466
|
+
const wizardManifest = buildWizardManifest({
|
|
12467
|
+
presetName: selectedPreset?.name ?? null,
|
|
12468
|
+
selectedModules: effectiveModules,
|
|
12469
|
+
selectedRoleNames: allRoleNames,
|
|
12470
|
+
assembleResult,
|
|
12471
|
+
initialRoutines: routines
|
|
12472
|
+
});
|
|
12473
|
+
await client._fetch(`/api/plugins/${pluginId}/company-settings/${companyId}`, {
|
|
12474
|
+
method: "PUT",
|
|
12475
|
+
body: JSON.stringify({ settingsJson: { wizardManifest } })
|
|
12476
|
+
});
|
|
12477
|
+
log("\u2713 Wizard manifest saved");
|
|
12478
|
+
} else {
|
|
12479
|
+
log("\u26A0 Could not find plugin ID \u2014 manifest not saved");
|
|
12480
|
+
}
|
|
12481
|
+
} catch (manifestErr) {
|
|
12482
|
+
log(
|
|
12483
|
+
`\u26A0 Could not save wizard manifest: ${manifestErr instanceof Error ? manifestErr.message : String(manifestErr)}`
|
|
12484
|
+
);
|
|
12485
|
+
}
|
|
12486
|
+
if (existingCompanyId && existingManifest && Array.isArray(existingManifest.roles)) {
|
|
12487
|
+
const newRoleSet = new Set(allRoleNames);
|
|
12488
|
+
const retiredRoles = existingManifest.roles.filter(
|
|
12489
|
+
(role) => !newRoleSet.has(role)
|
|
12490
|
+
);
|
|
12491
|
+
for (const role of retiredRoles) {
|
|
12492
|
+
try {
|
|
12493
|
+
const agentData = existingByTemplateRole.get(role);
|
|
12494
|
+
const agentInfo = agentData ? `**Agent ID:** ${agentData.id}
|
|
12495
|
+
**Agent name:** ${agentData.title || agentData.name || agentData.id}` : "_No active agent found for this role._";
|
|
12496
|
+
const issueTitle = `Review retired template role: ${role}`;
|
|
12497
|
+
const issueDescription = [
|
|
12498
|
+
`## Retired Role: \`${role}\``,
|
|
12499
|
+
"",
|
|
12500
|
+
"This template role was removed from the company configuration during an update.",
|
|
12501
|
+
"The agent is still active but no longer managed by the wizard.",
|
|
12502
|
+
"",
|
|
12503
|
+
"### Cleanup Checklist",
|
|
12504
|
+
"",
|
|
12505
|
+
"- [ ] Review the agent's current work and open issues",
|
|
12506
|
+
"- [ ] Reassign any in-progress issues to other team members",
|
|
12507
|
+
"- [ ] Consider pausing the agent's heartbeat",
|
|
12508
|
+
"- [ ] Remove module-specific skill files if applicable",
|
|
12509
|
+
"- [ ] Consider terminating the agent if no longer needed",
|
|
12510
|
+
"",
|
|
12511
|
+
agentInfo
|
|
12512
|
+
].join("\n");
|
|
12513
|
+
const createdIssue = await client.createIssue(companyId, {
|
|
12514
|
+
title: issueTitle,
|
|
12515
|
+
description: issueDescription,
|
|
12516
|
+
priority: "low",
|
|
12517
|
+
status: "todo",
|
|
12518
|
+
...boardOperationsIssue?.id ? { projectId: boardOperationsIssue.id, goalId: boardOperationsIssue.id } : {}
|
|
12519
|
+
});
|
|
12520
|
+
log(
|
|
12521
|
+
`\u2713 Retired-role review issue created for "${role}": ${createdIssue.identifier || createdIssue.id}`
|
|
12522
|
+
);
|
|
12523
|
+
} catch (retiredRoleErr) {
|
|
12524
|
+
log(
|
|
12525
|
+
`\u26A0 Could not create retired-role review issue for "${role}": ${retiredRoleErr instanceof Error ? retiredRoleErr.message : String(retiredRoleErr)}`
|
|
12526
|
+
);
|
|
12527
|
+
}
|
|
12528
|
+
}
|
|
12529
|
+
}
|
|
12199
12530
|
return {
|
|
12200
12531
|
companyId,
|
|
12201
12532
|
issuePrefix: company.issuePrefix,
|