@starlein/paperclip-plugin-company-wizard 0.6.2 → 0.6.4

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 CHANGED
@@ -4,6 +4,42 @@ All notable changes to the Company Wizard plugin are documented here.
4
4
 
5
5
  The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
6
 
7
+ ## [0.6.4] - 2026-09-16
8
+
9
+ ### Fixed
10
+
11
+ - Assembled Company Skills now include the YAML `name` and `description` frontmatter required by Codex. Provisioning also normalizes skill markdown before creating or updating `SKILL.md`, and keeps Paperclip's stored skill name equal to the Codex-compatible slug so a later rename cannot reintroduce an invalid name.
12
+ - Existing frontmatter is preserved instead of adding a duplicate block. Role-specific skill variants receive their final, disambiguated slug in the generated frontmatter.
13
+
14
+ ### Changed
15
+
16
+ - When `templatesPath` points to an empty directory and a custom GitHub template URL is configured, the wizard offers an explicit sync bound to that directory and saved source. The download is validated before replacing the empty directory; an operator-managed directory with files is left untouched (PR #52).
17
+
18
+ ### Upgrade notes
19
+
20
+ - Install or update the plugin package and reload it to activate the worker fix. Installing this release does not rewrite existing companies or skill files; refresh an existing company to regenerate its managed skills with valid frontmatter.
21
+
22
+ ## [0.6.3] - 2026-09-08
23
+
24
+ Includes PR #50 and preserves all changes from the previously published v0.6.2 tag, which had not yet been merged into main.
25
+
26
+ ### Fixed
27
+
28
+ - Empty or incorrectly nested `templatesPath` directories no longer silently return an empty catalog and leave the wizard stuck with only **Custom**. Local, bundled, and cached sources must contain a valid base CEO template; minimal CEO-only libraries remain supported without optional presets or modules.
29
+ - The template data endpoint returns actionable errors, and the UI blocks unusable catalogs with recovery instructions, including empty responses from older workers.
30
+ - **Test Configuration** validates template availability and metadata before checking Paperclip connectivity. Previously a working API login could mask unusable templates. It does not make a paid AI request or verify model entitlement.
31
+ - Remote template refresh validates downloaded metadata before replacing the cache, preserving the previous working copy on invalid downloads. Explicit operator-managed paths remain untouched.
32
+
33
+ ### Changed
34
+
35
+ - OpenAI wizard generation uses `gpt-6-astra` with `reasoning.effort: high` for both synchronous interview calls and background configuration/bootstrap generation. Anthropic behavior and provisioned CEO/team adapter model defaults are unchanged.
36
+ - README and settings guidance clarify that `templatesPath` overrides `templatesRepoUrl` and is not a download destination. Clear an unintended empty local path, save, and reload to use bundled release templates; keep `companiesDir` unchanged.
37
+
38
+ ### Upgrade notes
39
+
40
+ - Update the installed plugin package and reload it to activate the worker/UI fixes and new OpenAI model. Refreshing templates alone is insufficient.
41
+ - No existing companies, agent model settings, credentials, or local template files are automatically changed by this release.
42
+
7
43
  ## [0.6.2] - 2026-09-07
8
44
 
9
45
  Follow-up review of the 0.6.1 consolidation against Paperclip source `3fb4b65f9d974d8687db8a060f20ec66b6071a79` (upstream master through 2026-09-06). Fixes two template defects that silently dropped provisioned routines and a set of instruction/doc drifts left by the Skills Store migration.
package/README.md CHANGED
@@ -17,7 +17,9 @@
17
17
 
18
18
  > **Fork:** This is a community-maintained fork of [yesterday-AI/paperclip-plugin-company-wizard](https://github.com/yesterday-AI/paperclip-plugin-company-wizard), updated for Paperclip plugin API v1 and the current published SDK with substantial bug fixes. End-to-end company setup is governed through current Paperclip workflows as of v0.5.0.
19
19
 
20
- **Version 0.6.2:** re-reviewed against Paperclip master through 2026-09-06. Fixes routines that were silently rejected (invalid `concurrencyPolicy`) or rendered as `undefined` in the bootstrap issue, repoints instructions at Skills Store slugs and working-directory doc paths, and corrects the review-gate error/round-cap guidance. 0.6.1 consolidated PRs #44, #46 and #47 with run-scoped hire approvals and explicit bootstrap start. See [compatibility notes](docs/PAPERCLIP-COMPATIBILITY.md).
20
+ **Version 0.6.4:** adds an explicit sync option for a configured empty template directory and fixes generated Company Skills so Codex can load their `SKILL.md` files. See the [changelog](CHANGELOG.md) and [compatibility notes](docs/PAPERCLIP-COMPATIBILITY.md).
21
+
22
+ **Upgrading from 0.6.3:** update the installed plugin package and reload it; refreshing templates alone does not update the worker. Newly provisioned or refreshed Company Skills gain Codex-compatible YAML frontmatter. Existing skills are not changed merely by installing the release. If `templatesPath` is intentionally empty, the wizard can offer an explicit sync from the configured GitHub template URL; clearing the path still selects bundled templates. `companiesDir` does not need to change.
21
23
 
22
24
  Requires Node **24.11+**, matching the current Paperclip SDK/shared runtime requirement.
23
25
 
@@ -57,7 +59,7 @@ Requires Node **24.11+**, matching the current Paperclip SDK/shared runtime requ
57
59
 
58
60
  #### AI wizard
59
61
 
60
- - Choose Anthropic or OpenAI in plugin settings. Anthropic generation uses `claude-opus-5` with adaptive thinking, max effort, and a 65,536-token ceiling; OpenAI/Codex generation uses `gpt-5.6-sol` with high reasoning effort and the same output ceiling.
62
+ - Choose Anthropic or OpenAI in plugin settings. Anthropic generation uses `claude-opus-5` with adaptive thinking, max effort, and a 65,536-token ceiling; OpenAI/Codex generation uses `gpt-6-astra` with high reasoning effort and the same output ceiling. The AI wizard provider/model is separate from the CEO/team adapter model settings.
61
63
  - All provider calls run as background jobs in the worker (start + poll), eliminating the 30 s RPC timeout that previously crashed config generation
62
64
  - AI wizard now generates domain-specific initial issues from the project brief that lead the bootstrap backlog ahead of generic scaffolding issues
63
65
  - Preset roles are defensively merged with AI-selected roles so preset roles are no longer silently dropped
@@ -74,7 +76,7 @@ Requires Node **24.11+**, matching the current Paperclip SDK/shared runtime requ
74
76
  - **Explicit approval and bootstrap controls** — select pending hires from this run, approve them with board authority, then explicitly start bootstrap; the wizard never disables the company's approval policy
75
77
  - **Repository workspace setup** — choose between a fresh local Git repo or an existing external repository (GitHub, GitLab, etc.) via the manual wizard step or inline on the review/summary screen (available in both the manual and AI paths; the external option opens a repo-URL field)
76
78
  - **Routine schedules** tightened to run every few hours around the clock (auto-assign every 2 h, stall-detection every 3 h, backlog grooming every 4 h) with `skip_if_active` concurrency policy
77
- - **"Update templates" button** on the onboarding screen — deletes the cached templates dir and re-downloads from GitHub without restarting the plugin
79
+ - **"Update templates" button** on the onboarding screen — validates custom GitHub downloads before atomically replacing their source-specific cache; bundled templates stay release-pinned and operator-managed local paths are never overwritten
78
80
 
79
81
  </details>
80
82
 
@@ -605,7 +607,7 @@ Configure the plugin via **Settings → Plugins → Company Wizard** in the Pape
605
607
  | Field | Required | Description |
606
608
  | --- | --- | --- |
607
609
  | `companiesDir` | No | Where assembled company workspaces are written. Defaults to `~/.paperclip/instances/default/companies`. Override for Docker setups. |
608
- | `templatesPath` | No | Existing operator-managed template directory. Never overwritten by refresh. Default: bundled templates from this installed plugin release. |
610
+ | `templatesPath` | No | Existing operator-managed template root, not a download destination. Overrides `templatesRepoUrl`; never populated or overwritten by refresh. Leave empty to use bundled templates or a custom GitHub source. |
609
611
  | `templatesRepoUrl` | No | Custom GitHub tree URL opts into a source-specific remote cache. The official default uses bundled templates. Refresh explicitly before preview to update a custom source. |
610
612
  | `paperclipUrl` | No | Paperclip instance URL. Defaults to `http://localhost:3100` or `PAPERCLIP_PUBLIC_URL` env var. |
611
613
  | `paperclipEmail` | No | Board login email. Required for authenticated (non-`local_trusted`) instances. |
@@ -613,6 +615,8 @@ Configure the plugin via **Settings → Plugins → Company Wizard** in the Pape
613
615
  | `aiProvider` | No | AI wizard provider: `anthropic` (default) or `openai`. |
614
616
  | `anthropicApiKey` | No | Anthropic API key for AI wizard mode. Stored as a governed secret ref. Required when `aiProvider` is `anthropic`. |
615
617
  | `openaiApiKey` | No | OpenAI API key for GPT/Codex AI wizard mode. Stored as a governed secret ref. Required when `aiProvider` is `openai`. |
618
+ If the wizard only shows **Custom** and `/templates` contains empty arrays, check `templatesPath` first. It must point directly to the template root (normally containing `roles/`, `modules/`, and `presets/`), not an empty directory or the repository root above `templates/`. Clear the field to use the installed release templates; the official GitHub URL does not override an explicit local path. Save and reload the wizard. **Test Configuration** now validates template availability and metadata before checking Paperclip connectivity; it does not make a paid AI generation request or verify model entitlement. A custom CEO-only library is supported, but `roles/ceo/role.meta.json` must declare `name: "ceo"` and `base: true`.
619
+
616
620
  For enriched personas: there is no plugin setting. Template fragments are applied automatically when present.
617
621
 
618
622
  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. External repository base refs are taken from project/worktree settings; leaving the ref blank lets Paperclip resolve its default instead of the wizard inventing `main`, `master`, or `origin/*`.
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.6.2",
5
+ version: "0.6.4",
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>",
@@ -38,7 +38,7 @@ var manifest = {
38
38
  },
39
39
  templatesPath: {
40
40
  type: "string",
41
- description: "Optional operator-managed templates directory. Defaults to templates bundled with this plugin release. Local files are never overwritten by refresh."
41
+ description: "Optional existing template root containing roles/, modules/, and presets/. Overrides the GitHub URL. Leave empty to use bundled release templates or a custom GitHub source. Refresh never overwrites this directory. For an existing empty directory, the wizard offers an explicit sync from the configured template URL."
42
42
  },
43
43
  templatesRepoUrl: {
44
44
  type: "string",
@@ -49,7 +49,7 @@ var manifest = {
49
49
  type: "string",
50
50
  enum: ["anthropic", "openai"],
51
51
  default: "anthropic",
52
- description: "AI provider used for company generation. Anthropic uses Claude Opus 5 at max effort; OpenAI uses GPT-5.6 Sol at high reasoning effort."
52
+ description: "AI provider used for company generation. Anthropic uses Claude Opus 5 at max effort; OpenAI uses GPT-6-Astra at high reasoning effort."
53
53
  },
54
54
  anthropicApiKey: {
55
55
  // Paperclip's secret picker submits an EnvSecretRefBinding object,
@@ -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.6.2',\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 // No numeric host floor: the loader compares this against the host version\n // `createApp` resolves (git describe \u2192 stamped build version \u2192 the server\n // package version), so a packaged install reports its package version (0.3.1)\n // and `compareSemver` would reject any CalVer floor on a current host.\n // Keep API v1/capabilities explicit and validate feature availability at runtime.\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 'skills.managed',\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. Auto-detected: ~/instances/default/companies in Docker setups, ~/.paperclip/instances/default/companies otherwise. Rarely needs manual override.',\n },\n templatesPath: {\n type: 'string',\n description:\n 'Optional operator-managed templates directory. Defaults to templates bundled with this plugin release. Local files are never overwritten by refresh.',\n },\n templatesRepoUrl: {\n type: 'string',\n default: 'https://github.com/starlein/paperclip-plugin-company-wizard/tree/main/templates',\n description:\n 'Optional custom GitHub tree URL. The official default uses bundled release templates; a custom URL opts into a refreshable remote cache.',\n },\n aiProvider: {\n type: 'string',\n enum: ['anthropic', 'openai'],\n default: 'anthropic',\n description:\n 'AI provider used for company generation. Anthropic uses Claude Opus 5 at max effort; OpenAI uses GPT-5.6 Sol at high reasoning effort.',\n },\n anthropicApiKey: {\n // Paperclip's secret picker submits an EnvSecretRefBinding object,\n // while direct keys and older hosts still submit strings. Keep both\n // representations schema-valid; the host validates governed bindings\n // and the worker resolves them before calling Anthropic.\n type: ['string', 'object'],\n format: 'secret-ref',\n description:\n 'Anthropic API key for the AI wizard. Paste a key or select a saved Paperclip company secret; Paperclip stores pasted values as governed secret references.',\n },\n openaiApiKey: {\n type: ['string', 'object'],\n format: 'secret-ref',\n description:\n 'OpenAI API key for GPT/Codex company generation. Paste a key or select a saved Paperclip company secret; required when AI Provider is openai.',\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 },\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"],
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.6.4',\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 // No numeric host floor: the loader compares this against the host version\n // `createApp` resolves (git describe \u2192 stamped build version \u2192 the server\n // package version), so a packaged install reports its package version (0.3.1)\n // and `compareSemver` would reject any CalVer floor on a current host.\n // Keep API v1/capabilities explicit and validate feature availability at runtime.\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 'skills.managed',\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. Auto-detected: ~/instances/default/companies in Docker setups, ~/.paperclip/instances/default/companies otherwise. Rarely needs manual override.',\n },\n templatesPath: {\n type: 'string',\n description:\n 'Optional existing template root containing roles/, modules/, and presets/. Overrides the GitHub URL. Leave empty to use bundled release templates or a custom GitHub source. Refresh never overwrites this directory. For an existing empty directory, the wizard offers an explicit sync from the configured template URL.',\n },\n templatesRepoUrl: {\n type: 'string',\n default: 'https://github.com/starlein/paperclip-plugin-company-wizard/tree/main/templates',\n description:\n 'Optional custom GitHub tree URL. The official default uses bundled release templates; a custom URL opts into a refreshable remote cache.',\n },\n aiProvider: {\n type: 'string',\n enum: ['anthropic', 'openai'],\n default: 'anthropic',\n description:\n 'AI provider used for company generation. Anthropic uses Claude Opus 5 at max effort; OpenAI uses GPT-6-Astra at high reasoning effort.',\n },\n anthropicApiKey: {\n // Paperclip's secret picker submits an EnvSecretRefBinding object,\n // while direct keys and older hosts still submit strings. Keep both\n // representations schema-valid; the host validates governed bindings\n // and the worker resolves them before calling Anthropic.\n type: ['string', 'object'],\n format: 'secret-ref',\n description:\n 'Anthropic API key for the AI wizard. Paste a key or select a saved Paperclip company secret; Paperclip stores pasted values as governed secret references.',\n },\n openaiApiKey: {\n type: ['string', 'object'],\n format: 'secret-ref',\n description:\n 'OpenAI API key for GPT/Codex company generation. Paste a key or select a saved Paperclip company secret; required when AI Provider is openai.',\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 },\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;AAAA;AAAA;AAAA;AAAA;AAAA,EAM9B,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,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,YAAY;AAAA,QACV,MAAM;AAAA,QACN,MAAM,CAAC,aAAa,QAAQ;AAAA,QAC5B,SAAS;AAAA,QACT,aACE;AAAA,MACJ;AAAA,MACA,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA,QAKf,MAAM,CAAC,UAAU,QAAQ;AAAA,QACzB,QAAQ;AAAA,QACR,aACE;AAAA,MACJ;AAAA,MACA,cAAc;AAAA,QACZ,MAAM,CAAC,UAAU,QAAQ;AAAA,QACzB,QAAQ;AAAA,QACR,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,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/ui/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  // src/ui/index.tsx
2
2
  import {
3
- usePluginData
3
+ usePluginData,
4
+ usePluginAction as usePluginAction9
4
5
  } from "@paperclipai/plugin-sdk/ui";
6
+ import { useState as useState12 } from "react";
5
7
 
6
8
  // node_modules/.pnpm/lucide-react@0.574.0_react@19.2.4/node_modules/lucide-react/dist/esm/createLucideIcon.js
7
9
  import { forwardRef as forwardRef2, createElement as createElement2 } from "react";
@@ -8060,9 +8062,26 @@ function WizardShell() {
8060
8062
  }
8061
8063
 
8062
8064
  // src/ui/index.tsx
8063
- import { jsx as jsx22, jsxs as jsxs16 } from "react/jsx-runtime";
8065
+ import { Fragment as Fragment4, jsx as jsx22, jsxs as jsxs16 } from "react/jsx-runtime";
8064
8066
  function WizardPage(_props) {
8065
- const { data: templates, loading, error } = usePluginData("templates");
8067
+ const { data: templates, loading, error, refresh } = usePluginData("templates");
8068
+ const syncTemplates = usePluginAction9("sync-empty-templates");
8069
+ const [syncing, setSyncing] = useState12(false);
8070
+ const [syncError, setSyncError] = useState12(null);
8071
+ const handleSync = async () => {
8072
+ if (syncing || !templates?.syncOffer?.canSync) return;
8073
+ setSyncing(true);
8074
+ setSyncError(null);
8075
+ try {
8076
+ const result = await syncTemplates({ confirmation: templates.syncOffer.token });
8077
+ if (!result.ok) throw new Error(result.error || "Template sync failed.");
8078
+ await refresh();
8079
+ } catch (err) {
8080
+ setSyncError(err instanceof Error ? err.message : "Template sync failed.");
8081
+ } finally {
8082
+ setSyncing(false);
8083
+ }
8084
+ };
8066
8085
  if (error) {
8067
8086
  return /* @__PURE__ */ jsxs16("div", { className: "flex items-center justify-center min-h-[400px] text-sm text-destructive", children: [
8068
8087
  "Failed to load templates: ",
@@ -8074,10 +8093,39 @@ function WizardPage(_props) {
8074
8093
  /* @__PURE__ */ jsx22(LoaderCircle, { className: "h-6 w-6 animate-spin text-muted-foreground" }),
8075
8094
  /* @__PURE__ */ jsxs16("div", { className: "space-y-1.5", children: [
8076
8095
  /* @__PURE__ */ jsx22("p", { className: "text-sm font-medium", children: "Loading templates" }),
8077
- /* @__PURE__ */ jsx22("p", { className: "text-xs text-muted-foreground max-w-xs", children: "Checking your templates directory. If no local templates are found, they'll be downloaded from GitHub \u2014 this may take a moment." })
8096
+ /* @__PURE__ */ jsx22("p", { className: "text-xs text-muted-foreground max-w-xs", children: "Checking bundled or operator-managed templates. A custom GitHub source may need to be downloaded \u2014 this may take a moment." })
8078
8097
  ] })
8079
8098
  ] });
8080
8099
  }
8100
+ if (templates.error || !templates.roles.some((role) => role.name === "ceo")) {
8101
+ return /* @__PURE__ */ jsxs16(
8102
+ "div",
8103
+ {
8104
+ role: "alert",
8105
+ className: "flex flex-col items-center justify-center min-h-[400px] gap-3 px-6 text-sm text-center",
8106
+ children: [
8107
+ /* @__PURE__ */ jsx22(TriangleAlert, { className: "h-6 w-6 text-destructive" }),
8108
+ /* @__PURE__ */ jsx22("p", { className: "font-medium", children: templates.syncOffer ? "Template directory is empty" : "Templates are unavailable" }),
8109
+ templates.syncOffer?.canSync && /* @__PURE__ */ jsxs16(Fragment4, { children: [
8110
+ /* @__PURE__ */ jsx22("p", { className: "text-muted-foreground", children: "Sync downloads and validates the configured template URL into this empty directory. Existing files are never overwritten." }),
8111
+ /* @__PURE__ */ jsx22(
8112
+ "button",
8113
+ {
8114
+ type: "button",
8115
+ disabled: syncing,
8116
+ onClick: handleSync,
8117
+ className: "rounded-md bg-primary px-4 py-2 text-primary-foreground disabled:opacity-50",
8118
+ children: syncing ? "Syncing templates\u2026" : "Confirm sync from configured template URL"
8119
+ }
8120
+ )
8121
+ ] }),
8122
+ syncError && /* @__PURE__ */ jsx22("p", { role: "alert", className: "text-destructive", children: syncError }),
8123
+ /* @__PURE__ */ jsx22("p", { className: "max-w-2xl text-destructive", children: templates.error || "No CEO template was loaded." }),
8124
+ /* @__PURE__ */ jsx22("p", { className: "max-w-2xl text-muted-foreground", children: "Open Company Wizard plugin settings. Clear templatesPath to use bundled templates or your custom GitHub source, or point it to a populated template root. The local path overrides the GitHub URL. Only the explicit sync offer can populate an empty local directory. Test Configuration, save, then reload this page." })
8125
+ ]
8126
+ }
8127
+ );
8128
+ }
8081
8129
  return /* @__PURE__ */ jsxs16("div", { className: "space-y-3", children: [
8082
8130
  templates.loadErrors && templates.loadErrors.length > 0 && /* @__PURE__ */ jsx22("div", { className: "mx-4 mt-4 rounded-lg border border-amber-500/30 bg-amber-500/10 p-3 text-xs text-amber-800 dark:text-amber-200", children: /* @__PURE__ */ jsxs16("div", { className: "flex items-start gap-2", children: [
8083
8131
  /* @__PURE__ */ jsx22(TriangleAlert, { className: "h-4 w-4 shrink-0 mt-0.5" }),