smartlisa 0.1.11 → 0.1.12

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "lisa",
3
3
  "description": "Project planning with milestones, epics, and stories. Break down work, track progress, and implement with full context.",
4
- "version": "0.1.11",
4
+ "version": "0.1.12",
5
5
  "author": {
6
6
  "name": "Rodrigo Klosowski",
7
7
  "url": "https://rklosowski.com/"
package/dist/cli.js CHANGED
@@ -93,6 +93,7 @@ var ValueSchema = z.object({
93
93
  var DiscoveryContextSchema = z.object({
94
94
  problem: z.string().optional(),
95
95
  vision: z.string().optional(),
96
+ users: z.array(z.string()).default([]),
96
97
  values: z.array(ValueSchema).default([]),
97
98
  success_criteria: z.array(z.string()).default([]),
98
99
  gathered: z.string().datetime().optional()
@@ -118,8 +119,6 @@ var DiscoveryDepth = z.enum(["quick", "standard", "deep"]);
118
119
  var DiscoveryHistorySchema = z.object({
119
120
  entries: z.array(DiscoveryHistoryEntrySchema).default([]),
120
121
  started: z.string().datetime().optional(),
121
- completed: z.string().datetime().optional(),
122
- is_complete: z.boolean().default(false),
123
122
  // Depth preference - affects which topics Claude explores
124
123
  depth_preference: DiscoveryDepth.optional(),
125
124
  // Last activity timestamp for continuous discovery
@@ -199,12 +198,13 @@ var EpicSchema = z.object({
199
198
  coverage: z.number().default(0)
200
199
  })
201
200
  });
201
+ var StoryType = z.enum(["feature", "bug", "chore", "spike"]);
202
202
  var StorySchema = z.object({
203
203
  id: z.string(),
204
204
  // E1.S1, E1.S2, etc.
205
205
  title: z.string(),
206
206
  description: z.string(),
207
- type: z.enum(["feature", "bug", "chore", "spike"]),
207
+ type: StoryType,
208
208
  requirements: z.array(z.string()).default([]),
209
209
  // E1.R1, E1.R2, etc.
210
210
  acceptance_criteria: z.array(z.string()).default([]),
@@ -215,6 +215,31 @@ var StorySchema = z.object({
215
215
  assignee: z.string().nullable().default(null),
216
216
  blocked_reason: z.string().optional()
217
217
  });
218
+ var StoryInputSchema = z.object({
219
+ id: z.string().optional(),
220
+ // Auto-generated if not provided
221
+ title: z.string().min(1, "Story title is required"),
222
+ description: z.string().min(1, "Story description is required"),
223
+ type: StoryType.default("feature"),
224
+ requirements: z.array(z.string()).default([]),
225
+ acceptance_criteria: z.array(z.string()).default([]).transform(
226
+ (arr) => (
227
+ // Also accept 'criteria' as alias
228
+ arr
229
+ )
230
+ ),
231
+ criteria: z.array(z.string()).optional(),
232
+ // Alias for acceptance_criteria
233
+ dependencies: z.array(z.string()).default([]),
234
+ estimated_points: z.number().optional(),
235
+ status: StoryStatus.default("todo"),
236
+ assignee: z.string().nullable().default(null),
237
+ blocked_reason: z.string().optional()
238
+ }).transform((data) => {
239
+ const acceptance_criteria = data.criteria?.length ? [...data.acceptance_criteria, ...data.criteria] : data.acceptance_criteria;
240
+ const { criteria, ...rest } = data;
241
+ return { ...rest, acceptance_criteria };
242
+ });
218
243
  var StoriesFileSchema = z.object({
219
244
  epic_id: z.string(),
220
245
  stories: z.array(StorySchema).default([]),
@@ -811,13 +836,13 @@ var StateManager = class {
811
836
  await this.writeStuckQueue({ stuck: [], resolved: [] });
812
837
  await this.writeFeedbackQueue({ feedback: [], incorporated: [] });
813
838
  await this.writeDiscoveryContext({
839
+ users: [],
814
840
  values: [],
815
841
  success_criteria: []
816
842
  });
817
843
  await this.writeConstraints({ constraints: [] });
818
844
  await this.writeDiscoveryHistory({
819
- entries: [],
820
- is_complete: false
845
+ entries: []
821
846
  });
822
847
  await this.writeMilestoneIndex({ milestones: [] });
823
848
  const defaultConfig = {
@@ -894,8 +919,8 @@ var StateManager = class {
894
919
  async readDiscoveryHistory() {
895
920
  return this.adapter.readJson(PATHS.discovery.history, DiscoveryHistorySchema);
896
921
  }
897
- async writeDiscoveryHistory(history) {
898
- await this.adapter.writeJson(PATHS.discovery.history, history);
922
+ async writeDiscoveryHistory(history2) {
923
+ await this.adapter.writeJson(PATHS.discovery.history, history2);
899
924
  }
900
925
  // --------------------------------------------------------------------------
901
926
  // Milestones
@@ -1299,11 +1324,11 @@ function success(data, sections = [], aiGuidance) {
1299
1324
  aiGuidance
1300
1325
  };
1301
1326
  }
1302
- function error(message, code, data = null) {
1327
+ function error(message, code, sections) {
1303
1328
  return {
1304
1329
  status: "error",
1305
- data,
1306
- sections: [{ type: "text", content: message, style: "error" }],
1330
+ data: null,
1331
+ sections: sections ?? [{ type: "text", content: message, style: "error" }],
1307
1332
  error: message,
1308
1333
  errorCode: code
1309
1334
  };
@@ -1741,10 +1766,231 @@ function getHowGuidance(storyId, hasArchitecture) {
1741
1766
  );
1742
1767
  }
1743
1768
 
1769
+ // src/core/prompts/discovery.ts
1770
+ function getDiscoveryGuidance(context2, _history, constraints, depth, gaps, justInitialized) {
1771
+ const hasGaps = gaps.length > 0;
1772
+ const hasSomeContext = !!context2?.problem || !!context2?.vision;
1773
+ let situation;
1774
+ if (justInitialized) {
1775
+ situation = "Project initialized, starting discovery";
1776
+ } else if (!hasSomeContext) {
1777
+ situation = "Discovery starting - no context gathered yet";
1778
+ } else if (hasGaps) {
1779
+ situation = `Discovery in progress (${depth} depth) - gaps in: ${gaps.join(", ")}`;
1780
+ } else {
1781
+ situation = "Discovery has sufficient context - ready to move to planning when you are";
1782
+ }
1783
+ const instructions = [];
1784
+ if (!hasSomeContext) {
1785
+ instructions.push("Start a discovery conversation to deeply understand the project");
1786
+ instructions.push("Capture the problem domain, users, values, and constraints");
1787
+ instructions.push(`Ask the user: "${getStarterQuestion(gaps[0] || "problem")}"`);
1788
+ instructions.push("If this is an existing codebase, briefly acknowledge what you learned (1-2 sentences), then ask the question");
1789
+ instructions.push("Focus on understanding, not on what to build next");
1790
+ } else {
1791
+ instructions.push("Continue the discovery conversation naturally");
1792
+ instructions.push("Run 'lisa status context' first to review what's been discovered so far");
1793
+ instructions.push("Run 'lisa discover history' to see all Q&A entries recorded");
1794
+ }
1795
+ instructions.push("Ask follow-up questions based on user's answers");
1796
+ instructions.push("For short answers on important topics, probe deeper");
1797
+ instructions.push("For detailed answers, acknowledge and move on");
1798
+ if (gaps.includes("other")) {
1799
+ instructions.push("For research/benchmarks: use web search to find competitors and best practices");
1800
+ }
1801
+ instructions.push("Record key insights as you go");
1802
+ instructions.push(
1803
+ "When user indicates what they want to do next (plan, add milestones/epics, continue discovery, etc.), follow their lead"
1804
+ );
1805
+ const commands = [
1806
+ {
1807
+ command: "discover add-entry",
1808
+ args: "--category <cat> --question '<q>' --answer '<a>'",
1809
+ description: "Record a discovery insight",
1810
+ when: "After gathering important context"
1811
+ },
1812
+ {
1813
+ command: "plan milestones",
1814
+ description: "View/create milestones",
1815
+ when: "When user wants to structure work"
1816
+ },
1817
+ {
1818
+ command: "plan add-milestone",
1819
+ args: "--name '<name>' --description '<desc>'",
1820
+ description: "Add a milestone directly",
1821
+ when: "When user has a specific milestone in mind"
1822
+ },
1823
+ {
1824
+ command: "discover --deep",
1825
+ description: "Switch to deep discovery",
1826
+ when: "If user wants more thorough exploration"
1827
+ },
1828
+ {
1829
+ command: "discover --quick",
1830
+ description: "Switch to quick discovery",
1831
+ when: "If user wants to move faster"
1832
+ }
1833
+ ];
1834
+ return {
1835
+ situation,
1836
+ instructions,
1837
+ commands,
1838
+ context: {
1839
+ depth,
1840
+ gaps,
1841
+ // Full discovery context so AI knows what's been learned
1842
+ discovery: context2 ? {
1843
+ problem: context2.problem,
1844
+ vision: context2.vision,
1845
+ values: context2.values,
1846
+ successCriteria: context2.success_criteria
1847
+ } : null,
1848
+ constraints: constraints?.constraints || []
1849
+ }
1850
+ };
1851
+ }
1852
+ function getStarterQuestion(category) {
1853
+ const starters = {
1854
+ problem: "What problem are we solving?",
1855
+ vision: "What does the ideal end state look like?",
1856
+ users: "Who are the primary users?",
1857
+ values: "What's the most important quality this solution must have?",
1858
+ constraints: "What's your current tech stack and team setup?",
1859
+ success: "How will we know if this is successful?",
1860
+ other: "What existing solutions have you looked at?"
1861
+ };
1862
+ return starters[category] || starters.problem;
1863
+ }
1864
+ function getAddEntryGuidance() {
1865
+ return {
1866
+ situation: "Discovery entry recorded",
1867
+ instructions: [
1868
+ "Continue the conversation naturally based on what user wants",
1869
+ "You can: continue discovery, move to planning, add milestones/epics, or follow user's lead"
1870
+ ],
1871
+ commands: [
1872
+ {
1873
+ command: "discover add-entry",
1874
+ args: "--category <cat> --question '<q>' --answer '<a>'",
1875
+ description: "Record another insight",
1876
+ when: "After gathering context"
1877
+ },
1878
+ {
1879
+ command: "plan milestones",
1880
+ description: "View/create milestones",
1881
+ when: "When ready to structure work"
1882
+ },
1883
+ {
1884
+ command: "plan add-milestone",
1885
+ args: "--name '<name>' --description '<desc>'",
1886
+ description: "Add milestone directly",
1887
+ when: "When user has specific milestone"
1888
+ }
1889
+ ]
1890
+ };
1891
+ }
1892
+ var EPIC_DISCOVERY_QUESTIONS = [
1893
+ { id: "problem", question: "What problem does this epic solve?", required: true },
1894
+ { id: "scope", question: "What's in scope for this epic?", required: true },
1895
+ { id: "out_of_scope", question: "What's explicitly out of scope?", required: false },
1896
+ { id: "constraints", question: "Are there any technical constraints specific to this epic?", required: false },
1897
+ { id: "success", question: "What does success look like for this epic?", required: true }
1898
+ ];
1899
+ var MILESTONE_DISCOVERY_QUESTIONS = [
1900
+ { id: "goal", question: "What's the goal of this milestone?", required: true },
1901
+ { id: "done", question: "What does 'done' look like for this milestone?", required: true },
1902
+ { id: "dependencies", question: "Are there any dependencies or blockers for this milestone?", required: false }
1903
+ ];
1904
+ function getElementDiscoveryGuidance(elementType, elementName, discovery) {
1905
+ const questions = elementType === "epic" ? EPIC_DISCOVERY_QUESTIONS : MILESTONE_DISCOVERY_QUESTIONS;
1906
+ const answeredQuestions = new Set(discovery.history.map((e) => e.question));
1907
+ const remaining = questions.filter((q) => !answeredQuestions.has(q.question));
1908
+ const requiredRemaining = remaining.filter((q) => q.required);
1909
+ let situation;
1910
+ if (discovery.status === "complete") {
1911
+ situation = `${elementType} discovery complete for ${elementName}`;
1912
+ } else if (remaining.length === 0) {
1913
+ situation = `All questions answered for ${elementType} ${elementName}, ready to complete`;
1914
+ } else {
1915
+ situation = `${elementType} discovery in progress for ${elementName} - ${remaining.length} questions remaining`;
1916
+ }
1917
+ const instructions = [];
1918
+ if (discovery.status === "complete") {
1919
+ instructions.push("Discovery is complete. You can still add more context if needed.");
1920
+ } else {
1921
+ instructions.push("Ask the remaining questions conversationally, one at a time");
1922
+ instructions.push("Record answers using the add-entry command");
1923
+ if (remaining.length > 0) {
1924
+ instructions.push(`Start with: "${remaining[0].question}"`);
1925
+ }
1926
+ if (remaining.length === 0) {
1927
+ instructions.push("All questions answered - complete the discovery");
1928
+ }
1929
+ }
1930
+ const commands = [
1931
+ {
1932
+ command: `discover add-element-entry`,
1933
+ args: `--element-type ${elementType} --element-id ${discovery.element_id} --category <cat> --question '<q>' --answer '<a>'`,
1934
+ description: "Record an answer",
1935
+ when: "After getting an answer from the user"
1936
+ }
1937
+ ];
1938
+ if (remaining.length === 0 && discovery.status !== "complete") {
1939
+ commands.push({
1940
+ command: `discover complete-element`,
1941
+ args: `--element-type ${elementType} --element-id ${discovery.element_id}`,
1942
+ description: "Mark discovery complete",
1943
+ when: "When all required questions are answered"
1944
+ });
1945
+ }
1946
+ return {
1947
+ situation,
1948
+ instructions,
1949
+ commands,
1950
+ context: {
1951
+ elementType,
1952
+ elementId: discovery.element_id,
1953
+ remainingQuestions: remaining.map((q) => ({
1954
+ id: q.id,
1955
+ question: q.question,
1956
+ required: q.required
1957
+ })),
1958
+ gatheredContext: {
1959
+ problem: discovery.problem,
1960
+ scope: discovery.scope,
1961
+ outOfScope: discovery.out_of_scope,
1962
+ successCriteria: discovery.success_criteria,
1963
+ constraints: discovery.constraints.length
1964
+ }
1965
+ }
1966
+ };
1967
+ }
1968
+ function getNotInitializedGuidance() {
1969
+ return {
1970
+ situation: "No Lisa project found in this directory",
1971
+ instructions: [
1972
+ "Ask the user for a project name, then run 'discover init' to initialize"
1973
+ ],
1974
+ commands: [
1975
+ {
1976
+ command: "discover init",
1977
+ args: "{ name: '<project name>' }",
1978
+ description: "Initialize Lisa project",
1979
+ when: "After getting the project name from user"
1980
+ }
1981
+ ]
1982
+ };
1983
+ }
1984
+
1744
1985
  // src/core/commands/status.ts
1745
1986
  async function overview(state) {
1746
1987
  if (!await state.isInitialized()) {
1747
- return error("No Lisa project found. Run 'discover init' first.", "NOT_INITIALIZED");
1988
+ const sections2 = [
1989
+ section.info("No Lisa project found in this directory."),
1990
+ section.blank(),
1991
+ section.info("Run 'discover init' to start planning.")
1992
+ ];
1993
+ return success(null, sections2, getNotInitializedGuidance());
1748
1994
  }
1749
1995
  const project = await state.readProject();
1750
1996
  const index = await state.readMilestoneIndex();
@@ -2395,162 +2641,6 @@ async function how(state, options) {
2395
2641
  return success(data, sections, aiGuidance);
2396
2642
  }
2397
2643
 
2398
- // src/core/prompts/discovery.ts
2399
- function getDiscoveryGuidance(context2, history, _constraints, depth, gaps) {
2400
- const isComplete = history?.is_complete || false;
2401
- const hasGaps = gaps.length > 0;
2402
- const hasSomeContext = !!context2?.problem || !!context2?.vision;
2403
- let situation;
2404
- if (isComplete) {
2405
- situation = "Discovery complete, can continue anytime to add more context";
2406
- } else if (!hasSomeContext) {
2407
- situation = "Discovery starting - no context gathered yet";
2408
- } else if (hasGaps) {
2409
- situation = `Discovery in progress (${depth} depth) - gaps in: ${gaps.join(", ")}`;
2410
- } else {
2411
- situation = "Discovery in progress - sufficient context for current depth, consider completing";
2412
- }
2413
- const instructions = [];
2414
- if (!hasSomeContext) {
2415
- instructions.push("Start a natural conversation to understand the project");
2416
- instructions.push(`Ask about: "${getStarterQuestion(gaps[0] || "problem")}"`);
2417
- } else {
2418
- instructions.push("Continue the discovery conversation naturally");
2419
- }
2420
- instructions.push("Ask follow-up questions based on user's answers");
2421
- instructions.push("For short answers on important topics, probe deeper");
2422
- instructions.push("For detailed answers, acknowledge and move on");
2423
- if (gaps.includes("other")) {
2424
- instructions.push("For research/benchmarks: use web search to find competitors and best practices");
2425
- }
2426
- instructions.push("Record key insights as you go");
2427
- if (!hasGaps && !isComplete) {
2428
- instructions.push("Sufficient context gathered for this depth - suggest completing discovery");
2429
- }
2430
- const commands = [
2431
- {
2432
- command: "discover add-entry",
2433
- args: "--category <cat> --question '<q>' --answer '<a>'",
2434
- description: "Record a discovery insight",
2435
- when: "After gathering important context"
2436
- }
2437
- ];
2438
- if (!hasGaps || isComplete) {
2439
- commands.push({
2440
- command: "discover complete",
2441
- description: "Mark discovery as complete checkpoint",
2442
- when: "When sufficient context gathered"
2443
- });
2444
- }
2445
- commands.push({
2446
- command: "discover --deep",
2447
- description: "Switch to deep discovery",
2448
- when: "If user wants more thorough exploration"
2449
- });
2450
- commands.push({
2451
- command: "discover --quick",
2452
- description: "Switch to quick discovery",
2453
- when: "If user wants to move faster"
2454
- });
2455
- return {
2456
- situation,
2457
- instructions,
2458
- commands,
2459
- context: {
2460
- depth,
2461
- gaps
2462
- }
2463
- };
2464
- }
2465
- function getStarterQuestion(category) {
2466
- const starters = {
2467
- problem: "What problem are we solving?",
2468
- vision: "What does the ideal end state look like?",
2469
- users: "Who are the primary users?",
2470
- values: "What's the most important quality this solution must have?",
2471
- constraints: "What's your current tech stack and team setup?",
2472
- success: "How will we know if this is successful?",
2473
- other: "What existing solutions have you looked at?"
2474
- };
2475
- return starters[category] || starters.problem;
2476
- }
2477
- var EPIC_DISCOVERY_QUESTIONS = [
2478
- { id: "problem", question: "What problem does this epic solve?", required: true },
2479
- { id: "scope", question: "What's in scope for this epic?", required: true },
2480
- { id: "out_of_scope", question: "What's explicitly out of scope?", required: false },
2481
- { id: "constraints", question: "Are there any technical constraints specific to this epic?", required: false },
2482
- { id: "success", question: "What does success look like for this epic?", required: true }
2483
- ];
2484
- var MILESTONE_DISCOVERY_QUESTIONS = [
2485
- { id: "goal", question: "What's the goal of this milestone?", required: true },
2486
- { id: "done", question: "What does 'done' look like for this milestone?", required: true },
2487
- { id: "dependencies", question: "Are there any dependencies or blockers for this milestone?", required: false }
2488
- ];
2489
- function getElementDiscoveryGuidance(elementType, elementName, discovery) {
2490
- const questions = elementType === "epic" ? EPIC_DISCOVERY_QUESTIONS : MILESTONE_DISCOVERY_QUESTIONS;
2491
- const answeredQuestions = new Set(discovery.history.map((e) => e.question));
2492
- const remaining = questions.filter((q) => !answeredQuestions.has(q.question));
2493
- const requiredRemaining = remaining.filter((q) => q.required);
2494
- let situation;
2495
- if (discovery.status === "complete") {
2496
- situation = `${elementType} discovery complete for ${elementName}`;
2497
- } else if (remaining.length === 0) {
2498
- situation = `All questions answered for ${elementType} ${elementName}, ready to complete`;
2499
- } else {
2500
- situation = `${elementType} discovery in progress for ${elementName} - ${remaining.length} questions remaining`;
2501
- }
2502
- const instructions = [];
2503
- if (discovery.status === "complete") {
2504
- instructions.push("Discovery is complete. You can still add more context if needed.");
2505
- } else {
2506
- instructions.push("Ask the remaining questions conversationally, one at a time");
2507
- instructions.push("Record answers using the add-entry command");
2508
- if (remaining.length > 0) {
2509
- instructions.push(`Start with: "${remaining[0].question}"`);
2510
- }
2511
- if (remaining.length === 0) {
2512
- instructions.push("All questions answered - complete the discovery");
2513
- }
2514
- }
2515
- const commands = [
2516
- {
2517
- command: `discover add-element-entry`,
2518
- args: `--element-type ${elementType} --element-id ${discovery.element_id} --category <cat> --question '<q>' --answer '<a>'`,
2519
- description: "Record an answer",
2520
- when: "After getting an answer from the user"
2521
- }
2522
- ];
2523
- if (remaining.length === 0 && discovery.status !== "complete") {
2524
- commands.push({
2525
- command: `discover complete-element`,
2526
- args: `--element-type ${elementType} --element-id ${discovery.element_id}`,
2527
- description: "Mark discovery complete",
2528
- when: "When all required questions are answered"
2529
- });
2530
- }
2531
- return {
2532
- situation,
2533
- instructions,
2534
- commands,
2535
- context: {
2536
- elementType,
2537
- elementId: discovery.element_id,
2538
- remainingQuestions: remaining.map((q) => ({
2539
- id: q.id,
2540
- question: q.question,
2541
- required: q.required
2542
- })),
2543
- gatheredContext: {
2544
- problem: discovery.problem,
2545
- scope: discovery.scope,
2546
- outOfScope: discovery.out_of_scope,
2547
- successCriteria: discovery.success_criteria,
2548
- constraints: discovery.constraints.length
2549
- }
2550
- }
2551
- };
2552
- }
2553
-
2554
2644
  // src/core/commands/discover.ts
2555
2645
  var DISCOVERY_GUIDANCE_DATA = [
2556
2646
  {
@@ -2660,37 +2750,32 @@ var DISCOVERY_GUIDANCE_DATA = [
2660
2750
  includedIn: ["standard", "deep"]
2661
2751
  }
2662
2752
  ];
2663
- var DISCOVERY_QUESTIONS = [
2664
- { id: "problem", category: "problem", question: "What problem are we solving?", required: true },
2665
- { id: "vision", category: "vision", question: "What does success look like?", required: true },
2666
- { id: "users", category: "users", question: "Who are the primary users?", required: false },
2667
- { id: "value1", category: "values", question: "What is the most important quality?", required: false },
2668
- { id: "success1", category: "success", question: "How will we know if this is successful?", required: true }
2669
- ];
2670
- function checkCategoryHasContent(category, context2, constraints) {
2753
+ function checkCategoryHasContent(category, context2, constraints, history2) {
2754
+ const hasHistoryEntry = history2?.entries.some((e) => e.category === category) || false;
2671
2755
  switch (category) {
2672
2756
  case "problem":
2673
- return !!context2?.problem;
2757
+ return !!context2?.problem || hasHistoryEntry;
2674
2758
  case "vision":
2675
- return !!context2?.vision;
2759
+ return !!context2?.vision || hasHistoryEntry;
2676
2760
  case "users":
2677
- return false;
2678
- // Stored in history
2761
+ return context2?.users && context2.users.length > 0 || hasHistoryEntry;
2679
2762
  case "values":
2680
- return context2?.values && context2.values.length > 0 || false;
2763
+ return context2?.values && context2.values.length > 0 || hasHistoryEntry;
2681
2764
  case "constraints":
2682
- return constraints?.constraints && constraints.constraints.length > 0 || false;
2765
+ return constraints?.constraints && constraints.constraints.length > 0 || hasHistoryEntry;
2683
2766
  case "success":
2684
- return context2?.success_criteria && context2.success_criteria.length > 0 || false;
2767
+ return context2?.success_criteria && context2.success_criteria.length > 0 || hasHistoryEntry;
2768
+ case "other":
2769
+ return hasHistoryEntry;
2685
2770
  default:
2686
2771
  return false;
2687
2772
  }
2688
2773
  }
2689
- function findDiscoveryGaps(context2, constraints, depth) {
2774
+ function findDiscoveryGaps(context2, constraints, history2, depth) {
2690
2775
  const gaps = [];
2691
2776
  const guidanceForDepth = DISCOVERY_GUIDANCE_DATA.filter((g) => g.includedIn.includes(depth));
2692
2777
  for (const guidance of guidanceForDepth) {
2693
- if (!checkCategoryHasContent(guidance.category, context2, constraints)) {
2778
+ if (!checkCategoryHasContent(guidance.category, context2, constraints, history2)) {
2694
2779
  gaps.push(guidance.category);
2695
2780
  }
2696
2781
  }
@@ -2715,6 +2800,7 @@ function createEmptyElementDiscovery(elementType, elementId, source) {
2715
2800
  }
2716
2801
  async function updateContextFromEntry(state, entry) {
2717
2802
  const context2 = await state.readDiscoveryContext() || {
2803
+ users: [],
2718
2804
  values: [],
2719
2805
  success_criteria: []
2720
2806
  };
@@ -2730,6 +2816,12 @@ async function updateContextFromEntry(state, entry) {
2730
2816
  context2.gathered = now();
2731
2817
  await state.writeDiscoveryContext(context2);
2732
2818
  break;
2819
+ case "users":
2820
+ if (!context2.users) context2.users = [];
2821
+ context2.users.push(entry.answer);
2822
+ context2.gathered = now();
2823
+ await state.writeDiscoveryContext(context2);
2824
+ break;
2733
2825
  case "values":
2734
2826
  const valueId = `V${context2.values.length + 1}`;
2735
2827
  const value = {
@@ -2778,28 +2870,10 @@ async function init(state, options) {
2778
2870
  const projectName = options.name || "Untitled Project";
2779
2871
  const project = await state.initialize(projectName);
2780
2872
  const sections = [
2781
- section.header("Initializing Lisa"),
2782
- section.success(`Created .lisa/ directory`),
2783
- section.success(`Project: ${project.name}`),
2784
- section.success(`ID: ${project.id}`),
2785
- section.blank(),
2786
- section.info("Next step: Run discovery to gather project context")
2873
+ section.success(`Lisa initialized: ${project.name}`)
2787
2874
  ];
2788
- const aiGuidance = {
2789
- situation: "Project initialized, ready to start discovery",
2790
- instructions: [
2791
- "Start a natural discovery conversation to gather project context",
2792
- "Ask about the problem being solved, vision, constraints, and success criteria",
2793
- "Keep it conversational - don't list upcoming steps or announce what you'll do"
2794
- ],
2795
- commands: [
2796
- {
2797
- command: "discover",
2798
- description: "Start or continue discovery conversation",
2799
- when: "To gather project context"
2800
- }
2801
- ]
2802
- };
2875
+ const defaultGaps = ["problem", "vision", "users", "values", "constraints", "success"];
2876
+ const aiGuidance = getDiscoveryGuidance(null, null, null, "standard", defaultGaps, true);
2803
2877
  return success({ project: { id: project.id, name: project.name } }, sections, aiGuidance);
2804
2878
  }
2805
2879
  async function status(state) {
@@ -2808,87 +2882,122 @@ async function status(state) {
2808
2882
  }
2809
2883
  const context2 = await state.readDiscoveryContext();
2810
2884
  const constraints = await state.readConstraints();
2811
- const history = await state.readDiscoveryHistory();
2812
- const answeredQuestions = new Set(history?.entries.map((e) => e.question) || []);
2813
- const requiredQuestions = DISCOVERY_QUESTIONS.filter((q) => q.required);
2814
- const answeredRequired = requiredQuestions.filter(
2815
- (q) => answeredQuestions.has(q.question)
2816
- ).length;
2885
+ const history2 = await state.readDiscoveryHistory();
2886
+ const coreCategories = [
2887
+ "problem",
2888
+ "vision",
2889
+ "users",
2890
+ "values",
2891
+ "constraints",
2892
+ "success"
2893
+ ];
2894
+ const completedCategories = coreCategories.filter(
2895
+ (cat) => checkCategoryHasContent(cat, context2, constraints, history2)
2896
+ );
2817
2897
  const progress = {
2818
- answeredRequired,
2819
- totalRequired: requiredQuestions.length,
2820
- percent: requiredQuestions.length > 0 ? Math.round(answeredRequired / requiredQuestions.length * 100) : 0
2898
+ answeredRequired: completedCategories.length,
2899
+ totalRequired: coreCategories.length,
2900
+ percent: Math.round(completedCategories.length / coreCategories.length * 100)
2821
2901
  };
2822
2902
  const data = {
2823
2903
  context: context2,
2824
2904
  constraints,
2825
- history,
2826
- progress,
2827
- isComplete: history?.is_complete || false
2905
+ history: history2,
2906
+ progress
2828
2907
  };
2829
2908
  const sections = [
2830
2909
  section.header("Discovery Status"),
2831
2910
  section.subheader("Progress"),
2832
- section.progress(progress.answeredRequired, progress.totalRequired, "Required questions"),
2911
+ section.progress(progress.answeredRequired, progress.totalRequired, "Core categories"),
2833
2912
  section.blank(),
2834
2913
  section.subheader("Context Gathered")
2835
2914
  ];
2836
- if (context2?.problem) {
2837
- sections.push(section.success(`Problem: ${context2.problem.slice(0, 60)}...`));
2915
+ if (checkCategoryHasContent("problem", context2, constraints, history2)) {
2916
+ sections.push(section.success(`Problem: ${context2?.problem?.slice(0, 60) || "(in history)"}${context2?.problem && context2.problem.length > 60 ? "..." : ""}`));
2838
2917
  } else {
2839
2918
  sections.push(section.dim(" Problem: Not yet defined"));
2840
2919
  }
2841
- if (context2?.vision) {
2842
- sections.push(section.success(`Vision: ${context2.vision.slice(0, 60)}...`));
2920
+ if (checkCategoryHasContent("vision", context2, constraints, history2)) {
2921
+ sections.push(section.success(`Vision: ${context2?.vision?.slice(0, 60) || "(in history)"}${context2?.vision && context2.vision.length > 60 ? "..." : ""}`));
2843
2922
  } else {
2844
2923
  sections.push(section.dim(" Vision: Not yet defined"));
2845
2924
  }
2846
- if (context2?.values && context2.values.length > 0) {
2847
- sections.push(section.success(`Values: ${context2.values.length} defined`));
2925
+ if (checkCategoryHasContent("users", context2, constraints, history2)) {
2926
+ sections.push(section.success(`Users: ${context2?.users?.length || 0} defined`));
2927
+ } else {
2928
+ sections.push(section.dim(" Users: None defined"));
2929
+ }
2930
+ if (checkCategoryHasContent("values", context2, constraints, history2)) {
2931
+ sections.push(section.success(`Values: ${context2?.values?.length || 0} defined`));
2848
2932
  } else {
2849
2933
  sections.push(section.dim(" Values: None defined"));
2850
2934
  }
2851
- if (context2?.success_criteria && context2.success_criteria.length > 0) {
2852
- sections.push(section.success(`Success Criteria: ${context2.success_criteria.length} defined`));
2935
+ if (checkCategoryHasContent("success", context2, constraints, history2)) {
2936
+ sections.push(section.success(`Success Criteria: ${context2?.success_criteria?.length || 0} defined`));
2853
2937
  } else {
2854
2938
  sections.push(section.dim(" Success Criteria: None defined"));
2855
2939
  }
2856
2940
  sections.push(section.blank());
2857
2941
  sections.push(section.subheader("Constraints"));
2858
- if (constraints?.constraints && constraints.constraints.length > 0) {
2859
- for (const c of constraints.constraints) {
2942
+ if (checkCategoryHasContent("constraints", context2, constraints, history2)) {
2943
+ for (const c of constraints?.constraints || []) {
2860
2944
  sections.push(section.text(` [${c.type}] ${c.constraint}`));
2861
2945
  }
2862
2946
  } else {
2863
2947
  sections.push(section.dim(" No constraints defined"));
2864
2948
  }
2865
2949
  sections.push(section.blank());
2866
- if (history?.is_complete) {
2867
- sections.push(section.success("Discovery is COMPLETE"));
2950
+ const hasContext = checkCategoryHasContent("problem", context2, constraints, history2) || checkCategoryHasContent("vision", context2, constraints, history2);
2951
+ if (hasContext && progress.percent >= 50) {
2952
+ sections.push(section.success("Ready for planning - or continue adding context"));
2868
2953
  } else {
2869
- sections.push(section.warning("Discovery is INCOMPLETE"));
2954
+ sections.push(section.info("Continue discovery to gather more context"));
2870
2955
  }
2871
2956
  return success(data, sections);
2872
2957
  }
2958
+ async function history(state) {
2959
+ if (!await state.isInitialized()) {
2960
+ return error("No Lisa project found.", "NOT_INITIALIZED");
2961
+ }
2962
+ const historyData = await state.readDiscoveryHistory();
2963
+ const entries = historyData?.entries || [];
2964
+ const sections = [
2965
+ section.header("Discovery History"),
2966
+ section.info(`${entries.length} entries recorded`),
2967
+ section.blank()
2968
+ ];
2969
+ if (entries.length === 0) {
2970
+ sections.push(section.dim("No discovery entries yet. Run 'lisa discover' to start."));
2971
+ } else {
2972
+ for (const entry of entries) {
2973
+ const date = new Date(entry.timestamp).toLocaleDateString();
2974
+ sections.push(section.subheader(`[${entry.category}] ${date}`));
2975
+ sections.push(section.dim(` Q: ${entry.question}`));
2976
+ sections.push(section.text(` A: ${entry.answer}`));
2977
+ sections.push(section.blank());
2978
+ }
2979
+ }
2980
+ return success({ entries, count: entries.length }, sections);
2981
+ }
2873
2982
  async function start(state, options = {}) {
2874
2983
  if (!await state.isInitialized()) {
2875
2984
  return error("No Lisa project found. Run 'discover init' first.", "NOT_INITIALIZED");
2876
2985
  }
2877
- const history = await state.readDiscoveryHistory();
2986
+ const history2 = await state.readDiscoveryHistory();
2878
2987
  const context2 = await state.readDiscoveryContext();
2879
2988
  const constraints = await state.readConstraints();
2880
- const depth = options.depth || history?.depth_preference || "standard";
2881
- if (options.depth && history && history.depth_preference !== options.depth) {
2882
- history.depth_preference = options.depth;
2883
- history.last_active = now();
2884
- await state.writeDiscoveryHistory(history);
2989
+ const depth = options.depth || history2?.depth_preference || "standard";
2990
+ if (options.depth && history2 && history2.depth_preference !== options.depth) {
2991
+ history2.depth_preference = options.depth;
2992
+ history2.last_active = now();
2993
+ await state.writeDiscoveryHistory(history2);
2885
2994
  }
2886
- const gaps = findDiscoveryGaps(context2, constraints, depth);
2995
+ const gaps = findDiscoveryGaps(context2, constraints, history2, depth);
2887
2996
  const data = {
2888
2997
  depth,
2889
2998
  context: context2,
2890
2999
  constraints,
2891
- history,
3000
+ history: history2,
2892
3001
  gaps
2893
3002
  };
2894
3003
  const depthLabels = {
@@ -2937,7 +3046,7 @@ async function start(state, options = {}) {
2937
3046
  sections.push(section.blank());
2938
3047
  const guidanceForDepth = DISCOVERY_GUIDANCE_DATA.filter((g) => g.includedIn.includes(depth));
2939
3048
  for (const guidance of guidanceForDepth) {
2940
- const hasContent = checkCategoryHasContent(guidance.category, context2, constraints);
3049
+ const hasContent = checkCategoryHasContent(guidance.category, context2, constraints, history2);
2941
3050
  const icon = hasContent ? "\u2713" : "\u25CB";
2942
3051
  const statusText = hasContent ? "(has content)" : "(explore this)";
2943
3052
  sections.push(section.text(` ${icon} [${guidance.category}] ${guidance.purpose} ${statusText}`));
@@ -2949,16 +3058,16 @@ async function start(state, options = {}) {
2949
3058
  sections.push(section.blank());
2950
3059
  sections.push(section.divider());
2951
3060
  sections.push(section.blank());
2952
- const aiGuidance = getDiscoveryGuidance(context2, history, constraints, depth, gaps);
3061
+ const aiGuidance = getDiscoveryGuidance(context2, history2, constraints, depth, gaps);
2953
3062
  return success(data, sections, aiGuidance);
2954
3063
  }
2955
3064
  async function addEntry(state, options) {
2956
3065
  if (!await state.isInitialized()) {
2957
3066
  return error("No Lisa project found.", "NOT_INITIALIZED");
2958
3067
  }
2959
- let history = await state.readDiscoveryHistory();
2960
- if (!history) {
2961
- history = { entries: [], is_complete: false };
3068
+ let history2 = await state.readDiscoveryHistory();
3069
+ if (!history2) {
3070
+ history2 = { entries: [] };
2962
3071
  }
2963
3072
  const entry = {
2964
3073
  timestamp: now(),
@@ -2966,56 +3075,17 @@ async function addEntry(state, options) {
2966
3075
  answer: options.answer,
2967
3076
  category: options.category
2968
3077
  };
2969
- history.entries.push(entry);
2970
- if (!history.started) {
2971
- history.started = now();
3078
+ history2.entries.push(entry);
3079
+ if (!history2.started) {
3080
+ history2.started = now();
2972
3081
  }
2973
- history.last_active = now();
2974
- await state.writeDiscoveryHistory(history);
3082
+ history2.last_active = now();
3083
+ await state.writeDiscoveryHistory(history2);
2975
3084
  await updateContextFromEntry(state, entry);
2976
3085
  const sections = [
2977
3086
  section.success(`Added ${options.category} entry`)
2978
3087
  ];
2979
- return success({ entry }, sections);
2980
- }
2981
- async function complete(state) {
2982
- if (!await state.isInitialized()) {
2983
- return error("No Lisa project found.", "NOT_INITIALIZED");
2984
- }
2985
- const history = await state.readDiscoveryHistory();
2986
- if (!history) {
2987
- return error("No discovery history found.", "NO_HISTORY");
2988
- }
2989
- history.is_complete = true;
2990
- history.completed = now();
2991
- history.last_active = now();
2992
- await state.writeDiscoveryHistory(history);
2993
- const sections = [
2994
- section.success("Discovery checkpoint saved!"),
2995
- section.blank(),
2996
- section.info("You can continue discovery anytime with: discover"),
2997
- section.info("Next step: Generate milestones with 'plan milestones'")
2998
- ];
2999
- const aiGuidance = {
3000
- situation: "Discovery marked complete, ready for milestone planning",
3001
- instructions: [
3002
- "Discovery is complete but can be continued anytime",
3003
- "Next step is to generate milestones based on discovery context"
3004
- ],
3005
- commands: [
3006
- {
3007
- command: "plan milestones",
3008
- description: "Generate milestones from discovery",
3009
- when: "To create the project roadmap"
3010
- },
3011
- {
3012
- command: "discover",
3013
- description: "Continue adding discovery context",
3014
- when: "If more context is needed"
3015
- }
3016
- ]
3017
- };
3018
- return success({ completed: true }, sections, aiGuidance);
3088
+ return success({ entry }, sections, getAddEntryGuidance());
3019
3089
  }
3020
3090
  async function findEpicByIdOrSlug(state, epicIdOrSlug) {
3021
3091
  const epicDirs = await state.listEpicDirs();
@@ -3455,6 +3525,30 @@ function getStoriesGuidance(ctx) {
3455
3525
  }
3456
3526
  };
3457
3527
  }
3528
+ function getAddEpicGuidance(epicId) {
3529
+ return {
3530
+ situation: `Epic ${epicId} created, ready for discovery or PRD`,
3531
+ instructions: [
3532
+ "Ask user if they want to run discovery for this epic",
3533
+ "Discovery helps gather scope, constraints, and success criteria",
3534
+ "If they skip, proceed directly to PRD generation"
3535
+ ],
3536
+ commands: [
3537
+ {
3538
+ command: "discover element",
3539
+ args: `{ elementType: 'epic', elementId: '${epicId}' }`,
3540
+ description: "Run epic discovery",
3541
+ when: "To gather more context before PRD"
3542
+ },
3543
+ {
3544
+ command: "plan epic",
3545
+ args: epicId,
3546
+ description: "Plan epic (PRD generation)",
3547
+ when: "To skip discovery and proceed to PRD"
3548
+ }
3549
+ ]
3550
+ };
3551
+ }
3458
3552
 
3459
3553
  // src/core/commands/plan.ts
3460
3554
  async function showMilestones(state) {
@@ -3463,11 +3557,10 @@ async function showMilestones(state) {
3463
3557
  }
3464
3558
  const index = await state.readMilestoneIndex();
3465
3559
  const context2 = await state.readDiscoveryContext();
3466
- const history = await state.readDiscoveryHistory();
3467
- const discoveryComplete = history?.is_complete || false;
3468
3560
  const sections = [section.header("Milestones")];
3469
- if (!discoveryComplete) {
3470
- sections.push(section.warning("Discovery is not complete. Complete discovery first."));
3561
+ const hasContext = !!context2?.problem || !!context2?.vision;
3562
+ if (!hasContext) {
3563
+ sections.push(section.warning("No discovery context found. Run discovery first."));
3471
3564
  sections.push(section.dim(" Run: discover"));
3472
3565
  return success(
3473
3566
  {
@@ -3709,29 +3802,7 @@ async function addEpic(state, options) {
3709
3802
  section.blank(),
3710
3803
  section.info("Next: Run discovery for this epic or proceed to PRD")
3711
3804
  ];
3712
- const aiGuidance = {
3713
- situation: `Epic ${epicId} created, ready for discovery or PRD`,
3714
- instructions: [
3715
- "Ask user if they want to run discovery for this epic",
3716
- "Discovery helps gather scope, constraints, and success criteria",
3717
- "If they skip, proceed directly to PRD generation"
3718
- ],
3719
- commands: [
3720
- {
3721
- command: "discover element",
3722
- args: `{ elementType: 'epic', elementId: '${epicId}' }`,
3723
- description: "Run epic discovery",
3724
- when: "To gather more context before PRD"
3725
- },
3726
- {
3727
- command: "plan epic",
3728
- args: epicId,
3729
- description: "Plan epic (PRD generation)",
3730
- when: "To skip discovery and proceed to PRD"
3731
- }
3732
- ]
3733
- };
3734
- return success({ epic }, sections, aiGuidance);
3805
+ return success({ epic }, sections, getAddEpicGuidance(epicId));
3735
3806
  }
3736
3807
  async function planEpic(state, options) {
3737
3808
  if (!await state.isInitialized()) {
@@ -3983,15 +4054,39 @@ async function saveStories(state, options) {
3983
4054
  if (!epicDir) {
3984
4055
  return error(`Epic ${options.epicId} not found.`, "NOT_FOUND");
3985
4056
  }
4057
+ const validatedStories = [];
4058
+ const validationErrors = [];
4059
+ for (let i = 0; i < options.stories.length; i++) {
4060
+ const storyInput = options.stories[i];
4061
+ const result = StoryInputSchema.safeParse(storyInput);
4062
+ if (!result.success) {
4063
+ const issues = result.error.issues.map((issue) => {
4064
+ const path3 = issue.path.length > 0 ? `${issue.path.join(".")}: ` : "";
4065
+ return `${path3}${issue.message}`;
4066
+ });
4067
+ validationErrors.push(`Story ${i + 1} (${storyInput.title || "untitled"}): ${issues.join(", ")}`);
4068
+ } else {
4069
+ const story2 = {
4070
+ ...result.data,
4071
+ id: result.data.id || `${options.epicId}.S${i + 1}`
4072
+ };
4073
+ validatedStories.push(story2);
4074
+ }
4075
+ }
4076
+ if (validationErrors.length > 0) {
4077
+ const sections2 = [
4078
+ section.error("Story validation failed:"),
4079
+ ...validationErrors.map((err) => section.dim(` \u2022 ${err}`)),
4080
+ section.blank(),
4081
+ section.info("Required fields: title, description"),
4082
+ section.info("Optional fields: type (feature|bug|chore|spike), requirements, criteria, dependencies")
4083
+ ];
4084
+ return error(validationErrors.join("\n"), "VALIDATION_ERROR", sections2);
4085
+ }
3986
4086
  const slug = epicDir.split("-").slice(1).join("-");
3987
4087
  const storiesFile = {
3988
4088
  epic_id: options.epicId,
3989
- stories: options.stories.map((s, i) => ({
3990
- ...s,
3991
- id: s.id || `${options.epicId}.S${i + 1}`,
3992
- status: s.status || "todo",
3993
- assignee: s.assignee || null
3994
- })),
4089
+ stories: validatedStories,
3995
4090
  coverage: {},
3996
4091
  validation: {
3997
4092
  coverage_complete: false,
@@ -5438,10 +5533,6 @@ var LisaEngine = class {
5438
5533
  * Add a discovery entry
5439
5534
  */
5440
5535
  addEntry: (options) => addEntry(this.state, options),
5441
- /**
5442
- * Mark discovery as complete
5443
- */
5444
- complete: () => complete(this.state),
5445
5536
  /**
5446
5537
  * Show discovery status
5447
5538
  */
@@ -5457,7 +5548,11 @@ var LisaEngine = class {
5457
5548
  /**
5458
5549
  * Complete element discovery
5459
5550
  */
5460
- completeElement: (options) => completeElement(this.state, options)
5551
+ completeElement: (options) => completeElement(this.state, options),
5552
+ /**
5553
+ * Show discovery history (all Q&A entries)
5554
+ */
5555
+ history: () => history(this.state)
5461
5556
  };
5462
5557
  // ==========================================================================
5463
5558
  // Plan Commands
@@ -5901,7 +5996,7 @@ function showDiscoverHelp() {
5901
5996
  console.log(" (none) Start or continue discovery session");
5902
5997
  console.log(" init <name> Initialize a new project");
5903
5998
  console.log(" status Show discovery progress and gaps");
5904
- console.log(" complete Mark discovery phase as complete");
5999
+ console.log(" history Show all discovery Q&A entries");
5905
6000
  console.log(" add-entry Add a discovery entry (project-level)");
5906
6001
  console.log(" epic <id> Start discovery for a specific epic");
5907
6002
  console.log(" milestone <id> Start discovery for a milestone");
@@ -6187,8 +6282,8 @@ async function main() {
6187
6282
  handleResult(result);
6188
6283
  break;
6189
6284
  }
6190
- case "complete": {
6191
- const result = await engine.discover.complete();
6285
+ case "history": {
6286
+ const result = await engine.discover.history();
6192
6287
  handleResult(result);
6193
6288
  break;
6194
6289
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smartlisa",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "AI-powered planning system for Claude Code",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -8,58 +8,60 @@ user-invocable: true
8
8
 
9
9
  Plan and organize projects into milestones, epics, and stories.
10
10
 
11
+ ## Core Principles
12
+
13
+ 1. **Follow command output instructions.** Every Lisa command returns AI guidance with next steps. Read and follow them exactly.
14
+
15
+ 2. **Present before creating.** When the user describes work to be done:
16
+ - Summarize what you understood
17
+ - Propose the milestones, epics, or stories you plan to create
18
+ - Wait for user confirmation before running any `add-milestone`, `add-epic`, or `add-story` commands
19
+ - Never auto-create artifacts without explicit approval
20
+
11
21
  ## Quick Start
12
22
 
13
23
  ```bash
14
- # Check project status
24
+ # Check if project exists
15
25
  lisa status
16
26
 
17
- # Start a new project
27
+ # New project - get name first, then:
18
28
  lisa discover init "Project Name"
19
29
 
20
- # View the board
30
+ # View board
21
31
  lisa status board
22
32
  ```
23
33
 
24
- ## Workflow
25
-
26
- ### New Project
34
+ ## New Project Flow
27
35
 
28
- 1. **Ask for project name** - Confirm what they're building
29
- 2. **Initialize**: `lisa discover init "Project Name"`
30
- 3. **Check for existing code** - Read key files to understand patterns
31
- 4. **Discovery conversation** - Natural Q&A about problem, vision, constraints
32
- - For brownfield: suggest answers based on what you read
36
+ 1. Ask user for project name
37
+ 2. Run `lisa discover init "Project Name"`
38
+ 3. **Follow the INSTRUCTIONS section** in the output - it tells you what to do next
33
39
 
34
- ### Existing Project
40
+ ## Existing Project
35
41
 
36
- 1. **Check status**: `lisa status`
37
- 2. **View board**: `lisa status board`
38
- 3. **Add to plan** or **work on stories** as needed
42
+ 1. Run `lisa status` to see current state
43
+ 2. Follow the guidance in the output
39
44
 
40
- ## Commands Reference
45
+ ## Commands
41
46
 
42
47
  | Action | Command |
43
48
  |--------|---------|
44
- | Project overview | `lisa status` |
45
- | Kanban board | `lisa status board` |
46
- | Story details | `lisa status show <id>` |
47
- | Start discovery | `lisa discover init "Name"` |
49
+ | Status | `lisa status` |
50
+ | Board | `lisa status board` |
51
+ | Initialize | `lisa discover init "Name"` |
48
52
  | Continue discovery | `lisa discover` |
53
+ | Add discovery entry | `lisa discover add-entry --category <cat> --question '<q>' --answer '<a>'` |
49
54
  | View milestones | `lisa plan milestones` |
50
55
  | Add milestone | `lisa plan add-milestone --name 'Name' --description 'Desc'` |
51
56
  | Add epic | `lisa plan add-epic --milestone M1 --name 'Name' --description 'Desc'` |
52
57
  | Generate stories | `lisa plan stories E1` |
53
58
  | Mark progress | `lisa feedback mark <id> <status>` |
54
- | Validate plan | `lisa validate` |
55
59
 
56
60
  ## ID Formats
57
61
 
58
- | Type | Format | Example |
59
- |------|--------|---------|
60
- | Milestone | `M#` | `M1` |
61
- | Epic | `E#` | `E1` |
62
- | Story | `E#.S#` | `E1.S2` |
62
+ - Milestone: `M1`, `M2`
63
+ - Epic: `E1`, `E2`
64
+ - Story: `E1.S1`, `E1.S2`
63
65
 
64
66
  ## References
65
67
 
@@ -15,7 +15,7 @@ lisa discover [subcommand] [options]
15
15
  | *(none)* | Start or continue discovery session |
16
16
  | `init <name>` | Initialize new project |
17
17
  | `status` | Show discovery progress and gaps |
18
- | `complete` | Mark discovery phase complete |
18
+ | `history` | Show all discovery Q&A entries |
19
19
  | `add-entry` | Add discovery entry manually |
20
20
  | `epic <id>` | Start discovery for specific epic |
21
21
  | `milestone <id>` | Start discovery for milestone |
@@ -32,7 +32,7 @@ lisa discover [subcommand] [options]
32
32
 
33
33
  | Option | Description |
34
34
  |--------|-------------|
35
- | `--category <cat>` | Category: `problem`, `goals`, `users`, `constraints`, `scope`, `technical`, `risks`, `success` |
35
+ | `--category <cat>` | Category: `problem`, `vision`, `users`, `values`, `constraints`, `success`, `other` |
36
36
  | `--question '<q>'` | The discovery question |
37
37
  | `--answer '<a>'` | The answer/information |
38
38
 
@@ -9,77 +9,75 @@ User says: "Help me plan a todo app"
9
9
  ```bash
10
10
  # 1. Initialize the project
11
11
  lisa discover init "Todo App"
12
-
13
- # 2. Start discovery (ask about problem, users, goals)
14
- lisa discover
15
-
16
- # 3. Check discovery progress
17
- lisa discover status
18
-
19
- # 4. For comprehensive planning, use deep mode
20
- lisa discover --deep
12
+ # 2. Follow the INSTRUCTIONS in the output (it will tell you to ask discovery questions)
21
13
  ```
22
14
 
23
15
  **Key points:**
24
- - Always ask user for the project name before initializing
25
- - Discovery is iterative - run it multiple times to fill gaps
26
- - Check status to see what's missing
16
+ - Ask user for project name before initializing
17
+ - After init, follow the AI guidance in the command output
18
+ - The guidance will prompt you to start a discovery conversation
27
19
 
28
20
  ---
29
21
 
30
- ## Example 2: Brownfield Project (Existing Codebase)
22
+ ## Example 2: Existing Codebase
31
23
 
32
24
  User says: "Help me plan features for my existing app"
33
25
 
34
26
  ```bash
35
- # 1. Initialize with existing codebase
27
+ # 1. Initialize
36
28
  lisa discover init "My Existing App"
37
-
38
- # 2. Analyze the codebase first
39
- lisa discover codebase
40
-
41
- # 3. Continue with regular discovery
42
- lisa discover
29
+ # 2. Follow the INSTRUCTIONS - acknowledge what you learned, then ask discovery questions
43
30
  ```
44
31
 
45
32
  **Key points:**
46
- - Run `codebase` analysis before general discovery
47
- - This captures existing patterns, tech stack, and structure
33
+ - Briefly acknowledge what you learned from the codebase (1-2 sentences)
34
+ - Then ask the discovery question (e.g., "What problem are we solving?")
35
+ - Do NOT offer menu options - just ask the question
48
36
 
49
37
  ---
50
38
 
51
39
  ## Example 3: Creating the Roadmap
52
40
 
53
- User says: "Break this into milestones and epics"
54
-
41
+ User says: "I have some tickets related to knowledge improvements... need to edit digests, massage prompts..."
42
+
43
+ **Step 1: Summarize what you understood**
44
+ > "I understand you have work around Knowledge V1 MVP with several areas:
45
+ > - Editing knowledge evaluation digests
46
+ > - Prompt improvements for interview questions
47
+ > - New action set digests
48
+ > - Deprecating old digest sections
49
+ >
50
+ > Here's what I propose to create:
51
+ >
52
+ > **Milestone: Knowledge V1 MVP**
53
+ > - Epic 1: Digest Editing - ability to edit evaluation digests
54
+ > - Epic 2: Interview Question Improvements - prompt massage for focus
55
+ > - Epic 3: Action Set Digests - new digest type
56
+ > - Epic 4: Digest Cleanup - deprecate pre-arrival sections
57
+ >
58
+ > Does this structure look right? Any adjustments?"
59
+
60
+ **Step 2: Wait for user confirmation**
61
+
62
+ **Step 3: Only after approval, create the artifacts**
55
63
  ```bash
56
- # 1. Check discovery is sufficient
57
- lisa discover status
58
-
59
- # 2. Generate/view milestones
60
- lisa plan milestones
61
-
62
- # 3. Add milestones manually if needed
63
64
  lisa plan add-milestone \
64
- --name 'MVP' \
65
- --description 'Core todo CRUD functionality'
66
-
67
- lisa plan add-milestone \
68
- --name 'Collaboration' \
69
- --description 'Shared lists and real-time sync'
70
-
71
- # 4. Generate epics for milestone
72
- lisa plan epics M1
65
+ --name 'Knowledge V1 MVP' \
66
+ --description 'Core knowledge system improvements including digest editing and cleanup'
73
67
 
74
- # 5. Add epics manually if needed
75
68
  lisa plan add-epic \
76
69
  --milestone M1 \
77
- --name 'Task Management' \
78
- --description 'Create, edit, delete, complete tasks'
70
+ --name 'Digest Editing' \
71
+ --description 'Enable editing of knowledge evaluation digests'
72
+ # ... etc
79
73
  ```
80
74
 
81
75
  **Key points:**
82
- - Focus on one milestone at a time with `plan epics M1`
76
+ - **ALWAYS present proposed structure before creating**
77
+ - Summarize user's intent first
78
+ - List milestones and epics you plan to create
79
+ - Wait for explicit approval
80
+ - Never auto-create artifacts
83
81
 
84
82
  ---
85
83
 
@@ -73,6 +73,13 @@ lisa feedback mark E1.S2 blocked --reason "Describe the issue"
73
73
 
74
74
  **Important:** Never mark done without user confirmation.
75
75
 
76
+ ## Execution
77
+
78
+ Run Lisa commands with:
79
+ ```bash
80
+ lisa <command> # if installed globally
81
+ ```
82
+
76
83
  ## Commands Reference
77
84
 
78
85
  | Action | Command |