pilotlynx 0.0.1 → 0.1.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 (216) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +345 -0
  3. package/dist/agents/improve.agent.d.ts +2 -0
  4. package/dist/agents/improve.agent.js +54 -0
  5. package/dist/agents/improve.agent.js.map +1 -0
  6. package/dist/agents/project-add.agent.d.ts +2 -0
  7. package/dist/agents/project-add.agent.js +26 -0
  8. package/dist/agents/project-add.agent.js.map +1 -0
  9. package/dist/agents/project-create.agent.d.ts +2 -0
  10. package/dist/agents/project-create.agent.js +25 -0
  11. package/dist/agents/project-create.agent.js.map +1 -0
  12. package/dist/agents/run.agent.d.ts +3 -0
  13. package/dist/agents/run.agent.js +37 -0
  14. package/dist/agents/run.agent.js.map +1 -0
  15. package/dist/agents/secrets-migration.agent.d.ts +15 -0
  16. package/dist/agents/secrets-migration.agent.js +63 -0
  17. package/dist/agents/secrets-migration.agent.js.map +1 -0
  18. package/dist/agents/sync-template.agent.d.ts +2 -0
  19. package/dist/agents/sync-template.agent.js +21 -0
  20. package/dist/agents/sync-template.agent.js.map +1 -0
  21. package/dist/cli.d.ts +2 -0
  22. package/dist/cli.js +66 -0
  23. package/dist/cli.js.map +1 -0
  24. package/dist/commands/cost.d.ts +2 -0
  25. package/dist/commands/cost.js +96 -0
  26. package/dist/commands/cost.js.map +1 -0
  27. package/dist/commands/doctor.d.ts +2 -0
  28. package/dist/commands/doctor.js +39 -0
  29. package/dist/commands/doctor.js.map +1 -0
  30. package/dist/commands/env.d.ts +2 -0
  31. package/dist/commands/env.js +26 -0
  32. package/dist/commands/env.js.map +1 -0
  33. package/dist/commands/improve.d.ts +2 -0
  34. package/dist/commands/improve.js +43 -0
  35. package/dist/commands/improve.js.map +1 -0
  36. package/dist/commands/init.d.ts +2 -0
  37. package/dist/commands/init.js +131 -0
  38. package/dist/commands/init.js.map +1 -0
  39. package/dist/commands/insights.d.ts +2 -0
  40. package/dist/commands/insights.js +45 -0
  41. package/dist/commands/insights.js.map +1 -0
  42. package/dist/commands/link.d.ts +2 -0
  43. package/dist/commands/link.js +27 -0
  44. package/dist/commands/link.js.map +1 -0
  45. package/dist/commands/logs.d.ts +2 -0
  46. package/dist/commands/logs.js +75 -0
  47. package/dist/commands/logs.js.map +1 -0
  48. package/dist/commands/project.d.ts +4 -0
  49. package/dist/commands/project.js +127 -0
  50. package/dist/commands/project.js.map +1 -0
  51. package/dist/commands/projects.d.ts +2 -0
  52. package/dist/commands/projects.js +22 -0
  53. package/dist/commands/projects.js.map +1 -0
  54. package/dist/commands/relay.d.ts +2 -0
  55. package/dist/commands/relay.js +171 -0
  56. package/dist/commands/relay.js.map +1 -0
  57. package/dist/commands/run.d.ts +2 -0
  58. package/dist/commands/run.js +49 -0
  59. package/dist/commands/run.js.map +1 -0
  60. package/dist/commands/schedule.d.ts +2 -0
  61. package/dist/commands/schedule.js +158 -0
  62. package/dist/commands/schedule.js.map +1 -0
  63. package/dist/commands/status.d.ts +2 -0
  64. package/dist/commands/status.js +62 -0
  65. package/dist/commands/status.js.map +1 -0
  66. package/dist/commands/sync.d.ts +2 -0
  67. package/dist/commands/sync.js +23 -0
  68. package/dist/commands/sync.js.map +1 -0
  69. package/dist/commands/unlink.d.ts +2 -0
  70. package/dist/commands/unlink.js +26 -0
  71. package/dist/commands/unlink.js.map +1 -0
  72. package/dist/commands/verify.d.ts +2 -0
  73. package/dist/commands/verify.js +32 -0
  74. package/dist/commands/verify.js.map +1 -0
  75. package/dist/lib/agent-runner.d.ts +10 -0
  76. package/dist/lib/agent-runner.js +133 -0
  77. package/dist/lib/agent-runner.js.map +1 -0
  78. package/dist/lib/bash-security.d.ts +5 -0
  79. package/dist/lib/bash-security.js +83 -0
  80. package/dist/lib/bash-security.js.map +1 -0
  81. package/dist/lib/callbacks.d.ts +3 -0
  82. package/dist/lib/callbacks.js +77 -0
  83. package/dist/lib/callbacks.js.map +1 -0
  84. package/dist/lib/command-ops/doctor-ops.d.ts +8 -0
  85. package/dist/lib/command-ops/doctor-ops.js +197 -0
  86. package/dist/lib/command-ops/doctor-ops.js.map +1 -0
  87. package/dist/lib/command-ops/env-ops.d.ts +12 -0
  88. package/dist/lib/command-ops/env-ops.js +53 -0
  89. package/dist/lib/command-ops/env-ops.js.map +1 -0
  90. package/dist/lib/command-ops/improve-ops.d.ts +12 -0
  91. package/dist/lib/command-ops/improve-ops.js +77 -0
  92. package/dist/lib/command-ops/improve-ops.js.map +1 -0
  93. package/dist/lib/command-ops/link-ops.d.ts +17 -0
  94. package/dist/lib/command-ops/link-ops.js +74 -0
  95. package/dist/lib/command-ops/link-ops.js.map +1 -0
  96. package/dist/lib/command-ops/project-ops.d.ts +12 -0
  97. package/dist/lib/command-ops/project-ops.js +56 -0
  98. package/dist/lib/command-ops/project-ops.js.map +1 -0
  99. package/dist/lib/command-ops/run-ops.d.ts +10 -0
  100. package/dist/lib/command-ops/run-ops.js +59 -0
  101. package/dist/lib/command-ops/run-ops.js.map +1 -0
  102. package/dist/lib/command-ops/secrets-migration-ops.d.ts +29 -0
  103. package/dist/lib/command-ops/secrets-migration-ops.js +169 -0
  104. package/dist/lib/command-ops/secrets-migration-ops.js.map +1 -0
  105. package/dist/lib/command-ops/status-ops.d.ts +19 -0
  106. package/dist/lib/command-ops/status-ops.js +95 -0
  107. package/dist/lib/command-ops/status-ops.js.map +1 -0
  108. package/dist/lib/command-ops/sync-ops.d.ts +5 -0
  109. package/dist/lib/command-ops/sync-ops.js +15 -0
  110. package/dist/lib/command-ops/sync-ops.js.map +1 -0
  111. package/dist/lib/command-ops/verify-ops.d.ts +7 -0
  112. package/dist/lib/command-ops/verify-ops.js +12 -0
  113. package/dist/lib/command-ops/verify-ops.js.map +1 -0
  114. package/dist/lib/config.d.ts +36 -0
  115. package/dist/lib/config.js +118 -0
  116. package/dist/lib/config.js.map +1 -0
  117. package/dist/lib/cron.d.ts +3 -0
  118. package/dist/lib/cron.js +61 -0
  119. package/dist/lib/cron.js.map +1 -0
  120. package/dist/lib/env-loader.d.ts +1 -0
  121. package/dist/lib/env-loader.js +8 -0
  122. package/dist/lib/env-loader.js.map +1 -0
  123. package/dist/lib/global-config.d.ts +7 -0
  124. package/dist/lib/global-config.js +50 -0
  125. package/dist/lib/global-config.js.map +1 -0
  126. package/dist/lib/logger.d.ts +2 -0
  127. package/dist/lib/logger.js +26 -0
  128. package/dist/lib/logger.js.map +1 -0
  129. package/dist/lib/observation.d.ts +3 -0
  130. package/dist/lib/observation.js +48 -0
  131. package/dist/lib/observation.js.map +1 -0
  132. package/dist/lib/policy.d.ts +3 -0
  133. package/dist/lib/policy.js +15 -0
  134. package/dist/lib/policy.js.map +1 -0
  135. package/dist/lib/project.d.ts +9 -0
  136. package/dist/lib/project.js +127 -0
  137. package/dist/lib/project.js.map +1 -0
  138. package/dist/lib/prompts.d.ts +3 -0
  139. package/dist/lib/prompts.js +49 -0
  140. package/dist/lib/prompts.js.map +1 -0
  141. package/dist/lib/registry.d.ts +12 -0
  142. package/dist/lib/registry.js +90 -0
  143. package/dist/lib/registry.js.map +1 -0
  144. package/dist/lib/relay/channel.d.ts +31 -0
  145. package/dist/lib/relay/channel.js +69 -0
  146. package/dist/lib/relay/channel.js.map +1 -0
  147. package/dist/lib/relay/chat.d.ts +2 -0
  148. package/dist/lib/relay/chat.js +77 -0
  149. package/dist/lib/relay/chat.js.map +1 -0
  150. package/dist/lib/relay/config.d.ts +5 -0
  151. package/dist/lib/relay/config.js +22 -0
  152. package/dist/lib/relay/config.js.map +1 -0
  153. package/dist/lib/relay/history.d.ts +3 -0
  154. package/dist/lib/relay/history.js +62 -0
  155. package/dist/lib/relay/history.js.map +1 -0
  156. package/dist/lib/relay/locks.d.ts +9 -0
  157. package/dist/lib/relay/locks.js +45 -0
  158. package/dist/lib/relay/locks.js.map +1 -0
  159. package/dist/lib/relay/notify.d.ts +6 -0
  160. package/dist/lib/relay/notify.js +168 -0
  161. package/dist/lib/relay/notify.js.map +1 -0
  162. package/dist/lib/relay/router.d.ts +2 -0
  163. package/dist/lib/relay/router.js +191 -0
  164. package/dist/lib/relay/router.js.map +1 -0
  165. package/dist/lib/relay/service.d.ts +9 -0
  166. package/dist/lib/relay/service.js +222 -0
  167. package/dist/lib/relay/service.js.map +1 -0
  168. package/dist/lib/relay/types.d.ts +47 -0
  169. package/dist/lib/relay/types.js +31 -0
  170. package/dist/lib/relay/types.js.map +1 -0
  171. package/dist/lib/sandbox.d.ts +24 -0
  172. package/dist/lib/sandbox.js +83 -0
  173. package/dist/lib/sandbox.js.map +1 -0
  174. package/dist/lib/schedule.d.ts +16 -0
  175. package/dist/lib/schedule.js +92 -0
  176. package/dist/lib/schedule.js.map +1 -0
  177. package/dist/lib/secrets-migration.d.ts +35 -0
  178. package/dist/lib/secrets-migration.js +119 -0
  179. package/dist/lib/secrets-migration.js.map +1 -0
  180. package/dist/lib/secrets.d.ts +1 -0
  181. package/dist/lib/secrets.js +45 -0
  182. package/dist/lib/secrets.js.map +1 -0
  183. package/dist/lib/shell-escape.d.ts +3 -0
  184. package/dist/lib/shell-escape.js +6 -0
  185. package/dist/lib/shell-escape.js.map +1 -0
  186. package/dist/lib/tools.d.ts +5 -0
  187. package/dist/lib/tools.js +26 -0
  188. package/dist/lib/tools.js.map +1 -0
  189. package/dist/lib/types.d.ts +156 -0
  190. package/dist/lib/types.js +56 -0
  191. package/dist/lib/types.js.map +1 -0
  192. package/dist/lib/validation.d.ts +4 -0
  193. package/dist/lib/validation.js +26 -0
  194. package/dist/lib/validation.js.map +1 -0
  195. package/package.json +75 -12
  196. package/prompts/improve.yaml +15 -0
  197. package/prompts/project-add.yaml +43 -0
  198. package/prompts/project-create.yaml +28 -0
  199. package/prompts/relay-chat.yaml +24 -0
  200. package/prompts/run.yaml +9 -0
  201. package/prompts/secrets-migration.yaml +35 -0
  202. package/prompts/sync-template.yaml +18 -0
  203. package/template/.claude/rules/.gitkeep +0 -0
  204. package/template/.claude/settings.json +17 -0
  205. package/template/.claude/skills/.gitkeep +0 -0
  206. package/template/.mcp.json +3 -0
  207. package/template/CLAUDE.md +79 -0
  208. package/template/PROJECT_BRIEF.md +22 -0
  209. package/template/RUNBOOK.md +45 -0
  210. package/template/artifacts/.gitkeep +0 -0
  211. package/template/logs/.gitkeep +0 -0
  212. package/template/memory/MEMORY.md +15 -0
  213. package/template/schedule.yaml +9 -0
  214. package/template/workflows/daily_feedback.ts +24 -0
  215. package/template/workflows/project_review.ts +24 -0
  216. package/template/workflows/task_execute.ts +24 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 PilotLynx Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,345 @@
1
+ # PilotLynx
2
+
3
+ [![npm version](https://img.shields.io/npm/v/pilotlynx.svg)](https://www.npmjs.com/package/pilotlynx)
4
+ [![CI](https://github.com/pilotlynx/pilotlynx/actions/workflows/ci.yml/badge.svg)](https://github.com/pilotlynx/pilotlynx/actions/workflows/ci.yml)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
6
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D20-brightgreen.svg)](https://nodejs.org/)
7
+
8
+ Local monorepo orchestration for Claude Agent SDK workflows. One CLI to manage project scaffolding, policy-gated secrets, cron scheduling, and cross-project self-improvement.
9
+
10
+ ## What Makes PilotLynx Different
11
+
12
+ Three features that don't exist in other AI workflow tools:
13
+
14
+ ### Cron Ping
15
+
16
+ Define cron schedules per project. PilotLynx uses tick-based scheduling — no daemon, no background process. You run `plynx schedule tick` from a system cron entry and it figures out what's due.
17
+
18
+ **`schedule.yaml`** (in each project):
19
+
20
+ ```yaml
21
+ schedules:
22
+ - workflow: daily_feedback
23
+ cron: "0 9 * * *"
24
+ timezone: America/New_York
25
+ catchUpPolicy: run_latest
26
+ ```
27
+
28
+ **How a tick works:**
29
+
30
+ 1. Read every project's `schedule.yaml`
31
+ 2. Compare cron expressions against last recorded run times
32
+ 3. Apply the catch-up policy to any missed runs
33
+ 4. Execute due workflows and record the new last-run time
34
+
35
+ **Catch-up policies** (when the machine was off or tick didn't fire):
36
+
37
+ | Policy | Behavior |
38
+ |--------|----------|
39
+ | `run_latest` | Run only the most recent missed occurrence (default) |
40
+ | `run_all` | Run every missed occurrence in order |
41
+ | `skip` | Discard all missed runs, wait for the next future occurrence |
42
+
43
+ Missed runs older than **7 days** are always discarded regardless of policy.
44
+
45
+ `plynx init` auto-installs a system cron entry (`*/15 * * * *`) so scheduling works out of the box. Each tick also runs the self-improvement loop automatically (once per 24h, configurable).
46
+
47
+ ```bash
48
+ plynx schedule status myproject # see what's scheduled, last/next runs
49
+ ```
50
+
51
+ ### Self-Improvement Loop
52
+
53
+ `plynx improve` triggers a two-phase cycle that makes projects learn from their own run history:
54
+
55
+ **Phase 1 — Observation (Lynx-owned, read-only):** Reads conversation logs, user feedback, and run outcomes across all projects. Produces per-project summaries and cross-project insights (stored in `pilotlynx/shared/insights/`).
56
+
57
+ **Phase 2 — Improvement (project-owned, Lynx-triggered):** Invokes each project's `daily_feedback` workflow with the distilled summary. The project's own agent decides what to update — brief, runbook, skills, or memory.
58
+
59
+ Key design constraint: **Lynx never writes project files.** The orchestrator observes and triggers; only the project's own agent modifies its files.
60
+
61
+ Auto-runs via `schedule tick` once per 24h. Manual trigger anytime with `plynx improve`. Toggle in `plynx.yaml`:
62
+
63
+ ```yaml
64
+ autoImprove:
65
+ enabled: false # default: true
66
+ ```
67
+
68
+ ```bash
69
+ plynx insights # view cross-project insights
70
+ plynx insights --since 2025-01-10 # filter by date
71
+ ```
72
+
73
+ ### Shared Env
74
+
75
+ One `.env` file, per-project allowlists. A project sees only the secrets its policy permits — injected at runtime, never written to files.
76
+
77
+ **`pilotlynx/shared/policies/secrets-access.yaml`:**
78
+
79
+ ```yaml
80
+ version: 1
81
+ shared:
82
+ - ANTHROPIC_API_KEY # every project gets this
83
+
84
+ projects:
85
+ my-web-app:
86
+ allowed:
87
+ - GITHUB_TOKEN
88
+ - DATABASE_URL
89
+ mappings:
90
+ SLACK_URL: SLACK_WEBHOOK # project sees SLACK_URL, sourced from .env's SLACK_WEBHOOK
91
+
92
+ my-cli-tool:
93
+ allowed:
94
+ - GITHUB_TOKEN
95
+ ```
96
+
97
+ **Inspect and export:**
98
+
99
+ ```bash
100
+ plynx env myproject # dotenv format
101
+ plynx env myproject --export # export KEY=value (eval-able)
102
+ plynx env myproject --json # {"KEY": "value"}
103
+ plynx link myproject --direnv # generate .envrc for MCP server ${VAR} expansion
104
+ ```
105
+
106
+ **Auto-migration:** When you adopt an existing project with `plynx project add`, PilotLynx detects secrets in the project's `.env` and `.mcp.json` literals, consolidates them into the central store, and updates the policy — no manual copy-paste.
107
+
108
+ **Default is deny-all.** No policy file = zero secrets injected. See [`docs/secrets-and-mcp.md`](docs/secrets-and-mcp.md) for the full guide.
109
+
110
+ ## Why PilotLynx
111
+
112
+ PilotLynx occupies a specific niche: **workspace-level orchestration of isolated Claude Agent SDK projects**. No single existing tool covers this combination. Here's how it compares:
113
+
114
+ | Tool | What it solves | What PilotLynx adds |
115
+ |------|---------------|---------------------|
116
+ | [Claude Agent SDK](https://docs.anthropic.com/en/docs/agents) | Build individual AI agents in TypeScript | Multi-project orchestration, scaffolding, shared secrets, scheduling |
117
+ | [OpenClaw](https://github.com/openclaw/openclaw) | General-purpose personal AI assistant (email, calendar, web) with 20+ messaging integrations | Developer-focused CLI for code projects, policy-gated secrets, template-based scaffolding, cross-project self-improvement |
118
+ | [CrewAI](https://github.com/crewAIInc/crewAI) | Multi-agent collaboration with role-based agents (Python) | File-based durable state in git, project isolation, TypeScript-native with Agent SDK |
119
+ | [LangGraph](https://github.com/langchain-ai/langgraph) | Stateful multi-step agent graphs | Workspace-level concerns: secrets policy, cron scheduling, cross-project insights |
120
+ | [Turborepo](https://turbo.build/repo) | Monorepo build orchestration and caching | AI workflow orchestration, not build — schedules agents, injects secrets, tracks run logs |
121
+ | [AgentStack](https://github.com/AgentOps-AI/AgentStack) | Scaffolding for CrewAI/LangGraph projects | Claude Agent SDK native, multi-project workspace, self-improvement loop |
122
+ | [Infisical](https://infisical.com/) | Secrets management platform | Lightweight file-based secrets with per-project allowlists, no external service |
123
+
124
+ **What PilotLynx uniquely combines:**
125
+ - CLI-first developer workflow (not conversation-first, not GUI-first)
126
+ - Claude Agent SDK native — every CLI command is an agent
127
+ - Multi-project isolation with shared infrastructure (secrets, policies, insights)
128
+ - Tick-based cron scheduling with catch-up policies
129
+ - Cross-project self-improvement loop
130
+ - All state in committed files — no database, no external service
131
+
132
+ ## Requirements
133
+
134
+ - **Node.js** 20 or later
135
+ - **Authentication** (one of the following):
136
+ - **Anthropic API key** — set `ANTHROPIC_API_KEY` in `pilotlynx/.env`
137
+ - **Claude Code subscription** (Pro / Max / Teams) — run `claude login` once. No API key needed; the Agent SDK reads OAuth tokens from `~/.claude/` automatically.
138
+ - **Claude Code** (optional) — PilotLynx works standalone, but each CLI command also maps to a Claude Code skill for in-editor use
139
+
140
+ ## Install
141
+
142
+ ```bash
143
+ npm install -g pilotlynx
144
+ ```
145
+
146
+ > **Permission denied?** If you see `EACCES` errors, either prefix with `sudo` or (recommended) use a Node version manager like [nvm](https://github.com/nvm-sh/nvm) / [fnm](https://github.com/Schniz/fnm) which installs to user-owned directories. You can also run without installing globally:
147
+ >
148
+ > ```bash
149
+ > npx pilotlynx <command>
150
+ > ```
151
+
152
+ ## Quick Start
153
+
154
+ ### 1. Create a workspace
155
+
156
+ ```bash
157
+ mkdir my-agents && cd my-agents
158
+ plynx init --name my-agents
159
+ ```
160
+
161
+ This creates:
162
+
163
+ ```
164
+ my-agents/
165
+ pilotlynx/ # config directory
166
+ plynx.yaml # workspace marker
167
+ projects.yaml # project registry (name → path)
168
+ template/ # project scaffold template
169
+ shared/policies/ # secrets + tool access policies
170
+ shared/docs/ # shared documentation
171
+ shared/insights/ # cross-project learnings
172
+ .gitignore
173
+ ```
174
+
175
+ It also writes a global config at `~/.config/pilotlynx/config.yaml` (Linux) so the CLI works from any directory, and installs a cron entry for `plynx schedule tick` every 15 minutes.
176
+
177
+ ### 2. Create or add a project
178
+
179
+ ```bash
180
+ # Create a new project from template
181
+ plynx project create myproject
182
+
183
+ # Or adopt an existing directory (at any path)
184
+ plynx project add myrepo --path /path/to/existing/repo
185
+ ```
186
+
187
+ `create` scaffolds from the template into `myproject/` (at the workspace root) with:
188
+ - `CLAUDE.md` — project rules
189
+ - `PROJECT_BRIEF.md` — goals and decisions
190
+ - `RUNBOOK.md` — operational procedures
191
+ - `workflows/` — TypeScript Agent SDK workflow files
192
+ - `memory/` — durable knowledge (committed to git)
193
+
194
+ `add` adopts an existing directory: adds missing scaffolding files without overwriting anything, registers the project, migrates detected secrets into the central store, then runs an interactive agent that examines the existing code and helps fill in project docs.
195
+
196
+ Both commands register the project in `pilotlynx/projects.yaml` and prompt for secrets access configuration.
197
+
198
+ ### 3. Run a workflow
199
+
200
+ ```bash
201
+ plynx run myproject daily_feedback
202
+ ```
203
+
204
+ Loads secrets from `.env` per the project's allowlist, then executes the workflow.
205
+
206
+ ### 4. Check project structure
207
+
208
+ ```bash
209
+ plynx verify myproject
210
+ ```
211
+
212
+ Reports missing files or directories.
213
+
214
+ ## Commands
215
+
216
+ | Command | What it does |
217
+ |---------|-------------|
218
+ | `plynx init` | Create a new workspace |
219
+ | `plynx project create <name>` | Scaffold a project from template |
220
+ | `plynx project add <name> --path <dir>` | Add an existing directory as a project |
221
+ | `plynx projects list` | List all projects with paths |
222
+ | `plynx run <project> <workflow>` | Run a workflow with secrets injection |
223
+ | `plynx verify <project>` | Validate project structure |
224
+ | `plynx improve` | Run self-improvement loop across projects |
225
+ | `plynx schedule tick` | Run due scheduled workflows |
226
+ | `plynx schedule status <project>` | Show schedules, last/next run times, auto-improve state |
227
+ | `plynx logs <project>` | View recent run logs (`--last`, `--workflow`, `--failures`) |
228
+ | `plynx insights` | View cross-project insights (`--last`, `--since`) |
229
+ | `plynx sync template <project>` | Apply template updates to a project |
230
+ | `plynx env <project>` | Output policy-filtered secrets (`--export`, `--json`, `--envrc`) |
231
+ | `plynx link <project>` | Configure a project for direct access (`--direnv` for `.envrc`) |
232
+ | `plynx unlink <project>` | Remove direct-access configuration |
233
+
234
+ ## Other Features
235
+
236
+ - Every CLI command is a Claude Agent SDK agent — the CLI is a thin wrapper with no business logic
237
+ - Bounded workflows with clear start/end — no long-lived sessions, failed runs rerun deterministically
238
+ - All state is committed files — briefs, runbooks, skills, memory in git, zero dependence on session state
239
+ - Scoped context — workflows see only their project directory plus shared docs/insights
240
+ - No external plugins — all skills are local, committed, and code-reviewable
241
+ - Tool access policies independent from secrets policies (defense-in-depth)
242
+ - Filesystem sandboxing via bwrap (Linux) and sandbox-exec (macOS)
243
+
244
+ ## Architecture: CLI = Agent SDK
245
+
246
+ The CLI is a thin wrapper around Claude Agent SDK agents. Every `plynx` command invokes a dedicated agent, making the CLI a convenience layer rather than the primary execution surface.
247
+
248
+ - **Each command = one agent.** `plynx project create foo` runs a "project-create" agent that scaffolds the directory from the template.
249
+ - **Most CLI commands have corresponding Claude Code skills** for use inside projects.
250
+ - **Business logic lives in agents.** Exception: `plynx init` scaffolds the workspace directly since no workspace exists yet for agent context.
251
+
252
+ ## Working Directly in a Project
253
+
254
+ PilotLynx stores its config location in a global file (`~/.config/pilotlynx/config.yaml` on Linux, OS-appropriate on macOS/Windows) so the CLI works from any directory — no need to be inside the workspace.
255
+
256
+ For MCP servers that need secrets via `${VAR}` expansion, use [direnv](https://direnv.net/):
257
+
258
+ ```bash
259
+ plynx link myproject --direnv # generates .envrc with policy-filtered secrets
260
+ cd myproject && direnv allow # activate
261
+ ```
262
+
263
+ The `.envrc` is gitignored. Regenerate it when secrets change.
264
+
265
+ ## Project Registry
266
+
267
+ Projects are tracked in `pilotlynx/projects.yaml`:
268
+
269
+ ```yaml
270
+ version: 1
271
+ projects:
272
+ my-app:
273
+ path: my-app # relative to workspace root
274
+ external-repo:
275
+ path: /home/user/repos/external-repo # absolute path
276
+ ```
277
+
278
+ Paths under the workspace root are stored as relative; paths outside are stored as absolute. This keeps the registry portable — move the workspace and relative paths still resolve.
279
+
280
+ ## Project Structure
281
+
282
+ Every project follows the same layout:
283
+
284
+ ```
285
+ myproject/
286
+ CLAUDE.md # project-specific agent rules
287
+ PROJECT_BRIEF.md # goals, decisions, constraints
288
+ RUNBOOK.md # how to operate this project
289
+ .mcp.json # MCP server config
290
+ .claude/settings.json # shared project permissions
291
+ .claude/skills/ # project-scoped skills
292
+ .claude/rules/ # modular topic-specific rules
293
+ workflows/ # TypeScript Agent SDK workflows
294
+ memory/MEMORY.md # durable knowledge entrypoint (git-tracked)
295
+ artifacts/ # output files (gitignored)
296
+ logs/ # run logs (gitignored)
297
+ schedule.yaml # cron schedules for workflows
298
+ ```
299
+
300
+ ## Workflows
301
+
302
+ Each project has workflows under `workflows/` — TypeScript scripts that run Claude Agent SDK.
303
+
304
+ ### Execution Model
305
+
306
+ - Bounded, isolated runs with a clear start and end.
307
+ - Each run produces a logged outcome: success or failure, plus a short summary.
308
+ - Failed workflows support deterministic rerun with the same inputs.
309
+ - Retries are bounded and explicit — no infinite retry loops.
310
+
311
+ ### Standard Workflows
312
+
313
+ Each project should support these baseline workflows:
314
+
315
+ | Workflow | Purpose |
316
+ |----------|---------|
317
+ | `daily_feedback` | Review recent activity and update project memory |
318
+ | `task_execute` | Execute a specific task from prompt input |
319
+ | `project_review` | Produce a short project status update |
320
+
321
+ ## Security Model
322
+
323
+ - Project workflows operate inside their project folder and must not access other project directories.
324
+ - Secrets are injected via env and never stored in committed files.
325
+ - No external skills marketplace — all skills are local and committed.
326
+ - Tool access is policy-gated — secrets allowlists and tool allowlists are independent controls (defense-in-depth).
327
+
328
+ ## Claude Code Compatibility
329
+
330
+ - The workspace can be opened directly in Claude Code.
331
+ - `plynx` works from the workspace root, from project directories (via global config), and from any other location.
332
+ - `plynx link --direnv` generates `.envrc` for MCP servers that need secrets via `${VAR}` expansion.
333
+ - Each CLI command maps to a Claude Code skill — same agent, same behavior.
334
+
335
+ ## Design Decisions
336
+
337
+ **Minimal dependencies (11 total).** Each dependency earns its place: `commander` for CLI parsing, `chalk` for terminal colors, `cli-table3` for table output, `croner` for cron parsing, `yaml`/`zod` for config, `dotenv` for secrets loading, `env-paths` for OS-appropriate config paths, `proper-lockfile` for concurrent tick safety, `grammy` for Telegram relay, and `@anthropic-ai/claude-agent-sdk` for the core runtime. No ORMs, no template engines, no framework overhead.
338
+
339
+ **File-based state over databases.** All state — project briefs, runbooks, skills, memory, run logs, schedule state — lives in committed files. This makes workspaces portable, git-friendly, and inspectable with standard tools. No database to provision or migrate.
340
+
341
+ **Simple template interpolation over template engines.** Project scaffolding uses direct file copying with string replacement rather than Handlebars/EJS/etc. This avoids a class of injection vulnerabilities and keeps templates readable as plain files.
342
+
343
+ ## License
344
+
345
+ MIT
@@ -0,0 +1,2 @@
1
+ import type { AgentConfig } from '../lib/types.js';
2
+ export declare function getImproveAgentConfig(logSummaries: Record<string, string>): AgentConfig;
@@ -0,0 +1,54 @@
1
+ import { getWorkspaceRoot, ENV_FILE } from '../lib/config.js';
2
+ import { loadPrompt, loadSystemPrompt } from '../lib/prompts.js';
3
+ import { resolve, dirname } from 'node:path';
4
+ function improveToolCallback() {
5
+ const envFile = resolve(ENV_FILE());
6
+ const envDir = dirname(envFile);
7
+ return async (toolName, input) => {
8
+ const filePath = input?.file_path ?? input?.path;
9
+ if (filePath) {
10
+ const resolved = resolve(filePath);
11
+ // Deny access to .env files in config root
12
+ if (resolved === envFile || /[/\\]\.env(\..+)?$/.test(resolved)) {
13
+ if (resolved.startsWith(envDir)) {
14
+ return { behavior: 'deny', message: 'Cannot access .env files' };
15
+ }
16
+ }
17
+ }
18
+ return { behavior: 'allow', updatedInput: input };
19
+ };
20
+ }
21
+ export function getImproveAgentConfig(logSummaries) {
22
+ const summaryText = Object.entries(logSummaries)
23
+ .map(([project, summary]) => `## ${project}\n${summary}`)
24
+ .join('\n\n');
25
+ return {
26
+ prompt: loadPrompt('improve', 'improve_analyze', { summaryText }),
27
+ cwd: getWorkspaceRoot(),
28
+ allowedTools: ['Read', 'Glob', 'Grep'],
29
+ // Intentional: uses string systemPrompt (not preset 'claude_code') because
30
+ // this agent is read-only and doesn't need CLAUDE.md context or Claude Code tools.
31
+ systemPrompt: loadSystemPrompt('improve', 'improve_analyze'),
32
+ maxTurns: 10,
33
+ canUseTool: improveToolCallback(),
34
+ outputFormat: {
35
+ type: 'json_schema',
36
+ schema: {
37
+ type: 'object',
38
+ properties: {
39
+ projectFeedback: {
40
+ type: 'object',
41
+ description: 'Map of project name to feedback string',
42
+ additionalProperties: { type: 'string' },
43
+ },
44
+ crossProjectInsights: {
45
+ type: 'string',
46
+ description: 'Abstract cross-project learnings, no project names or secrets',
47
+ },
48
+ },
49
+ required: ['projectFeedback', 'crossProjectInsights'],
50
+ },
51
+ },
52
+ };
53
+ }
54
+ //# sourceMappingURL=improve.agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"improve.agent.js","sourceRoot":"","sources":["../../src/agents/improve.agent.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAc,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE7C,SAAS,mBAAmB;IAC1B,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAChC,OAAO,KAAK,EAAE,QAAgB,EAAE,KAAc,EAA6B,EAAE;QAC3E,MAAM,QAAQ,GAAI,KAAa,EAAE,SAAS,IAAK,KAAa,EAAE,IAAI,CAAC;QACnE,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;YACnC,2CAA2C;YAC3C,IAAI,QAAQ,KAAK,OAAO,IAAI,oBAAoB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAChE,IAAI,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;oBAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,0BAA0B,EAAE,CAAC;gBACnE,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;IACpD,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,YAAoC;IACxE,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC;SAC7C,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,MAAM,OAAO,KAAK,OAAO,EAAE,CAAC;SACxD,IAAI,CAAC,MAAM,CAAC,CAAC;IAEhB,OAAO;QACL,MAAM,EAAE,UAAU,CAAC,SAAS,EAAE,iBAAiB,EAAE,EAAE,WAAW,EAAE,CAAC;QACjE,GAAG,EAAE,gBAAgB,EAAE;QACvB,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;QACtC,2EAA2E;QAC3E,mFAAmF;QACnF,YAAY,EAAE,gBAAgB,CAAC,SAAS,EAAE,iBAAiB,CAAE;QAC7D,QAAQ,EAAE,EAAE;QACZ,UAAU,EAAE,mBAAmB,EAAE;QACjC,YAAY,EAAE;YACZ,IAAI,EAAE,aAAa;YACnB,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,eAAe,EAAE;wBACf,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,wCAAwC;wBACrD,oBAAoB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;qBACzC;oBACD,oBAAoB,EAAE;wBACpB,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,+DAA+D;qBAC7E;iBACF;gBACD,QAAQ,EAAE,CAAC,iBAAiB,EAAE,sBAAsB,CAAC;aACtD;SACF;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { AgentConfig } from '../lib/types.js';
2
+ export declare function getProjectAddAgentConfig(name: string, availableSecretKeys: string[], currentSecretsPolicy: string, migrationSummary?: string): AgentConfig;
@@ -0,0 +1,26 @@
1
+ import { getProjectDir, POLICIES_DIR } from '../lib/config.js';
2
+ import { loadPrompt } from '../lib/prompts.js';
3
+ import { join } from 'node:path';
4
+ import { projectSetupCallback } from '../lib/callbacks.js';
5
+ export function getProjectAddAgentConfig(name, availableSecretKeys, currentSecretsPolicy, migrationSummary) {
6
+ const projectDir = getProjectDir(name);
7
+ return {
8
+ prompt: loadPrompt('project-add', 'project_add', {
9
+ name,
10
+ projectDir,
11
+ availableSecretKeys: availableSecretKeys.join(', ') || '(none configured)',
12
+ currentSecretsPolicy,
13
+ secretsPolicyPath: join(POLICIES_DIR(), 'secrets-access.yaml'),
14
+ migrationSummary: migrationSummary || '',
15
+ }),
16
+ cwd: projectDir,
17
+ additionalDirectories: [POLICIES_DIR()],
18
+ allowedTools: ['Read', 'Write', 'Edit', 'Glob', 'Grep', 'Bash', 'AskUserQuestion'],
19
+ settingSources: ['project'],
20
+ systemPrompt: { type: 'preset', preset: 'claude_code' },
21
+ permissionMode: 'acceptEdits',
22
+ maxTurns: 20,
23
+ canUseTool: projectSetupCallback(projectDir, POLICIES_DIR()),
24
+ };
25
+ }
26
+ //# sourceMappingURL=project-add.agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-add.agent.js","sourceRoot":"","sources":["../../src/agents/project-add.agent.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAE3D,MAAM,UAAU,wBAAwB,CACtC,IAAY,EACZ,mBAA6B,EAC7B,oBAA4B,EAC5B,gBAAyB;IAEzB,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACvC,OAAO;QACL,MAAM,EAAE,UAAU,CAAC,aAAa,EAAE,aAAa,EAAE;YAC/C,IAAI;YACJ,UAAU;YACV,mBAAmB,EAAE,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,mBAAmB;YAC1E,oBAAoB;YACpB,iBAAiB,EAAE,IAAI,CAAC,YAAY,EAAE,EAAE,qBAAqB,CAAC;YAC9D,gBAAgB,EAAE,gBAAgB,IAAI,EAAE;SACzC,CAAC;QACF,GAAG,EAAE,UAAU;QACf,qBAAqB,EAAE,CAAC,YAAY,EAAE,CAAC;QACvC,YAAY,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,CAAC;QAClF,cAAc,EAAE,CAAC,SAAS,CAAC;QAC3B,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE;QACvD,cAAc,EAAE,aAAa;QAC7B,QAAQ,EAAE,EAAE;QACZ,UAAU,EAAE,oBAAoB,CAAC,UAAU,EAAE,YAAY,EAAE,CAAC;KAC7D,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { AgentConfig } from '../lib/types.js';
2
+ export declare function getProjectCreateAgentConfig(name: string, availableSecretKeys?: string[], currentSecretsPolicy?: string): AgentConfig;
@@ -0,0 +1,25 @@
1
+ import { getProjectDir, POLICIES_DIR } from '../lib/config.js';
2
+ import { loadPrompt } from '../lib/prompts.js';
3
+ import { join } from 'node:path';
4
+ import { projectSetupCallback } from '../lib/callbacks.js';
5
+ export function getProjectCreateAgentConfig(name, availableSecretKeys = [], currentSecretsPolicy = '') {
6
+ const projectDir = getProjectDir(name);
7
+ return {
8
+ prompt: loadPrompt('project-create', 'project_create', {
9
+ name,
10
+ projectDir,
11
+ availableSecretKeys: availableSecretKeys.join(', ') || '(none configured)',
12
+ currentSecretsPolicy: currentSecretsPolicy || 'version: 1\nshared: []\nprojects: {}\n',
13
+ secretsPolicyPath: join(POLICIES_DIR(), 'secrets-access.yaml'),
14
+ }),
15
+ cwd: projectDir,
16
+ additionalDirectories: [POLICIES_DIR()],
17
+ allowedTools: ['Read', 'Write', 'Edit', 'Glob', 'Bash', 'AskUserQuestion'],
18
+ settingSources: ['project'],
19
+ systemPrompt: { type: 'preset', preset: 'claude_code' },
20
+ permissionMode: 'acceptEdits',
21
+ maxTurns: 20,
22
+ canUseTool: projectSetupCallback(projectDir, POLICIES_DIR()),
23
+ };
24
+ }
25
+ //# sourceMappingURL=project-create.agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-create.agent.js","sourceRoot":"","sources":["../../src/agents/project-create.agent.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAE3D,MAAM,UAAU,2BAA2B,CACzC,IAAY,EACZ,sBAAgC,EAAE,EAClC,uBAA+B,EAAE;IAEjC,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACvC,OAAO;QACL,MAAM,EAAE,UAAU,CAAC,gBAAgB,EAAE,gBAAgB,EAAE;YACrD,IAAI;YACJ,UAAU;YACV,mBAAmB,EAAE,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,mBAAmB;YAC1E,oBAAoB,EAAE,oBAAoB,IAAI,wCAAwC;YACtF,iBAAiB,EAAE,IAAI,CAAC,YAAY,EAAE,EAAE,qBAAqB,CAAC;SAC/D,CAAC;QACF,GAAG,EAAE,UAAU;QACf,qBAAqB,EAAE,CAAC,YAAY,EAAE,CAAC;QACvC,YAAY,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,CAAC;QAC1E,cAAc,EAAE,CAAC,SAAS,CAAC;QAC3B,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE;QACvD,cAAc,EAAE,aAAa;QAC7B,QAAQ,EAAE,EAAE;QACZ,UAAU,EAAE,oBAAoB,CAAC,UAAU,EAAE,YAAY,EAAE,CAAC;KAC7D,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { AgentConfig } from '../lib/types.js';
2
+ export { pathEnforcementCallback } from '../lib/callbacks.js';
3
+ export declare function getRunAgentConfig(project: string, workflow: string, projectEnv: Record<string, string>, feedbackPrompt?: string): AgentConfig;
@@ -0,0 +1,37 @@
1
+ import { getProjectDir, SHARED_DOCS_DIR, INSIGHTS_DIR } from '../lib/config.js';
2
+ import { buildProjectTools } from '../lib/tools.js';
3
+ import { loadPrompt } from '../lib/prompts.js';
4
+ import { detectSandbox } from '../lib/sandbox.js';
5
+ import { pathEnforcementCallback } from '../lib/callbacks.js';
6
+ export { pathEnforcementCallback } from '../lib/callbacks.js';
7
+ export function getRunAgentConfig(project, workflow, projectEnv, feedbackPrompt) {
8
+ const projectDir = getProjectDir(project);
9
+ const toolPolicy = buildProjectTools(project);
10
+ const promptName = feedbackPrompt ? 'run_with_feedback' : 'run_default';
11
+ const vars = { workflow };
12
+ if (feedbackPrompt)
13
+ vars.feedback = feedbackPrompt;
14
+ const prompt = loadPrompt('run', promptName, vars);
15
+ const sandbox = detectSandbox();
16
+ if (sandbox.level === 'kernel') {
17
+ console.error(`[plynx] Filesystem sandbox: ${sandbox.mechanism} (kernel-level isolation)`);
18
+ }
19
+ else {
20
+ console.error('[plynx] Filesystem sandbox: regex-only (bwrap not available)');
21
+ }
22
+ return {
23
+ prompt,
24
+ cwd: projectDir,
25
+ additionalDirectories: [SHARED_DOCS_DIR(), INSIGHTS_DIR()],
26
+ env: projectEnv,
27
+ allowedTools: toolPolicy.allowedTools.length > 0 ? toolPolicy.allowedTools : undefined,
28
+ disallowedTools: toolPolicy.disallowedTools.length > 0 ? toolPolicy.disallowedTools : undefined,
29
+ settingSources: ['project'],
30
+ systemPrompt: { type: 'preset', preset: 'claude_code' },
31
+ permissionMode: 'bypassPermissions',
32
+ allowDangerouslySkipPermissions: true,
33
+ maxTurns: 50,
34
+ canUseTool: pathEnforcementCallback(projectDir, [SHARED_DOCS_DIR(), INSIGHTS_DIR()]),
35
+ };
36
+ }
37
+ //# sourceMappingURL=run.agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.agent.js","sourceRoot":"","sources":["../../src/agents/run.agent.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAE9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAE9D,MAAM,UAAU,iBAAiB,CAC/B,OAAe,EACf,QAAgB,EAChB,UAAkC,EAClC,cAAuB;IAEvB,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IAC1C,MAAM,UAAU,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAC9C,MAAM,UAAU,GAAG,cAAc,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,aAAa,CAAC;IACxE,MAAM,IAAI,GAA2B,EAAE,QAAQ,EAAE,CAAC;IAClD,IAAI,cAAc;QAAE,IAAI,CAAC,QAAQ,GAAG,cAAc,CAAC;IACnD,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC;IAEnD,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;IAChC,IAAI,OAAO,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,CAAC,KAAK,CAAC,+BAA+B,OAAO,CAAC,SAAS,2BAA2B,CAAC,CAAC;IAC7F,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,8DAA8D,CAAC,CAAC;IAChF,CAAC;IAED,OAAO;QACL,MAAM;QACN,GAAG,EAAE,UAAU;QACf,qBAAqB,EAAE,CAAC,eAAe,EAAE,EAAE,YAAY,EAAE,CAAC;QAC1D,GAAG,EAAE,UAAU;QACf,YAAY,EAAE,UAAU,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS;QACtF,eAAe,EAAE,UAAU,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS;QAC/F,cAAc,EAAE,CAAC,SAAS,CAAC;QAC3B,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE;QACvD,cAAc,EAAE,mBAAmB;QACnC,+BAA+B,EAAE,IAAI;QACrC,QAAQ,EAAE,EAAE;QACZ,UAAU,EAAE,uBAAuB,CAAC,UAAU,EAAE,CAAC,eAAe,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC;KACrF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { AgentConfig } from '../lib/types.js';
2
+ import type { MigrationPlan } from '../lib/secrets-migration.js';
3
+ export interface MigrationAgentOutput {
4
+ approved: boolean;
5
+ conflictResolutions: Record<string, {
6
+ action: 'skip' | 'rename' | 'overwrite';
7
+ newName?: string;
8
+ }>;
9
+ }
10
+ interface SecretsMigrationInput {
11
+ projectName: string;
12
+ plan: MigrationPlan;
13
+ }
14
+ export declare function getSecretsMigrationAgentConfig(input: SecretsMigrationInput): AgentConfig;
15
+ export {};
@@ -0,0 +1,63 @@
1
+ import { loadPrompt, loadSystemPrompt } from '../lib/prompts.js';
2
+ function formatKeyList(keys) {
3
+ if (keys.length === 0)
4
+ return '(none)';
5
+ return keys.map(k => `- ${k.key} (from ${k.source})`).join('\n');
6
+ }
7
+ export function getSecretsMigrationAgentConfig(input) {
8
+ const { projectName, plan } = input;
9
+ const newKeys = plan.keys.filter(k => k.category === 'new');
10
+ const deduped = plan.keys.filter(k => k.category === 'deduplicated');
11
+ const conflicts = plan.keys.filter(k => k.category === 'conflicting');
12
+ const mcpNote = plan.rewrittenMcpJson
13
+ ? 'Literal values in .mcp.json will be replaced with ${VAR} references for migrated keys.'
14
+ : '';
15
+ return {
16
+ prompt: loadPrompt('secrets-migration', 'secrets_migration_confirm', {
17
+ projectName,
18
+ totalMigratable: String(plan.keys.length),
19
+ newKeysCount: String(newKeys.length),
20
+ newKeysList: formatKeyList(newKeys),
21
+ dedupedCount: String(deduped.length),
22
+ dedupedList: formatKeyList(deduped),
23
+ conflictsCount: String(conflicts.length),
24
+ conflictsList: formatKeyList(conflicts),
25
+ mcpNote,
26
+ }),
27
+ systemPrompt: loadSystemPrompt('secrets-migration', 'secrets_migration_confirm'),
28
+ allowedTools: ['AskUserQuestion'],
29
+ maxTurns: 8,
30
+ outputFormat: {
31
+ type: 'json_schema',
32
+ schema: {
33
+ type: 'object',
34
+ properties: {
35
+ approved: {
36
+ type: 'boolean',
37
+ description: 'Whether the user approved the migration',
38
+ },
39
+ conflictResolutions: {
40
+ type: 'object',
41
+ description: 'Resolution for each conflicting key',
42
+ additionalProperties: {
43
+ type: 'object',
44
+ properties: {
45
+ action: {
46
+ type: 'string',
47
+ enum: ['skip', 'rename', 'overwrite'],
48
+ },
49
+ newName: {
50
+ type: 'string',
51
+ description: 'New key name when action is rename',
52
+ },
53
+ },
54
+ required: ['action'],
55
+ },
56
+ },
57
+ },
58
+ required: ['approved', 'conflictResolutions'],
59
+ },
60
+ },
61
+ };
62
+ }
63
+ //# sourceMappingURL=secrets-migration.agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secrets-migration.agent.js","sourceRoot":"","sources":["../../src/agents/secrets-migration.agent.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAgBjE,SAAS,aAAa,CAAC,IAAuC;IAC5D,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAC;IACvC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,8BAA8B,CAAC,KAA4B;IACzE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC;IAEpC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC;IAC5D,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,cAAc,CAAC,CAAC;IACrE,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,aAAa,CAAC,CAAC;IAEtE,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB;QACnC,CAAC,CAAC,wFAAwF;QAC1F,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO;QACL,MAAM,EAAE,UAAU,CAAC,mBAAmB,EAAE,2BAA2B,EAAE;YACnE,WAAW;YACX,eAAe,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;YACzC,YAAY,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;YACpC,WAAW,EAAE,aAAa,CAAC,OAAO,CAAC;YACnC,YAAY,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;YACpC,WAAW,EAAE,aAAa,CAAC,OAAO,CAAC;YACnC,cAAc,EAAE,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC;YACxC,aAAa,EAAE,aAAa,CAAC,SAAS,CAAC;YACvC,OAAO;SACR,CAAC;QACF,YAAY,EAAE,gBAAgB,CAAC,mBAAmB,EAAE,2BAA2B,CAAC;QAChF,YAAY,EAAE,CAAC,iBAAiB,CAAC;QACjC,QAAQ,EAAE,CAAC;QACX,YAAY,EAAE;YACZ,IAAI,EAAE,aAAa;YACnB,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,QAAQ,EAAE;wBACR,IAAI,EAAE,SAAS;wBACf,WAAW,EAAE,yCAAyC;qBACvD;oBACD,mBAAmB,EAAE;wBACnB,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,qCAAqC;wBAClD,oBAAoB,EAAE;4BACpB,IAAI,EAAE,QAAQ;4BACd,UAAU,EAAE;gCACV,MAAM,EAAE;oCACN,IAAI,EAAE,QAAQ;oCACd,IAAI,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,WAAW,CAAC;iCACtC;gCACD,OAAO,EAAE;oCACP,IAAI,EAAE,QAAQ;oCACd,WAAW,EAAE,oCAAoC;iCAClD;6BACF;4BACD,QAAQ,EAAE,CAAC,QAAQ,CAAC;yBACrB;qBACF;iBACF;gBACD,QAAQ,EAAE,CAAC,UAAU,EAAE,qBAAqB,CAAC;aAC9C;SACF;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { AgentConfig } from '../lib/types.js';
2
+ export declare function getSyncTemplateAgentConfig(project: string): AgentConfig;