@a-company/paradigm 5.8.0 → 5.8.2

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.
@@ -6,16 +6,20 @@ import {
6
6
  computeIntegrityHash,
7
7
  createAgentProfile,
8
8
  init_agent_loader,
9
+ isAgentActive,
10
+ listAllGlobalAgentIds,
9
11
  loadAgentProfile,
10
12
  loadAllAgentProfiles,
13
+ loadProjectRoster,
11
14
  mergeAgentProfileWithManifest,
12
15
  queryExpertise,
13
16
  saveAgentProfile,
17
+ saveProjectRoster,
14
18
  syncExpertiseFromLore,
15
19
  updateExpertiseFromAssessment,
16
20
  updateExpertiseFromLore,
17
21
  verifyIntegrity
18
- } from "./chunk-ITPJJIHG.js";
22
+ } from "./chunk-MA7G4CTI.js";
19
23
  import "./chunk-7N7GSU6K.js";
20
24
  init_agent_loader();
21
25
  export {
@@ -24,11 +28,15 @@ export {
24
28
  checkToolPermission,
25
29
  computeIntegrityHash,
26
30
  createAgentProfile,
31
+ isAgentActive,
32
+ listAllGlobalAgentIds,
27
33
  loadAgentProfile,
28
34
  loadAllAgentProfiles,
35
+ loadProjectRoster,
29
36
  mergeAgentProfileWithManifest,
30
37
  queryExpertise,
31
38
  saveAgentProfile,
39
+ saveProjectRoster,
32
40
  syncExpertiseFromLore,
33
41
  updateExpertiseFromAssessment,
34
42
  updateExpertiseFromLore,
@@ -2277,6 +2277,18 @@ var SessionTracker = class {
2277
2277
  if (checkpoint && Date.now() - checkpoint.timestamp > CHECKPOINT_MAX_AGE_MS) {
2278
2278
  return null;
2279
2279
  }
2280
+ if (checkpoint) {
2281
+ for (const key of ["modifiedFiles", "symbolsTouched", "decisions"]) {
2282
+ const val = checkpoint[key];
2283
+ if (typeof val === "string") {
2284
+ try {
2285
+ checkpoint[key] = JSON.parse(val);
2286
+ } catch {
2287
+ checkpoint[key] = [];
2288
+ }
2289
+ }
2290
+ }
2291
+ }
2280
2292
  return checkpoint;
2281
2293
  }
2282
2294
  /**
@@ -3232,7 +3244,7 @@ async function buildRecoveryPreamble(rootDir) {
3232
3244
  } catch {
3233
3245
  }
3234
3246
  try {
3235
- const { loadNominations } = await import("./nomination-engine-LPLCCDW2.js");
3247
+ const { loadNominations } = await import("./nomination-engine-LLREC5BZ.js");
3236
3248
  const urgent = loadNominations(rootDir, { pending_only: true }).filter((n) => n.urgency === "critical" || n.urgency === "high");
3237
3249
  if (urgent.length > 0) {
3238
3250
  lines.push("");
@@ -41,6 +41,36 @@ import * as path from "path";
41
41
  import * as os from "os";
42
42
  import * as crypto from "crypto";
43
43
  import * as yaml from "js-yaml";
44
+ function loadProjectRoster(rootDir) {
45
+ const rosterPath = path.join(rootDir, ROSTER_FILE);
46
+ if (!fs.existsSync(rosterPath)) return null;
47
+ try {
48
+ const data = yaml.load(fs.readFileSync(rosterPath, "utf8"));
49
+ return data?.active ?? null;
50
+ } catch {
51
+ return null;
52
+ }
53
+ }
54
+ function isAgentActive(agentId, rootDir) {
55
+ const roster = loadProjectRoster(rootDir);
56
+ if (!roster) return true;
57
+ return roster.includes(agentId);
58
+ }
59
+ function saveProjectRoster(rootDir, active) {
60
+ const rosterPath = path.join(rootDir, ROSTER_FILE);
61
+ const dir = path.dirname(rosterPath);
62
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
63
+ const data = { version: "1.0", active: active.sort() };
64
+ fs.writeFileSync(rosterPath, yaml.dump(data, { lineWidth: -1, noRefs: true }), "utf8");
65
+ }
66
+ function listAllGlobalAgentIds() {
67
+ if (!fs.existsSync(GLOBAL_AGENTS_DIR)) return [];
68
+ try {
69
+ return fs.readdirSync(GLOBAL_AGENTS_DIR).filter((f) => f.endsWith(AGENT_EXT)).map((f) => f.replace(AGENT_EXT, ""));
70
+ } catch {
71
+ return [];
72
+ }
73
+ }
44
74
  function loadAgentProfile(rootDir, agentId) {
45
75
  const projectPath = path.join(rootDir, PROJECT_AGENTS_DIR, `${agentId}${AGENT_EXT}`);
46
76
  if (fs.existsSync(projectPath)) {
@@ -499,18 +529,23 @@ function detectProjectName(rootDir) {
499
529
  }
500
530
  return path.basename(rootDir);
501
531
  }
502
- var GLOBAL_AGENTS_DIR, PROJECT_AGENTS_DIR, AGENT_EXT, EMA_ALPHA;
532
+ var GLOBAL_AGENTS_DIR, PROJECT_AGENTS_DIR, AGENT_EXT, ROSTER_FILE, EMA_ALPHA;
503
533
  var init_agent_loader = __esm({
504
534
  "../paradigm-mcp/src/utils/agent-loader.ts"() {
505
535
  init_agents();
506
536
  GLOBAL_AGENTS_DIR = path.join(os.homedir(), ".paradigm", "agents");
507
537
  PROJECT_AGENTS_DIR = ".paradigm/agents";
508
538
  AGENT_EXT = ".agent";
539
+ ROSTER_FILE = ".paradigm/roster.yaml";
509
540
  EMA_ALPHA = 0.3;
510
541
  }
511
542
  });
512
543
 
513
544
  export {
545
+ loadProjectRoster,
546
+ isAgentActive,
547
+ saveProjectRoster,
548
+ listAllGlobalAgentIds,
514
549
  loadAgentProfile,
515
550
  loadAllAgentProfiles,
516
551
  saveAgentProfile,
@@ -4,7 +4,7 @@ import {
4
4
  loadAgentProfile,
5
5
  loadAllAgentProfiles,
6
6
  saveAgentProfile
7
- } from "./chunk-ITPJJIHG.js";
7
+ } from "./chunk-MA7G4CTI.js";
8
8
  import {
9
9
  init_journal_loader,
10
10
  journal_loader_exports
package/dist/index.js CHANGED
@@ -111,7 +111,7 @@ ${chalk2.magenta("\u2569 ")}${chalk2.cyan("\u2534 \u2534\u2534\u2514\u2500\u253
111
111
  program.name("paradigm").description("Unified developer tools ecosystem").version(VERSION).addHelpText("before", banner);
112
112
  program.command("init").description("Initialize Paradigm in the current project").option("-f, --force", "Overwrite existing files").option("--name <name>", "Project name").option("--ide <ide>", "Target IDE: cursor, copilot, windsurf, claude").option("--stack <stack>", "Stack preset (e.g., nextjs, fastapi, swift-ios). Auto-detected if omitted.").option("--migrate", "Output migration prompt for existing IDE files").option("--quick", "Non-interactive mode with smart defaults").option("--dry-run", "Show what would be created without creating").action(initCommand);
113
113
  program.command("shift").description("Full project setup in one command (init + team init + scan + sync all IDEs + doctor)").option("-f, --force", "Reinitialize even if already setup").option("-q, --quick", "Skip slow operations (scan)").option("--verify", "Run health checks after setup").option("--ide <ide>", "Target specific IDE instead of all").option("--configure-models", "Force model configuration prompts for team agents").option("--stack <stack>", "Stack preset (e.g., nextjs, fastapi, swift-ios). Auto-detected if omitted.").option("--workspace <name>", "Create or join a multi-project workspace with this name (creates ../.paradigm-workspace)").option("--workspace-path <path>", "Custom workspace file location (default: ../.paradigm-workspace)").action(async (options) => {
114
- const { shiftCommand } = await import("./shift-2NYRFVEZ.js");
114
+ const { shiftCommand } = await import("./shift-VJUGMADR.js");
115
115
  await shiftCommand(options);
116
116
  });
117
117
  program.command("presets").description("List available stack presets for paradigm init/shift").option("-d, --discipline <discipline>", "Filter by discipline (e.g., fullstack, api, mobile)").action(async (options) => {
package/dist/mcp.js CHANGED
@@ -79,7 +79,7 @@ import {
79
79
  validateProtocol,
80
80
  validatePurposeFile,
81
81
  validateUniversityContent
82
- } from "./chunk-SU3WDCRR.js";
82
+ } from "./chunk-3UCH56D5.js";
83
83
  import "./chunk-L27I3CPZ.js";
84
84
  import {
85
85
  getWorkLogSummary,
@@ -133,16 +133,18 @@ import {
133
133
  queryEvents,
134
134
  resolveDebate,
135
135
  searchNotebooks
136
- } from "./chunk-B2RC3HEB.js";
136
+ } from "./chunk-V7BZBBI6.js";
137
137
  import {
138
138
  buildProfileEnrichment,
139
139
  init_agent_loader,
140
+ listAllGlobalAgentIds,
140
141
  loadAgentProfile,
141
142
  loadAllAgentProfiles,
143
+ loadProjectRoster,
142
144
  queryExpertise,
143
- saveAgentProfile,
145
+ saveProjectRoster,
144
146
  verifyIntegrity
145
- } from "./chunk-ITPJJIHG.js";
147
+ } from "./chunk-MA7G4CTI.js";
146
148
  import {
147
149
  getJournalStats,
148
150
  init_journal_loader,
@@ -5686,6 +5688,7 @@ payloads:
5686
5688
  import * as fs12 from "fs";
5687
5689
  import * as path13 from "path";
5688
5690
  import * as yaml8 from "js-yaml";
5691
+ init_agent_loader();
5689
5692
  var SYMBOL_PATTERN = /[@#$%^!?&~][a-zA-Z0-9_-]+/g;
5690
5693
  var DEFAULT_MODELS = {
5691
5694
  architect: "opus",
@@ -5990,6 +5993,14 @@ async function handleOrchestrateInline(args, ctx) {
5990
5993
  trackToolCall(text2.length, "paradigm_orchestrate_inline");
5991
5994
  return { handled: true, text: text2 };
5992
5995
  }
5996
+ const roster = loadProjectRoster(ctx.rootDir);
5997
+ if (roster && manifest.agents) {
5998
+ const filtered = {};
5999
+ for (const [id, def] of Object.entries(manifest.agents)) {
6000
+ if (roster.includes(id)) filtered[id] = def;
6001
+ }
6002
+ manifest.agents = filtered;
6003
+ }
5993
6004
  const symbols = extractSymbols(task);
5994
6005
  const classification = classifyTaskLocal(task);
5995
6006
  const plan = planAgentSequence(task, manifest.agents, agentOverride, classification);
@@ -6021,10 +6032,10 @@ async function handleOrchestrateInline(args, ctx) {
6021
6032
  }
6022
6033
  let agentProfiles = /* @__PURE__ */ new Map();
6023
6034
  try {
6024
- const { loadAgentProfile: loadAgentProfile2, buildProfileEnrichment: buildProfileEnrichment2 } = await import("./agent-loader-DBF4OARL.js");
6035
+ const { loadAgentProfile: loadAgentProfile2, buildProfileEnrichment: buildProfileEnrichment2 } = await import("./agent-loader-X7TDYLFL.js");
6025
6036
  const { loadDecisions: loadDecisions3 } = await import("./decision-loader-WWCLIQPJ.js");
6026
6037
  const { loadJournalEntries: loadJournalEntries2 } = await import("./journal-loader-5EYSBFFY.js");
6027
- const { loadNominations: loadNominations2 } = await import("./nomination-engine-LPLCCDW2.js");
6038
+ const { loadNominations: loadNominations2 } = await import("./nomination-engine-LLREC5BZ.js");
6028
6039
  const recentDecisions = loadDecisions3(ctx.rootDir, { status: "active", limit: 5 }).map((d) => ({ title: d.title, decision: d.decision.slice(0, 150) }));
6029
6040
  const pendingNominations = loadNominations2(ctx.rootDir, { pending_only: true, limit: 10 }).map((n) => ({ urgency: n.urgency, brief: n.brief }));
6030
6041
  for (const stage of plan.stages) {
@@ -6190,6 +6201,16 @@ async function handleAgentPrompt(args, ctx) {
6190
6201
  const handoffContext = args.handoffContext;
6191
6202
  const previousAgent = args.previousAgent;
6192
6203
  const manifest = loadAgentsManifest(ctx.rootDir);
6204
+ const rosterForPrompt = loadProjectRoster(ctx.rootDir);
6205
+ if (rosterForPrompt && !rosterForPrompt.includes(agentName)) {
6206
+ const text2 = JSON.stringify({
6207
+ warning: `Agent "${agentName}" is not on this project's roster`,
6208
+ suggestion: `Run paradigm_agent_activate id="${agentName}" to add it, or check .paradigm/roster.yaml`,
6209
+ activeRoster: rosterForPrompt
6210
+ }, null, 2);
6211
+ trackToolCall(text2.length, "paradigm_agent_prompt");
6212
+ return { handled: true, text: text2 };
6213
+ }
6193
6214
  const manifestAgent = manifest?.agents[agentName];
6194
6215
  const agentDef = {
6195
6216
  name: manifestAgent?.name || agentName,
@@ -6205,10 +6226,10 @@ async function handleAgentPrompt(args, ctx) {
6205
6226
  let profileEnrichment;
6206
6227
  let nickname;
6207
6228
  try {
6208
- const { loadAgentProfile: loadAgentProfile2, buildProfileEnrichment: buildProfileEnrichment2 } = await import("./agent-loader-DBF4OARL.js");
6229
+ const { loadAgentProfile: loadAgentProfile2, buildProfileEnrichment: buildProfileEnrichment2 } = await import("./agent-loader-X7TDYLFL.js");
6209
6230
  const { loadDecisions: loadDecisions3 } = await import("./decision-loader-WWCLIQPJ.js");
6210
6231
  const { loadJournalEntries: loadJournalEntries2 } = await import("./journal-loader-5EYSBFFY.js");
6211
- const { loadNominations: loadNominations2 } = await import("./nomination-engine-LPLCCDW2.js");
6232
+ const { loadNominations: loadNominations2 } = await import("./nomination-engine-LLREC5BZ.js");
6212
6233
  const profile = loadAgentProfile2(ctx.rootDir, agentName);
6213
6234
  if (profile) {
6214
6235
  nickname = profile.nickname;
@@ -10132,7 +10153,7 @@ async function handleLoreTool(name, args, ctx) {
10132
10153
  try {
10133
10154
  const agentId = process.env.PARADIGM_AGENT_ID;
10134
10155
  if (agentId && symbols_touched && symbols_touched.length > 0) {
10135
- const { updateExpertiseFromLore } = await import("./agent-loader-DBF4OARL.js");
10156
+ const { updateExpertiseFromLore } = await import("./agent-loader-X7TDYLFL.js");
10136
10157
  updateExpertiseFromLore(ctx.rootDir, agentId, {
10137
10158
  symbols_touched,
10138
10159
  confidence: confidence != null && confidence >= 0 && confidence <= 1 ? confidence : void 0
@@ -10303,7 +10324,7 @@ async function handleLoreTool(name, args, ctx) {
10303
10324
  try {
10304
10325
  const agentId = process.env.PARADIGM_AGENT_ID;
10305
10326
  if (agentId && success && entryToAssess.symbols_touched?.length) {
10306
- const { updateExpertiseFromAssessment } = await import("./agent-loader-DBF4OARL.js");
10327
+ const { updateExpertiseFromAssessment } = await import("./agent-loader-X7TDYLFL.js");
10307
10328
  updateExpertiseFromAssessment(ctx.rootDir, agentId, {
10308
10329
  symbols_touched: entryToAssess.symbols_touched,
10309
10330
  verdict
@@ -18123,6 +18144,7 @@ async function handleAgentTool(name, args, ctx) {
18123
18144
  switch (name) {
18124
18145
  case "paradigm_agent_list": {
18125
18146
  const profiles = loadAllAgentProfiles(ctx.rootDir);
18147
+ const roster = loadProjectRoster(ctx.rootDir);
18126
18148
  if (profiles.length === 0) {
18127
18149
  return {
18128
18150
  handled: true,
@@ -18133,15 +18155,18 @@ async function handleAgentTool(name, args, ctx) {
18133
18155
  }, null, 2)
18134
18156
  };
18135
18157
  }
18158
+ const activeProfiles = roster ? profiles.filter((p) => roster.includes(p.id)) : profiles;
18159
+ const inactiveCount = roster ? profiles.length - activeProfiles.length : 0;
18136
18160
  return {
18137
18161
  handled: true,
18138
18162
  text: JSON.stringify({
18139
- count: profiles.length,
18140
- agents: profiles.map((p) => ({
18163
+ count: activeProfiles.length,
18164
+ totalAvailable: profiles.length,
18165
+ ...roster ? { rosterActive: true, inactiveCount } : { rosterActive: false },
18166
+ agents: activeProfiles.map((p) => ({
18141
18167
  id: p.id,
18142
18168
  role: p.role,
18143
18169
  nickname: p.nickname,
18144
- benched: p.benched || false,
18145
18170
  personality: p.personality,
18146
18171
  topExpertise: (p.expertise || []).sort((a, b) => b.confidence - a.confidence).slice(0, 5).map((e) => ({
18147
18172
  symbol: e.symbol,
@@ -18239,15 +18264,20 @@ async function handleAgentTool(name, args, ctx) {
18239
18264
  text: JSON.stringify({ error: `Agent "${benchId}" not found` }, null, 2)
18240
18265
  };
18241
18266
  }
18242
- benchProfile.benched = true;
18243
- benchProfile.updated = (/* @__PURE__ */ new Date()).toISOString();
18244
- saveAgentProfile(benchId, benchProfile, "global");
18267
+ let currentRoster = loadProjectRoster(ctx.rootDir);
18268
+ if (currentRoster) {
18269
+ currentRoster = currentRoster.filter((id) => id !== benchId);
18270
+ } else {
18271
+ currentRoster = listAllGlobalAgentIds().filter((id) => id !== benchId);
18272
+ }
18273
+ saveProjectRoster(ctx.rootDir, currentRoster);
18245
18274
  return {
18246
18275
  handled: true,
18247
18276
  text: JSON.stringify({
18248
18277
  id: benchId,
18249
- benched: true,
18250
- note: `${benchId} is now benched. Maestro will skip this agent during orchestration.`
18278
+ removedFromRoster: true,
18279
+ rosterCount: currentRoster.length,
18280
+ note: `${benchId} removed from this project's roster. Still available globally.`
18251
18281
  }, null, 2)
18252
18282
  };
18253
18283
  }
@@ -18260,15 +18290,21 @@ async function handleAgentTool(name, args, ctx) {
18260
18290
  text: JSON.stringify({ error: `Agent "${activateId}" not found` }, null, 2)
18261
18291
  };
18262
18292
  }
18263
- activateProfile.benched = false;
18264
- activateProfile.updated = (/* @__PURE__ */ new Date()).toISOString();
18265
- saveAgentProfile(activateId, activateProfile, "global");
18293
+ let activateRoster = loadProjectRoster(ctx.rootDir);
18294
+ if (activateRoster) {
18295
+ if (!activateRoster.includes(activateId)) {
18296
+ activateRoster.push(activateId);
18297
+ saveProjectRoster(ctx.rootDir, activateRoster);
18298
+ }
18299
+ } else {
18300
+ }
18266
18301
  return {
18267
18302
  handled: true,
18268
18303
  text: JSON.stringify({
18269
18304
  id: activateId,
18270
- benched: false,
18271
- note: `${activateId} is now active. Maestro will include this agent in orchestration.`
18305
+ addedToRoster: true,
18306
+ rosterCount: activateRoster?.length ?? "all (no roster)",
18307
+ note: `${activateId} is active on this project's roster.`
18272
18308
  }, null, 2)
18273
18309
  };
18274
18310
  }
@@ -18445,7 +18481,7 @@ async function handleNotebookTool(name, args, ctx) {
18445
18481
  const concepts = args.concepts || [];
18446
18482
  const tags = args.tags || [];
18447
18483
  const confidence = args.confidence ?? 0.7;
18448
- const scope = args.scope || "global";
18484
+ const scope = args.scope || (ctx.rootDir ? "project" : "global");
18449
18485
  const result = addNotebookEntry(
18450
18486
  agentId,
18451
18487
  {
@@ -18474,7 +18510,7 @@ async function handleNotebookTool(name, args, ctx) {
18474
18510
  case "paradigm_notebook_promote": {
18475
18511
  const agentId = args.agentId;
18476
18512
  const loreEntryId = args.loreEntryId;
18477
- const scope = args.scope || "global";
18513
+ const scope = args.scope || (ctx.rootDir ? "project" : "global");
18478
18514
  const result = await promoteFromLore(agentId, loreEntryId, ctx.rootDir, scope);
18479
18515
  if (!result) {
18480
18516
  return {
@@ -21155,7 +21191,7 @@ Update command:
21155
21191
  trackToolCall(noWsText.length, name);
21156
21192
  return { content: [{ type: "text", text: noWsText }] };
21157
21193
  }
21158
- const { rebuildStaticFiles: rebuildStaticFiles2 } = await import("./reindex-J5SEDVTT.js");
21194
+ const { rebuildStaticFiles: rebuildStaticFiles2 } = await import("./reindex-U2HEB6GW.js");
21159
21195
  const memberResults = [];
21160
21196
  for (const member of ctx.workspace.config.members) {
21161
21197
  const memberAbsPath = path34.resolve(path34.dirname(ctx.workspace.workspacePath), member.path);
@@ -17,8 +17,8 @@ import {
17
17
  processEvent,
18
18
  processPendingEvents,
19
19
  resolveDebate
20
- } from "./chunk-B2RC3HEB.js";
21
- import "./chunk-ITPJJIHG.js";
20
+ } from "./chunk-V7BZBBI6.js";
21
+ import "./chunk-MA7G4CTI.js";
22
22
  import "./chunk-MCMOGQMU.js";
23
23
  import "./chunk-7N7GSU6K.js";
24
24
  init_nomination_engine();
@@ -3,7 +3,7 @@ import {
3
3
  getReindexToolsList,
4
4
  handleReindexTool,
5
5
  rebuildStaticFiles
6
- } from "./chunk-SU3WDCRR.js";
6
+ } from "./chunk-3UCH56D5.js";
7
7
  import "./chunk-L27I3CPZ.js";
8
8
  import "./chunk-SDDCVUCV.js";
9
9
  import "./chunk-5VKJBNJL.js";
@@ -46,16 +46,191 @@ import "./chunk-YMDLDELF.js";
46
46
  import "./chunk-PDX44BCA.js";
47
47
 
48
48
  // src/commands/shift.ts
49
- import * as fs from "fs";
50
- import * as path from "path";
49
+ import * as fs2 from "fs";
50
+ import * as path2 from "path";
51
51
  import chalk from "chalk";
52
52
  import ora from "ora";
53
53
  import * as yaml from "js-yaml";
54
+
55
+ // src/core/project-type.ts
56
+ import * as fs from "fs";
57
+ import * as path from "path";
58
+ import { Glob } from "glob";
59
+ function detectProjectType(cwd) {
60
+ const exists = (p) => {
61
+ if (p.includes("*")) {
62
+ try {
63
+ const matches = new Glob(p, { cwd, nodir: true }).walkSync();
64
+ return matches.length > 0;
65
+ } catch {
66
+ return false;
67
+ }
68
+ }
69
+ return fs.existsSync(path.join(cwd, p));
70
+ };
71
+ if (exists("project.godot") || exists("Assets/ProjectSettings")) return "game";
72
+ if (exists("Package.swift") && !exists("package.json")) {
73
+ return exists("Sources/*/App") || exists("**/AppDelegate.swift") ? "macos-app" : "ios-app";
74
+ }
75
+ if (exists("pubspec.yaml")) return "flutter-app";
76
+ if (exists("supabase") && (exists("next.config.*") || exists("vite.config.*"))) return "saas-web-app";
77
+ if (exists("next.config.*") || exists("vite.config.*") || exists("nuxt.config.*")) return "web-app";
78
+ if (exists("Dockerfile") || exists("prisma") || exists("drizzle.config.*")) return "backend-api";
79
+ if (exists("Cargo.toml")) return "rust-project";
80
+ if (exists("pyproject.toml") || exists("setup.py") || exists("requirements.txt")) return "python-project";
81
+ return "generic";
82
+ }
83
+ var ROSTER_SUGGESTIONS = {
84
+ "saas-web-app": [
85
+ "architect",
86
+ "builder",
87
+ "reviewer",
88
+ "tester",
89
+ "security",
90
+ "documentor",
91
+ "designer",
92
+ "copywriter",
93
+ "performance",
94
+ "devops",
95
+ "dba",
96
+ "e2e",
97
+ "dx",
98
+ "seo",
99
+ "pm",
100
+ "product",
101
+ "sales",
102
+ "legal",
103
+ "a11y",
104
+ "qa",
105
+ "advocate",
106
+ "debugger",
107
+ "release",
108
+ "narrator"
109
+ ],
110
+ "web-app": [
111
+ "architect",
112
+ "builder",
113
+ "reviewer",
114
+ "tester",
115
+ "security",
116
+ "documentor",
117
+ "designer",
118
+ "copywriter",
119
+ "performance",
120
+ "devops",
121
+ "e2e",
122
+ "seo",
123
+ "a11y",
124
+ "qa",
125
+ "debugger"
126
+ ],
127
+ "backend-api": [
128
+ "architect",
129
+ "builder",
130
+ "reviewer",
131
+ "tester",
132
+ "security",
133
+ "documentor",
134
+ "devops",
135
+ "dba",
136
+ "performance",
137
+ "dx",
138
+ "qa",
139
+ "debugger",
140
+ "release"
141
+ ],
142
+ "ios-app": [
143
+ "architect",
144
+ "builder",
145
+ "reviewer",
146
+ "tester",
147
+ "security",
148
+ "documentor",
149
+ "designer",
150
+ "mobile",
151
+ "performance",
152
+ "a11y",
153
+ "qa",
154
+ "debugger"
155
+ ],
156
+ "macos-app": [
157
+ "architect",
158
+ "builder",
159
+ "reviewer",
160
+ "tester",
161
+ "security",
162
+ "documentor",
163
+ "designer",
164
+ "performance",
165
+ "qa",
166
+ "debugger"
167
+ ],
168
+ "flutter-app": [
169
+ "architect",
170
+ "builder",
171
+ "reviewer",
172
+ "tester",
173
+ "security",
174
+ "documentor",
175
+ "designer",
176
+ "mobile",
177
+ "performance",
178
+ "a11y",
179
+ "debugger"
180
+ ],
181
+ "game": [
182
+ "architect",
183
+ "builder",
184
+ "reviewer",
185
+ "tester",
186
+ "documentor",
187
+ "gamedev",
188
+ "3d",
189
+ "audio",
190
+ "designer",
191
+ "performance",
192
+ "debugger"
193
+ ],
194
+ "rust-project": [
195
+ "architect",
196
+ "builder",
197
+ "reviewer",
198
+ "tester",
199
+ "security",
200
+ "documentor",
201
+ "performance",
202
+ "debugger",
203
+ "qa"
204
+ ],
205
+ "python-project": [
206
+ "architect",
207
+ "builder",
208
+ "reviewer",
209
+ "tester",
210
+ "security",
211
+ "documentor",
212
+ "performance",
213
+ "debugger",
214
+ "qa"
215
+ ],
216
+ "generic": [
217
+ "architect",
218
+ "builder",
219
+ "reviewer",
220
+ "tester",
221
+ "security",
222
+ "documentor",
223
+ "debugger",
224
+ "qa"
225
+ ]
226
+ };
227
+
228
+ // src/commands/shift.ts
54
229
  async function shiftCommand(options = {}) {
55
230
  const cwd = process.cwd();
56
- const projectName = path.basename(cwd);
57
- const paradigmDir = path.join(cwd, ".paradigm");
58
- const isInitialized = fs.existsSync(paradigmDir) && fs.statSync(paradigmDir).isDirectory();
231
+ const projectName = path2.basename(cwd);
232
+ const paradigmDir = path2.join(cwd, ".paradigm");
233
+ const isInitialized = fs2.existsSync(paradigmDir) && fs2.statSync(paradigmDir).isDirectory();
59
234
  console.log(chalk.blue("\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"));
60
235
  console.log(chalk.blue("\u2502") + chalk.white.bold(" paradigm shift ") + chalk.blue("\u2502"));
61
236
  console.log(chalk.blue("\u2502") + chalk.gray(" Full project setup in one command ") + chalk.blue("\u2502"));
@@ -83,10 +258,10 @@ async function shiftCommand(options = {}) {
83
258
  }
84
259
  } else {
85
260
  spinner.succeed(chalk.gray("Step 1/6: Already initialized (use --force to reinit)"));
86
- const configPath = path.join(paradigmDir, "config.yaml");
87
- if (fs.existsSync(configPath)) {
261
+ const configPath = path2.join(paradigmDir, "config.yaml");
262
+ if (fs2.existsSync(configPath)) {
88
263
  try {
89
- const configContent = fs.readFileSync(configPath, "utf8");
264
+ const configContent = fs2.readFileSync(configPath, "utf8");
90
265
  const config = yaml.load(configContent);
91
266
  if (!config.discipline || config.discipline === "auto") {
92
267
  const detected = detectDiscipline(cwd);
@@ -96,7 +271,7 @@ async function shiftCommand(options = {}) {
96
271
  `discipline: ${detected}`
97
272
  );
98
273
  if (updated !== configContent) {
99
- fs.writeFileSync(configPath, updated, "utf8");
274
+ fs2.writeFileSync(configPath, updated, "utf8");
100
275
  console.log(chalk.green(` \u2713 Detected discipline: ${chalk.cyan(detected)} (updated config.yaml)`));
101
276
  }
102
277
  } else if (!config.discipline) {
@@ -106,7 +281,7 @@ async function shiftCommand(options = {}) {
106
281
  discipline: ${detected}`
107
282
  );
108
283
  if (withDiscipline !== configContent) {
109
- fs.writeFileSync(configPath, withDiscipline, "utf8");
284
+ fs2.writeFileSync(configPath, withDiscipline, "utf8");
110
285
  console.log(chalk.green(` \u2713 Added discipline: ${chalk.cyan(detected)} to config.yaml`));
111
286
  }
112
287
  }
@@ -127,17 +302,17 @@ discipline: ${detected}`
127
302
  }
128
303
  }
129
304
  {
130
- const configPath = path.join(paradigmDir, "config.yaml");
131
- if (options.workspace && fs.existsSync(configPath)) {
132
- const wsFilePath = options.workspacePath ? path.resolve(cwd, options.workspacePath) : path.join(path.dirname(cwd), ".paradigm-workspace");
133
- if (fs.existsSync(wsFilePath)) {
305
+ const configPath = path2.join(paradigmDir, "config.yaml");
306
+ if (options.workspace && fs2.existsSync(configPath)) {
307
+ const wsFilePath = options.workspacePath ? path2.resolve(cwd, options.workspacePath) : path2.join(path2.dirname(cwd), ".paradigm-workspace");
308
+ if (fs2.existsSync(wsFilePath)) {
134
309
  try {
135
- const wsConfig = yaml.load(fs.readFileSync(wsFilePath, "utf8"));
136
- const currentName = path.basename(cwd);
137
- const wsDir = path.dirname(wsFilePath);
138
- const relPath = "./" + path.relative(wsDir, cwd);
310
+ const wsConfig = yaml.load(fs2.readFileSync(wsFilePath, "utf8"));
311
+ const currentName = path2.basename(cwd);
312
+ const wsDir = path2.dirname(wsFilePath);
313
+ const relPath = "./" + path2.relative(wsDir, cwd);
139
314
  const alreadyMember = wsConfig.members.some(
140
- (m) => path.resolve(wsDir, m.path) === cwd
315
+ (m) => path2.resolve(wsDir, m.path) === cwd
141
316
  );
142
317
  if (!alreadyMember) {
143
318
  const role = detectProjectRole(currentName, cwd);
@@ -146,7 +321,7 @@ discipline: ${detected}`
146
321
  path: relPath,
147
322
  ...role && { role }
148
323
  });
149
- fs.writeFileSync(
324
+ fs2.writeFileSync(
150
325
  wsFilePath,
151
326
  yaml.dump(wsConfig, { indent: 2, lineWidth: 120, noRefs: true, sortKeys: false, quotingType: '"' }),
152
327
  "utf8"
@@ -160,66 +335,66 @@ discipline: ${detected}`
160
335
  }
161
336
  } else {
162
337
  try {
163
- const currentName = path.basename(cwd);
164
- const wsDir = path.dirname(wsFilePath);
165
- const relPath = "./" + path.relative(wsDir, cwd);
338
+ const currentName = path2.basename(cwd);
339
+ const wsDir = path2.dirname(wsFilePath);
340
+ const relPath = "./" + path2.relative(wsDir, cwd);
166
341
  const role = detectProjectRole(currentName, cwd);
167
342
  const wsConfig = {
168
343
  version: "1.0",
169
344
  name: options.workspace,
170
345
  members: [{ name: currentName, path: relPath, ...role && { role } }]
171
346
  };
172
- fs.mkdirSync(path.dirname(wsFilePath), { recursive: true });
173
- fs.writeFileSync(
347
+ fs2.mkdirSync(path2.dirname(wsFilePath), { recursive: true });
348
+ fs2.writeFileSync(
174
349
  wsFilePath,
175
350
  yaml.dump(wsConfig, { indent: 2, lineWidth: 120, noRefs: true, sortKeys: false, quotingType: '"' }),
176
351
  "utf8"
177
352
  );
178
- console.log(chalk.green(` \u2713 Created workspace: ${chalk.cyan(options.workspace)} at ${chalk.gray(path.relative(cwd, wsFilePath))}`));
353
+ console.log(chalk.green(` \u2713 Created workspace: ${chalk.cyan(options.workspace)} at ${chalk.gray(path2.relative(cwd, wsFilePath))}`));
179
354
  } catch (e) {
180
355
  console.log(chalk.yellow(` \u26A0 Failed to create workspace: ${e.message}`));
181
356
  }
182
357
  }
183
358
  try {
184
- const configContent = fs.readFileSync(configPath, "utf8");
359
+ const configContent = fs2.readFileSync(configPath, "utf8");
185
360
  const config = yaml.load(configContent);
186
- const relWsPath = path.relative(cwd, wsFilePath);
361
+ const relWsPath = path2.relative(cwd, wsFilePath);
187
362
  if (config.workspace !== relWsPath) {
188
363
  if (config.workspace) {
189
364
  const updated = configContent.replace(
190
365
  /^workspace:\s*.*$/m,
191
366
  `workspace: "${relWsPath}"`
192
367
  );
193
- fs.writeFileSync(configPath, updated, "utf8");
368
+ fs2.writeFileSync(configPath, updated, "utf8");
194
369
  } else {
195
370
  const updated = configContent.trimEnd() + `
196
371
  workspace: "${relWsPath}"
197
372
  `;
198
- fs.writeFileSync(configPath, updated, "utf8");
373
+ fs2.writeFileSync(configPath, updated, "utf8");
199
374
  }
200
375
  console.log(chalk.green(` \u2713 Linked workspace in config.yaml`));
201
376
  }
202
377
  } catch (e) {
203
378
  log.operation("shift").debug("Workspace config link failed", { error: e.message });
204
379
  }
205
- } else if (fs.existsSync(configPath)) {
380
+ } else if (fs2.existsSync(configPath)) {
206
381
  try {
207
- const configContent = fs.readFileSync(configPath, "utf8");
382
+ const configContent = fs2.readFileSync(configPath, "utf8");
208
383
  const config = yaml.load(configContent);
209
384
  if (!config.workspace) {
210
- let searchDir = path.dirname(cwd);
385
+ let searchDir = path2.dirname(cwd);
211
386
  for (let i = 0; i < 3; i++) {
212
- const wsCandidate = path.join(searchDir, ".paradigm-workspace");
213
- if (fs.existsSync(wsCandidate)) {
214
- const relPath = path.relative(cwd, wsCandidate);
387
+ const wsCandidate = path2.join(searchDir, ".paradigm-workspace");
388
+ if (fs2.existsSync(wsCandidate)) {
389
+ const relPath = path2.relative(cwd, wsCandidate);
215
390
  const updated = configContent.trimEnd() + `
216
391
  workspace: "${relPath}"
217
392
  `;
218
- fs.writeFileSync(configPath, updated, "utf8");
393
+ fs2.writeFileSync(configPath, updated, "utf8");
219
394
  console.log(chalk.green(` \u2713 Found workspace: ${chalk.cyan(relPath)} (added to config.yaml)`));
220
395
  break;
221
396
  }
222
- const parent = path.dirname(searchDir);
397
+ const parent = path2.dirname(searchDir);
223
398
  if (parent === searchDir) break;
224
399
  searchDir = parent;
225
400
  }
@@ -247,6 +422,26 @@ workspace: "${relPath}"
247
422
  } else {
248
423
  spinner.succeed(chalk.gray("Step 2/6: Team already configured (use --force to reinit)"));
249
424
  }
425
+ const rosterPath = path2.join(cwd, ".paradigm", "roster.yaml");
426
+ if (!fs2.existsSync(rosterPath) || options.force) {
427
+ try {
428
+ const projectType = detectProjectType(cwd);
429
+ const suggested = ROSTER_SUGGESTIONS[projectType] || ROSTER_SUGGESTIONS["generic"];
430
+ const rosterData = { version: "1.0", project: projectName, type: projectType, active: suggested.sort() };
431
+ fs2.writeFileSync(rosterPath, yaml.dump(rosterData, { lineWidth: -1, noRefs: true }), "utf8");
432
+ console.log(chalk.green(` \u2713 Agent roster set: ${chalk.cyan(suggested.length)} agents for ${chalk.cyan(projectType)}`));
433
+ } catch (e) {
434
+ log.operation("shift").debug("Roster setup failed", { error: e.message });
435
+ }
436
+ } else {
437
+ try {
438
+ const existing = yaml.load(fs2.readFileSync(rosterPath, "utf8"));
439
+ const count = existing?.active?.length ?? 0;
440
+ console.log(chalk.gray(` \u2713 Agent roster exists (${count} agents active)`));
441
+ } catch {
442
+ console.log(chalk.gray(" \u2713 Agent roster exists"));
443
+ }
444
+ }
250
445
  if (!options.quick) {
251
446
  spinner.start("Step 3/6: Scanning and indexing symbols...");
252
447
  try {
@@ -259,10 +454,10 @@ workspace: "${relPath}"
259
454
  spinner.succeed(chalk.gray("Step 3/6: Skipped scan (--quick mode)"));
260
455
  }
261
456
  {
262
- const configPath = path.join(paradigmDir, "config.yaml");
263
- if (fs.existsSync(configPath)) {
457
+ const configPath = path2.join(paradigmDir, "config.yaml");
458
+ if (fs2.existsSync(configPath)) {
264
459
  try {
265
- const configForWs = yaml.load(fs.readFileSync(configPath, "utf8"));
460
+ const configForWs = yaml.load(fs2.readFileSync(configPath, "utf8"));
266
461
  if (configForWs.workspace) {
267
462
  spinner.start("Step 3b/6: Reindexing workspace members...");
268
463
  try {
@@ -278,29 +473,29 @@ workspace: "${relPath}"
278
473
  }
279
474
  }
280
475
  }
281
- const portalPath = path.join(cwd, "portal.yaml");
282
- if (!fs.existsSync(portalPath)) {
476
+ const portalPath = path2.join(cwd, "portal.yaml");
477
+ if (!fs2.existsSync(portalPath)) {
283
478
  const defaultPortal = { version: "1.0.0", gates: {}, routes: {} };
284
- fs.writeFileSync(portalPath, yaml.dump(defaultPortal, { lineWidth: -1, noRefs: true }), "utf8");
479
+ fs2.writeFileSync(portalPath, yaml.dump(defaultPortal, { lineWidth: -1, noRefs: true }), "utf8");
285
480
  }
286
- const lorePath = path.join(cwd, ".paradigm", "lore");
287
- if (!fs.existsSync(lorePath)) {
288
- fs.mkdirSync(lorePath, { recursive: true });
481
+ const lorePath = path2.join(cwd, ".paradigm", "lore");
482
+ if (!fs2.existsSync(lorePath)) {
483
+ fs2.mkdirSync(lorePath, { recursive: true });
289
484
  }
290
- const uniBase = path.join(cwd, ".paradigm", "university");
485
+ const uniBase = path2.join(cwd, ".paradigm", "university");
291
486
  for (const subdir of ["content/notes", "content/policies", "content/quizzes", "content/paths", "diplomas"]) {
292
- const dirPath = path.join(uniBase, subdir);
293
- if (!fs.existsSync(dirPath)) {
294
- fs.mkdirSync(dirPath, { recursive: true });
487
+ const dirPath = path2.join(uniBase, subdir);
488
+ if (!fs2.existsSync(dirPath)) {
489
+ fs2.mkdirSync(dirPath, { recursive: true });
295
490
  }
296
491
  }
297
- const uniConfigPath = path.join(uniBase, "config.yaml");
298
- if (!fs.existsSync(uniConfigPath)) {
492
+ const uniConfigPath = path2.join(uniBase, "config.yaml");
493
+ if (!fs2.existsSync(uniConfigPath)) {
299
494
  let projectName2 = "Project";
300
495
  try {
301
- const configPath = path.join(cwd, ".paradigm", "config.yaml");
302
- if (fs.existsSync(configPath)) {
303
- const configData = yaml.load(fs.readFileSync(configPath, "utf8"));
496
+ const configPath = path2.join(cwd, ".paradigm", "config.yaml");
497
+ if (fs2.existsSync(configPath)) {
498
+ const configData = yaml.load(fs2.readFileSync(configPath, "utf8"));
304
499
  if (configData.project && typeof configData.project === "string") {
305
500
  projectName2 = configData.project;
306
501
  }
@@ -334,7 +529,7 @@ workspace: "${relPath}"
334
529
  includeGlobalPLSAT: true
335
530
  }
336
531
  };
337
- fs.writeFileSync(uniConfigPath, yaml.dump(uniConfig, { lineWidth: -1, noRefs: true }), "utf8");
532
+ fs2.writeFileSync(uniConfigPath, yaml.dump(uniConfig, { lineWidth: -1, noRefs: true }), "utf8");
338
533
  }
339
534
  spinner.start("Step 4/6: Syncing IDE configurations...");
340
535
  try {
@@ -391,19 +586,20 @@ workspace: "${relPath}"
391
586
  { path: ".purpose", desc: "Root feature definitions" },
392
587
  { path: ".paradigm/lore/", desc: "Project lore timeline", isDir: true },
393
588
  { path: "portal.yaml", desc: "Authorization gates" },
589
+ { path: ".paradigm/roster.yaml", desc: "Agent roster for this project" },
394
590
  { path: "CLAUDE.md", desc: "Claude Code AI instructions" },
395
591
  { path: "AGENTS.md", desc: "Universal AI agent instructions" },
396
592
  { path: ".cursor/rules/", desc: "Cursor AI instructions", isDir: true },
397
593
  { path: ".claude/hooks/", desc: "Claude Code enforcement hooks", isDir: true, optional: true },
398
594
  { path: ".cursor/hooks/", desc: "Cursor enforcement hooks", isDir: true, optional: true }
399
595
  ];
400
- const configPathForSummary = path.join(paradigmDir, "config.yaml");
401
- if (fs.existsSync(configPathForSummary)) {
596
+ const configPathForSummary = path2.join(paradigmDir, "config.yaml");
597
+ if (fs2.existsSync(configPathForSummary)) {
402
598
  try {
403
- const cfg = yaml.load(fs.readFileSync(configPathForSummary, "utf8"));
599
+ const cfg = yaml.load(fs2.readFileSync(configPathForSummary, "utf8"));
404
600
  if (typeof cfg.workspace === "string") {
405
- const wsAbsPath = path.resolve(cwd, cfg.workspace);
406
- const wsRelPath = path.relative(cwd, wsAbsPath);
601
+ const wsAbsPath = path2.resolve(cwd, cfg.workspace);
602
+ const wsRelPath = path2.relative(cwd, wsAbsPath);
407
603
  files.push({ path: wsRelPath, desc: "Multi-project workspace", optional: true });
408
604
  }
409
605
  } catch (e) {
@@ -411,8 +607,8 @@ workspace: "${relPath}"
411
607
  }
412
608
  }
413
609
  for (const file of files) {
414
- const fullPath = path.join(cwd, file.path);
415
- if (fs.existsSync(fullPath)) {
610
+ const fullPath = path2.join(cwd, file.path);
611
+ if (fs2.existsSync(fullPath)) {
416
612
  console.log(chalk.green(" \u2713 ") + chalk.white(file.path.padEnd(28)) + chalk.gray(file.desc));
417
613
  } else if (!file.optional) {
418
614
  console.log(chalk.yellow(" \u25CB ") + chalk.gray(file.path.padEnd(28)) + chalk.gray(`(${file.desc})`));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a-company/paradigm",
3
- "version": "5.8.0",
3
+ "version": "5.8.2",
4
4
  "description": "Unified CLI for Paradigm developer tools",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",