edsger 0.69.0 → 0.71.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.
Files changed (78) hide show
  1. package/dist/api/github.d.ts +1 -1
  2. package/dist/api/github.js +1 -1
  3. package/dist/commands/architecture-diagram/index.d.ts +8 -0
  4. package/dist/commands/architecture-diagram/index.js +10 -0
  5. package/dist/commands/class-diagram/index.d.ts +7 -0
  6. package/dist/commands/class-diagram/index.js +9 -0
  7. package/dist/commands/data-flow/index.d.ts +5 -5
  8. package/dist/commands/data-flow/index.js +8 -8
  9. package/dist/commands/diagram-shared/index.d.ts +21 -0
  10. package/dist/commands/diagram-shared/index.js +37 -0
  11. package/dist/commands/discover/index.d.ts +14 -0
  12. package/dist/commands/discover/index.js +29 -0
  13. package/dist/commands/er-diagram/index.d.ts +19 -0
  14. package/dist/commands/er-diagram/index.js +55 -0
  15. package/dist/commands/flowchart/index.d.ts +8 -0
  16. package/dist/commands/flowchart/index.js +10 -0
  17. package/dist/commands/screen-flow/index.d.ts +5 -5
  18. package/dist/commands/screen-flow/index.js +8 -8
  19. package/dist/commands/sequence-diagram/index.d.ts +19 -0
  20. package/dist/commands/sequence-diagram/index.js +55 -0
  21. package/dist/commands/state-diagram/index.d.ts +7 -0
  22. package/dist/commands/state-diagram/index.js +9 -0
  23. package/dist/index.js +139 -5
  24. package/dist/phases/architecture-diagram/index.d.ts +15 -0
  25. package/dist/phases/architecture-diagram/index.js +51 -0
  26. package/dist/phases/class-diagram/index.d.ts +14 -0
  27. package/dist/phases/class-diagram/index.js +76 -0
  28. package/dist/phases/data-flow/index.d.ts +2 -2
  29. package/dist/phases/data-flow/index.js +37 -37
  30. package/dist/phases/data-flow/mcp-server.d.ts +1 -1
  31. package/dist/phases/data-flow/mcp-server.js +2 -2
  32. package/dist/phases/data-flow/types.d.ts +1 -1
  33. package/dist/phases/data-flow/types.js +1 -1
  34. package/dist/phases/diagram-shared/clone-repos.d.ts +63 -0
  35. package/dist/phases/diagram-shared/clone-repos.js +153 -0
  36. package/dist/phases/diagram-shared/generate.d.ts +42 -0
  37. package/dist/phases/diagram-shared/generate.js +162 -0
  38. package/dist/phases/diagram-shared/graph.d.ts +62 -0
  39. package/dist/phases/diagram-shared/graph.js +169 -0
  40. package/dist/phases/diagram-shared/mcp.d.ts +35 -0
  41. package/dist/phases/diagram-shared/mcp.js +68 -0
  42. package/dist/phases/diagram-shared/prompts.d.ts +23 -0
  43. package/dist/phases/diagram-shared/prompts.js +35 -0
  44. package/dist/phases/discover-services/index.d.ts +29 -0
  45. package/dist/phases/discover-services/index.js +528 -0
  46. package/dist/phases/er-diagram/index.d.ts +28 -0
  47. package/dist/phases/er-diagram/index.js +290 -0
  48. package/dist/phases/er-diagram/mcp-server.d.ts +77 -0
  49. package/dist/phases/er-diagram/mcp-server.js +144 -0
  50. package/dist/phases/er-diagram/prompts.d.ts +14 -0
  51. package/dist/phases/er-diagram/prompts.js +36 -0
  52. package/dist/phases/er-diagram/types.d.ts +76 -0
  53. package/dist/phases/er-diagram/types.js +84 -0
  54. package/dist/phases/flowchart/index.d.ts +15 -0
  55. package/dist/phases/flowchart/index.js +50 -0
  56. package/dist/phases/output-contracts.js +178 -2
  57. package/dist/phases/screen-flow/index.d.ts +3 -3
  58. package/dist/phases/screen-flow/index.js +47 -45
  59. package/dist/phases/screen-flow/mcp-server.js +2 -2
  60. package/dist/phases/sequence-diagram/index.d.ts +30 -0
  61. package/dist/phases/sequence-diagram/index.js +290 -0
  62. package/dist/phases/sequence-diagram/mcp-server.d.ts +64 -0
  63. package/dist/phases/sequence-diagram/mcp-server.js +134 -0
  64. package/dist/phases/sequence-diagram/prompts.d.ts +14 -0
  65. package/dist/phases/sequence-diagram/prompts.js +36 -0
  66. package/dist/phases/sequence-diagram/types.d.ts +52 -0
  67. package/dist/phases/sequence-diagram/types.js +93 -0
  68. package/dist/phases/state-diagram/index.d.ts +15 -0
  69. package/dist/phases/state-diagram/index.js +53 -0
  70. package/dist/skills/phase/architecture-diagram/SKILL.md +41 -0
  71. package/dist/skills/phase/class-diagram/SKILL.md +44 -0
  72. package/dist/skills/phase/er-diagram/SKILL.md +71 -0
  73. package/dist/skills/phase/flowchart/SKILL.md +38 -0
  74. package/dist/skills/phase/sequence-diagram/SKILL.md +67 -0
  75. package/dist/skills/phase/state-diagram/SKILL.md +38 -0
  76. package/dist/workspace/session-workspace.d.ts +2 -2
  77. package/dist/workspace/session-workspace.js +2 -2
  78. package/package.json +1 -1
@@ -0,0 +1,15 @@
1
+ /**
2
+ * state-diagram phase: map a state machine — states + transitions — for a
3
+ * status lifecycle / workflow found in the code (status enums, XState
4
+ * machines, approval flows, etc.). Persisted to the diagrams tables with
5
+ * `type = 'state'`. Built on the shared diagram framework.
6
+ */
7
+ import { type DiagramPhaseResult } from '../diagram-shared/generate.js';
8
+ export interface StateDiagramPhaseOptions {
9
+ productId?: string;
10
+ repoId?: string;
11
+ diagramId: string;
12
+ guidance?: string;
13
+ verbose?: boolean;
14
+ }
15
+ export declare function runStateDiagramPhase(options: StateDiagramPhaseOptions): Promise<DiagramPhaseResult>;
@@ -0,0 +1,53 @@
1
+ /**
2
+ * state-diagram phase: map a state machine — states + transitions — for a
3
+ * status lifecycle / workflow found in the code (status enums, XState
4
+ * machines, approval flows, etc.). Persisted to the diagrams tables with
5
+ * `type = 'state'`. Built on the shared diagram framework.
6
+ */
7
+ import { z } from 'zod';
8
+ import { generateDiagram, } from '../diagram-shared/generate.js';
9
+ import { buildDiagramSystemPrompt, buildDiagramUserPrompt, } from '../diagram-shared/prompts.js';
10
+ const stateNode = z.object({
11
+ slug: z.string().min(1),
12
+ name: z.string().min(1),
13
+ kind: z.enum(['initial', 'state', 'final', 'choice', 'composite']),
14
+ file: z.string().optional(),
15
+ description: z.string().optional(),
16
+ onEntry: z.string().optional(),
17
+ onExit: z.string().optional(),
18
+ activity: z.string().optional(),
19
+ });
20
+ const stateEdge = z.object({
21
+ fromSlug: z.string().min(1),
22
+ toSlug: z.string().min(1),
23
+ kind: z.enum(['transition']),
24
+ /** trigger [guard] / action, e.g. "submit [valid] / persist()". */
25
+ label: z.string().optional(),
26
+ sourceFile: z.string().optional(),
27
+ });
28
+ export function runStateDiagramPhase(options) {
29
+ return generateDiagram({
30
+ ...options,
31
+ workspaceKey: 'state-diagram',
32
+ fenceName: 'state_diagram',
33
+ nounPlural: 'states',
34
+ edgeNounPlural: 'transitions',
35
+ mcpConfig: {
36
+ name: 'state-diagram',
37
+ toolName: 'state_diagram',
38
+ summaryDescribe: '1-3 sentence narrative of what this state machine models and its lifecycle.',
39
+ nodesSchema: z.array(stateNode),
40
+ nodesDescribe: 'Every state: initial / state / final / choice / composite. slug MUST be unique.',
41
+ edgesSchema: z.array(stateEdge),
42
+ edgesDescribe: 'Transitions. label carries "trigger [guard] / action". Every fromSlug / toSlug MUST reference a state slug.',
43
+ },
44
+ buildSystemPrompt: (a) => buildDiagramSystemPrompt('phase/state-diagram', 'state-diagram', a),
45
+ buildUserPrompt: (a) => buildDiagramUserPrompt({
46
+ ...a,
47
+ task: 'Map the primary state machine for',
48
+ mcpName: 'state-diagram',
49
+ toolName: 'state_diagram',
50
+ process: 'Find the most important stateful lifecycle in the code: a status enum + the code that transitions it (order status, approval/review state, job/task state, an XState/state-machine definition, a wizard). Pick ONE machine (guidance may name it). Read the transition sites to capture each transition\'s trigger, guard, and action. Include exactly one `initial` pseudostate and the `final` state(s).',
51
+ }),
52
+ });
53
+ }
@@ -0,0 +1,41 @@
1
+ ---
2
+ description: Map a product's high-level architecture — components/modules/services/datastores and their dependencies — into a component diagram
3
+ kind: phase
4
+ user-invocable: false
5
+ ---
6
+
7
+ You are a staff engineer reverse-engineering a product's **architecture** from source code. Your output is a structured graph the desktop app renders as a component / dependency diagram (C4 container/component level). You read the repo structure and code — not a running system.
8
+
9
+ **Components (nodes)** — each is `{ slug, name, kind, file?, description?, tech?, responsibilities? }`:
10
+
11
+ - `kind`: `ui` (front-end / app surface), `service` (a deployable backend / API / worker), `module` (an internal code module/layer), `package` (a workspace/library package), `datastore` (DB / cache / bucket / queue), `external` (third-party system or API)
12
+ - `tech`: framework / technology hint (`next.js`, `electron`, `postgres`, `stripe`)
13
+ - `responsibilities`: 1-4 short bullets of what it owns
14
+ - `file`: the directory or entry file that anchors it
15
+
16
+ **Dependencies (edges)** — each is `{ fromSlug, toSlug, kind, label?, sourceFile? }`. `fromSlug` is the depender:
17
+
18
+ - `depends-on` — generic dependency
19
+ - `calls` — runtime call (HTTP/RPC/IPC) to another component
20
+ - `imports` — code-level import dependency between modules/packages
21
+ - `data` — reads/writes a datastore or sends to a queue
22
+ - `label`: optional clarifier (`REST`, `reads`, `publishes`)
23
+
24
+ **Discipline**:
25
+
26
+ - Be grounded — every component maps to real code (a package, a service dir, a datastore client, a third-party SDK). No invented services.
27
+ - Operate at the right altitude: aim for ~10-25 components. Group leaf files into their owning module/package; do NOT draw a file-level import graph.
28
+ - Capture the boundaries that matter: app surfaces, backend services/functions, shared packages, datastores, and external systems.
29
+ - Deduplicate; one node per component.
30
+
31
+ **Process**:
32
+
33
+ <!-- if:hasCodebase -->
34
+ 1. Detect the top-level structure: monorepo workspaces / packages, top-level `src` dirs, deployment units (apps, services, edge functions), `package.json`/manifests.
35
+ 2. Create a component per meaningful unit with the right kind; identify datastores (DB clients, migrations, cache) and external systems (third-party SDKs/APIs).
36
+ 3. Wire dependencies from the import graph between packages/modules, cross-service calls, and datastore/external access.
37
+ 4. Compose the summary (what kind of system, its main building blocks).
38
+ <!-- endif -->
39
+ <!-- if:!hasCodebase -->
40
+ 5. Infer a reasonable architecture from the product description + guidance; say in the summary that it is inferred. Use concrete component names, no placeholders.
41
+ <!-- endif -->
@@ -0,0 +1,44 @@
1
+ ---
2
+ description: Map a codebase's core object-oriented types and their relationships into a UML class diagram
3
+ kind: phase
4
+ user-invocable: false
5
+ ---
6
+
7
+ You are a senior engineer reverse-engineering a **UML class diagram** from source code. Your output is a structured graph the desktop app renders as a class diagram. You read code — classes, interfaces, type definitions — and describe the types and how they relate.
8
+
9
+ **Types (nodes)** — each is `{ slug, name, kind, file?, description?, stereotype?, attributes?, methods? }`:
10
+
11
+ - `kind`: `class`, `interface`, `abstract` (abstract base class), `enum`
12
+ - `attributes`: `[{ name, type?, visibility?, isStatic? }]` — the defining fields (`visibility` ∈ public/private/protected)
13
+ - `methods`: `[{ name, params?, returnType?, visibility?, isStatic?, isAbstract? }]` — the key operations (`params` is a short signature string like `(id: string)`)
14
+ - `stereotype`: optional UML stereotype (`«service»`, `«entity»`, `«controller»`) if it clarifies the role
15
+ - You need not list EVERY member of large types — capture the ones that define the type's responsibility, and note the trim in the summary.
16
+
17
+ **Relationships (edges)** — each is `{ fromSlug, toSlug, kind, label?, sourceFile? }`. `fromSlug` is the child / owner / dependent side:
18
+
19
+ - `inheritance` — `extends` a class
20
+ - `implementation` — `implements` an interface
21
+ - `composition` — owns the lifecycle of the other (strong has-a)
22
+ - `aggregation` — holds a reference but doesn't own its lifecycle (weak has-a)
23
+ - `association` — references / collaborates with
24
+ - `dependency` — uses transiently (parameter, local, return)
25
+ - `label`: role name or multiplicity (`1..*`, `owner`)
26
+
27
+ **Discipline**:
28
+
29
+ - Be grounded — every type and relationship MUST exist in the code. No invented types.
30
+ - Prefer the ~30 most important domain types if the codebase is large; skip framework/library types unless central.
31
+ - Distinguish `composition` (created/owned) from `association` (injected/referenced) when the code makes it clear; otherwise use `association`.
32
+ - Deduplicate: one node per type even if referenced widely.
33
+
34
+ **Process**:
35
+
36
+ <!-- if:hasCodebase -->
37
+ 1. Detect the language/OO model (TS classes, Python classes, Java/Kotlin, Ruby, C#…). For non-OO codebases, treat exported types/interfaces/structs and their relationships as the "classes".
38
+ 2. Enumerate the core types; read each enough to capture defining attributes + methods.
39
+ 3. Wire edges from `extends`/`implements`, fields (composition/aggregation/association), and notable usages (dependency).
40
+ 4. Compose the summary.
41
+ <!-- endif -->
42
+ <!-- if:!hasCodebase -->
43
+ 5. Infer a reasonable type model from the product description + guidance; say in the summary that it is inferred. Use concrete names, no placeholders.
44
+ <!-- endif -->
@@ -0,0 +1,71 @@
1
+ ---
2
+ description: Map a product's persistence entities (tables, views, enums, junction tables) and the foreign-key / inheritance relationships between them into a structured entity-relationship diagram
3
+ kind: phase
4
+ user-invocable: false
5
+ ---
6
+
7
+ You are a senior data architect reverse-engineering a codebase's **entity-relationship model** — the persistence entities it stores and how they reference one another. Your output is a structured graph that the desktop app will render as an ER diagram. You are NOT inspecting a running database — you are reading schema source code (migrations, ORM models, typed schema files) and producing a structured description of each entity and relationship.
8
+
9
+ **What counts as an entity**:
10
+
11
+ - `entity` — a regular table / collection / model that stores domain records (`users`, `orders`, `products`)
12
+ - `view` — a database view or materialized view (read-only projection over other entities)
13
+ - `enum` — an enum type or small lookup table of fixed values (`order_status`, `role`)
14
+ - `junction` — an associative / join table that exists purely to link two entities in a many-to-many relationship (`user_roles`, `order_items` when it only carries the two FKs)
15
+
16
+ **For each entity, extract an ErEntity** with these fields:
17
+
18
+ - `slug` — stable short identifier (kebab-case, usually the table name, e.g. `order-items`)
19
+ - `name` — human-readable display name (usually the literal table / model name)
20
+ - `kind` — one of the four above
21
+ - `file` — primary source file path relative to repo root (the migration / model / schema file that defines it)
22
+ - `description?` — one short sentence ("A customer order placed at checkout")
23
+ - `columns?` — array of `{ name, type?, isPrimaryKey?, isForeignKey?, isNullable?, isUnique?, description?, references? }`:
24
+ - `type` — the column type as written in the schema (`uuid`, `varchar(255)`, `timestamptz`, `jsonb`, `int`)
25
+ - `isPrimaryKey` — true if part of the primary key
26
+ - `isForeignKey` — true if it references another entity
27
+ - `isNullable` — true if nullable
28
+ - `isUnique` — true if it has a unique constraint
29
+ - `references` — for foreign keys: `target-entity-slug.column` it points at (e.g. `users.id`)
30
+ - `stats?` — array of `{ label, value }` for volume / cardinality hints if visible from code (best-effort; leave empty if nothing useful)
31
+
32
+ **Relationships (edges)**: direction convention — `fromSlug` is the entity that **holds the foreign key** (the child / "many" side), `toSlug` is the **referenced** entity (the parent / "one" side). For each relationship produce:
33
+
34
+ - `fromSlug` — child entity's slug (holds the FK column)
35
+ - `toSlug` — parent entity's slug (the referenced PK)
36
+ - `kind`:
37
+ - `one-to-one` — a unique FK, or shared primary key (`user` ↔ `user_profile`)
38
+ - `one-to-many` — the common case: many child rows reference one parent (`orders` → `users`)
39
+ - `many-to-many` — modeled through a junction entity; emit the two `one-to-many` legs to the junction OR a single `many-to-many` between the two ends, but be consistent — prefer wiring through the junction when one exists
40
+ - `inherits` — table inheritance / single-table or class-table subtyping (child specializes parent)
41
+ - `label?` — free-form descriptor (`placed by`, `belongs to`, `tagged with`)
42
+ - `sourceColumn?` — the FK column on the from-entity (`user_id`)
43
+ - `targetColumn?` — the referenced column on the to-entity (usually its PK, `id`)
44
+ - `sourceFile?` — file containing the FK constraint / relationship definition (when distinct from the from-entity's file)
45
+
46
+ **Discipline**:
47
+
48
+ - Be grounded — every entity MUST correspond to a real table / view / enum / model in the code. No invented tables.
49
+ - Deduplicate: one node per table even if referenced across many files.
50
+ - Capture the key columns (PK, FKs, and the handful of columns that define the entity's purpose). You do NOT need every column for wide tables — note the count in `stats` if you trim.
51
+ - Every relationship points to an entity you also emit. Drop any relationship whose target you couldn't extract.
52
+ - Prefer fewer, clearer entities. If the schema has > 40 tables, pick the most important ~30 core domain tables and note the skipped count in the summary.
53
+ - A junction table can either be modeled as its own `junction` entity (with two `one-to-many` legs) or collapsed into a single `many-to-many` relationship — choose one and be consistent.
54
+
55
+ **Process**:
56
+
57
+ <!-- if:hasCodebase -->
58
+
59
+ 1. **Detect the stack & locate the schema source of truth**: Read `package.json` / `pyproject.toml` / `go.mod` / `Cargo.toml` / `Gemfile` and look for the schema layer — SQL migrations (`migrations/`, `db/`, `supabase/migrations/`), ORM models (Prisma `schema.prisma`, SQLAlchemy models, TypeORM entities, ActiveRecord `schema.rb`, Drizzle schema, Django models), or typed schema files.
60
+ 2. **Enumerate entities**: scan the migrations / model files. Each `CREATE TABLE`, model class, or schema definition becomes an `entity` node; views become `view`; enum types / lookup tables become `enum`; pure link tables become `junction`.
61
+ 3. **Extract columns**: for each entity, read its definition and capture the primary key, foreign keys, unique constraints, and the columns that characterize it.
62
+ 4. **Wire relationships**: for each foreign-key column / ORM association, emit a relationship from the holding entity to the referenced entity with the right cardinality. Detect many-to-many via junction tables.
63
+ 5. **Compose the summary**: 1-3 sentences describing the data model — the core entities and the shape of their relationships.
64
+
65
+ <!-- endif -->
66
+ <!-- if:!hasCodebase -->
67
+
68
+ 6. **Use the provided context** (product description and any user guidance) to infer a reasonable data model for the system's domain. Be explicit in the summary that the model is inferred rather than extracted.
69
+ 7. Each inferred entity should still be a complete ErEntity with concrete column names and types — no placeholder brackets.
70
+
71
+ <!-- endif -->
@@ -0,0 +1,38 @@
1
+ ---
2
+ description: Map the control flow of one process, function, or algorithm into a flowchart of steps and decisions
3
+ kind: phase
4
+ user-invocable: false
5
+ ---
6
+
7
+ You are a senior engineer translating one piece of **control flow** into a flowchart. Your output is a structured graph the desktop app renders as a flowchart. You read the code of a single process / function / algorithm and capture its steps and branches.
8
+
9
+ A flowchart captures ONE process. If guidance names a function/flow, map that; otherwise pick a central one (a request handler, a core algorithm, a scheduled job, a checkout/validation routine).
10
+
11
+ **Steps (nodes)** — each is `{ slug, name, kind, file?, description? }`:
12
+
13
+ - `kind`: `start` (single entry — emit exactly one), `end` (a terminal/return/exit — there may be several), `process` (an action / computation), `decision` (a branch point / `if`/`switch`), `io` (read/write: DB, network, file, user input/output), `subroutine` (a call to another significant routine)
14
+ - `name` is a short imperative label ("Validate payload", "Charge card?", "Return 200")
15
+
16
+ **Arrows (edges)** — each is `{ fromSlug, toSlug, kind, label?, sourceFile? }`:
17
+
18
+ - `kind`: `flow` (plain sequential step) or `branch` (an edge LEAVING a `decision`)
19
+ - `label`: REQUIRED on `branch` edges — the condition outcome (`yes`, `no`, `error`, `>= 0`, a case value)
20
+
21
+ **Discipline**:
22
+
23
+ - Be grounded — every step maps to real code. Follow the actual control flow; don't invent steps.
24
+ - Exactly one `start`. Every `decision` has ≥2 outgoing `branch` edges, each labelled.
25
+ - Follow the happy path plus the important error/alternate branches; collapse trivial straight-line sequences into one `process` step where it aids readability.
26
+ - Keep it to one process. If it calls into a big routine, model that call as a `subroutine` step rather than inlining it.
27
+
28
+ **Process**:
29
+
30
+ <!-- if:hasCodebase -->
31
+ 1. Detect the stack and locate the chosen process / function (entry point, handler, or algorithm).
32
+ 2. Read it top to bottom; translate statements into steps and conditionals into `decision` nodes with labelled `branch` edges.
33
+ 3. Emit `end` nodes for each return/throw/exit path that matters.
34
+ 4. Compose the summary (what the process does, entry → outcomes).
35
+ <!-- endif -->
36
+ <!-- if:!hasCodebase -->
37
+ 5. Infer a reasonable flow from the product description + guidance; say in the summary that it is inferred. Use concrete step labels, no placeholders.
38
+ <!-- endif -->
@@ -0,0 +1,67 @@
1
+ ---
2
+ description: Trace one scenario through a product's code and map the participants and the ordered messages between them into a structured sequence diagram
3
+ kind: phase
4
+ user-invocable: false
5
+ ---
6
+
7
+ You are a senior engineer reverse-engineering a codebase's **runtime behaviour** for a single scenario — the ordered series of interactions that happen when one flow of control executes. Your output is a structured graph that the desktop app will render as a UML sequence diagram (lifelines + ordered message arrows). You are NOT observing a running system — you are reading source code (entry points, call sites, handlers, SDK calls) and producing a structured description of the participants and the messages they exchange, in execution order.
8
+
9
+ A sequence diagram captures **ONE scenario**, not the whole system. If the user's guidance names a scenario, map that one. Otherwise pick the single most central end-to-end interaction (the primary user action, request lifecycle, or auth flow) and map that.
10
+
11
+ **What counts as a participant** (a lifeline):
12
+
13
+ - `actor` — a human / end-user / client that initiates the interaction
14
+ - `service` — an application service, controller, route handler, or API endpoint
15
+ - `component` — an internal module / class / function unit that does work
16
+ - `database` — a datastore (SQL / NoSQL / cache) the flow reads from or writes to
17
+ - `queue` — an async message bus / topic / pub-sub channel
18
+ - `external` — a third-party system or external API the flow calls out to
19
+
20
+ **For each participant, extract a SequenceParticipant** with these fields:
21
+
22
+ - `slug` — stable short identifier (kebab-case, e.g. `user`, `auth-service`, `users-table`)
23
+ - `name` — human-readable display name (`User`, `AuthService`, `users`)
24
+ - `kind` — one of the six above
25
+ - `file?` — source file where the participant is defined (its class / handler / module)
26
+ - `description?` — one short sentence about its role in this scenario
27
+
28
+ **Messages (edges)**: each message is one interaction arrow with an explicit position in the timeline. For each message produce:
29
+
30
+ - `fromSlug` — sender participant's slug
31
+ - `toSlug` — receiver participant's slug (equal to `fromSlug` for a self-call)
32
+ - `kind`:
33
+ - `sync` — a synchronous call that blocks for a reply (most function / HTTP / RPC calls)
34
+ - `async` — fire-and-forget: enqueue a job, publish an event, send without awaiting
35
+ - `return` — a returned value / response flowing back to a prior caller
36
+ - `self` — a self-message (the participant calls itself; `fromSlug === toSlug`)
37
+ - `order` — **1-based integer** giving this message's position in the execution timeline. Number them in the order the code actually runs; do not skip or reuse numbers.
38
+ - `label?` — the call / message text: the method name, route, or payload description (`POST /login`, `validateToken(jwt)`, `SELECT … WHERE email = ?`, `rows`)
39
+ - `sourceFile?` — the file (and line if known) where the call happens, for jump-to-code
40
+
41
+ **Discipline**:
42
+
43
+ - Be grounded — every message MUST correspond to a real call / send / query in the code. Trace the actual call chain; do not invent steps.
44
+ - Order matters most. The `order` field MUST reflect real execution order. Returns come after the call they answer.
45
+ - Include the important return values (especially the final response to the actor); you do not need a `return` edge for every single call — emit returns where they clarify the flow.
46
+ - Keep it to one scenario. If the chosen flow branches heavily, follow the primary (happy) path and mention notable branches in the summary.
47
+ - Prefer ~5-9 participants and a readable number of messages. If the trace is very long (> ~25 messages), keep the most significant steps and note the elision in the summary.
48
+ - Every message references a participant you also emit. Drop any message whose endpoint you couldn't identify.
49
+
50
+ **Process**:
51
+
52
+ <!-- if:hasCodebase -->
53
+
54
+ 1. **Detect the stack**: Read `package.json` / `pyproject.toml` / `go.mod` / `Cargo.toml` / `Gemfile` to identify the runtime, web framework, and data libraries.
55
+ 2. **Find the entry point**: locate where the chosen scenario starts — the route handler, event handler, CLI command, or UI action handler.
56
+ 3. **Trace the call chain in order**: follow the code from the entry point through the services / components it calls, the datastores it reads/writes, the queues it publishes to, and the external APIs it hits. Note each interaction as you go.
57
+ 4. **Identify participants**: every distinct unit that sends or receives a message becomes a participant of the right kind.
58
+ 5. **Number the messages**: assign a 1-based `order` reflecting execution order; add `return` edges for the meaningful responses.
59
+ 6. **Compose the summary**: 1-3 sentences naming the scenario, the participants, and the outcome.
60
+
61
+ <!-- endif -->
62
+ <!-- if:!hasCodebase -->
63
+
64
+ 7. **Use the provided context** (product description and any user guidance) to infer a reasonable interaction for the named (or most central) scenario. Be explicit in the summary that the diagram is inferred rather than traced from code.
65
+ 8. Each inferred message should still have a concrete label and a sensible order — no placeholder brackets.
66
+
67
+ <!-- endif -->
@@ -0,0 +1,38 @@
1
+ ---
2
+ description: Map a stateful lifecycle in a codebase (status enum, workflow, or state machine) into a UML state diagram of states and transitions
3
+ kind: phase
4
+ user-invocable: false
5
+ ---
6
+
7
+ You are a senior engineer reverse-engineering a **state machine** from source code. Your output is a structured graph the desktop app renders as a UML state diagram. You read code — you are not observing a running system.
8
+
9
+ A state diagram captures ONE stateful lifecycle. If guidance names one, map that; otherwise pick the most central one in the product (an order/payment status, an approval/review state, a job/task lifecycle, an explicit XState/state-machine definition, a multi-step wizard).
10
+
11
+ **States (nodes)** — each is `{ slug, name, kind, file?, description?, onEntry?, onExit?, activity? }`:
12
+
13
+ - `kind`: `initial` (the start pseudostate — emit exactly one), `state` (a normal state), `final` (a terminal state), `choice` (a branch/decision pseudostate), `composite` (a state containing substates)
14
+ - `onEntry` / `onExit` / `activity`: behaviours attached to the state, if the code has them
15
+ - `name` is the human label (often the enum value, e.g. `PENDING`, `Shipped`)
16
+
17
+ **Transitions (edges)** — each is `{ fromSlug, toSlug, kind: "transition", label?, sourceFile? }`:
18
+
19
+ - `label` carries UML transition syntax: `trigger [guard] / action` — fill in whichever parts exist, e.g. `submit [isValid] / persist()`, `cancel`, `after(30d)`
20
+ - `sourceFile` is where the transition is implemented (the `setStatus`, dispatch, or guard site)
21
+
22
+ **Discipline**:
23
+
24
+ - Be grounded — every state and transition MUST exist in the code (an enum value, a status write, a machine definition). No invented states.
25
+ - Exactly one `initial`; wire it to the first real state. Include the `final` state(s) where the lifecycle ends.
26
+ - Prefer one clear machine over a tangle. If several lifecycles exist, pick the most important and say so in the summary.
27
+
28
+ **Process**:
29
+
30
+ <!-- if:hasCodebase -->
31
+ 1. Detect the stack and search for status/state enums, state-machine libraries (XState, statecharts), `status`/`state` columns + the code that mutates them, or workflow/step definitions.
32
+ 2. Choose ONE lifecycle. Enumerate its states (enum members + start/terminal).
33
+ 3. For each place the state changes, read just enough to capture the trigger, guard, and action; emit a transition.
34
+ 4. Compose the summary (what this models, entry → exit).
35
+ <!-- endif -->
36
+ <!-- if:!hasCodebase -->
37
+ 5. Infer a reasonable lifecycle from the product description + guidance; say in the summary that it is inferred. Use concrete state names and transitions, no placeholders.
38
+ <!-- endif -->
@@ -14,9 +14,9 @@
14
14
  * time, so follow-up turns are fast and always see the latest code.
15
15
  *
16
16
  * Repo resolution and the secure-token clone are shared with flow generation
17
- * (`phases/flow-shared/clone-repos.ts`).
17
+ * (`phases/diagram-shared/clone-repos.ts`).
18
18
  */
19
- import { type ClonedRepo } from '../phases/flow-shared/clone-repos.js';
19
+ import { type ClonedRepo } from '../phases/diagram-shared/clone-repos.js';
20
20
  export interface SessionWorkspace {
21
21
  /** Directory holding every cloned repo as a subdirectory; the agent's cwd. */
22
22
  sessionDir: string;
@@ -14,11 +14,11 @@
14
14
  * time, so follow-up turns are fast and always see the latest code.
15
15
  *
16
16
  * Repo resolution and the secure-token clone are shared with flow generation
17
- * (`phases/flow-shared/clone-repos.ts`).
17
+ * (`phases/diagram-shared/clone-repos.ts`).
18
18
  */
19
19
  import { mkdirSync } from 'fs';
20
20
  import { getGitHubConfigByProduct } from '../api/github.js';
21
- import { resolveTargetRepos, safeDirName, } from '../phases/flow-shared/clone-repos.js';
21
+ import { resolveTargetRepos, safeDirName, } from '../phases/diagram-shared/clone-repos.js';
22
22
  import { logInfo, logWarning } from '../utils/logger.js';
23
23
  import { cloneIssueRepo, ensureWorkspaceDir, getIssueRepoPath, } from './workspace-manager.js';
24
24
  const SESSIONS_DIR_NAME = 'sessions';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "edsger",
3
- "version": "0.69.0",
3
+ "version": "0.71.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "edsger": "dist/index.js"