openfleet 0.3.15 → 0.4.1

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 (49) hide show
  1. package/README.md +52 -2
  2. package/dist/agents/{reviewer.d.ts → architect.d.ts} +1 -1
  3. package/dist/agents/{planner.d.ts → builder.d.ts} +1 -1
  4. package/dist/agents/index.d.ts +6 -8
  5. package/dist/agents/{housekeeping.d.ts → introspector.d.ts} +1 -1
  6. package/dist/agents/names.d.ts +6 -8
  7. package/dist/agents/{actor.d.ts → recon.d.ts} +1 -1
  8. package/dist/agents/{reflector.d.ts → validator.d.ts} +1 -1
  9. package/dist/config.d.ts +14 -13
  10. package/dist/index.js +446 -873
  11. package/dist/models.d.ts +3 -3
  12. package/dist/templates/.openfleet/.templates/task-tree.md +3 -3
  13. package/dist/templates/.openfleet/README.md +28 -25
  14. package/dist/templates/.openfleet/VERSION +1 -0
  15. package/dist/templates/.openfleet/gitignore.template +2 -7
  16. package/dist/templates/.openfleet/migrations/0.4.0.md +74 -0
  17. package/dist/templates/.openfleet/{agents/Apollo.md → private/agents/Architect.md} +2 -2
  18. package/dist/templates/.openfleet/{agents/Hercules.md → private/agents/Builder.md} +2 -2
  19. package/dist/templates/.openfleet/{agents/Mnemosyne.md → private/agents/Introspector.md} +2 -40
  20. package/dist/templates/.openfleet/{agents/Athena.md → private/agents/Recon.md} +2 -2
  21. package/dist/templates/.openfleet/{agents/Chiron.md → private/agents/Validator.md} +2 -2
  22. package/dist/templates/.openfleet/{experience → private/experience}/README.md +1 -2
  23. package/dist/templates/.openfleet/private/preferences.md +113 -0
  24. package/dist/templates/.openfleet/public/standards/code-style.md +11 -0
  25. package/dist/transcript/hooks.d.ts +0 -13
  26. package/dist/utils/directory-init.d.ts +1 -0
  27. package/package.json +1 -1
  28. package/dist/agents/read-only.d.ts +0 -2
  29. package/dist/agents/scout.d.ts +0 -2
  30. package/dist/templates/.openfleet/experience/blunders/README.md +0 -6
  31. package/dist/templates/.openfleet/reviews/README.md +0 -15
  32. package/dist/templates/.openfleet/sessions/README.md +0 -16
  33. package/dist/templates/.openfleet/standards/code-style.md +0 -3
  34. package/dist/tools/save-conversation/counter.d.ts +0 -31
  35. package/dist/tools/save-conversation/session-writer.d.ts +0 -17
  36. package/dist/tools/save-conversation/slug-generator.d.ts +0 -14
  37. package/dist/tools/save-conversation/types.d.ts +0 -28
  38. /package/dist/templates/.openfleet/{agents → private/agents}/Zeus.md +0 -0
  39. /package/dist/templates/.openfleet/{experience → private/experience}/lessons/README.md +0 -0
  40. /package/dist/templates/.openfleet/{experience → private/experience}/runbooks/README.md +0 -0
  41. /package/dist/templates/.openfleet/{status.md → private/status.md} +0 -0
  42. /package/dist/templates/.openfleet/{stories → private/stories}/README.md +0 -0
  43. /package/dist/templates/.openfleet/{transcripts → private/transcripts}/README.md +0 -0
  44. /package/dist/templates/.openfleet/{docs → public/docs}/README.md +0 -0
  45. /package/dist/templates/.openfleet/{standards → public/standards}/README.md +0 -0
  46. /package/dist/templates/.openfleet/{standards → public/standards}/architecture.md +0 -0
  47. /package/dist/templates/.openfleet/{standards → public/standards}/review-checklist.md +0 -0
  48. /package/dist/templates/.openfleet/{standards → public/standards}/testing.md +0 -0
  49. /package/dist/templates/.openfleet/{experience → public}/troubleshooting/README.md +0 -0
package/dist/index.js CHANGED
@@ -2,30 +2,33 @@
2
2
  // src/config.ts
3
3
  import * as path from "path";
4
4
  var OPENFLEET_DIR = path.join(process.cwd(), ".openfleet");
5
+ var PUBLIC_DIR = path.join(OPENFLEET_DIR, "public");
6
+ var PRIVATE_DIR = path.join(OPENFLEET_DIR, "private");
5
7
  var PATHS = {
6
8
  agentsMd: path.join(process.cwd(), "AGENTS.md"),
7
9
  root: OPENFLEET_DIR,
8
- statusFile: path.join(OPENFLEET_DIR, "status.md"),
10
+ public: PUBLIC_DIR,
11
+ private: PRIVATE_DIR,
9
12
  templates: path.join(OPENFLEET_DIR, ".templates"),
10
- agents: path.join(OPENFLEET_DIR, "agents"),
11
- agentZeus: path.join(OPENFLEET_DIR, "agents", "Zeus.md"),
12
- agentAthena: path.join(OPENFLEET_DIR, "agents", "Athena.md"),
13
- agentApollo: path.join(OPENFLEET_DIR, "agents", "Apollo.md"),
14
- agentHercules: path.join(OPENFLEET_DIR, "agents", "Hercules.md"),
15
- agentChiron: path.join(OPENFLEET_DIR, "agents", "Chiron.md"),
16
- agentMnemosyne: path.join(OPENFLEET_DIR, "agents", "Mnemosyne.md"),
17
- sessions: path.join(OPENFLEET_DIR, "sessions"),
18
- stories: path.join(OPENFLEET_DIR, "stories"),
19
- docs: path.join(OPENFLEET_DIR, "docs"),
20
- experience: path.join(OPENFLEET_DIR, "experience"),
21
- runbooks: path.join(OPENFLEET_DIR, "experience", "runbooks"),
22
- troubleshooting: path.join(OPENFLEET_DIR, "experience", "troubleshooting"),
23
- lessons: path.join(OPENFLEET_DIR, "experience", "lessons"),
24
- blunders: path.join(OPENFLEET_DIR, "experience", "blunders"),
25
- standards: path.join(OPENFLEET_DIR, "standards"),
26
- reviews: path.join(OPENFLEET_DIR, "reviews"),
27
- transcripts: path.join(OPENFLEET_DIR, "transcripts"),
28
- logFile: path.join(OPENFLEET_DIR, "openfleet.log")
13
+ versionFile: path.join(OPENFLEET_DIR, "VERSION"),
14
+ statusFile: path.join(PRIVATE_DIR, "status.md"),
15
+ preferencesFile: path.join(PRIVATE_DIR, "preferences.md"),
16
+ agents: path.join(PRIVATE_DIR, "agents"),
17
+ agentOrchestrator: path.join(PRIVATE_DIR, "agents", "Zeus.md"),
18
+ agentRecon: path.join(PRIVATE_DIR, "agents", "Recon.md"),
19
+ agentArchitect: path.join(PRIVATE_DIR, "agents", "Architect.md"),
20
+ agentBuilder: path.join(PRIVATE_DIR, "agents", "Builder.md"),
21
+ agentValidator: path.join(PRIVATE_DIR, "agents", "Validator.md"),
22
+ agentIntrospector: path.join(PRIVATE_DIR, "agents", "Introspector.md"),
23
+ stories: path.join(PRIVATE_DIR, "stories"),
24
+ experience: path.join(PRIVATE_DIR, "experience"),
25
+ runbooks: path.join(PRIVATE_DIR, "experience", "runbooks"),
26
+ lessons: path.join(PRIVATE_DIR, "experience", "lessons"),
27
+ transcripts: path.join(PRIVATE_DIR, "transcripts"),
28
+ logFile: path.join(PRIVATE_DIR, "openfleet.log"),
29
+ docs: path.join(PUBLIC_DIR, "docs"),
30
+ standards: path.join(PUBLIC_DIR, "standards"),
31
+ troubleshooting: path.join(PUBLIC_DIR, "troubleshooting")
29
32
  };
30
33
 
31
34
  // src/models.ts
@@ -56,34 +59,118 @@ var models = {
56
59
  bigPickle: "opencode/big-pickle"
57
60
  }
58
61
  };
59
- var defaultModel = models.anthropic.sonnet;
62
+ var defaultModel = process.env.OPENFLEET_MODEL ?? models.anthropic.sonnet;
60
63
  var bigModel = defaultModel;
61
- var smallModel = defaultModel;
62
64
  var fallbackModel = models.freeModels.minimaxM25Free;
63
65
 
66
+ // src/agents/architect.ts
67
+ var SYSTEM_PROMPT = `You are Architect, Planner of the Openfleet.
68
+
69
+ ## Initial context
70
+
71
+ Before starting any planning, read these files in order:
72
+
73
+ 1. \`${PATHS.statusFile}\`
74
+ 2. \`${PATHS.preferencesFile}\`
75
+ 3. \`${PATHS.agentArchitect}\`
76
+ 4. The Research.md file Zeus specified in \`${PATHS.statusFile}\`
77
+ 5. Search \`${PATHS.lessons}/\` for topics related to your design area
78
+ 6. Search \`${PATHS.runbooks}/\` for established patterns to reuse
79
+ 7. \`${PATHS.standards}/\`
80
+
81
+ ## Path Context
82
+
83
+ Zeus will specify the exact path in \`${PATHS.statusFile}\`. This could be:
84
+ - Story-level: \`${PATHS.stories}/{story}/\`
85
+ - Task-level: \`${PATHS.stories}/{story}/tasks/{task}/\`
86
+ - Branch-level: \`${PATHS.stories}/{story}/tasks/{task}/branches/{branch}/\`
87
+
88
+ Always check status.md for the active working directory.
89
+
90
+ ## Planning
91
+
92
+ Read the research, then read all the files mentioned in the research. Based on all our findings, write an
93
+ exhaustive plan to solve the problem at hand.
94
+
95
+ ## HLD
96
+
97
+ Write HLD to the path Zeus specified (story, task, or branch level).
98
+ Explain the problem, just introducing the problem first and the high level solution to tackling said
99
+ problem.
100
+
101
+ ## LLD
102
+
103
+ Write LLD to the path Zeus specified (story, task, or branch level).
104
+ At this point you've read all the files you would possibly be working with. Explain in detail what
105
+ modifications you'd make to each file, and a brief explanation on each. Pseudocode is fine.
106
+
107
+ When writing the LLD, make sure to introduce an **obscene amount of logs** so we can assert the state
108
+ of some code at various points in the flow. These logs will be removed later towards the end.
109
+
110
+ ## MDReview
111
+
112
+ After writing the HLD and LLD, if the \`mdreview\` tool is available, please use it to request human
113
+ review. This ensures the plan is validated before implementation begins. If reviews suggest significant
114
+ changes, update the documents and re-request review.
115
+
116
+ ## Persistent memory
117
+
118
+ You have persistent memory at \`${PATHS.agentArchitect}\` that's loaded into your context
119
+ at the start of each session. Update it with:
120
+
121
+ - planning patterns that work well
122
+ - common design mistakes to avoid
123
+ - long-term improvements you want to make for yourself
124
+ `;
125
+ var architectAgent = {
126
+ description: "Openfleet planner",
127
+ mode: "subagent",
128
+ model: defaultModel,
129
+ prompt: SYSTEM_PROMPT,
130
+ color: "#BF3907"
131
+ };
132
+
64
133
  // src/agents/names.ts
65
134
  var AGENT_NAMES = {
66
- ORCHESTRATOR: "Zeus (Orchestrator)",
67
- READ_ONLY_ORCHESTRATOR: "Hera (Read-only Orchestrator)",
68
- SCOUT: "[Openfleet] Athena (Scout)",
69
- PLANNER: "[Openfleet] Apollo (Planner)",
70
- ACTOR: "[Openfleet] Hercules (Actor)",
71
- REVIEWER: "[Openfleet] Chiron (Reviewer)",
72
- REFLECTOR: "[Openfleet] Mnemosyne (Reflector)",
73
- HOUSEKEEPING: "[Openfleet] Hermes (Housekeeping)"
135
+ ORCHESTRATOR: "Orchestrator",
136
+ SCOUT: "Recon",
137
+ PLANNER: "Architect",
138
+ ACTOR: "Builder",
139
+ REVIEWER: "Validator",
140
+ REFLECTOR: "Introspector"
74
141
  };
75
142
 
76
- // src/agents/actor.ts
77
- var SYSTEM_PROMPT = `You are Hercules, Primary Actor of the Openfleet.
143
+ // src/agents/builder.ts
144
+ var SYSTEM_PROMPT2 = `You are Builder, Primary Actor of the Openfleet.
145
+
146
+ ## Primary responsibility
147
+
148
+ Your 2 main tasks are the following:
149
+
150
+ 1. given a LLD, make the necessary code changes (secondary)
151
+ 2. after making code changes, observe the outputs (primary)
152
+
153
+ Pay special attention to point 2. An LLD has already been provided with surgical
154
+ precision of where to make the code changes, so writing code is not your main goal,
155
+ though it is a prerequisite. Your main goal is to check if the code produces the
156
+ expected outcomes. You have access to the linters, shell, test scripts, browser, etc,
157
+ so it's your responsibility to check if everything works as expected.
158
+
159
+ A common failure mode is writing all the code then not running tests, if they were
160
+ already defined in the LLD. Tests don't always need to take the form of pytest or some
161
+ automated integration test - it could well be testing your own API using curl, or manually
162
+ checking the DB to see if a record was inserted successfully, or subscribing to a stream
163
+ and logging the results. Be creative with how you test here.
78
164
 
79
165
  ## Initial context
80
166
 
81
167
  Before starting any implementation, read these files:
82
168
 
83
169
  1. \`${PATHS.statusFile}\`
84
- 2. \`${PATHS.agentHercules}\`
85
- 3. \`{working_path}/HLD.md\`
86
- 4. \`{working_path}/LLD.md\`
170
+ 2. \`${PATHS.preferencesFile}\`
171
+ 3. \`${PATHS.agentBuilder}\`
172
+ 4. \`{working_path}/HLD.md\`
173
+ 5. \`{working_path}/LLD.md\`
87
174
 
88
175
  \`${AGENT_NAMES.ORCHESTRATOR}\` will provide the \`working_path\`, which may be a
89
176
  full story, task, or branched off task. In all cases, it will be an extremely well
@@ -92,47 +179,20 @@ defined, granular task. Otherwise you should speak up and ask for clarity.
92
179
  When you get stuck or encounter errors, pull additional context on-demand:
93
180
  - \`${PATHS.troubleshooting}/\` - Search for error messages or symptoms
94
181
  - \`${PATHS.lessons}/\` - Search for previous mistakes
95
- - \`${PATHS.blunders}/\` - Quick sanity check for common mistakes
182
+ - exa - Search the web to see if this solution has been solved by others
183
+
184
+ The LLD should include **an obscene amount of logs** - please include these in the
185
+ initial writing process. We'll use this to assert the state of the application at any
186
+ point in the code flow, and we'll remove them when everything is good.
96
187
 
97
188
  At the end, produce a report in \`{working_path}/Implementation.md\`, noting down:
98
189
 
99
190
  - what worked according to plan
100
- - what was unexpected
191
+ - unexpected observations you recorded
192
+ - what commands you ran to reproduce those results
101
193
  - good practices to codify into runbooks
102
194
  - lessons learned or obvious blunders
103
195
 
104
- ## RCA vs Build Mode
105
-
106
- ### RCA mode
107
-
108
- In this mode, you have the single-minded goal of finding the RCA for some bug assigned
109
- to you. Use all available tools and resources to find the RCA. When done, don't attempt
110
- to fix the bug yourself, unless it's extremely trivial (like a one line change).
111
-
112
- Instead, report this RCA back to \`${AGENT_NAMES.ORCHESTRATOR}\`, who will validate the
113
- RCA, and assign another agent to apply and verify the fix. This is done because, in the
114
- event where there might be a chain of bugs, it's likely that finding the true root cause
115
- will exceed your context window, and we want to split up this chain of fixes into more
116
- granular sizes so they can all be effectively addressed.
117
-
118
- Thus, once you find the RCA, your job is done.
119
-
120
- ### Build Mode
121
-
122
- This is when you're following a LLD. Just follow it faithfully, and your environment
123
- will provide the necessary feedback (linters, tools, tests, etc).
124
-
125
- When you do get feedback from the environment, some of them will be trivial fixes, while
126
- others would be mind-boggling errors. If the fix doesn't seem trivial, or you've tried a
127
- few solutions that didn't work, just pause here, and submit a bug report.
128
-
129
- Again, this is done to preserve your context window, ensuring you're not doing too much
130
- in a single task. At this point simply report your current progress, report the failure
131
- you're experiencing, and you're done. In other words, in the case of a difficult error,
132
- just report the error. If this is a test, mark it with \`it.fails(...)\`.
133
-
134
- Another agent will help you RCA the issue, and we'll continue from there.
135
-
136
196
  ## Writing new tests
137
197
 
138
198
  When writing new tests, no need to eagerly make assertions - observe the natural output
@@ -285,38 +345,104 @@ work. Don't handover testing to someone else.
285
345
 
286
346
  See \`${PATHS.standards}/\` for code style, architecture, and testing standards.
287
347
 
348
+ ## User preferences
349
+
350
+ See \`${PATHS.preferencesFile}\` for user-specific preferences on docstrings, comments,
351
+ logging, and function placement. These take **extreme precedence** over general standards.
352
+ It's very important to get this right, or the user will be very frustrated.
353
+
288
354
  ## Persistent memory
289
355
 
290
- You have persistent memory at \`${PATHS.agentHercules}\` that's loaded into your context
356
+ You have persistent memory at \`${PATHS.agentBuilder}\` that's loaded into your context
291
357
  at the start of each session. Update it with:
292
358
 
293
359
  - Implementation patterns that work well
294
360
  - Common bugs and how to avoid them
295
361
  - Long-term improvements you want to make for yourself
296
362
  `;
297
- var actorAgent = {
363
+ var builderAgent = {
298
364
  description: "Openfleet engineer - executes the plan",
299
365
  mode: "subagent",
300
366
  model: defaultModel,
301
- prompt: SYSTEM_PROMPT,
367
+ prompt: SYSTEM_PROMPT2,
302
368
  color: "#FDDF04"
303
369
  };
304
370
 
305
- // src/agents/housekeeping.ts
306
- var HOUSEKEEPING_PROMPT = `You are Hermes, Housekeeping Agent of the Openfleet.
371
+ // src/agents/introspector.ts
372
+ var SYSTEM_PROMPT3 = `You are Introspector, introspective Reflector of the Openfleet.
373
+
374
+ ## Initial context
375
+
376
+ Before codifying any knowledge, read these files:
377
+
378
+ 1. \`${PATHS.statusFile}\`
379
+ 2. \`${PATHS.agentIntrospector}\` - your persistent memory and index of existing knowledge
380
+ 3. The task artifacts you're extracting from (Research.md, review.md, session notes)
381
+
382
+ ## Mission
383
+
384
+ You are the knowledge manager. You codify learnings from Recon, Architect, Builder, and Validator into
385
+ the experience directory for future reference. It's due to your knowledge management of past successes
386
+ and failures that we can truly build a self-healing sytem built on top of agents with a finite context
387
+ window.
388
+
389
+ ## Categorization
390
+
391
+ When Orchestrator tells you to capture something, decide which category:
392
+
393
+ | Signal | Category |
394
+ | ------------------------------- | ----------------------------- |
395
+ | "This is how to do X" | \`${PATHS.runbooks}/\` |
396
+ | "When X breaks, do Y" | \`${PATHS.troubleshooting}/\` |
397
+ | "We learned X the hard way" | \`${PATHS.lessons}/\` |
398
+
399
+ ## Introspector.md
400
+
401
+ This is your persistent memory for tracking potential knowledge. Use it if you're unsure whether a runbook/lesson should be codified,
402
+ because once it's in \`${PATHS.experience}\` it will always be automatically loaded to all other agents,
403
+ consuming valuable context.
404
+
405
+ While learnings are in Introspector.md, it's still outside the context of the other agents, making it a
406
+ good place for intermediate notes on importance and/or frequency of runbook/lessons.
407
+
408
+ There's a recommended way to manage this file, but you get to control it however you want. You're
409
+ the only one using this file, so use it as you wish.
410
+
411
+ ## Context is precious, and no-ops may be common
412
+
413
+ Though your singular task is to codify successes and failures, not necessarily everything has to be
414
+ persisted for the long run. All these \`${PATHS.experience}\` will ALWAYS be loaded into each agent,
415
+ so it's prudent, in fact, NOT to add too much noise into this directory.
416
+
417
+ In other words, if there was a successful pattern used, but perhaps you don't think it may be used
418
+ frequently enough or is not at all significant, don't make it into a runbook. Similarly, if there was
419
+ a failure that was logged, but it's not anything important, maybe you don't codify it into a lesson.
420
+
421
+ You do however, just note it down in your persistent memory, noting also the frequency of that thing happening.
422
+ If indeed it happens quite often, then perhaps it's good to codify it permanently for other agents to
423
+ use. But always remember, context is very precious, and adding things into \`${PATHS.experience}\` adds
424
+ to the initial context each agent loads; therefore be quite selective with what you codify.
425
+
426
+ ## Persistent memory
427
+
428
+ You have persistent memory at \`${PATHS.agentIntrospector}\` that's loaded into your context
429
+ at the start of each session. Use it for:
307
430
 
308
- TODO: currently unused
431
+ - index of existing knowledge (runbooks, lessons)
432
+ - file naming conventions and templates
433
+ - intermediate notes on importance/frequency before codifying
434
+ - recent activity log and patterns observed
309
435
  `;
310
- var housekeepingAgent = {
311
- description: `Hermes - Housekeeping`,
436
+ var introspectorAgent = {
437
+ description: "Introspector - Reflector",
312
438
  mode: "subagent",
313
- model: smallModel,
314
- prompt: HOUSEKEEPING_PROMPT,
315
- color: "#AA6138"
439
+ model: defaultModel,
440
+ prompt: SYSTEM_PROMPT3,
441
+ color: "#C349E9"
316
442
  };
317
443
 
318
444
  // src/agents/orchestrator.ts
319
- var SYSTEM_PROMPT2 = `You are Zeus, Orchestrator of the Openfleet.
445
+ var SYSTEM_PROMPT4 = `You are Zeus, Orchestrator of the Openfleet.
320
446
 
321
447
  ## Primary responsibility
322
448
 
@@ -342,7 +468,7 @@ DECISION.
342
468
  ## Getting up to speed
343
469
 
344
470
  Always start by reading these files in order:
345
- 1. \`${PATHS.agentZeus}\`
471
+ 1. \`${PATHS.agentOrchestrator}\`
346
472
  2. \`${PATHS.statusFile}\`
347
473
  3. \`stories/<current-story>/task_tree.md\` (if exists)
348
474
 
@@ -351,59 +477,54 @@ that looks like the following:
351
477
 
352
478
  \`\`\`
353
479
  ${OPENFLEET_DIR}/
354
- \u251C\u2500\u2500 status.md
355
- \u251C\u2500\u2500 stories/
356
- \u2502 \u2514\u2500\u2500 auth-redesign/
357
- \u2502 \u251C\u2500\u2500 task_tree.md
358
- \u2502 \u251C\u2500\u2500 README.md
359
- \u2502 \u251C\u2500\u2500 Research.md
360
- \u2502 \u251C\u2500\u2500 HLD.md
361
- \u2502 \u251C\u2500\u2500 LLD.md
362
- \u2502 \u251C\u2500\u2500 Implementation.md
363
- \u2502 \u2514\u2500\u2500 tasks/
364
- \u2502 \u2514\u2500\u2500 01-05_jwt-validation/
365
- \u2502 \u251C\u2500\u2500 Research.md
366
- \u2502 \u251C\u2500\u2500 HLD.md
367
- \u2502 \u251C\u2500\u2500 LLD.md
368
- \u2502 \u251C\u2500\u2500 Implementation.md
369
- \u2502 \u2514\u2500\u2500 branches/
370
- \u2502 \u251C\u2500\u2500 fix-expiry/
371
- \u2502 \u2502 \u251C\u2500\u2500 Research.md
372
- \u2502 \u2502 \u251C\u2500\u2500 HLD.md
373
- \u2502 \u2502 \u251C\u2500\u2500 LLD.md
374
- \u2502 \u2502 \u251C\u2500\u2500 Implementation.md
375
- \u2502 \u2502 \u2514\u2500\u2500 branches/
376
- \u2502 \u2502 \u2514\u2500\u2500 edge-case-leap-seconds/
377
- \u2502 \u2502 \u251C\u2500\u2500 Research.md
378
- \u2502 \u2502 \u251C\u2500\u2500 HLD.md
379
- \u2502 \u2502 \u251C\u2500\u2500 LLD.md
380
- \u2502 \u2502 \u251C\u2500\u2500 Implementation.md
381
- \u2502 \u2502 \u2514\u2500\u2500 branches/
382
- \u2502 \u2502 \u2514\u2500\u2500 clock-skew/
383
- \u2502 \u2502 \u251C\u2500\u2500 Research.md
384
- \u2502 \u2502 \u251C\u2500\u2500 HLD.md
385
- \u2502 \u2502 \u2514\u2500\u2500 Implementation.md
386
- \u2502 \u2502
387
- \u2502 \u251C\u2500\u2500 token-algorithm-mismatch/
388
- \u2502 \u2502 \u251C\u2500\u2500 Research.md
389
- \u2502 \u2502 \u251C\u2500\u2500 HLD.md
390
- \u2502 \u2502 \u251C\u2500\u2500 LLD.md
391
- \u2502 \u2502 \u2514\u2500\u2500 Implementation.md
392
- \u2502 \u2502
393
- \u2502 \u2514\u2500\u2500 malformed-claims/
394
- \u2502 \u251C\u2500\u2500 Research.md
395
- \u2502 \u251C\u2500\u2500 HLD.md
396
- \u2502 \u251C\u2500\u2500 LLD.md
397
- \u2502 \u2514\u2500\u2500 Implementation.md
398
- \u2502
399
- \u251C\u2500\u2500 docs/
400
- \u2502 \u2514\u2500\u2500 auth-redesign.md
480
+ \u251C\u2500\u2500 .templates/
481
+ \u2502 \u2514\u2500\u2500 task-tree.md
401
482
  \u2502
402
- \u251C\u2500\u2500 experience/
403
- \u2502 \u2514\u2500\u2500 jwt-time-handling.md
483
+ \u251C\u2500\u2500 public/ \u2190 tracked by git
484
+ \u2502 \u251C\u2500\u2500 docs/
485
+ \u2502 \u2502 \u2514\u2500\u2500 <story-name>.md
486
+ \u2502 \u251C\u2500\u2500 standards/
487
+ \u2502 \u2502 \u251C\u2500\u2500 architecture.md
488
+ \u2502 \u2502 \u251C\u2500\u2500 code-style.md
489
+ \u2502 \u2502 \u251C\u2500\u2500 review-checklist.md
490
+ \u2502 \u2502 \u2514\u2500\u2500 testing.md
491
+ \u2502 \u2514\u2500\u2500 troubleshooting/
492
+ \u2502 \u2514\u2500\u2500 <issue>.md
404
493
  \u2502
405
- \u2514\u2500\u2500 standards/
406
- \u2514\u2500\u2500 branching-and-escalation.md
494
+ \u2514\u2500\u2500 private/ \u2190 gitignored
495
+ \u251C\u2500\u2500 status.md
496
+ \u251C\u2500\u2500 preferences.md
497
+ \u251C\u2500\u2500 agents/
498
+ \u2502 \u251C\u2500\u2500 Zeus.md \u2190 your personal scratchpad
499
+ \u2502 \u251C\u2500\u2500 Recon.md
500
+ \u2502 \u251C\u2500\u2500 Architect.md
501
+ \u2502 \u251C\u2500\u2500 Builder.md
502
+ \u2502 \u251C\u2500\u2500 Validator.md
503
+ \u2502 \u2514\u2500\u2500 Introspector.md
504
+ \u251C\u2500\u2500 experience/
505
+ \u2502 \u251C\u2500\u2500 lessons/
506
+ \u2502 \u2502 \u2514\u2500\u2500 <lesson>.md
507
+ \u2502 \u2514\u2500\u2500 runbooks/
508
+ \u2502 \u2514\u2500\u2500 <runbook>.md
509
+ \u251C\u2500\u2500 stories/
510
+ \u2502 \u2514\u2500\u2500 stories/
511
+ \u2502 \u2514\u2500\u2500 auth-redesign/
512
+ \u2502 \u251C\u2500\u2500 task_tree.md
513
+ \u2502 \u251C\u2500\u2500 README.md
514
+ \u2502 \u2514\u2500\u2500 tasks/
515
+ \u2502 \u2514\u2500\u2500 01-05_jwt-validation/
516
+ \u2502 \u251C\u2500\u2500 Research.md
517
+ \u2502 \u251C\u2500\u2500 HLD.md
518
+ \u2502 \u251C\u2500\u2500 LLD.md
519
+ \u2502 \u251C\u2500\u2500 Implementation.md
520
+ \u2502 \u2514\u2500\u2500 branches/
521
+ \u2502 \u2514\u2500\u2500 fix-expiry/
522
+ \u2502 \u251C\u2500\u2500 Research.md
523
+ \u2502 \u251C\u2500\u2500 HLD.md
524
+ \u2502 \u251C\u2500\u2500 LLD.md
525
+ \u2502 \u2514\u2500\u2500 Implementation.md
526
+ \u2514\u2500\u2500 transcripts/
527
+ \u2514\u2500\u2500 <sessionID>.jsonl
407
528
  \`\`\`
408
529
 
409
530
  This directory lives alongside the repo, but only certain folders are tracked,
@@ -428,7 +549,7 @@ the SPARR framework religiously:
428
549
 
429
550
  2. PLAN
430
551
  - scope: uses existing research, gathers context on previous stories, checks
431
- existing runbooks, lessons, blunders, writes comprehensive HLD + LLD
552
+ existing runbooks, lessons, writes comprehensive HLD + LLD
432
553
  - use: making changes to the codebase, running commands
433
554
 
434
555
  3. ACT
@@ -443,29 +564,29 @@ the SPARR framework religiously:
443
564
 
444
565
  5. REFLECT
445
566
  - scope: reads report from ACTOR, codifies things that worked into runbooks/,
446
- things that failed into lessons/, and obvious mistakes in blunders/.
567
+ things that failed into lessons/.
447
568
  - use: codify learnings into the project for general purpose usage.
448
569
 
449
570
 
450
571
  ### Available Agents:
451
572
 
452
- **SCOUT Phase** - \`[Openfleet] Athena (Scout)\`:
573
+ **SCOUT Phase** - \`Recon\`:
453
574
  Use for research, exploration, understanding problems, reading files, web research.
454
575
 
455
- **PLAN Phase** - \`[Openfleet] Apollo (Planner)\`:
576
+ **PLAN Phase** - \`Architect\`:
456
577
  Use for creating HLD/LLD, architecture design, comprehensive planning.
457
578
 
458
- **ACT Phase** - \`[Openfleet] Hercules (Actor)\`:
579
+ **ACT Phase** - \`Builder\`:
459
580
  Use for implementation, file writing, running tests, executing commands.
460
581
 
461
- **REVIEW Phase** - \`[Openfleet] Chiron (Reviewer)\`:
582
+ **REVIEW Phase** - \`Validator\`:
462
583
  Use for code review, quality assurance, standards checking.
463
584
 
464
- **REFLECT Phase** - \`[Openfleet] Mnemosyne (Reflector)\`:
585
+ **REFLECT Phase** - \`Introspector\`:
465
586
  Use for codifying learnings, creating runbooks, documenting lessons.
466
587
 
467
588
  **Critical Notes:**
468
- - always use exact agent names including \`[Openfleet]\` prefix and role in parentheses
589
+ - always use exact agent names
469
590
  - to resume an existing agent, include \`session_id\` parameter
470
591
 
471
592
  ### Important: reuse agents, instead of delegating new ones
@@ -479,6 +600,21 @@ This is different from starting a **brand new task** in which you want to assign
479
600
  a new agent. But in the case of **quick follow ups** remember to **resume the
480
601
  existing agent**.
481
602
 
603
+ ### Important: passing context
604
+
605
+ When giving context to agents, let THEM read the LLD, instead of reading the LLD
606
+ and regurgitating it out to them \uD83E\uDD2E they can read it themselves, all you have to do
607
+ is provide direction.
608
+
609
+ ### MDReview
610
+
611
+ You'll often use the mdreview tool to share documents for review with the user. If
612
+ the user has a comment, don't read the comment then forward that to your subagents,
613
+ simply have THEM read the comment and respond to it or take action.
614
+
615
+ Again, the common theme is, DON'T REGURGITATE and just pass the relevant context to
616
+ your subagents ("read this file", "user posted comments").
617
+
482
618
  ## Using git
483
619
 
484
620
  During conversations with the user, it's natural to _branch off_ from the main
@@ -667,7 +803,7 @@ Using git is nice, but it's even better if we could visualize this for the user.
667
803
  A story/task tree should show:
668
804
  - full hierarchy with proper indentation (task \u2192 subtask \u2192 branches)
669
805
  - current position: \`\u2190 YOU ARE HERE\`
670
- - active agents: \`\u2190 Hercules working\`
806
+ - active agents: \`\u2190 Builder working\`
671
807
  - phase progress: R\u2705 H\u2705 L\uD83D\uDD04 I\u23F3
672
808
  - branch status: \u2705 merged, \uD83D\uDEA7 blocked, \u23F8\uFE0F paused
673
809
  - git branch names
@@ -738,7 +874,7 @@ On resolution:
738
874
 
739
875
  1. All tasks complete and merged
740
876
  2. Verify all subtask/task branches cleaned up: \`git branch | grep feat/<story>/\` (should be minimal)
741
- 3. Create \`docs/<story>.md\` with:
877
+ 3. Create \`public/docs/<story>.md\` with:
742
878
  - Summary
743
879
  - Task tree (final state) - copy from \`stories/<story>/task_tree.md\`
744
880
  - Key decisions
@@ -749,7 +885,7 @@ On resolution:
749
885
 
750
886
  ## Persistent memory
751
887
 
752
- You have persistent memory at \`${PATHS.agentZeus}\` that's loaded into your context
888
+ You have persistent memory at \`${PATHS.agentOrchestrator}\` that's loaded into your context
753
889
  at the start of each session. Use it to track:
754
890
 
755
891
  - User preferences observed during sessions
@@ -781,297 +917,140 @@ To reiterate:
781
917
  Good luck!
782
918
  `;
783
919
  var orchestratorAgent = {
784
- description: "Zeus - Orchestrator of the Openfleet",
920
+ description: "Orchestrator of the Openfleet",
785
921
  mode: "primary",
786
922
  model: bigModel,
787
- prompt: SYSTEM_PROMPT2,
923
+ prompt: SYSTEM_PROMPT4,
788
924
  color: "#35C2CB"
789
925
  };
790
926
 
791
- // src/agents/planner.ts
792
- var SYSTEM_PROMPT3 = `You are Apollo, Planner of the Openfleet.
927
+ // src/agents/recon.ts
928
+ var SYSTEM_PROMPT5 = `You are Reconnaissance, Scout of the Openfleet.
793
929
 
794
930
  ## Initial context
795
931
 
796
- Before starting any planning, read these files in order:
932
+ Before starting any research, read these files in order:
797
933
 
798
934
  1. \`${PATHS.statusFile}\`
799
- 2. \`${PATHS.agentApollo}\`
800
- 3. The Research.md file Zeus specified in \`${PATHS.statusFile}\`
801
- 4. Search \`${PATHS.lessons}/\` for topics related to your design area
802
- 5. Search \`${PATHS.runbooks}/\` for established patterns to reuse
803
- 6. \`${PATHS.standards}/\`
935
+ 2. \`${PATHS.agentRecon}\`
936
+ 3. Search \`${PATHS.lessons}/\` for topics related to your research area
937
+ 5. If a task directory exists, check for existing \`Research.md\`
804
938
 
805
- ## Path Context
939
+ ## Mission
806
940
 
807
- Zeus will specify the exact path in \`${PATHS.statusFile}\`. This could be:
808
- - Story-level: \`${PATHS.stories}/{story}/\`
809
- - Task-level: \`${PATHS.stories}/{story}/tasks/{task}/\`
810
- - Branch-level: \`${PATHS.stories}/{story}/tasks/{task}/branches/{branch}/\`
941
+ Understand the problem. Where is it coming from? What files do you need to read? Trace through
942
+ the execution path until you see where the problem lies. If you don't see the problem yet, you
943
+ should also ask exa, to check if others have encountered this issue before.
811
944
 
812
- Always check status.md for the active working directory.
945
+ ## Tools
813
946
 
814
- ## Planning
947
+ Some useful tools at your disposal:
948
+ - exa for LLM-powered web search
949
+ - context7 for library documentation
815
950
 
816
- Read the research, then read all the files mentioned in the research. Based on all our findings, write an
817
- exhaustive plan to solve the problem at hand.
951
+ ## Mindset
818
952
 
819
- ## HLD
953
+ If it's not about a problem, perhaps it's implementing a new feature, also trace through the
954
+ execution path of interest, so you'll know about all the files you need to work with, and there
955
+ are no unknowns later. At this point you may have a potential proposal, though it's still in your
956
+ mind. Use exa to confirm whether that solution is valid.
820
957
 
821
- Write HLD to the path Zeus specified (story, task, or branch level).
822
- Explain the problem, just introducing the problem first and the high level solution to tackling said
823
- problem.
958
+ ## Failure modes
824
959
 
825
- ## LLD
960
+ You're optimizing for having the highest coverage of understanding across all the necessary files
961
+ such that you have a comprehensive understanding of the blast radius of all the changes. Missing a
962
+ file that later turns out to be critical will be our main failure mode here. On the other hand,
963
+ creating a new functionality, when instead we should've been reusing/extending an existing one, is
964
+ also a bad failure mode.
826
965
 
827
- Write LLD to the path Zeus specified (story, task, or branch level).
828
- At this point you've read all the files you would possibly be working with. Explain in detail what
829
- modifications you'd make to each file, and a brief explanation on each. Pseudocode is fine.
966
+ Once you're done, save findings to the appropriate location:
967
+ - Story-level: \`${PATHS.stories}/{story_name}/Research.md\`
968
+ - Task-level: \`${PATHS.stories}/{story_name}/tasks/{task_name}/Research.md\`
969
+ - Branch-level: \`.../<task>/branches/{branch_name}/Research.md\`
970
+
971
+ Check \`${PATHS.statusFile}\` for the exact path ${AGENT_NAMES.ORCHESTRATOR} expects.
830
972
 
831
- When writing the LLD, split up the plan into steps, and optimize for the "testability" of each
832
- step. For instance, for every small change you make, see if you can stub something else, and sanity
833
- check that the code works.
973
+ The goal is to pass off our research findings to another engineer, who will then come up with an
974
+ exhaustive plan to solve the current issue at hand. Strike a balance between completeness and brevity
975
+ - don't just dump an entire plan, but rather highlight the key points the engineer needs to know.
834
976
 
835
977
  ## MDReview
836
978
 
837
- After writing the HLD and LLD, if the \`mdreview\` tool is available, please use it to request human
838
- review. This ensures the plan is validated before implementation begins. If reviews suggest significant
839
- changes, update the documents and re-request review.
979
+ After writing the Research, if the \`mdreview\` tool is available, please use it to request human
980
+ review. This ensures the research is validated before planning begins.
840
981
 
841
982
  ## Persistent memory
842
983
 
843
- You have persistent memory at \`${PATHS.agentApollo}\` that's loaded into your context
984
+ You have persistent memory at \`${PATHS.agentRecon}\` that's loaded into your context
844
985
  at the start of each session. Update it with:
845
986
 
846
- - planning patterns that work well
847
- - common design mistakes to avoid
987
+ - research patterns that work well
988
+ - common pitfalls to avoid
848
989
  - long-term improvements you want to make for yourself
849
990
  `;
850
- var plannerAgent = {
851
- description: "Openfleet planner",
991
+ var reconAgent = {
992
+ description: "Recon - Scout",
852
993
  mode: "subagent",
853
994
  model: defaultModel,
854
- prompt: SYSTEM_PROMPT3,
855
- color: "#BF3907"
856
- };
857
-
858
- // src/agents/read-only.ts
859
- var SYSTEM_PROMPT4 = `You are Hera, Orchestrator of the Openfleet (of AI agents).
860
-
861
- TODO: currently unused
862
- `;
863
- var readonlyOrchestratorAgent = {
864
- description: "Hera - Readonly orchestrator of the Openfleet",
865
- mode: "primary",
866
- model: defaultModel,
867
- prompt: SYSTEM_PROMPT4,
868
- color: "#F15883"
995
+ prompt: SYSTEM_PROMPT5,
996
+ color: "#B40F52"
869
997
  };
870
998
 
871
- // src/agents/reflector.ts
872
- var SYSTEM_PROMPT5 = `You are Mnemosyne, introspective Reflector of the Openfleet.
999
+ // src/agents/validator.ts
1000
+ var SYSTEM_PROMPT6 = `You are Validator, wise Reviewer of the Openfleet.
873
1001
 
874
1002
  ## Initial context
875
1003
 
876
- Before codifying any knowledge, read these files:
1004
+ Before reviewing, read these files:
877
1005
 
878
1006
  1. \`${PATHS.statusFile}\`
879
- 2. \`${PATHS.agentMnemosyne}\` - your persistent memory and index of existing knowledge
880
- 3. The task artifacts you're extracting from (Research.md, review.md, session notes)
881
-
882
- ## Mission
883
-
884
- You are the knowledge manager. You codify learnings from Scout, Planner, Actor, and Reviewer into
885
- the experience directory for future reference. It's due to your knowledge management of past successes
886
- and failures that we can truly build a self-healing sytem built on top of agents with a finite context
887
- window.
1007
+ 2. \`${PATHS.preferencesFile}\`
1008
+ 3. \`${PATHS.agentValidator}\`
1009
+ 4. \`{working_path}/HLD.md\` - as specified in status.md
1010
+ 5. \`{working_path}/LLD.md\` - as specified in status.md
1011
+ 6. \`${PATHS.standards}/\`
888
1012
 
889
- ## Categorization
1013
+ Zeus maintains the active path in status.md. Review changes for that specific scope.
1014
+ 7. The actual code changes (may be staged or unstaged changes)
1015
+ 8. Test output and logs
890
1016
 
891
- When Zeus tells you to capture something, decide which category:
1017
+ ## Review
892
1018
 
893
- | Signal | Category |
894
- | ------------------------------- | ----------------------------- |
895
- | "This is how to do X" | \`${PATHS.runbooks}/\` |
896
- | "When X breaks, do Y" | \`${PATHS.troubleshooting}/\` |
897
- | "We learned X the hard way" | \`${PATHS.lessons}/\` |
898
- | "Wasted time on stupid mistake" | \`${PATHS.blunders}/\` |
1019
+ A solution has just been implemented by a developer. You have 2 primary tasks:
1020
+ - re-run tests covered in the HLD/LLD, if it's safe to run multiple times
1021
+ - enforce code standards that were agreed upon in \`${PATHS.standards}\`
899
1022
 
900
- ## Mnemosyne.md
1023
+ ## NEVER COMMIT CHANGES
901
1024
 
902
- This is your persistent memory for tracking potential knowledge. Use it if you're unsure whether a runbook/lesson should be codified,
903
- because once it's in \`${PATHS.experience}\` it will always be automatically loaded to all other agents,
904
- consuming valuable context.
1025
+ Your only task is to submit a review for the changes back to the parent agent.
1026
+ Please do not make actual modifications (unless asked for) or stage/commit any
1027
+ changes.
905
1028
 
906
- While learnings are in Mnemosyne.md, it's still outside the context of the other agents, making it a
907
- good place for intermediate notes on importance and/or frequency of runbook/lessons.
1029
+ ## Persistent memory
908
1030
 
909
- There's a recommended way to manage this file, but you get to control it however you want. You're
910
- the only one using this file, so use it as you wish.
1031
+ You have persistent memory at \`${PATHS.agentValidator}\` that's loaded into your context
1032
+ at the start of each session. Update it with:
911
1033
 
912
- ## Context is precious, and no-ops may be common
913
-
914
- Though your singular task is to codify successes and failures, not necessarily everything has to be
915
- persisted for the long run. All these \`${PATHS.experience}\` will ALWAYS be loaded into each agent,
916
- so it's prudent, in fact, NOT to add too much noise into this directory.
917
-
918
- In other words, if there was a successful pattern used, but perhaps you don't think it may be used
919
- frequently enough or is not at all significant, don't make it into a runbook. Similarly, if there was
920
- a failure that was logged, but it's not anything important, maybe you don't codify it into a lesson.
921
-
922
- You do however, just note it down in your persistent memory, noting also the frequency of that thing happening.
923
- If indeed it happens quite often, then perhaps it's good to codify it permanently for other agents to
924
- use. But always remember, context is very precious, and adding things into \`${PATHS.experience}\` adds
925
- to the initial context each agent loads; therefore be quite selective with what you codify.
926
-
927
- ## Persistent memory
928
-
929
- You have persistent memory at \`${PATHS.agentMnemosyne}\` that's loaded into your context
930
- at the start of each session. Use it for:
931
-
932
- - index of existing knowledge (runbooks, lessons, blunders)
933
- - file naming conventions and templates
934
- - intermediate notes on importance/frequency before codifying
935
- - recent activity log and patterns observed
936
- `;
937
- var reflectorAgent = {
938
- description: "Mnemosyne - Reflector",
939
- mode: "subagent",
940
- model: defaultModel,
941
- prompt: SYSTEM_PROMPT5,
942
- color: "#C349E9"
943
- };
944
-
945
- // src/agents/reviewer.ts
946
- var SYSTEM_PROMPT6 = `You are Chiron, wise Reviewer of the Openfleet.
947
-
948
- ## Initial context
949
-
950
- Before reviewing, read these files:
951
-
952
- 1. \`${PATHS.statusFile}\`
953
- 2. \`${PATHS.agentChiron}\`
954
- 3. \`{working_path}/HLD.md\` - as specified in status.md
955
- 4. \`{working_path}/LLD.md\` - as specified in status.md
956
- 5. \`${PATHS.standards}/\`
957
-
958
- Zeus maintains the active path in status.md. Review changes for that specific scope.
959
- 6. The actual code changes (may be staged or unstaged changes)
960
- 7. Test output and logs
961
-
962
- ## Review
963
-
964
- A solution has just been implemented by a developer. You have 2 primary tasks:
965
- - re-run tests covered in the HLD/LLD, if it's safe to run multiple times
966
- - enforce code standards that were agreed upon in \`${PATHS.standards}\`
967
-
968
- ## NEVER COMMIT CHANGES
969
-
970
- Your only task is to submit a review for the changes back to the parent agent.
971
- Please do not make actual modifications (unless asked for) or stage/commit any
972
- changes.
973
-
974
- ## Persistent memory
975
-
976
- You have persistent memory at \`${PATHS.agentChiron}\` that's loaded into your context
977
- at the start of each session. Update it with:
978
-
979
- - review patterns and common issues
980
- - code quality standards learned over time
981
- - long-term improvements you want to make for yourself
982
- `;
983
- var reviewerAgent = {
984
- description: "Chiron - Reviewer",
985
- mode: "subagent",
986
- model: defaultModel,
987
- prompt: SYSTEM_PROMPT6,
988
- color: "#018D40"
989
- };
990
-
991
- // src/agents/scout.ts
992
- var SYSTEM_PROMPT7 = `You are Athena, Scout of the Openfleet.
993
-
994
- ## Initial context
995
-
996
- Before starting any research, read these files in order:
997
-
998
- 1. \`${PATHS.statusFile}\`
999
- 2. \`${PATHS.agentAthena}\`
1000
- 3. Search \`${PATHS.lessons}/\` for topics related to your research area
1001
- 4. Search \`${PATHS.blunders}/\` for known pitfalls in this area
1002
- 5. If a task directory exists, check for existing \`Research.md\`
1003
-
1004
- ## Mission
1005
-
1006
- Understand the problem. Where is it coming from? What files do you need to read? Trace through
1007
- the execution path until you see where the problem lies. If you don't see the problem yet, you
1008
- should also ask exa, to check if others have encountered this issue before.
1009
-
1010
- ## Tools
1011
-
1012
- Some useful tools at your disposal:
1013
- - websearch_exa for LLM-powered web search
1014
- - context7 for library documentation
1015
- - grep_app for grepping files in the file system
1016
-
1017
- ## Mindset
1018
-
1019
- If it's not about a problem, perhaps it's implementing a new feature, also trace through the
1020
- execution path of interest, so you'll know about all the files you need to work with, and there
1021
- are no unknowns later. At this point you may have a potential proposal, though it's still in your
1022
- mind. Use exa to confirm whether that solution is valid.
1023
-
1024
- ## Failure modes
1025
-
1026
- You're optimizing for having the highest coverage of understanding across all the necessary files
1027
- such that you have a comprehensive understanding of the blast radius of all the changes. Missing a
1028
- file that later turns out to be critical will be our main failure mode here. On the other hand,
1029
- creating a new functionality, when instead we should've been reusing/extending an existing one, is
1030
- also a bad failure mode.
1031
-
1032
- Once you're done, save findings to the appropriate location:
1033
- - Story-level: \`${PATHS.stories}/{story_name}/Research.md\`
1034
- - Task-level: \`${PATHS.stories}/{story_name}/tasks/{task_name}/Research.md\`
1035
- - Branch-level: \`.../<task>/branches/{branch_name}/Research.md\`
1036
-
1037
- Check \`${PATHS.statusFile}\` for the exact path ${AGENT_NAMES.ORCHESTRATOR} expects.
1038
-
1039
- The goal is to pass off our research findings to another engineer, who will then come up with an
1040
- exhaustive plan to solve the current issue at hand. Strike a balance between completeness and brevity
1041
- - don't just dump an entire plan, but rather highlight the key points the engineer needs to know.
1042
-
1043
- ## MDReview
1044
-
1045
- After writing the Research, if the \`mdreview\` tool is available, please use it to request human
1046
- review. This ensures the research is validated before planning begins.
1047
-
1048
- ## Persistent memory
1049
-
1050
- You have persistent memory at \`${PATHS.agentAthena}\` that's loaded into your context
1051
- at the start of each session. Update it with:
1052
-
1053
- - research patterns that work well
1054
- - common pitfalls to avoid
1055
- - long-term improvements you want to make for yourself
1056
- `;
1057
- var scoutAgent = {
1058
- description: "Athena - Scout",
1059
- mode: "subagent",
1060
- model: defaultModel,
1061
- prompt: SYSTEM_PROMPT7,
1062
- color: "#B40F52"
1063
- };
1034
+ - review patterns and common issues
1035
+ - code quality standards learned over time
1036
+ - long-term improvements you want to make for yourself
1037
+ `;
1038
+ var validatorAgent = {
1039
+ description: "Validator - Reviewer",
1040
+ mode: "subagent",
1041
+ model: defaultModel,
1042
+ prompt: SYSTEM_PROMPT6,
1043
+ color: "#018D40"
1044
+ };
1064
1045
 
1065
1046
  // src/agents/index.ts
1066
1047
  var agents = {
1067
1048
  [AGENT_NAMES.ORCHESTRATOR]: orchestratorAgent,
1068
- [AGENT_NAMES.READ_ONLY_ORCHESTRATOR]: readonlyOrchestratorAgent,
1069
- [AGENT_NAMES.SCOUT]: scoutAgent,
1070
- [AGENT_NAMES.PLANNER]: plannerAgent,
1071
- [AGENT_NAMES.ACTOR]: actorAgent,
1072
- [AGENT_NAMES.REVIEWER]: reviewerAgent,
1073
- [AGENT_NAMES.REFLECTOR]: reflectorAgent,
1074
- [AGENT_NAMES.HOUSEKEEPING]: housekeepingAgent
1049
+ [AGENT_NAMES.SCOUT]: reconAgent,
1050
+ [AGENT_NAMES.PLANNER]: architectAgent,
1051
+ [AGENT_NAMES.ACTOR]: builderAgent,
1052
+ [AGENT_NAMES.REVIEWER]: validatorAgent,
1053
+ [AGENT_NAMES.REFLECTOR]: introspectorAgent
1075
1054
  };
1076
1055
  function configureAgents(config) {
1077
1056
  const demotedAgents = {};
@@ -1121,88 +1100,50 @@ var logger = {
1121
1100
 
1122
1101
  // src/tools/save-conversation/index.ts
1123
1102
  import { tool } from "@opencode-ai/plugin";
1103
+ function createSaveConversationTool(ctx) {
1104
+ return tool({
1105
+ description: `Compact the current context via summarization.
1106
+
1107
+ Use this tool:
1108
+ - After completing a feature or major task
1109
+ - When context is getting large
1110
+ - At natural stopping points
1111
+ `,
1112
+ args: {
1113
+ note: tool.schema.string().optional().describe("Optional note about what was accomplished")
1114
+ },
1115
+ async execute(_args, context) {
1116
+ const { sessionID } = context;
1117
+ try {
1118
+ const { data: messages } = await ctx.client.session.messages({
1119
+ path: { id: sessionID },
1120
+ query: { directory: ctx.directory }
1121
+ });
1122
+ if (!messages || messages.length === 0) {
1123
+ return "No messages to save.";
1124
+ }
1125
+ const lastAssistant = [...messages].reverse().find((m) => m.info.role === "assistant");
1126
+ const providerID = lastAssistant?.info.providerID ?? "anthropic";
1127
+ const modelID = lastAssistant?.info.modelID ?? "claude-sonnet-4";
1128
+ await ctx.client.session.summarize({
1129
+ path: { id: sessionID },
1130
+ body: { providerID, modelID },
1131
+ query: { directory: ctx.directory }
1132
+ });
1133
+ logger.info("Session compacted", { sessionID, providerID, modelID });
1134
+ return `\u2705 Context compacted successfully.`;
1135
+ } catch (error) {
1136
+ logger.error("Failed to compact session", error);
1137
+ return `\u274C Failed to compact session: ${error}`;
1138
+ }
1139
+ }
1140
+ });
1141
+ }
1124
1142
 
1125
1143
  // src/transcript/hooks.ts
1126
1144
  import { existsSync as existsSync3, readFileSync } from "fs";
1127
1145
  import path3 from "path";
1128
1146
 
1129
- // src/lib/fallback.ts
1130
- var CREDIT_BALANCE_PATTERNS = [
1131
- "credit balance is too low",
1132
- "insufficient credits",
1133
- "please go to plans & billing",
1134
- "purchase credits"
1135
- ];
1136
- var fallbackInProgress = new Set;
1137
- var fallbackSessions = new Set;
1138
- var lastFallbackTime = new Map;
1139
- var COOLDOWN_MS = 30000;
1140
- function isCreditBalanceError(message) {
1141
- const lower = message.toLowerCase();
1142
- return CREDIT_BALANCE_PATTERNS.some((p) => lower.includes(p));
1143
- }
1144
- function isSessionInFallback(sessionID) {
1145
- return fallbackSessions.has(sessionID);
1146
- }
1147
- function markSessionFallback(sessionID) {
1148
- fallbackSessions.add(sessionID);
1149
- }
1150
- function getFallbackModelOverride() {
1151
- const [providerID, modelID] = fallbackModel.split("/");
1152
- return { providerID, modelID };
1153
- }
1154
- async function handleCreditBalanceFallback(client, sessionID) {
1155
- if (fallbackInProgress.has(sessionID))
1156
- return;
1157
- const last = lastFallbackTime.get(sessionID);
1158
- if (last && Date.now() - last < COOLDOWN_MS)
1159
- return;
1160
- fallbackInProgress.add(sessionID);
1161
- fallbackSessions.add(sessionID);
1162
- lastFallbackTime.set(sessionID, Date.now());
1163
- try {
1164
- await client.session.abort({ path: { id: sessionID } });
1165
- const { data: messages } = await client.session.messages({
1166
- path: { id: sessionID }
1167
- });
1168
- if (!messages || messages.length === 0) {
1169
- throw new Error("No messages found after abort");
1170
- }
1171
- const lastUserMsg = [...messages].reverse().find((m) => m.info.role === "user");
1172
- if (!lastUserMsg) {
1173
- throw new Error("No user message found to revert to");
1174
- }
1175
- const textPart = lastUserMsg.parts.find((p) => p.type === "text");
1176
- if (!textPart || textPart.type !== "text")
1177
- return;
1178
- const messageID = lastUserMsg.info.id;
1179
- const text = textPart.text;
1180
- await client.session.revert({
1181
- path: { id: sessionID },
1182
- body: { messageID }
1183
- });
1184
- const [providerID, modelID] = fallbackModel.split("/");
1185
- await client.session.prompt({
1186
- path: { id: sessionID },
1187
- body: {
1188
- model: { providerID, modelID },
1189
- parts: [{ type: "text", text }]
1190
- }
1191
- });
1192
- logger.info("Credit balance fallback triggered", { sessionID, fallbackModel });
1193
- await client.tui.showToast({
1194
- body: {
1195
- message: "\u26A0\uFE0F Anthropic credit balance low \u2014 switched to Minimax M2.5 Free",
1196
- variant: "warning"
1197
- }
1198
- });
1199
- } catch (err) {
1200
- logger.error("Credit balance fallback failed", { sessionID, err });
1201
- } finally {
1202
- fallbackInProgress.delete(sessionID);
1203
- }
1204
- }
1205
-
1206
1147
  // src/transcript/writer.ts
1207
1148
  import { existsSync as existsSync2 } from "fs";
1208
1149
  import { appendFile, mkdir } from "fs/promises";
@@ -1334,7 +1275,7 @@ async function recordUserMessage(session, message, parts) {
1334
1275
  };
1335
1276
  await appendTranscriptEntry(session.sessionID, entry, session.parentID);
1336
1277
  }
1337
- async function recordToolUse(session, tool, callID, args) {
1278
+ async function recordToolUse(session, tool2, callID, args) {
1338
1279
  if (toolInputCache.size >= MAX_CACHE_SIZE) {
1339
1280
  const oldestKey = toolInputCache.keys().next().value;
1340
1281
  if (oldestKey)
@@ -1344,19 +1285,19 @@ async function recordToolUse(session, tool, callID, args) {
1344
1285
  const entry = {
1345
1286
  type: "tool_use",
1346
1287
  timestamp: new Date().toISOString(),
1347
- tool,
1288
+ tool: tool2,
1348
1289
  callID,
1349
1290
  input: args
1350
1291
  };
1351
1292
  await appendTranscriptEntry(session.sessionID, entry, session.parentID);
1352
1293
  }
1353
- async function recordToolResult(session, tool, callID, output) {
1294
+ async function recordToolResult(session, tool2, callID, output) {
1354
1295
  const cachedInput = toolInputCache.get(callID);
1355
1296
  toolInputCache.delete(callID);
1356
1297
  const entry = {
1357
1298
  type: "tool_result",
1358
1299
  timestamp: new Date().toISOString(),
1359
- tool,
1300
+ tool: tool2,
1360
1301
  callID,
1361
1302
  input: cachedInput,
1362
1303
  output: {
@@ -1407,11 +1348,6 @@ function createTranscriptHooks(ctx) {
1407
1348
  const session = await getSessionInfo(ctx, input.sessionID);
1408
1349
  await recordUserMessage(session, output.message, output.parts);
1409
1350
  },
1410
- "chat.model": async (input, output) => {
1411
- if (isSessionInFallback(input.sessionID)) {
1412
- output.model = getFallbackModelOverride();
1413
- }
1414
- },
1415
1351
  "tool.execute.before": async (input, output) => {
1416
1352
  const session = await getSessionInfo(ctx, input.sessionID);
1417
1353
  await recordToolUse(session, input.tool, input.callID, output.args);
@@ -1442,432 +1378,60 @@ function createTranscriptHooks(ctx) {
1442
1378
  });
1443
1379
  }
1444
1380
  },
1445
- event: async ({ event }) => {
1446
- if (event.type === "session.created") {
1447
- const { info } = event.properties;
1448
- if (info.parentID && isSessionInFallback(info.parentID)) {
1449
- markSessionFallback(info.id);
1450
- }
1451
- }
1452
- if (event.type === "session.status") {
1453
- const { sessionID, status } = event.properties;
1454
- if (status.type === "retry" && isCreditBalanceError(status.message)) {
1455
- await handleCreditBalanceFallback(ctx.client, sessionID);
1456
- }
1457
- }
1458
- if (event.type === "session.error") {
1459
- const { sessionID, error } = event.properties;
1460
- if (sessionID && error && "message" in error.data && isCreditBalanceError(String(error.data.message))) {
1461
- await handleCreditBalanceFallback(ctx.client, sessionID);
1462
- }
1463
- }
1464
- if (event.type === "message.updated") {
1465
- const { info } = event.properties;
1466
- if (info.role === "assistant" && info.error) {
1467
- if ("message" in info.error.data && isCreditBalanceError(String(info.error.data.message))) {
1468
- await handleCreditBalanceFallback(ctx.client, info.sessionID);
1469
- }
1470
- }
1471
- }
1472
- }
1381
+ event: async ({ event }) => {}
1473
1382
  };
1474
1383
  }
1475
- // src/tools/save-conversation/counter.ts
1384
+ // src/utils/directory-init.ts
1476
1385
  import * as fs from "fs";
1477
1386
  import * as path4 from "path";
1478
- var SESSIONS_DIR = PATHS.sessions;
1479
- var MAX_COUNTER = 999;
1480
- var FILENAME_PATTERN = /^(\d{3})_(.+)\.md$/;
1481
- async function getNextCounter(date) {
1482
- try {
1483
- const dateDir = path4.join(SESSIONS_DIR, date);
1484
- ensureDateDir(dateDir);
1485
- const files = fs.readdirSync(dateDir);
1486
- const counters = files.map((file) => parseFilename(file)).filter((parsed) => parsed !== null).map((parsed) => parsed.counter);
1487
- const highestCounter = counters.length > 0 ? Math.max(...counters) : 0;
1488
- const nextCounter = highestCounter + 1;
1489
- if (nextCounter > MAX_COUNTER) {
1490
- logger.warn("Counter overflow detected", { date, counter: nextCounter });
1491
- return String(MAX_COUNTER).padStart(3, "0");
1492
- }
1493
- const result = String(nextCounter).padStart(3, "0");
1494
- return result;
1495
- } catch (error) {
1496
- logger.error("Failed to calculate counter, defaulting to 001", error);
1497
- return "001";
1498
- }
1499
- }
1500
- function parseFilename(filename) {
1501
- const match = filename.match(FILENAME_PATTERN);
1502
- if (!match)
1503
- return null;
1504
- const [, counterStr, slug] = match;
1505
- const counter = parseInt(counterStr, 10);
1506
- if (isNaN(counter) || counter < 1 || counter > MAX_COUNTER) {
1507
- return null;
1508
- }
1509
- return { counter, slug };
1510
- }
1511
- function ensureDateDir(dateDir) {
1512
- if (!fs.existsSync(dateDir)) {
1513
- fs.mkdirSync(dateDir, { recursive: true });
1514
- }
1515
- }
1516
- function getCurrentDate() {
1517
- const now = new Date;
1518
- const year = now.getUTCFullYear();
1519
- const month = String(now.getUTCMonth() + 1).padStart(2, "0");
1520
- const day = String(now.getUTCDate()).padStart(2, "0");
1521
- return `${year}-${month}-${day}`;
1522
- }
1523
-
1524
- // src/tools/save-conversation/session-writer.ts
1525
- import * as fs2 from "fs";
1526
- import * as path5 from "path";
1527
- var SESSIONS_DIR2 = PATHS.sessions;
1528
- function writeSession(entry) {
1529
- const dateDir = path5.join(SESSIONS_DIR2, entry.date);
1530
- ensureDateDir2(dateDir);
1531
- const filename = `${entry.counter}_${entry.slug}.md`;
1532
- const filepath = path5.join(dateDir, filename);
1533
- const content = buildSessionContent(entry);
1534
- try {
1535
- fs2.writeFileSync(filepath, content, { encoding: "utf8" });
1536
- return filepath;
1537
- } catch (error) {
1538
- logger.error("Failed to write session file", { path: filepath, error });
1539
- throw new Error(`Session save failed: ${error}`);
1540
- }
1541
- }
1542
- function buildSessionContent(entry) {
1543
- const savedDate = new Date(entry.savedAt);
1544
- const time = savedDate.toISOString().split("T")[1].split(".")[0];
1545
- return `# Session: ${entry.title}
1546
-
1547
- **Date**: ${entry.date}
1548
- **Time**: ${time} UTC
1549
- **Session ID**: ${entry.sessionID}
1550
- **Duration**: ${entry.duration ?? "Unknown"}
1551
- **Messages**: ${entry.messageCount}
1552
- **Tokens**: ${formatTokens(entry)}
1553
-
1554
- ## Summary
1555
-
1556
- ${entry.summary}
1557
-
1558
- ${entry.note ? `## Notes
1559
-
1560
- ${entry.note}
1561
- ` : ""}## Transcript Location
1562
-
1563
- \`${entry.transcriptPath}\`
1564
-
1565
- ## Recall Commands
1566
-
1567
- \`\`\`bash
1568
- # View full transcript
1569
- cat "${entry.transcriptPath}"
1570
-
1571
- # Search for specific content
1572
- grep "keyword" "${entry.transcriptPath}"
1573
-
1574
- # Count tool calls
1575
- grep -c "^## Tool Use:" "${entry.transcriptPath}"
1576
-
1577
- # Extract user messages only
1578
- grep -A 5 "^## User Message" "${entry.transcriptPath}"
1579
- \`\`\`
1580
-
1581
- ---
1582
-
1583
- *Session saved: ${entry.savedAt}*
1584
-
1585
- `;
1586
- }
1587
- function formatTokens(entry) {
1588
- if (entry.tokensInput !== undefined && entry.tokensOutput !== undefined) {
1589
- const total = entry.tokensInput + entry.tokensOutput;
1590
- return `${total.toLocaleString()} (${entry.tokensInput.toLocaleString()} in, ${entry.tokensOutput.toLocaleString()} out)`;
1591
- }
1592
- return entry.tokensBefore.toLocaleString();
1593
- }
1594
- function ensureDateDir2(dateDir) {
1595
- if (!fs2.existsSync(dateDir)) {
1596
- fs2.mkdirSync(dateDir, { recursive: true });
1597
- }
1598
- }
1599
- function calculateDuration(startTime, endTime) {
1600
- const diffMs = endTime.getTime() - startTime.getTime();
1601
- const diffMinutes = Math.floor(diffMs / 1000 / 60);
1602
- if (diffMinutes < 60) {
1603
- return `${diffMinutes} minute${diffMinutes !== 1 ? "s" : ""}`;
1604
- }
1605
- const hours = Math.floor(diffMinutes / 60);
1606
- const minutes = diffMinutes % 60;
1607
- if (minutes === 0) {
1608
- return `${hours} hour${hours !== 1 ? "s" : ""}`;
1609
- }
1610
- return `${hours} hour${hours !== 1 ? "s" : ""} ${minutes} minute${minutes !== 1 ? "s" : ""}`;
1611
- }
1612
-
1613
- // src/lib/anthropic.ts
1614
- import Anthropic from "@anthropic-ai/sdk";
1615
- var anthropicClient = null;
1616
- function getAnthropicClient() {
1617
- if (!anthropicClient) {
1618
- const apiKey = process.env.ANTHROPIC_API_KEY;
1619
- if (!apiKey) {
1620
- throw new Error("ANTHROPIC_API_KEY environment variable is required");
1621
- }
1622
- anthropicClient = new Anthropic({ apiKey });
1623
- }
1624
- return anthropicClient;
1625
- }
1626
-
1627
- // src/tools/save-conversation/slug-generator.ts
1628
- var FALLBACK_SLUG = "work-session";
1629
- var MAX_SLUG_LENGTH = 50;
1630
- var MIN_SLUG_LENGTH = 5;
1631
- async function generateSlug(contextString, context) {
1632
- try {
1633
- if (!contextString || contextString.trim().length === 0) {
1634
- logger.warn("No context to generate slug from, using fallback");
1635
- return FALLBACK_SLUG;
1636
- }
1637
- const rawSlug = await callAnthropicForSlug(contextString);
1638
- const sanitized = sanitizeSlug(rawSlug);
1639
- if (!isValidSlug(sanitized)) {
1640
- logger.warn("Generated slug invalid after sanitization", {
1641
- raw: rawSlug,
1642
- sanitized
1643
- });
1644
- return FALLBACK_SLUG;
1645
- }
1646
- return sanitized;
1647
- } catch (error) {
1648
- logger.error("Slug generation failed", error);
1649
- return FALLBACK_SLUG;
1650
- }
1651
- }
1652
- async function callAnthropicForSlug(context) {
1653
- const anthropic = getAnthropicClient();
1654
- const systemPrompt = `You are a concise session summarizer.
1655
-
1656
- Your job is to read a conversation description and output ONLY a short kebab-case slug
1657
- (2-4 words) that captures the main topic.
1658
-
1659
- Rules:
1660
- - Output ONLY the slug, nothing else
1661
- - Use lowercase letters and hyphens only
1662
- - 2-4 words maximum
1663
- - No quotes, no punctuation, no explanations
1664
- - Be specific and descriptive
1665
-
1666
- Examples:
1667
- - implement-user-auth
1668
- - fix-login-redirect
1669
- - refactor-api-client
1670
- - add-postgres-migration
1671
- - debug-websocket-error`;
1672
- const userPrompt = `Summarize this work session in 2-4 words (kebab-case format only):
1673
-
1674
- ${context}
1675
-
1676
- Output only the slug:`;
1677
- const message = await anthropic.messages.create({
1678
- model: "claude-3-haiku-20240307",
1679
- max_tokens: 20,
1680
- temperature: 0.3,
1681
- system: systemPrompt,
1682
- messages: [
1683
- {
1684
- role: "user",
1685
- content: userPrompt
1686
- }
1687
- ]
1688
- });
1689
- const textBlock = message.content.find((block) => block.type === "text");
1690
- if (!textBlock || textBlock.type !== "text") {
1691
- throw new Error("No text response from API");
1692
- }
1693
- return textBlock.text.trim();
1694
- }
1695
- function sanitizeSlug(raw) {
1696
- return raw.toLowerCase().trim().replace(/^["']|["']$/g, "").replace(/[\s_]+/g, "-").replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "").slice(0, MAX_SLUG_LENGTH);
1697
- }
1698
- function isValidSlug(slug) {
1699
- if (!slug || slug.length < MIN_SLUG_LENGTH || slug.length > MAX_SLUG_LENGTH) {
1700
- return false;
1701
- }
1702
- const pattern = /^[a-z0-9]+(-[a-z0-9]+)*$/;
1703
- return pattern.test(slug);
1704
- }
1705
- function slugToTitle(slug) {
1706
- return slug.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
1707
- }
1708
-
1709
- // src/tools/save-conversation/index.ts
1710
- var MAX_CONTEXT_LENGTH = 500;
1711
- function createSaveConversationTool(ctx) {
1712
- return tool({
1713
- description: `Save the current conversation to a session file and compact context.
1714
-
1715
- In line with your context management strategy, use this tool:
1716
- - After completing a feature or major task
1717
- - When context is getting large
1718
- - At natural stopping points
1719
-
1720
- The tool will:
1721
- 1. Generate a semantic filename based on conversation content
1722
- 2. Save full conversation with enhanced metadata
1723
- 3. Trigger context compaction (summarization)
1724
- 4. Return the session path for future reference
1725
- `,
1726
- args: {
1727
- note: tool.schema.string().optional().describe("Optional note about what was accomplished")
1728
- },
1729
- async execute(args, context) {
1730
- const startTime = new Date;
1731
- const { sessionID } = context;
1732
- try {
1733
- const { data: messages } = await ctx.client.session.messages({
1734
- path: { id: sessionID },
1735
- query: { directory: ctx.directory }
1736
- });
1737
- if (!messages || messages.length === 0) {
1738
- return "No messages to save.";
1739
- }
1740
- const { tokensInput, tokensOutput, tokensBefore } = calculateTokens(messages);
1741
- const contextString = buildContextString(messages, args.note);
1742
- const slug = await generateSlug(contextString);
1743
- const title = slugToTitle(slug);
1744
- const date = getCurrentDate();
1745
- const counter = await getNextCounter(date);
1746
- const endTime = new Date;
1747
- const duration = calculateDuration(startTime, endTime);
1748
- const transcriptPath = getTranscriptPath(sessionID);
1749
- const summary = await generateSummary(messages, slug);
1750
- const entry = {
1751
- sessionID,
1752
- savedAt: endTime.toISOString(),
1753
- date,
1754
- counter,
1755
- slug,
1756
- title,
1757
- summary,
1758
- note: args.note,
1759
- tokensBefore,
1760
- tokensInput,
1761
- tokensOutput,
1762
- transcriptPath,
1763
- messageCount: messages.length,
1764
- duration
1765
- };
1766
- const sessionPath = writeSession(entry);
1767
- logger.info("Session saved", { path: sessionPath });
1768
- const sessionFilename = `${counter}_${slug}.md`;
1769
- const sessionRelativePath = `sessions/${date}/${sessionFilename}`;
1770
- const lastAssistant = [...messages].reverse().find((m) => m.info.role === "assistant");
1771
- const providerID = lastAssistant?.info.role === "assistant" ? lastAssistant.info.providerID : "anthropic";
1772
- const modelID = lastAssistant?.info.role === "assistant" ? lastAssistant.info.modelID : "claude-sonnet-4";
1773
- ctx.client.session.summarize({
1774
- path: { id: sessionID },
1775
- body: { providerID, modelID },
1776
- query: { directory: ctx.directory }
1777
- }).catch((err) => {
1778
- logger.error("Summarize failed", err);
1779
- });
1780
- return `\u2705 Conversation saved!
1781
-
1782
- **Session**: \`${sessionRelativePath}\`
1783
- **Title**: ${title}
1784
- **Path**: ${sessionPath}
1785
- **Messages**: ${messages.length}
1786
- **Tokens**: ${tokensBefore.toLocaleString()} (${tokensInput.toLocaleString()} in, ${tokensOutput.toLocaleString()} out)
1787
-
1788
- ## Before compaction
1789
-
1790
- Update the following files to preserve context:
1791
-
1792
- 1. **\`${PATHS.statusFile}\`** - Add this session to "Recent Sessions":
1793
- - \`${sessionRelativePath}\` - ${title}
1794
-
1795
- 2. **Task docs** (if applicable) - Update any HLD/LLD with final state
1796
-
1797
- 3. **Lessons learned** (if any) - Note anything worth capturing for Mnemosyne
1798
-
1799
- Compaction running in background. Complete updates now.`;
1800
- } catch (error) {
1801
- logger.error("Failed to save conversation", error);
1802
- return `\u274C Failed to save conversation: ${error}`;
1803
- }
1804
- }
1805
- });
1806
- }
1807
- function calculateTokens(messages) {
1808
- let tokensInput = 0;
1809
- let tokensOutput = 0;
1810
- for (const message of messages) {
1811
- if (message.info.role === "assistant") {
1812
- tokensInput += message.info.tokens.input ?? 0;
1813
- tokensOutput += message.info.tokens.output ?? 0;
1814
- }
1815
- }
1816
- return {
1817
- tokensInput,
1818
- tokensOutput,
1819
- tokensBefore: tokensInput + tokensOutput
1820
- };
1821
- }
1822
- async function generateSummary(messages, slug) {
1823
- const messageCount = messages.length;
1824
- const userMessages = messages.filter((m) => m.info.role === "user").length;
1825
- const assistantMessages = messages.filter((m) => m.info.role === "assistant").length;
1826
- return `Work session focused on: ${slugToTitle(slug)}. Exchanged ${messageCount} messages (${userMessages} user, ${assistantMessages} assistant). See transcript for full details.`;
1827
- }
1828
- function buildContextString(messages, note) {
1829
- if (note) {
1830
- return note.slice(0, MAX_CONTEXT_LENGTH);
1831
- }
1832
- const lastUserMessages = messages.filter((m) => m.info.role === "user").slice(-3).map((m) => {
1833
- const summary = m.info.summary;
1834
- if (typeof summary === "object" && summary) {
1835
- return summary.title || summary.body || "";
1836
- }
1837
- return "";
1838
- }).filter(Boolean).join(". ").slice(0, MAX_CONTEXT_LENGTH);
1839
- return lastUserMessages || "Work session";
1840
- }
1387
+ import { fileURLToPath } from "url";
1388
+ // package.json
1389
+ var version = "0.4.0";
1841
1390
 
1842
1391
  // src/utils/directory-init.ts
1843
- import * as fs3 from "fs";
1844
- import * as path6 from "path";
1845
- import { fileURLToPath } from "url";
1846
- var TEMPLATES_DIR = path6.join(path6.dirname(fileURLToPath(import.meta.url)), "templates", ".openfleet");
1392
+ var TEMPLATES_DIR = path4.join(path4.dirname(fileURLToPath(import.meta.url)), "templates", ".openfleet");
1847
1393
  function initializeDirectories() {
1848
- if (fs3.existsSync(OPENFLEET_DIR)) {
1394
+ if (fs.existsSync(OPENFLEET_DIR)) {
1849
1395
  return;
1850
1396
  }
1851
1397
  copyDirectorySync(TEMPLATES_DIR, OPENFLEET_DIR);
1852
1398
  logger.info("Initialized .openfleet directory");
1853
1399
  }
1400
+ function checkMigrationNeeded() {
1401
+ if (!fs.existsSync(OPENFLEET_DIR))
1402
+ return false;
1403
+ if (!fs.existsSync(PATHS.versionFile))
1404
+ return true;
1405
+ const installedVersion = fs.readFileSync(PATHS.versionFile, "utf-8").trim();
1406
+ return installedVersion !== version;
1407
+ }
1854
1408
  function copyDirectorySync(src, dest) {
1855
- fs3.mkdirSync(dest, { recursive: true });
1856
- const entries = fs3.readdirSync(src, { withFileTypes: true });
1409
+ fs.mkdirSync(dest, { recursive: true });
1410
+ const entries = fs.readdirSync(src, { withFileTypes: true });
1857
1411
  for (const entry of entries) {
1858
- const srcPath = path6.join(src, entry.name);
1412
+ const srcPath = path4.join(src, entry.name);
1859
1413
  const destName = entry.name === "gitignore.template" ? ".gitignore" : entry.name;
1860
- const destPath = path6.join(dest, destName);
1414
+ const destPath = path4.join(dest, destName);
1861
1415
  if (entry.isDirectory()) {
1862
1416
  copyDirectorySync(srcPath, destPath);
1863
1417
  } else {
1864
- fs3.copyFileSync(srcPath, destPath);
1418
+ fs.copyFileSync(srcPath, destPath);
1865
1419
  }
1866
1420
  }
1867
1421
  }
1868
1422
 
1869
1423
  // src/utils/toast.ts
1870
1424
  var SPINNER_DOTS = ["\u28F7", "\u28EF", "\u28DF", "\u287F", "\u28BF", "\u28FB", "\u28FD", "\u28FE"];
1425
+ async function showToast(ctx, options) {
1426
+ await ctx.client.tui.showToast({
1427
+ body: {
1428
+ title: options.title,
1429
+ message: options.message,
1430
+ variant: options.variant,
1431
+ duration: options.duration
1432
+ }
1433
+ });
1434
+ }
1871
1435
  function showSpinnerToast(ctx, options) {
1872
1436
  const frameInterval = 150;
1873
1437
  let running = true;
@@ -1912,7 +1476,16 @@ var OpenfleetPlugin = async (ctx) => {
1912
1476
  const props = event.properties;
1913
1477
  if (!props?.info?.parentID) {
1914
1478
  setTimeout(async () => {
1915
- await showFleetToast(ctx);
1479
+ if (checkMigrationNeeded()) {
1480
+ await showToast(ctx, {
1481
+ title: "\u26A0\uFE0F Openfleet Migration Required",
1482
+ message: "Copy this: 'github.com/scottsus/openfleet/issues/11' to the chat, to migrate to v0.4.0",
1483
+ variant: "warning",
1484
+ duration: 1e4
1485
+ });
1486
+ } else {
1487
+ await showFleetToast(ctx);
1488
+ }
1916
1489
  }, 0);
1917
1490
  }
1918
1491
  }