legacy-squad 1.2.0 → 1.3.0

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/cli.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  // apps/cli/src/index.ts
4
4
  import { Command } from "commander";
5
- import path9 from "node:path";
5
+ import path10 from "node:path";
6
6
  import { existsSync } from "node:fs";
7
7
  import { fileURLToPath } from "node:url";
8
8
 
@@ -1318,7 +1318,7 @@ var Installer = class {
1318
1318
  mode: { execution: "read_only" },
1319
1319
  ide: { primary: "claude-code" },
1320
1320
  installed_at: (/* @__PURE__ */ new Date()).toISOString(),
1321
- framework_version: "1.2.0"
1321
+ framework_version: "1.3.0"
1322
1322
  };
1323
1323
  await writeFile2(
1324
1324
  path7.join(configDir, "project.yaml"),
@@ -1328,9 +1328,11 @@ var Installer = class {
1328
1328
  await mkdir2(path7.join(effectiveRoot, ".legacy-squad", "outputs", "reports"), { recursive: true });
1329
1329
  await mkdir2(path7.join(effectiveRoot, ".legacy-squad", "outputs", "assessments"), { recursive: true });
1330
1330
  await mkdir2(path7.join(effectiveRoot, ".legacy-squad", "logs"), { recursive: true });
1331
- const claudeCommandsDir = path7.join(effectiveRoot, ".claude", "commands", "legacy-squad");
1331
+ const claudeCommandsRoot = path7.join(effectiveRoot, ".claude", "commands");
1332
+ const claudeCommandsDir = path7.join(claudeCommandsRoot, "legacy-squad");
1332
1333
  await mkdir2(claudeCommandsDir, { recursive: true });
1333
1334
  await this.copySlashCommands(templateDir, claudeCommandsDir);
1335
+ await this.copyOrchestrator(templateDir, claudeCommandsRoot);
1334
1336
  await this.generateAgentsMd(effectiveRoot, repoIndex.project.name);
1335
1337
  const logContent = [
1336
1338
  `Legacy Squad Framework \u2014 Install Log`,
@@ -1390,6 +1392,21 @@ var Installer = class {
1390
1392
  }
1391
1393
  }
1392
1394
  }
1395
+ /**
1396
+ * DA-012: copia o template do orchestrator para `.claude/commands/legacy-squad.md`
1397
+ * (raiz de commands, não subdir). No Claude Code, arquivos na raiz de commands viram
1398
+ * o comando puro `/<filename>` — então este caminho expressa `/legacy-squad` (validado
1399
+ * emp.). Falha silenciosamente se o template não existir, no mesmo estilo de copySlashCommands.
1400
+ */
1401
+ async copyOrchestrator(templateDir, commandsRoot) {
1402
+ const sourcePath = path7.join(templateDir, "legacy-squad.md");
1403
+ const targetPath = path7.join(commandsRoot, "legacy-squad.md");
1404
+ try {
1405
+ const content = await readFile2(sourcePath, "utf-8");
1406
+ await writeFile2(targetPath, content, "utf-8");
1407
+ } catch {
1408
+ }
1409
+ }
1393
1410
  async generateAgentsMd(projectRoot, projectName) {
1394
1411
  const lines = [
1395
1412
  `# Legacy Squad Agents \u2014 ${projectName}`,
@@ -1442,6 +1459,7 @@ var Doctor = class {
1442
1459
  checks.push(await this.checkFile(projectRoot, ".legacy-squad/memory/context-packs.json", "Context Packs"));
1443
1460
  checks.push(await this.checkFile(projectRoot, ".legacy-squad/config/project.yaml", "Project Config"));
1444
1461
  checks.push(await this.checkDir(projectRoot, ".claude/commands/legacy-squad", "Claude Code Agents"));
1462
+ checks.push(await this.checkFile(projectRoot, ".claude/commands/legacy-squad.md", "Orchestrator /legacy-squad"));
1445
1463
  checks.push(await this.checkFile(projectRoot, "AGENTS.md", "Codex AGENTS.md"));
1446
1464
  checks.push(await this.checkDir(projectRoot, ".legacy-squad/outputs/assessments", "Assessments Dir"));
1447
1465
  checks.push(await this.checkDir(projectRoot, ".legacy-squad/outputs/reports", "Reports Dir"));
@@ -1507,19 +1525,281 @@ var Doctor = class {
1507
1525
  }
1508
1526
  };
1509
1527
 
1528
+ // packages/agents/src/lifecycle-detector.ts
1529
+ import path9 from "node:path";
1530
+ var REPO_INDEX_PATH = ".legacy-squad/memory/repo-index.json";
1531
+ var FINDINGS_INDEX_PATH = ".legacy-squad/memory/findings/index.json";
1532
+ var assessmentPath = (slug) => `.legacy-squad/outputs/assessments/${slug}-assessment.md`;
1533
+ var PRS_PATH = ".legacy-squad/outputs/reports/PRS.md";
1534
+ var SDD_PATH = ".legacy-squad/outputs/sdd/SDD.md";
1535
+ var MMP_PATH = ".legacy-squad/outputs/mmp/MMP.md";
1536
+ var SPECS_PATH = ".legacy-squad/outputs/specs/INDEX.md";
1537
+ var MATURITY_LABELS = {
1538
+ 1: "Unknown",
1539
+ 2: "Understood",
1540
+ 3: "Assessed",
1541
+ 4: "Planned",
1542
+ 5: "Modernization Ready",
1543
+ 6: "Continuously Modernized"
1544
+ };
1545
+ var STEPS = [
1546
+ {
1547
+ id: "scan",
1548
+ label: "Scan",
1549
+ command: null,
1550
+ phase: "discovery",
1551
+ target: REPO_INDEX_PATH,
1552
+ reason: "Rode `npx legacy-squad install` para escanear o projeto e gerar o repo-index."
1553
+ },
1554
+ {
1555
+ id: "security",
1556
+ label: "Security assessment",
1557
+ command: "/legacy-squad:security",
1558
+ phase: "assessment",
1559
+ target: assessmentPath("security"),
1560
+ reason: "Inicie os assessments rodando `/legacy-squad:security`."
1561
+ },
1562
+ {
1563
+ id: "architecture",
1564
+ label: "Architecture assessment",
1565
+ command: "/legacy-squad:architecture",
1566
+ phase: "assessment",
1567
+ target: assessmentPath("architecture"),
1568
+ reason: "Rode `/legacy-squad:architecture`."
1569
+ },
1570
+ {
1571
+ id: "legacy-code",
1572
+ label: "Legacy code assessment",
1573
+ command: "/legacy-squad:legacy-code",
1574
+ phase: "assessment",
1575
+ target: assessmentPath("legacy-code"),
1576
+ reason: "Rode `/legacy-squad:legacy-code`."
1577
+ },
1578
+ {
1579
+ id: "business-rules",
1580
+ label: "Business rules assessment",
1581
+ command: "/legacy-squad:business-rules",
1582
+ phase: "assessment",
1583
+ target: assessmentPath("business-rules"),
1584
+ reason: "Rode `/legacy-squad:business-rules`."
1585
+ },
1586
+ {
1587
+ id: "modernization",
1588
+ label: "Modernization assessment",
1589
+ command: "/legacy-squad:modernization",
1590
+ phase: "assessment",
1591
+ target: assessmentPath("modernization"),
1592
+ reason: "Rode `/legacy-squad:modernization`."
1593
+ },
1594
+ {
1595
+ id: "generate-prs",
1596
+ label: "PRS",
1597
+ command: "/legacy-squad:generate-prs",
1598
+ phase: "assessment",
1599
+ target: PRS_PATH,
1600
+ reason: "Consolide o diagn\xF3stico com `/legacy-squad:generate-prs`."
1601
+ },
1602
+ {
1603
+ id: "generate-sdd",
1604
+ label: "SDD",
1605
+ command: "/legacy-squad:generate-sdd",
1606
+ phase: "design",
1607
+ target: SDD_PATH,
1608
+ reason: "Gere o desenho t\xE9cnico com `/legacy-squad:generate-sdd`."
1609
+ },
1610
+ {
1611
+ id: "generate-mmp",
1612
+ label: "MMP",
1613
+ command: "/legacy-squad:generate-mmp",
1614
+ phase: "planning",
1615
+ target: MMP_PATH,
1616
+ reason: "Gere o plano mestre com `/legacy-squad:generate-mmp`."
1617
+ },
1618
+ {
1619
+ id: "generate-specs",
1620
+ label: "Execution Specs",
1621
+ command: "/legacy-squad:generate-specs",
1622
+ phase: "execution",
1623
+ target: SPECS_PATH,
1624
+ reason: "Decomponha em specs com `/legacy-squad:generate-specs`."
1625
+ }
1626
+ ];
1627
+ var PHASE_ORDER = [
1628
+ { id: "discovery", label: "Discovery" },
1629
+ { id: "assessment", label: "Assessment" },
1630
+ { id: "design", label: "Design" },
1631
+ { id: "planning", label: "Planning" },
1632
+ { id: "execution", label: "Execution" }
1633
+ ];
1634
+ var ASSESSMENT_STEP_IDS = [
1635
+ "security",
1636
+ "architecture",
1637
+ "legacy-code",
1638
+ "business-rules",
1639
+ "modernization"
1640
+ ];
1641
+ var LifecycleDetector = class {
1642
+ constructor(fs) {
1643
+ this.fs = fs;
1644
+ }
1645
+ fs;
1646
+ /** Detecta e retorna o snapshot determinístico do lifecycle em `projectRoot`. */
1647
+ async detect(projectRoot) {
1648
+ const done = /* @__PURE__ */ new Map();
1649
+ for (const step of STEPS) {
1650
+ done.set(step.id, await this.fs.exists(path9.join(projectRoot, step.target)));
1651
+ }
1652
+ const installed = done.get("scan") === true;
1653
+ const project = installed ? await this.readProject(projectRoot) : null;
1654
+ const findingCount = installed ? await this.readFindingCount(projectRoot) : 0;
1655
+ const maturityLevel = this.computeMaturity(done);
1656
+ return {
1657
+ project,
1658
+ installed,
1659
+ findingCount,
1660
+ maturityLevel,
1661
+ maturityLabel: MATURITY_LABELS[maturityLevel],
1662
+ phases: this.buildPhases(done),
1663
+ nextStep: this.computeNextStep(done),
1664
+ complete: done.get("generate-specs") === true
1665
+ };
1666
+ }
1667
+ /** Agrupa os passos por fase, calculando a contagem de concluídos. */
1668
+ buildPhases(done) {
1669
+ return PHASE_ORDER.map(({ id, label }) => {
1670
+ const steps = STEPS.filter((s) => s.phase === id).map((s) => ({
1671
+ id: s.id,
1672
+ label: s.label,
1673
+ command: s.command,
1674
+ done: done.get(s.id) === true
1675
+ }));
1676
+ return {
1677
+ id,
1678
+ label,
1679
+ steps,
1680
+ doneCount: steps.filter((s) => s.done).length,
1681
+ totalCount: steps.length
1682
+ };
1683
+ });
1684
+ }
1685
+ /** Deriva o Maturity Level (§10) a partir dos artefatos presentes. */
1686
+ computeMaturity(done) {
1687
+ if (done.get("generate-specs")) return 5;
1688
+ if (done.get("generate-mmp")) return 4;
1689
+ if (ASSESSMENT_STEP_IDS.every((id) => done.get(id))) return 3;
1690
+ if (done.get("scan")) return 2;
1691
+ return 1;
1692
+ }
1693
+ /** Próximo passo = primeiro `target` ausente na ordem canônica; null se tudo concluído. */
1694
+ computeNextStep(done) {
1695
+ const [scanStep] = STEPS;
1696
+ if (!done.get("scan")) {
1697
+ return { id: "install", command: null, reason: scanStep.reason };
1698
+ }
1699
+ for (const step of STEPS) {
1700
+ if (!done.get(step.id)) {
1701
+ return { id: step.id, command: step.command, reason: step.reason };
1702
+ }
1703
+ }
1704
+ return null;
1705
+ }
1706
+ /** Lê nome, tipo e stack do repo-index; null se ausente ou ilegível. */
1707
+ async readProject(root) {
1708
+ try {
1709
+ const raw = await this.fs.readFile(path9.join(root, REPO_INDEX_PATH));
1710
+ const idx = JSON.parse(raw);
1711
+ return {
1712
+ name: idx.project?.name ?? "unknown",
1713
+ type: idx.project?.type ?? "unknown",
1714
+ stack: (idx.stack ?? []).map((s) => s.name ?? "").filter((n) => n.length > 0)
1715
+ };
1716
+ } catch {
1717
+ return null;
1718
+ }
1719
+ }
1720
+ /** Conta os achados no index slim (DA-011); 0 se ausente ou ilegível. */
1721
+ async readFindingCount(root) {
1722
+ try {
1723
+ const raw = await this.fs.readFile(path9.join(root, FINDINGS_INDEX_PATH));
1724
+ const parsed = JSON.parse(raw);
1725
+ return Array.isArray(parsed) ? parsed.length : 0;
1726
+ } catch {
1727
+ return 0;
1728
+ }
1729
+ }
1730
+ };
1731
+
1732
+ // packages/output/src/dashboard-renderer.ts
1733
+ var RULE = "\u2501".repeat(40);
1734
+ var STEP_DISPLAY = {
1735
+ scan: "scan",
1736
+ security: "security",
1737
+ architecture: "architecture",
1738
+ "legacy-code": "legacy-code",
1739
+ "business-rules": "business-rules",
1740
+ modernization: "modernization",
1741
+ "generate-prs": "PRS",
1742
+ "generate-sdd": "SDD",
1743
+ "generate-mmp": "MMP",
1744
+ "generate-specs": "Specs"
1745
+ };
1746
+ var display = (id) => STEP_DISPLAY[id] ?? id;
1747
+ function phaseIcon(phase) {
1748
+ if (phase.totalCount > 0 && phase.doneCount === phase.totalCount) return "\u2713";
1749
+ if (phase.doneCount > 0) return "\u25D0";
1750
+ return "\xB7";
1751
+ }
1752
+ function phaseDetail(phase) {
1753
+ if (phase.steps.length === 1) {
1754
+ return display(phase.steps[0].id);
1755
+ }
1756
+ const names = phase.steps.map((s) => display(s.id)).join(" \xB7 ");
1757
+ return `${phase.doneCount}/${phase.totalCount} ${names}`;
1758
+ }
1759
+ var DashboardRenderer = class {
1760
+ render(snapshot) {
1761
+ const lines = [RULE];
1762
+ if (snapshot.project) {
1763
+ const stack = snapshot.project.stack.join(", ");
1764
+ lines.push(` Legacy Squad \u2014 ${snapshot.project.name}`);
1765
+ lines.push(` ${snapshot.project.type}${stack ? ` \xB7 ${stack}` : ""}`);
1766
+ } else {
1767
+ lines.push(" Legacy Squad");
1768
+ lines.push(" (framework n\xE3o instalado neste diret\xF3rio)");
1769
+ }
1770
+ lines.push(RULE, "");
1771
+ lines.push(` Maturity Level ${snapshot.maturityLevel} \u2014 ${snapshot.maturityLabel}`);
1772
+ lines.push(` Findings ${snapshot.findingCount}`, "");
1773
+ const labelWidth = Math.max(...snapshot.phases.map((p) => p.label.length));
1774
+ for (const phase of snapshot.phases) {
1775
+ lines.push(` ${phaseIcon(phase)} ${phase.label.padEnd(labelWidth)} ${phaseDetail(phase)}`);
1776
+ }
1777
+ lines.push("");
1778
+ if (snapshot.nextStep) {
1779
+ const target = snapshot.nextStep.command ?? "npx legacy-squad install";
1780
+ lines.push(` \u2192 Pr\xF3ximo passo: ${target}`);
1781
+ lines.push(` ${snapshot.nextStep.reason}`);
1782
+ } else {
1783
+ lines.push(" \u2713 Lifecycle V1 completo \u2014 specs prontas para execu\xE7\xE3o.");
1784
+ }
1785
+ lines.push(RULE);
1786
+ return lines.join("\n");
1787
+ }
1788
+ };
1789
+
1510
1790
  // apps/cli/src/index.ts
1511
1791
  var program = new Command();
1512
1792
  function getTemplateDir() {
1513
- const cliDir = path9.dirname(fileURLToPath(import.meta.url));
1514
- const bundledPath = path9.resolve(cliDir, "templates", "claude-commands");
1793
+ const cliDir = path10.dirname(fileURLToPath(import.meta.url));
1794
+ const bundledPath = path10.resolve(cliDir, "templates", "claude-commands");
1515
1795
  if (existsSync(bundledPath)) return bundledPath;
1516
- const devPath = path9.resolve(cliDir, "..", "..", "..", "templates", "claude-commands");
1796
+ const devPath = path10.resolve(cliDir, "..", "..", "..", "templates", "claude-commands");
1517
1797
  if (existsSync(devPath)) return devPath;
1518
1798
  throw new Error("Templates not found. Run from the framework root or use the published package.");
1519
1799
  }
1520
- program.name("legacy-squad").description("AI-Powered Legacy Modernization Platform \u2014 Understand. Plan. Modernize.").version("1.2.0");
1800
+ program.name("legacy-squad").description("AI-Powered Legacy Modernization Platform \u2014 Understand. Plan. Modernize.").version("1.3.0");
1521
1801
  program.command("install").description("Install Legacy Squad Framework inside the current project").option("-p, --path <dir>", "Project root directory", ".").action(async (opts) => {
1522
- const projectRoot = path9.resolve(opts.path);
1802
+ const projectRoot = path10.resolve(opts.path);
1523
1803
  const templateDir = getTemplateDir();
1524
1804
  console.log("\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
1525
1805
  console.log(" Legacy Squad Framework V1 \u2014 Install");
@@ -1561,21 +1841,21 @@ program.command("install").description("Install Legacy Squad Framework inside th
1561
1841
  console.log(" 1. Open Claude Code: claude");
1562
1842
  console.log("");
1563
1843
  console.log(" Analysis (run in order):");
1564
- console.log(" /legacy-squad-security");
1565
- console.log(" /legacy-squad-architecture");
1566
- console.log(" /legacy-squad-legacy-code");
1567
- console.log(" /legacy-squad-business-rules");
1568
- console.log(" /legacy-squad-modernization");
1844
+ console.log(" /legacy-squad:security");
1845
+ console.log(" /legacy-squad:architecture");
1846
+ console.log(" /legacy-squad:legacy-code");
1847
+ console.log(" /legacy-squad:business-rules");
1848
+ console.log(" /legacy-squad:modernization");
1569
1849
  console.log("");
1570
1850
  console.log(" Consolidated artifacts (run after analysis):");
1571
- console.log(" /legacy-squad-generate-prs (Product Refactor Specification)");
1572
- console.log(" /legacy-squad-generate-sdd (Software Design Document)");
1573
- console.log(" /legacy-squad-generate-mmp (Modernization Master Plan)");
1574
- console.log(" /legacy-squad-generate-specs (Execution Specs for V2)");
1851
+ console.log(" /legacy-squad:generate-prs (Product Refactor Specification)");
1852
+ console.log(" /legacy-squad:generate-sdd (Software Design Document)");
1853
+ console.log(" /legacy-squad:generate-mmp (Modernization Master Plan)");
1854
+ console.log(" /legacy-squad:generate-specs (Execution Specs for V2)");
1575
1855
  console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n");
1576
1856
  });
1577
1857
  program.command("scan").description("Re-scan the project and update .legacy-squad/memory/").option("-p, --path <dir>", "Project root directory", ".").action(async (opts) => {
1578
- const projectRoot = path9.resolve(opts.path);
1858
+ const projectRoot = path10.resolve(opts.path);
1579
1859
  console.log(`
1580
1860
  \u{1F50D} Re-scanning: ${projectRoot}
1581
1861
  `);
@@ -1590,18 +1870,18 @@ program.command("scan").description("Re-scan the project and update .legacy-squa
1590
1870
  const compliance = new ComplianceEngine(fs);
1591
1871
  const findings = await compliance.evaluate(effectiveRoot, repoIndex);
1592
1872
  const { mkdir: mkdir3, writeFile: writeFile3 } = await import("node:fs/promises");
1593
- const memoryDir = path9.join(effectiveRoot, ".legacy-squad", "memory");
1873
+ const memoryDir = path10.join(effectiveRoot, ".legacy-squad", "memory");
1594
1874
  await mkdir3(memoryDir, { recursive: true });
1595
- await writeFile3(path9.join(memoryDir, "repo-index.json"), JSON.stringify(repoIndex, null, 2), "utf-8");
1875
+ await writeFile3(path10.join(memoryDir, "repo-index.json"), JSON.stringify(repoIndex, null, 2), "utf-8");
1596
1876
  await new FindingsWriter(fs).write(findings, memoryDir);
1597
1877
  console.log(`\u2705 Stack: ${repoIndex.stack.map((s) => s.name).join(", ")}`);
1598
1878
  console.log(`\u{1F4E6} Modules: ${repoIndex.modules.length}`);
1599
1879
  console.log(`\u{1F512} Findings: ${findings.length}`);
1600
- console.log(`\u{1F4C4} Updated: ${path9.join(effectiveRoot, ".legacy-squad", "memory")}
1880
+ console.log(`\u{1F4C4} Updated: ${path10.join(effectiveRoot, ".legacy-squad", "memory")}
1601
1881
  `);
1602
1882
  });
1603
1883
  program.command("doctor").description("Verify Legacy Squad installation health").option("-p, --path <dir>", "Project root directory", ".").action(async (opts) => {
1604
- const projectRoot = path9.resolve(opts.path);
1884
+ const projectRoot = path10.resolve(opts.path);
1605
1885
  console.log("\n\u{1FA7A} Legacy Squad Doctor\n");
1606
1886
  const doctor = new Doctor();
1607
1887
  const checks = await doctor.check(projectRoot);
@@ -1618,4 +1898,16 @@ program.command("doctor").description("Verify Legacy Squad installation health")
1618
1898
  console.log("\n\u2705 All checks passed.\n");
1619
1899
  }
1620
1900
  });
1901
+ program.command("status").description("Show the project lifecycle dashboard and the recommended next step").option("-p, --path <dir>", "Project root directory", ".").option("--json", "Output the raw lifecycle snapshot as JSON").action(async (opts) => {
1902
+ const projectRoot = path10.resolve(opts.path);
1903
+ const fs = new NodeFileSystem();
1904
+ const snapshot = await new LifecycleDetector(fs).detect(projectRoot);
1905
+ if (opts.json) {
1906
+ console.log(JSON.stringify(snapshot, null, 2));
1907
+ return;
1908
+ }
1909
+ console.log("");
1910
+ console.log(new DashboardRenderer().render(snapshot));
1911
+ console.log("");
1912
+ });
1621
1913
  program.parse();
@@ -0,0 +1,38 @@
1
+ Você é o **Orchestrator** do Legacy Squad Framework — o ponto de entrada que mostra onde o projeto está no lifecycle (Discovery → Assessment → Design → Planning → Execution) e qual é o próximo passo recomendado, respeitando dependências.
2
+
3
+ ## Passos
4
+
5
+ 1. **Obtenha o estado do lifecycle.** Tente primeiro:
6
+
7
+ ```
8
+ npx legacy-squad status --json
9
+ ```
10
+
11
+ O comando retorna um snapshot determinístico (`LifecycleSnapshot`) com `project`, `installed`, `findingCount`, `maturityLevel`, `phases` e `nextStep`.
12
+
13
+ 2. **Fallback** — se o comando não estiver disponível (ex.: o framework não foi instalado ainda neste projeto), inspecione `.legacy-squad/` diretamente:
14
+ - `memory/repo-index.json` — projeto instalado (Discovery concluído).
15
+ - `memory/findings/index.json` — contagem de achados (DA-011).
16
+ - `outputs/assessments/{security,architecture,legacy-code,business-rules,modernization}-assessment.md` — assessments por pilar.
17
+ - `outputs/reports/PRS.md`, `outputs/sdd/SDD.md`, `outputs/mmp/MMP.md`, `outputs/specs/INDEX.md` — artefatos.
18
+
19
+ Se nada existir, oriente o usuário a rodar `npx legacy-squad install`.
20
+
21
+ 3. **Renderize o dashboard** a partir do JSON. O `status` (sem `--json`) já imprime um dashboard formatado — você pode rodar `npx legacy-squad status` e mostrar a saída ao usuário. Se preferir reorganizar, use os campos do snapshot.
22
+
23
+ 4. **Ofereça o próximo passo.** Leia `snapshot.nextStep`:
24
+ - Se `nextStep.command` estiver definido, ofereça executá-lo (ex.: "Quer que eu rode `/legacy-squad:security` agora?").
25
+ - Se `nextStep` for `null`, o lifecycle V1 está completo (Level 5 — Modernization Ready) e as specs estão prontas para execução assistida (V2).
26
+ - Se `nextStep.id` for `install`, oriente o usuário a rodar `npx legacy-squad install` (você não roda comandos da CLI sem confirmação).
27
+
28
+ 5. **Respeite a ordem canônica** do lifecycle (FRAMEWORK_SPECIFICATION §3): scan → 5 assessments (security, architecture, legacy-code, business-rules, modernization) → PRS → SDD → MMP → Specs. Nunca pule passos: as dependências duras (SDD←architecture-assessment, MMP←modernization-assessment, Specs←MMP) já estão refletidas nessa ordem.
29
+
30
+ ## Output
31
+
32
+ Não escreva em `.legacy-squad/outputs/`. Este comando é apenas o orchestrator — quem produz artefatos são `/legacy-squad:security`, `/legacy-squad:generate-prs`, etc. Sua função é mostrar o estado e sugerir o próximo passo.
33
+
34
+ ## Restrições
35
+
36
+ - Não invente progresso: o snapshot é determinístico (calculado em TypeScript a partir da existência de arquivos canônicos). Se um arquivo não existe, o passo não está concluído — não tente "interpretar".
37
+ - Não execute o próximo passo sem confirmação explícita do usuário.
38
+ - O comando `npx legacy-squad status --json` lê o filesystem; ele não modifica nada.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "legacy-squad",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "AI-Powered Legacy Modernization Platform — Install-first, IDE-native, evidence-driven framework that transforms legacy systems into modernization-ready assets.",
5
5
  "keywords": [
6
6
  "legacy",
@@ -23,7 +23,7 @@
23
23
  "homepage": "https://github.com/hrpimenta/legacy-squad",
24
24
  "repository": {
25
25
  "type": "git",
26
- "url": "https://github.com/hrpimenta/legacy-squad.git"
26
+ "url": "git+https://github.com/hrpimenta/legacy-squad.git"
27
27
  },
28
28
  "license": "MIT",
29
29
  "author": "Legacy Squad Team",
@@ -56,4 +56,4 @@
56
56
  "engines": {
57
57
  "node": ">=18"
58
58
  }
59
- }
59
+ }