@starlein/paperclip-plugin-company-wizard 0.4.16 → 0.4.18

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/dist/ui/index.js CHANGED
@@ -581,7 +581,7 @@ var __iconNode45 = [
581
581
  var Zap = createLucideIcon("zap", __iconNode45);
582
582
 
583
583
  // src/ui/components/WizardShell.tsx
584
- import { useEffect as useEffect9 } from "react";
584
+ import { useEffect as useEffect9, useRef as useRef8 } from "react";
585
585
 
586
586
  // src/ui/context/WizardContext.tsx
587
587
  import { createContext, useCallback, useContext, useState } from "react";
@@ -679,6 +679,8 @@ function reducer(state, action) {
679
679
  }
680
680
  case "GO_TO":
681
681
  return { ...state, step: action.step, error: null };
682
+ case "RESTORE_NAV":
683
+ return { ...state, path: action.path, step: action.step, error: null };
682
684
  case "SET_COMPANY_NAME":
683
685
  return { ...state, companyName: action.value };
684
686
  case "SET_GOALS":
@@ -4024,6 +4026,19 @@ CardFooter.displayName = "CardFooter";
4024
4026
 
4025
4027
  // src/ui/components/steps/StepOnboarding.tsx
4026
4028
  import { Fragment, jsx as jsx3, jsxs } from "react/jsx-runtime";
4029
+ async function upgradeInstalledPlugin(pluginId, version) {
4030
+ const response = await fetch(`/api/plugins/${encodeURIComponent(pluginId)}/upgrade`, {
4031
+ method: "POST",
4032
+ headers: { "Content-Type": "application/json" },
4033
+ credentials: "include",
4034
+ body: JSON.stringify({ version })
4035
+ });
4036
+ if (!response.ok) {
4037
+ const body = await response.json().catch(() => null);
4038
+ throw new Error(body?.error || `Plugin upgrade failed (${response.status})`);
4039
+ }
4040
+ return response.json();
4041
+ }
4027
4042
  function PathCard({
4028
4043
  icon: Icon2,
4029
4044
  title,
@@ -4060,9 +4075,12 @@ function StepOnboarding() {
4060
4075
  const dispatch = useWizardDispatch();
4061
4076
  const refreshTemplates = usePluginAction("refresh-templates");
4062
4077
  const checkUpdate = usePluginAction("check-update");
4078
+ const preparePluginUpdate = usePluginAction("prepare-plugin-update");
4063
4079
  const [refreshing, setRefreshing] = useState2(false);
4064
4080
  const [refreshMsg, setRefreshMsg] = useState2(null);
4065
4081
  const [updateInfo, setUpdateInfo] = useState2(null);
4082
+ const [pluginUpdating, setPluginUpdating] = useState2(false);
4083
+ const [pluginUpdateMsg, setPluginUpdateMsg] = useState2(null);
4066
4084
  useEffect(() => {
4067
4085
  let cancelled = false;
4068
4086
  checkUpdate({}).then((result) => {
@@ -4090,6 +4108,43 @@ function StepOnboarding() {
4090
4108
  setRefreshing(false);
4091
4109
  }
4092
4110
  };
4111
+ const handlePluginUpdate = async () => {
4112
+ setPluginUpdating(true);
4113
+ setPluginUpdateMsg("Updating templates...");
4114
+ try {
4115
+ const prepared = await preparePluginUpdate({});
4116
+ if (!prepared?.ok) {
4117
+ throw new Error(prepared?.error || "Could not prepare plugin update");
4118
+ }
4119
+ if (!prepared.updateAvailable) {
4120
+ setUpdateInfo({
4121
+ ok: true,
4122
+ currentVersion: prepared.currentVersion,
4123
+ latestVersion: prepared.latestVersion,
4124
+ updateAvailable: false
4125
+ });
4126
+ setPluginUpdateMsg("Templates updated. Plugin is already current.");
4127
+ return;
4128
+ }
4129
+ if (!prepared.pluginId || !prepared.latestVersion) {
4130
+ throw new Error("Could not resolve installed plugin record or target version");
4131
+ }
4132
+ setPluginUpdateMsg(`Installing Company Wizard ${prepared.latestVersion}...`);
4133
+ await upgradeInstalledPlugin(prepared.pluginId, prepared.latestVersion);
4134
+ setUpdateInfo({
4135
+ ok: true,
4136
+ currentVersion: prepared.latestVersion,
4137
+ latestVersion: prepared.latestVersion,
4138
+ updateAvailable: false
4139
+ });
4140
+ setPluginUpdateMsg("Plugin updated. Reloading...");
4141
+ window.setTimeout(() => window.location.reload(), 1200);
4142
+ } catch (err) {
4143
+ setPluginUpdateMsg(err instanceof Error ? err.message : "Plugin update failed");
4144
+ } finally {
4145
+ setPluginUpdating(false);
4146
+ }
4147
+ };
4093
4148
  return /* @__PURE__ */ jsxs("div", { className: "space-y-8", children: [
4094
4149
  /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
4095
4150
  /* @__PURE__ */ jsx3("h1", { className: "text-2xl font-semibold tracking-tight", children: "Create a company" }),
@@ -4147,7 +4202,7 @@ function StepOnboarding() {
4147
4202
  "button",
4148
4203
  {
4149
4204
  onClick: handleRefresh,
4150
- disabled: refreshing,
4205
+ disabled: refreshing || pluginUpdating,
4151
4206
  className: "flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground transition-colors disabled:opacity-50",
4152
4207
  children: [
4153
4208
  /* @__PURE__ */ jsx3(RefreshCw, { className: cn("h-3 w-3", refreshing && "animate-spin") }),
@@ -4163,14 +4218,28 @@ function StepOnboarding() {
4163
4218
  updateInfo.currentVersion,
4164
4219
  " \u2192 ",
4165
4220
  updateInfo.latestVersion,
4221
+ /* @__PURE__ */ jsxs(
4222
+ "button",
4223
+ {
4224
+ type: "button",
4225
+ onClick: handlePluginUpdate,
4226
+ disabled: pluginUpdating,
4227
+ className: "inline-flex items-center gap-1 font-medium text-foreground hover:underline disabled:opacity-50 disabled:no-underline",
4228
+ title: "Install the latest Company Wizard plugin, refresh templates, and reload",
4229
+ children: [
4230
+ /* @__PURE__ */ jsx3(RefreshCw, { className: cn("h-3 w-3", pluginUpdating && "animate-spin") }),
4231
+ pluginUpdating ? "Updating..." : "Update now"
4232
+ ]
4233
+ }
4234
+ ),
4166
4235
  updateInfo.url && /* @__PURE__ */ jsxs(
4167
4236
  "a",
4168
4237
  {
4169
4238
  href: updateInfo.url,
4170
4239
  target: "_blank",
4171
4240
  rel: "noreferrer",
4172
- className: "inline-flex items-center gap-0.5 font-medium text-foreground hover:underline",
4173
- title: "Update the Company Wizard plugin package, then reload Paperclip",
4241
+ className: "inline-flex items-center gap-0.5 text-muted-foreground hover:text-foreground hover:underline",
4242
+ title: "Open the npm package page",
4174
4243
  children: [
4175
4244
  "npm",
4176
4245
  /* @__PURE__ */ jsx3(ExternalLink, { className: "h-3 w-3" })
@@ -4179,6 +4248,16 @@ function StepOnboarding() {
4179
4248
  )
4180
4249
  ] })
4181
4250
  ] }),
4251
+ pluginUpdateMsg && /* @__PURE__ */ jsx3(
4252
+ "span",
4253
+ {
4254
+ className: cn(
4255
+ "basis-full text-center text-xs",
4256
+ pluginUpdateMsg.includes("failed") || pluginUpdateMsg.includes("Could not") ? "text-destructive" : "text-muted-foreground"
4257
+ ),
4258
+ children: pluginUpdateMsg
4259
+ }
4260
+ ),
4182
4261
  refreshMsg && /* @__PURE__ */ jsx3("span", { className: "text-xs text-muted-foreground", children: refreshMsg })
4183
4262
  ] })
4184
4263
  ] });
@@ -6184,10 +6263,10 @@ function StepSummary() {
6184
6263
  import { useState as useState8, useRef as useRef4, useEffect as useEffect5 } from "react";
6185
6264
  import { usePluginAction as usePluginAction4 } from "@paperclipai/plugin-sdk/ui";
6186
6265
 
6187
- // raw:/paperclip/paperclip-plugin-company-wizard/src/ui/prompts/interview-system.md
6266
+ // raw:/home/runner/work/paperclip-plugin-company-wizard/paperclip-plugin-company-wizard/src/ui/prompts/interview-system.md
6188
6267
  var interview_system_default = 'You are the Company Wizard \u2014 an expert at assembling AI agent teams. You\'re enthusiastic but concise. Company Wizard bootstraps AI-agent company workspaces from composable templates.\n\nYou are conducting a guided interview to understand what company to set up.\n\n{{CATALOG}}\n\n## How Roles Work\n\n- **Base roles** (marked "always included") are auto-added. You do NOT list them in the JSON.\n- **All other roles** (listed under "Available Extra Roles") are OPTIONAL and must be EXPLICITLY listed in your JSON `roles` array if you want them.\n- **Critically: `engineer` is NOT a base role.** Most software projects need an engineer. If the project involves writing code, building software, or maintaining a repository, you MUST include `engineer` in your `roles` array. The preset does NOT auto-add roles \u2014 you must list every non-base role the company needs.\n- When in doubt, include the engineer. A company that builds software without an engineer agent will have no one to write code.\n\n## Interview Rules\n\n- Ask exactly ONE question per turn. Keep it short and energetic (1-2 sentences). Use a conversational tone.\n- Do NOT output JSON during questions \u2014 just ask the question as plain text.\n- Tailor each question based on previous answers. Show you understood what they said.\n- After 3 questions, summarize what you understood in a brief, enthusiastic paragraph. End with: "Ready to generate your configuration?"\n- When the user confirms, output a human-readable recommendation with reasoning, then the JSON config.\n\n## What to Ask About\n\nAcross your 3 questions, try to cover as many of these as the user\'s initial description left unclear:\n\n1. **What they\'re building** \u2014 Product type, target users, domain (fintech, SaaS, game, etc.)\n2. **Current stage** \u2014 Greenfield, existing codebase, research phase, relaunch?\n3. **Quality vs speed** \u2014 Ship fast, iterate? Or production-grade, high quality from the start?\n4. **Team needs** \u2014 Do they need code review, security, design, marketing, docs, DevOps?\n5. **Special requirements** \u2014 Compliance, accessibility, specific tech stack, CI/CD, game engine?\n6. **Repository** \u2014 Should Paperclip create a new Git repository/workspace, or should the agents use an existing external repo such as GitHub/GitLab? If external, ask for URL and branch/ref; never ask for tokens.\n\nDon\'t ask about things already clear from the initial description. Skip to what\'s missing.\n\n## Information Preservation\n\nThe user\'s interview answers are the primary source of context for the company. When generating the configuration:\n\n- **`companyDescription`**: Write a comprehensive 2-4 paragraph description that captures EVERYTHING learned during the interview \u2014 what the company does, what it\'s building, who it\'s for, key technical decisions, constraints, priorities, and any special context. This is the company\'s permanent record. Be thorough. Do NOT summarize into a single vague sentence.\n- **`goals`**: Array of goals. The first goal is the main user-specific company goal \u2014 its description is the most important field. Keep it outcome-first and product-first: the title and opening sentence must state the primary deliverable or operating outcome, not a supporting constraint. Write a THOROUGH, DETAILED description that includes EVERYTHING the user shared: full requirements, technical specs, acceptance criteria, constraints, edge cases, API contracts, user stories, design decisions, performance targets. Put compliance/security/accessibility/performance constraints in a clearly labelled "Constraints / quality bars" section unless the user explicitly says that constraint is the primary project. If the user\'s wording mixes a main outcome with secondary facts, determine which thing the agents should build/operate first and write that as the top-level goal; put side facts into acceptance criteria, risks, or sub-goals only when they are independent workstreams. Preset/module template goals are added by the wizard after your JSON, so do NOT replace the user\'s objective with generic preset goals like "Build a REST API" or "Set up CI/CD" unless the user explicitly asked only for that.\n- **`projects`**: Array of projects. Each has a `name`, `description`, `goals` array (goal titles it\'s linked to), and repository workspace metadata. If the user chose an external repo, use `workspace.sourceType: "git_repo"` with `repoUrl`, plus `repoRef`/`defaultRef` exactly when the user or repository context provides one; do not force a branch name or remote prefix. If no external repo was provided, use a fresh local Git repository with `workspace.sourceType: "local_path"`, `workspace.defaultRef: "main"` unless the user requested another initial branch, `workspace.setupCommand: "git init -b <defaultRef>"`, and `workspace.isPrimary: true`. Do not include `executionWorkspacePolicy`; the assembler applies isolated worktrees only when Paperclip\'s experimental isolated-workspaces setting is enabled and a usable project base ref exists.\n- **`issues`**: Array of 6-12 CONCRETE, domain-specific initial work items taken straight from what you learned in the interview \u2014 the real features, components, and integrations the user actually described, each with a `title`, a `description` with acceptance criteria, a `priority` (`critical`/`high`/`medium`/`low`), and `assignTo` set to a role on the team. These seed the backlog so the project starts in its actual domain. Issue titles should lead with the core product capability; secondary constraints belong in acceptance criteria or risk notes unless the issue is specifically about that constraint. Do NOT put generic scaffolding here (vision docs, linters, CI, branch protection) \u2014 the wizard adds those automatically.\n\n## RECOMMENDATION Format (when generating config)\n\n- One paragraph explaining your reasoning: why this preset, why these modules, why these roles.\n- A bullet list of the key choices.\n\nThen output the JSON (no markdown fences):\n{{CONFIG_FORMAT}}\n\n## Rules\n\n- `modules` should list ALL modules to activate (including preset ones).\n- `roles` should list ALL non-base roles the company needs. This includes roles that come with the preset. The system does not auto-add preset roles \u2014 you must list them explicitly.\n- If the project involves building software, `engineer` MUST be in `roles`.\n- The primary project MUST state whether it uses a fresh local Git repository or an external Git repository. Do not put credentials or tokens in repository fields.\n- Be pragmatic \u2014 don\'t over-engineer. Match the config to actual needs.\n';
6189
6268
 
6190
- // raw:/paperclip/paperclip-plugin-company-wizard/src/ui/prompts/single-shot-system.md
6269
+ // raw:/home/runner/work/paperclip-plugin-company-wizard/paperclip-plugin-company-wizard/src/ui/prompts/single-shot-system.md
6191
6270
  var single_shot_system_default = 'You are the Company Wizard. Company Wizard bootstraps AI-agent company workspaces from composable templates.\n\nGiven a natural language description of what the user wants to build, you select the best configuration.\n\n{{CATALOG}}\n\n## How Roles Work\n\n- **Base roles** (marked "always included") are auto-added. You do NOT list them in the JSON.\n- **All other roles** (listed under "Available Extra Roles") are OPTIONAL and must be EXPLICITLY listed in your JSON `roles` array if you want them.\n- **Critically: `engineer` is NOT a base role.** Most software projects need an engineer. If the project involves writing code, building software, or maintaining a repository, you MUST include `engineer` in your `roles` array. The preset does NOT auto-add roles \u2014 you must list every non-base role the company needs.\n- When in doubt, include the engineer. A company that builds software without an engineer agent will have no one to write code.\n\n## Instructions\n\n1. Analyze the user\'s description to understand: what they\'re building, their team size preference, quality vs speed priority, and any specific needs.\n2. Select the best preset as a starting point.\n3. List ALL modules to activate (including preset ones). Add extra modules beyond the preset if the description warrants them.\n4. List ALL non-base roles the company needs. This includes roles from the preset. If the project involves software, include `engineer`.\n5. Suggest a company name (PascalCase-friendly, short, memorable) if not obvious from the description.\n6. Write a thorough company description (2-4 paragraphs) capturing everything the user described \u2014 product, audience, tech stack, constraints, priorities, stage, and special context. This is the company\'s permanent record.\n7. Define goals as an array. The first goal is the main user-specific company goal \u2014 its description is the most important field. Keep it **outcome-first and product-first**: the title and opening sentence must state the primary deliverable or operating outcome, not a supporting constraint. Preserve compliance, security, accessibility, performance, tech-stack, and domain constraints inside the description under a clear "Constraints / quality bars" section unless the user explicitly says that constraint is the primary project. If the user\'s wording mixes a main outcome with secondary facts, ask yourself which thing the agents should build/operate first and write that as the top-level goal; put side facts into acceptance criteria, risks, or sub-goals only when they are independent workstreams. Include EVERYTHING the user described: full requirements, technical specs, acceptance criteria, constraints, edge cases, API contracts, user stories, performance targets. If the user provided a detailed spec, reproduce it in full, but do not let one constraint dominate the goal or initial issues. Preset/module template goals are added by the wizard after your JSON, so do NOT replace the user\'s objective with generic preset goals like "Build a REST API" or "Set up CI/CD" unless the user explicitly asked only for that.\n8. Define projects as an array. Most setups need one project linked to all goals. Name and describe the project concretely.\n9. Always decide the repository setup for the primary project:\n - If the user gives an existing GitHub/GitLab/remote Git repo, set `workspace.sourceType: "git_repo"`, include `repoUrl`, and set `repoRef`/`defaultRef` exactly when the user or repository context provides one. Do not force a branch name or remote prefix; Paperclip\'s project/worktree settings decide the worktree base ref.\n - If no external repository is given, assume Paperclip should create a fresh local Git repository. Set `workspace.sourceType: "local_path"`, `workspace.defaultRef: "main"` unless the user requested another initial branch, `workspace.setupCommand: "git init -b <defaultRef>"`, and `workspace.isPrimary: true`. Do NOT include an `executionWorkspacePolicy`; the assembler applies isolated worktrees only when Paperclip\'s experimental isolated-workspaces setting is enabled and a usable project base ref exists.\n - Never include credentials or tokens in repository URLs or project text.\n10. Define an `issues` array of 6-12 CONCRETE, domain-specific initial work items taken straight from the description \u2014 the real features, components, and integrations the user actually described, each with a `title`, a `description` with acceptance criteria, a `priority`, and `assignTo` set to a role on the team. These seed the backlog so the project starts in its actual domain instead of only doing generic setup. Issue titles should lead with the core product capability; secondary constraints belong in acceptance criteria or risk notes unless the issue is specifically about that constraint. Do NOT put generic scaffolding here (vision docs, linters, CI, branch protection) \u2014 the wizard adds those automatically.\n\nFirst write one paragraph explaining your reasoning: why this preset, why these modules, why these roles.\n\nThen output the JSON (no markdown fences):\n{{CONFIG_FORMAT}}\n';
6192
6271
 
6193
6272
  // src/ui/prompts/messages.json
@@ -7555,6 +7634,30 @@ var STEP_COMPONENTS = {
7555
7634
  provision: StepProvision,
7556
7635
  done: StepDone
7557
7636
  };
7637
+ var WIZARD_HISTORY_MARKER = "company-wizard";
7638
+ function isObject(value) {
7639
+ return typeof value === "object" && value !== null;
7640
+ }
7641
+ function isStep(value) {
7642
+ return typeof value === "string" && value in STEP_COMPONENTS;
7643
+ }
7644
+ function isWizardPath(value) {
7645
+ return value === null || value === "manual" || value === "ai" || value === "update";
7646
+ }
7647
+ function readWizardHistoryState(value) {
7648
+ if (!isObject(value)) return null;
7649
+ if (value.__paperclipPlugin !== WIZARD_HISTORY_MARKER) return null;
7650
+ if (!isStep(value.step) || !isWizardPath(value.path)) return null;
7651
+ return { step: value.step, path: value.path };
7652
+ }
7653
+ function buildWizardHistoryState(currentState, path, step) {
7654
+ return {
7655
+ ...isObject(currentState) ? currentState : {},
7656
+ __paperclipPlugin: WIZARD_HISTORY_MARKER,
7657
+ path,
7658
+ step
7659
+ };
7660
+ }
7558
7661
  function StepIndicator() {
7559
7662
  const state = useWizard();
7560
7663
  const current = getUserStepIndex(state);
@@ -7579,10 +7682,46 @@ function StepIndicator() {
7579
7682
  function WizardShell() {
7580
7683
  const state = useWizard();
7581
7684
  const dispatch = useWizardDispatch();
7685
+ const restoredFromHistory = useRef8(false);
7686
+ const seededHistory = useRef8(false);
7582
7687
  const StepComponent = STEP_COMPONENTS[state.step];
7583
7688
  useEffect9(() => {
7584
7689
  window.scrollTo({ top: 0 });
7585
7690
  }, [state.step]);
7691
+ useEffect9(() => {
7692
+ const handlePopState = (event) => {
7693
+ const historyState = readWizardHistoryState(event.state);
7694
+ if (!historyState?.step) return;
7695
+ restoredFromHistory.current = true;
7696
+ dispatch({
7697
+ type: "RESTORE_NAV",
7698
+ path: historyState.path ?? null,
7699
+ step: historyState.step
7700
+ });
7701
+ };
7702
+ window.addEventListener("popstate", handlePopState);
7703
+ return () => window.removeEventListener("popstate", handlePopState);
7704
+ }, [dispatch]);
7705
+ useEffect9(() => {
7706
+ if (!seededHistory.current) {
7707
+ seededHistory.current = true;
7708
+ window.history.replaceState(
7709
+ buildWizardHistoryState(window.history.state, state.path, state.step),
7710
+ "",
7711
+ window.location.href
7712
+ );
7713
+ return;
7714
+ }
7715
+ if (restoredFromHistory.current) {
7716
+ restoredFromHistory.current = false;
7717
+ return;
7718
+ }
7719
+ window.history.pushState(
7720
+ buildWizardHistoryState(window.history.state, state.path, state.step),
7721
+ "",
7722
+ window.location.href
7723
+ );
7724
+ }, [state.path, state.step]);
7586
7725
  return /* @__PURE__ */ jsxs15("div", { className: "flex flex-col", children: [
7587
7726
  getUserStepIndex(state) >= 1 && state.step !== "provision" && state.step !== "done" && /* @__PURE__ */ jsx21("div", { className: "flex items-center justify-end px-6 py-3", children: /* @__PURE__ */ jsx21(StepIndicator, {}) }),
7588
7727
  /* @__PURE__ */ jsx21("main", { className: "flex-1 flex items-start justify-center p-6", children: /* @__PURE__ */ jsx21("div", { className: "w-full max-w-2xl", children: /* @__PURE__ */ jsx21(StepComponent, {}) }) }),