@exaudeus/workrail 3.31.1 → 3.33.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 (82) hide show
  1. package/dist/cli/commands/index.d.ts +1 -0
  2. package/dist/cli/commands/index.js +3 -1
  3. package/dist/cli/commands/worktrain-await.js +11 -9
  4. package/dist/cli/commands/worktrain-daemon-install.d.ts +35 -0
  5. package/dist/cli/commands/worktrain-daemon-install.js +291 -0
  6. package/dist/cli/commands/worktrain-daemon.d.ts +31 -0
  7. package/dist/cli/commands/worktrain-daemon.js +272 -0
  8. package/dist/cli/commands/worktrain-spawn.js +11 -9
  9. package/dist/cli-worktrain.js +329 -0
  10. package/dist/cli.js +4 -22
  11. package/dist/console/standalone-console.d.ts +28 -0
  12. package/dist/console/standalone-console.js +142 -0
  13. package/dist/{console/assets/index-6H9DeFxj.js → console-ui/assets/index-BuJFLLfY.js} +1 -1
  14. package/dist/{console → console-ui}/index.html +1 -1
  15. package/dist/daemon/agent-loop.d.ts +26 -0
  16. package/dist/daemon/agent-loop.js +53 -2
  17. package/dist/daemon/daemon-events.d.ts +103 -0
  18. package/dist/daemon/daemon-events.js +56 -0
  19. package/dist/daemon/workflow-runner.d.ts +6 -3
  20. package/dist/daemon/workflow-runner.js +229 -33
  21. package/dist/infrastructure/session/HttpServer.js +133 -34
  22. package/dist/manifest.json +134 -70
  23. package/dist/mcp/output-schemas.d.ts +30 -30
  24. package/dist/mcp/transports/bridge-events.d.ts +4 -0
  25. package/dist/mcp/transports/fatal-exit.js +4 -0
  26. package/dist/mcp/transports/http-entry.js +2 -0
  27. package/dist/mcp/transports/stdio-entry.js +26 -6
  28. package/dist/mcp/v2/tools.d.ts +4 -4
  29. package/dist/trigger/adapters/github-poller.d.ts +44 -0
  30. package/dist/trigger/adapters/github-poller.js +190 -0
  31. package/dist/trigger/adapters/gitlab-poller.d.ts +27 -0
  32. package/dist/trigger/adapters/gitlab-poller.js +81 -0
  33. package/dist/trigger/delivery-client.d.ts +2 -1
  34. package/dist/trigger/delivery-client.js +4 -1
  35. package/dist/trigger/index.d.ts +4 -1
  36. package/dist/trigger/index.js +5 -1
  37. package/dist/trigger/polled-event-store.d.ts +22 -0
  38. package/dist/trigger/polled-event-store.js +173 -0
  39. package/dist/trigger/polling-scheduler.d.ts +20 -0
  40. package/dist/trigger/polling-scheduler.js +249 -0
  41. package/dist/trigger/trigger-listener.d.ts +5 -0
  42. package/dist/trigger/trigger-listener.js +53 -4
  43. package/dist/trigger/trigger-router.d.ts +4 -2
  44. package/dist/trigger/trigger-router.js +7 -4
  45. package/dist/trigger/trigger-store.js +114 -33
  46. package/dist/trigger/types.d.ts +17 -1
  47. package/dist/v2/durable-core/schemas/export-bundle/index.d.ts +224 -224
  48. package/dist/v2/durable-core/schemas/session/events.d.ts +42 -42
  49. package/dist/v2/durable-core/schemas/session/manifest.d.ts +6 -6
  50. package/dist/v2/durable-core/schemas/session/validation-event.d.ts +2 -2
  51. package/dist/v2/durable-core/tokens/payloads.d.ts +52 -52
  52. package/dist/v2/usecases/console-routes.js +3 -3
  53. package/dist/v2/usecases/console-service.js +133 -9
  54. package/dist/v2/usecases/console-types.d.ts +7 -0
  55. package/docs/design/daemon-conversation-logging-plan.md +98 -0
  56. package/docs/design/daemon-conversation-logging-review.md +55 -0
  57. package/docs/design/daemon-conversation-logging.md +129 -0
  58. package/docs/design/github-polling-adapter-design-candidates.md +226 -0
  59. package/docs/design/github-polling-adapter-design-review-findings.md +131 -0
  60. package/docs/design/github-polling-adapter-implementation-plan.md +284 -0
  61. package/docs/design/implementation_plan.md +192 -0
  62. package/docs/design/workflow-id-validation-at-startup.md +146 -0
  63. package/docs/design/workflow-id-validation-design-review.md +87 -0
  64. package/docs/design/workflow-id-validation-implementation-plan.md +185 -0
  65. package/docs/design/worktrain-system-prompt-report-issue-candidates.md +135 -0
  66. package/docs/design/worktrain-system-prompt-report-issue-design-review.md +73 -0
  67. package/docs/ideas/backlog.md +465 -0
  68. package/package.json +1 -1
  69. package/workflows/architecture-scalability-audit.json +1 -1
  70. package/workflows/bug-investigation.agentic.v2.json +3 -3
  71. package/workflows/coding-task-workflow-agentic.json +32 -32
  72. package/workflows/coding-task-workflow-agentic.lean.v2.json +1 -1
  73. package/workflows/coding-task-workflow-agentic.v2.json +7 -7
  74. package/workflows/mr-review-workflow.agentic.v2.json +21 -12
  75. package/workflows/personal-learning-materials-creation-branched.json +2 -2
  76. package/workflows/production-readiness-audit.json +1 -1
  77. package/workflows/relocation-workflow-us.json +2 -2
  78. package/workflows/ui-ux-design-workflow.json +14 -14
  79. package/workflows/workflow-for-workflows.json +3 -3
  80. package/workflows/workflow-for-workflows.v2.json +2 -2
  81. package/workflows/wr.discovery.json +1 -1
  82. /package/dist/{console → console-ui}/assets/index-8dh0Psu-.css +0 -0
@@ -0,0 +1,135 @@
1
+ # WorkTrain: System Prompt Preamble + report_issue Tool -- Design Candidates
2
+
3
+ ## Problem Understanding
4
+
5
+ ### Core Tensions
6
+
7
+ 1. **Preamble richness vs. existing test assertions** -- The current `buildSystemPrompt()` preamble is ~15 lines (identity, tools, execution contract, session state). The new spec replaces it with ~55 lines covering oracle hierarchy, self-directed reasoning, workflow-as-contract, silent failure, and tools-as-hands. The existing tests assert specific strings (`'You are WorkRail Auto'`, `'## Your tools'`, `'## Execution contract'`) must be present. The new content must include those strings or the tests break.
8
+
9
+ 2. **report_issue write durability vs. fire-and-forget contract** -- The JSONL file must be written reliably enough for a future coordinator to read it, but a disk-full or permission error must never interrupt the agent session. Resolution: same void+catch pattern as `DaemonEventEmitter`.
10
+
11
+ 3. **Purity of buildSystemPrompt vs. tool name references in prose** -- The new preamble mentions `report_issue` by name in the "silent failure" section. If the tool name ever changes, the system prompt text becomes stale. This is an accepted documentation-drift risk; tool names are stable identifiers.
12
+
13
+ 4. **YAGNI (no coordinator yet) vs. extractability (coordinator coming soon)** -- The auto-fix coordinator that will read the issue JSONL doesn't exist. Building a dedicated `IssueStore` class now is speculative. However, the file write must still work for the coordinator when it arrives.
14
+
15
+ ### Likely Seam
16
+
17
+ - **Preamble:** `buildSystemPrompt()` lines 1086-1108 in `src/daemon/workflow-runner.ts`. This is the correct seam -- pure function, all callers go through it.
18
+ - **report_issue tool:** The tools array in `runWorkflow()` at lines 1318-1323. New tool factory `makeReportIssueTool()` slots in here.
19
+ - **DaemonEvent union:** `src/daemon/daemon-events.ts` -- add `IssueReportedEvent` + extend union.
20
+
21
+ ### What Makes This Hard
22
+
23
+ - Existing test assertions constrain the new preamble content -- `'## Your tools'` and `'## Execution contract'` must survive the rewrite.
24
+ - `report_issue.execute()` must be fire-and-forget for the JSONL write. Junior devs would `await` it directly and let I/O errors propagate.
25
+ - `IssueReportedEvent` fields must be typed as literal union strings (not `string`), otherwise illegal kind/severity values are representable at compile time.
26
+
27
+ ---
28
+
29
+ ## Philosophy Constraints
30
+
31
+ From `/Users/etienneb/CLAUDE.md` and `~/.workrail/daemon-soul.md`:
32
+
33
+ - **Exhaustiveness everywhere** -- `DaemonEvent` must remain a discriminated union; new variant must follow the pattern
34
+ - **Make illegal states unrepresentable** -- `kind` and `severity` on IssueReportedEvent must be literal unions, not strings
35
+ - **YAGNI with discipline** -- don't build IssueStore class until the coordinator needs it
36
+ - **Observability as a constraint** -- fire-and-forget writes must never block correctness
37
+ - **Document 'why' not 'what'** -- JSDoc on BASE_SYSTEM_PROMPT explaining why it's a constant
38
+ - **Immutability by default** -- all DaemonEvent interfaces use `readonly` fields
39
+ - **Functional core, imperative shell** -- buildSystemPrompt is pure; JSONL write is at the shell boundary
40
+
41
+ ---
42
+
43
+ ## Impact Surface
44
+
45
+ - `tests/unit/workflow-runner-system-prompt.test.ts` -- 3 assertions on preamble content that must pass after rewrite
46
+ - `tests/unit/daemon-events.test.ts` -- existing event tests; adding a new event kind must not break exhaustiveness checks
47
+ - Any future TypeScript code that does `switch (event.kind)` on `DaemonEvent` -- must handle `'issue_reported'` or get a compile error (desired)
48
+ - `runWorkflow()` tools array -- adding `makeReportIssueTool` here; `sessionId` and `emitter` are already in scope
49
+ - The `BASE_SYSTEM_PROMPT` constant mentions the tool by name -- documentation drift if tool is renamed later
50
+
51
+ ---
52
+
53
+ ## Candidates
54
+
55
+ ### Part 1: New Preamble
56
+
57
+ #### Candidate A -- Inline replacement (no constant)
58
+ - **Summary:** Replace the 4-item preamble lines directly in the `lines` array inside `buildSystemPrompt()`.
59
+ - **Tensions resolved:** Existing tests still pass (required strings included). **Accepted:** Preamble not readable in isolation; harder to document with JSDoc.
60
+ - **Boundary:** Inside `buildSystemPrompt()`, same as today.
61
+ - **Failure mode:** If session state tag position shifts, tests break. Manageable.
62
+ - **Repo pattern:** Departs -- existing code has no named constant but the soul-template.ts extraction is a precedent.
63
+ - **Gains:** No indirection. **Losses:** Not visible as a document; can't be verified without calling buildSystemPrompt.
64
+ - **Scope:** Too narrow.
65
+
66
+ #### Candidate B -- Named `BASE_SYSTEM_PROMPT` constant (recommended)
67
+ - **Summary:** Extract the static preamble into `export const BASE_SYSTEM_PROMPT: string` defined above `buildSystemPrompt()`. The function uses it as the first element of the lines array. JSDoc explains why it's a constant vs inline.
68
+ - **Tensions resolved:** Preamble visible as a document; existing test assertions pass; honors 'Document why not what'.
69
+ - **Accepted:** Slight indirection; tool name drift risk (prose mentions `report_issue`).
70
+ - **Boundary:** Module-scoped constant, not exported (callers use `buildSystemPrompt`). Dynamic content (session state, soul, workspace) remains in the function.
71
+ - **Failure mode:** If a future author edits `BASE_SYSTEM_PROMPT` and removes `'## Your tools'` or `'## Execution contract'`, tests catch it immediately.
72
+ - **Repo pattern:** Follows soul-template.ts precedent (constant for stable content, function for dynamic assembly).
73
+ - **Gains:** Readable, documentable, testable in isolation. **Losses:** None significant.
74
+ - **Scope:** Best-fit.
75
+ - **Philosophy:** Honors 'Immutability by default' (const), 'Document why not what' (JSDoc), 'Determinism' (pure function unchanged).
76
+
77
+ ---
78
+
79
+ ### Part 2: report_issue Tool
80
+
81
+ #### Candidate A -- Inline tool factory with private async helper (recommended)
82
+ - **Summary:** `makeReportIssueTool(sessionId: string, emitter?: DaemonEventEmitter): AgentTool` -- custom inline JSON schema (no schemas param), `execute()` fires a void Promise for the JSONL write (same pattern as DaemonEventEmitter), emits `issue_reported` event, returns string confirmation. A module-level private `appendIssueAsync()` function handles the actual fs writes to keep execute() clean.
83
+ - **Tensions resolved:** Fire-and-forget (never blocks), type-safe kind/severity, YAGNI (no IssueStore class), natural tool-factory shape.
84
+ - **Accepted:** Less isolated unit-testability for the JSONL write path (no dirOverride). Extractable later.
85
+ - **Boundary:** Tool factory in `workflow-runner.ts` alongside make*Tool siblings. Private helper in same file.
86
+ - **Failure mode:** JSONL write fails silently. Accepted -- same contract as DaemonEventEmitter.
87
+ - **Repo pattern:** Follows tool factory pattern exactly (name, description, inputSchema, label, execute).
88
+ - **Gains:** Simple, correct, consistent with existing code. **Losses:** JSONL write not unit-testable in isolation today.
89
+ - **Scope:** Best-fit.
90
+ - **Philosophy:** Honors 'YAGNI with discipline', 'Exhaustiveness everywhere' (literal unions), 'Make illegal states unrepresentable', 'Observability as a constraint'.
91
+
92
+ #### Candidate B -- Dedicated `IssueStore` class (parallel to DaemonEventEmitter)
93
+ - **Summary:** Extract a class `IssueStore` with `append(sessionId, issue)` and `dirOverride` for tests. Injected into `makeReportIssueTool`. Separate file or same file.
94
+ - **Tensions resolved:** Full unit-testability with dirOverride, separation of concerns.
95
+ - **Accepted:** Over-engineering for current scope (coordinator doesn't exist). YAGNI violated.
96
+ - **Boundary:** New abstraction layer. Only one caller today.
97
+ - **Failure mode:** Premature abstraction; adds complexity with no current benefit.
98
+ - **Repo pattern:** Matches DaemonEventEmitter exactly -- but DaemonEventEmitter was built when multiple callers needed it immediately.
99
+ - **Gains:** Testable in isolation, clean interface for future coordinator. **Losses:** Speculative complexity today.
100
+ - **Scope:** Too broad (no coordinator in this PR).
101
+ - **Philosophy:** Conflicts with 'YAGNI with discipline'. Honors 'Prefer fakes over mocks'.
102
+
103
+ ---
104
+
105
+ ## Comparison and Recommendation
106
+
107
+ ### Part 1
108
+ Candidate B (BASE_SYSTEM_PROMPT constant) dominates on every axis. Not a close call.
109
+
110
+ ### Part 2
111
+ Candidate A (inline tool factory) wins on YAGNI. The only real loss is JSONL write isolation in tests -- acceptable since the write is purely observational (fire-and-forget), not correctness-affecting.
112
+
113
+ **If the auto-fix coordinator were being built in this PR**, Candidate B would be justified. It isn't.
114
+
115
+ ---
116
+
117
+ ## Self-Critique
118
+
119
+ ### Part 1 strongest counter-argument
120
+ 'The constant is 55 lines and clutters the file.' Counter: it's in a clearly labeled `## System prompt` section. A 55-line constant is readable. The alternative (55 lines of array items with string literals) is worse. Not a real objection.
121
+
122
+ ### Part 2 strongest counter-argument
123
+ 'DaemonEventEmitter is a class -- to be consistent, IssueStore should also be a class.' True in the abstract. But DaemonEventEmitter was built when the event stream was a first-class concern. Issue recording is secondary observability for a future feature. The consistency argument applies when there are multiple callers, not one.
124
+
125
+ ### Pivot conditions
126
+ - **Part 2:** If the coordinator PR is planned for this sprint, extract IssueStore now to save rework later.
127
+ - **Part 1:** If the BASE_SYSTEM_PROMPT constant is exported and used in tests directly, add it to the test file's import.
128
+
129
+ ---
130
+
131
+ ## Open Questions for the Main Agent
132
+
133
+ 1. Should `BASE_SYSTEM_PROMPT` be exported (for tests to import directly) or left module-private? Current test assertions only check the output of `buildSystemPrompt()`, so private is sufficient.
134
+ 2. Should `IssueReportedEvent` include `continueToken` (for coordinator to resume)? The spec says optional -- include it as `readonly continueToken?: string`.
135
+ 3. The new preamble's `## Your tools` section should list `report_issue` -- does it also list `Bash`, `Read`, `Write`, `continue_workflow`? Yes, for completeness.
@@ -0,0 +1,73 @@
1
+ # WorkTrain: System Prompt Preamble + report_issue Tool -- Design Review Findings
2
+
3
+ ## Tradeoff Review
4
+
5
+ | Tradeoff | Assessment |
6
+ |---|---|
7
+ | Tool name drift: preamble prose mentions `report_issue` | Acceptable. Prose is guidance, not tool registration. Agent uses the tools array. |
8
+ | JSONL write not unit-testable in isolation | **Resolved** by adding `issuesDirOverride?: string` to `makeReportIssueTool`. |
9
+ | No IssueStore class (YAGNI) | Acceptable. Coordinator doesn't exist in this PR. Extractable later. |
10
+ | Fatal severity doesn't abort the loop | Accepted limitation. Tool returns instructional text. Agent is told to stop. Recording the issue is the priority. |
11
+
12
+ ---
13
+
14
+ ## Failure Mode Review
15
+
16
+ | Failure Mode | Handling | Risk |
17
+ |---|---|---|
18
+ | Missing issues dir | `mkdir recursive` before appendFile (DaemonEventEmitter pattern) | Low |
19
+ | Preamble loses required test strings | Caught immediately by existing vitest assertions | Low (self-healing) |
20
+ | Agent ignores fatal severity and continues | Instructional return value. Can't force stop from inside tool without violating 'errors are data'. | Medium (accepted) |
21
+ | sessionId is process-local UUID not server ID | Consistent with all other tools in this file. Coordinator correlates via sessionId. | Low |
22
+
23
+ ---
24
+
25
+ ## Runner-Up / Simpler Alternative Review
26
+
27
+ **Part 1:** Inline preamble (runner-up) offers no advantages over the named constant. Candidate B dominates.
28
+
29
+ **Part 2:** IssueStore class (runner-up) offers `dirOverride` for isolated testing. A hybrid was adopted: add `issuesDirOverride?: string` parameter to `makeReportIssueTool` without extracting a full class. This resolves the testability weakness at negligible complexity cost.
30
+
31
+ **Simpler alternative (no dirOverride):** Technically satisfies acceptance criteria. Rejected because it violates 'prefer fakes over mocks' and departs from the established DaemonEventEmitter precedent for no benefit.
32
+
33
+ ---
34
+
35
+ ## Philosophy Alignment
36
+
37
+ | Principle | Status |
38
+ |---|---|
39
+ | Immutability by default | Satisfied: `const BASE_SYSTEM_PROMPT`; readonly IssueReportedEvent fields |
40
+ | Make illegal states unrepresentable | Satisfied: `kind` and `severity` are literal union types |
41
+ | Exhaustiveness everywhere | Satisfied: new DaemonEvent variant triggers TS compile error on unhandled switch |
42
+ | Errors are data | Satisfied: report_issue returns string confirmation, never throws |
43
+ | YAGNI with discipline | Satisfied: no IssueStore class |
44
+ | Observability as a constraint | Satisfied: fire-and-forget, never blocks correctness |
45
+ | Prefer fakes over mocks | Satisfied (after hybrid): issuesDirOverride allows temp-dir testing |
46
+ | Document why not what | Satisfied: JSDoc on BASE_SYSTEM_PROMPT constant; WHY comments on void+catch |
47
+
48
+ ---
49
+
50
+ ## Findings
51
+
52
+ ### Yellow (low-risk, note for implementer)
53
+
54
+ **Y1:** `BASE_SYSTEM_PROMPT` must include `'You are WorkRail Auto'`, `'## Your tools'`, and `'## Execution contract'` to preserve existing test assertions. The implementer must verify these strings survive the rewrite verbatim.
55
+
56
+ **Y2:** The new preamble's `## Your tools` section should list all 5 tools: `continue_workflow`, `Bash`, `Read`, `Write`, `report_issue`. If any tool is added/removed in the future, the preamble prose becomes stale. Accepted documentation-drift risk.
57
+
58
+ **Y3:** The `issuesDirOverride` parameter changes the signature of `makeReportIssueTool`. Wire it through `runWorkflow()` with `undefined` (production path). A test for the file write path should be added to `tests/unit/`.
59
+
60
+ ---
61
+
62
+ ## Recommended Revisions
63
+
64
+ 1. **Add `issuesDirOverride?: string` to `makeReportIssueTool`** -- adopt the hybrid over inline-only. (Already decided above.)
65
+ 2. **Use `void appendIssueAsync(...).catch(() => {})` idiom** -- identical to DaemonEventEmitter._append; don't await.
66
+ 3. **IssueReportedEvent fields:** Use `readonly` on all fields; `issueKind` not `kind` for the payload (since `kind` is the discriminant `'issue_reported'`). Wait -- looking at the spec: the tool's input schema field is `kind` (the issue type), but the event discriminant is also `kind: 'issue_reported'`. Rename the payload field to `issueKind` in `IssueReportedEvent` to avoid shadowing, while keeping the JSON input schema field as `kind` (per spec).
67
+
68
+ ---
69
+
70
+ ## Residual Concerns
71
+
72
+ - **Fatal severity + agent continuation:** The design cannot enforce stopping. This is a known limitation of the instruction-based approach. The coordinator will need to detect "fatal issue recorded, then agent continued for N more steps" and flag it. Out of scope for this PR.
73
+ - **Issue file format:** The spec says 'JSON line' but doesn't specify the schema. The implementer should include all input fields plus `ts: Date.now()` and `sessionId` for correlation -- consistent with how daemon events are written.