@flydocs/cli 0.5.0-beta.9 → 0.6.0-alpha.10

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 (74) hide show
  1. package/README.md +6 -0
  2. package/dist/cli.js +1553 -414
  3. package/package.json +1 -1
  4. package/template/.claude/CLAUDE.md +11 -9
  5. package/template/.claude/agents/implementation-agent.md +0 -1
  6. package/template/.claude/agents/pm-agent.md +0 -1
  7. package/template/.claude/agents/research-agent.md +0 -1
  8. package/template/.claude/agents/review-agent.md +0 -1
  9. package/template/.claude/commands/flydocs-setup.md +202 -35
  10. package/template/.claude/commands/flydocs-upgrade.md +342 -0
  11. package/template/.claude/commands/knowledge.md +61 -0
  12. package/template/.claude/skills/flydocs-cloud/SKILL.md +66 -39
  13. package/template/.claude/skills/flydocs-cloud/cursor-rule.mdc +5 -5
  14. package/template/.claude/skills/flydocs-cloud/scripts/assign.py +17 -27
  15. package/template/.claude/skills/flydocs-cloud/scripts/assign_cycle.py +14 -30
  16. package/template/.claude/skills/flydocs-cloud/scripts/assign_milestone.py +10 -32
  17. package/template/.claude/skills/flydocs-cloud/scripts/comment.py +15 -25
  18. package/template/.claude/skills/flydocs-cloud/scripts/create_issue.py +42 -59
  19. package/template/.claude/skills/flydocs-cloud/scripts/create_milestone.py +26 -37
  20. package/template/.claude/skills/flydocs-cloud/scripts/create_project.py +24 -31
  21. package/template/.claude/skills/flydocs-cloud/scripts/create_team.py +39 -0
  22. package/template/.claude/skills/flydocs-cloud/scripts/delete_milestone.py +21 -0
  23. package/template/.claude/skills/flydocs-cloud/scripts/estimate.py +17 -22
  24. package/template/.claude/skills/flydocs-cloud/scripts/flydocs_api.py +113 -169
  25. package/template/.claude/skills/flydocs-cloud/scripts/get_estimate_scale.py +23 -0
  26. package/template/.claude/skills/flydocs-cloud/scripts/get_issue.py +6 -59
  27. package/template/.claude/skills/flydocs-cloud/scripts/link.py +16 -35
  28. package/template/.claude/skills/flydocs-cloud/scripts/list_cycles.py +21 -28
  29. package/template/.claude/skills/flydocs-cloud/scripts/list_issues.py +16 -77
  30. package/template/.claude/skills/flydocs-cloud/scripts/list_labels.py +19 -0
  31. package/template/.claude/skills/flydocs-cloud/scripts/list_milestones.py +21 -33
  32. package/template/.claude/skills/flydocs-cloud/scripts/list_projects.py +24 -38
  33. package/template/.claude/skills/flydocs-cloud/scripts/list_providers.py +19 -0
  34. package/template/.claude/skills/flydocs-cloud/scripts/list_statuses.py +19 -0
  35. package/template/.claude/skills/flydocs-cloud/scripts/list_teams.py +19 -0
  36. package/template/.claude/skills/flydocs-cloud/scripts/priority.py +10 -19
  37. package/template/.claude/skills/flydocs-cloud/scripts/project_update.py +36 -50
  38. package/template/.claude/skills/flydocs-cloud/scripts/refresh_labels.py +87 -0
  39. package/template/.claude/skills/flydocs-cloud/scripts/set_identity.py +38 -0
  40. package/template/.claude/skills/flydocs-cloud/scripts/set_labels.py +68 -0
  41. package/template/.claude/skills/flydocs-cloud/scripts/set_preferences.py +49 -0
  42. package/template/.claude/skills/flydocs-cloud/scripts/set_provider.py +46 -0
  43. package/template/.claude/skills/flydocs-cloud/scripts/set_status_mapping.py +69 -0
  44. package/template/.claude/skills/flydocs-cloud/scripts/set_team.py +42 -0
  45. package/template/.claude/skills/flydocs-cloud/scripts/transition.py +11 -52
  46. package/template/.claude/skills/flydocs-cloud/scripts/update_description.py +16 -27
  47. package/template/.claude/skills/flydocs-cloud/scripts/update_issue.py +43 -54
  48. package/template/.claude/skills/flydocs-cloud/scripts/update_milestone.py +42 -0
  49. package/template/.claude/skills/flydocs-cloud/scripts/validate_setup.py +139 -0
  50. package/template/.claude/skills/flydocs-local/SKILL.md +1 -1
  51. package/template/.claude/skills/flydocs-local/scripts/assign.py +13 -4
  52. package/template/.claude/skills/flydocs-local/scripts/flydocs_api.py +5 -2
  53. package/template/.claude/skills/flydocs-workflow/SKILL.md +23 -18
  54. package/template/.claude/skills/flydocs-workflow/reference/comment-templates.md +1 -0
  55. package/template/.claude/skills/flydocs-workflow/reference/pr-workflow.md +105 -0
  56. package/template/.claude/skills/flydocs-workflow/reference/priority-estimates.md +37 -15
  57. package/template/.claude/skills/flydocs-workflow/session.md +24 -16
  58. package/template/.claude/skills/flydocs-workflow/stages/capture.md +8 -3
  59. package/template/.claude/skills/flydocs-workflow/stages/close.md +4 -3
  60. package/template/.claude/skills/flydocs-workflow/stages/implement.md +28 -4
  61. package/template/.claude/skills/flydocs-workflow/stages/refine.md +20 -4
  62. package/template/.claude/skills/flydocs-workflow/stages/review.md +14 -2
  63. package/template/.env.example +16 -7
  64. package/template/.flydocs/config.json +4 -18
  65. package/template/.flydocs/hooks/prompt-submit.py +27 -4
  66. package/template/.flydocs/version +1 -1
  67. package/template/AGENTS.md +8 -8
  68. package/template/CHANGELOG.md +183 -0
  69. package/template/flydocs/knowledge/INDEX.md +38 -53
  70. package/template/flydocs/knowledge/README.md +60 -9
  71. package/template/flydocs/knowledge/templates/decision.md +47 -0
  72. package/template/flydocs/knowledge/templates/feature.md +35 -0
  73. package/template/flydocs/knowledge/templates/note.md +25 -0
  74. package/template/manifest.json +12 -4
@@ -0,0 +1,342 @@
1
+ # FlyDocs Upgrade — Local to Cloud Migration (PM/Planning Agent)
2
+
3
+ AI-guided migration from local tier to cloud tier. Handles API connection,
4
+ issue migration, and local content disposition in a single guided flow.
5
+
6
+ Read the active mechanism skill's `SKILL.md` for script calling conventions
7
+ before executing any scripts.
8
+
9
+ Triggers: "upgrade to cloud", "migrate to cloud", "local to cloud", "flydocs upgrade"
10
+
11
+ ---
12
+
13
+ ## IMPORTANT: Use Plan Mode
14
+
15
+ **Before executing any migration steps, enter plan mode.** This migration
16
+ involves multiple phases with irreversible actions. Planning first ensures
17
+ the user understands what will happen:
18
+
19
+ 1. Run pre-flight checks (Phase 0) to inventory the current state
20
+ 2. Present a migration summary with issue counts and what each phase does
21
+ 3. Get user approval before making any changes
22
+
23
+ Only exit plan mode and begin execution after the user approves the plan.
24
+
25
+ ---
26
+
27
+ ## Phase 0: Pre-flight Checks
28
+
29
+ Before starting, verify the project is eligible for migration.
30
+
31
+ **Step 1: Read config and verify tier.**
32
+
33
+ Read `.flydocs/config.json` and check the `tier` field.
34
+
35
+ - If `tier` is `cloud`: abort with message:
36
+ ```
37
+ This project is already on the cloud tier. No migration needed.
38
+ Run /flydocs-setup to configure your cloud workspace.
39
+ ```
40
+ - If `tier` is not `local`: abort with error about unexpected tier value.
41
+
42
+ **Step 2: Inventory local issues.**
43
+
44
+ Scan `flydocs/issues/` for all issue files across status directories:
45
+
46
+ ```
47
+ flydocs/issues/backlog/*.md
48
+ flydocs/issues/ready/*.md
49
+ flydocs/issues/implementing/*.md
50
+ flydocs/issues/review/*.md
51
+ flydocs/issues/validating/*.md
52
+ flydocs/issues/done/*.md
53
+ flydocs/issues/closed/*.md
54
+ ```
55
+
56
+ For each issue file found, read the YAML frontmatter to extract:
57
+
58
+ - Title
59
+ - Type (feature, bug, chore, idea)
60
+ - Priority
61
+ - Status (from parent directory name)
62
+ - Any comments in the body
63
+
64
+ Count totals by status and type.
65
+
66
+ **Step 3: Check for API readiness.**
67
+
68
+ Check if `FLYDOCS_API_KEY` is set in the environment (from `.env` or
69
+ `.env.local`). If not, warn the user they will need it for Phase 1.
70
+
71
+ **Step 4: Present migration summary.**
72
+
73
+ ```
74
+ Migration Summary
75
+ ─────────────────
76
+ Current tier: local
77
+ Target tier: cloud
78
+
79
+ Local issues found: [N total]
80
+ - Backlog: [n]
81
+ - Ready: [n]
82
+ - Implementing: [n]
83
+ - Review: [n]
84
+ - Done: [n]
85
+
86
+ Migration will:
87
+ 1. Connect to cloud provider (Linear) via flydocs connect
88
+ 2. Create [N] issues in Linear with matching status
89
+ 3. Archive, delete, or keep local issue files (your choice)
90
+
91
+ API key: [set / not set — will be needed in Phase 1]
92
+
93
+ Ready to proceed?
94
+ ```
95
+
96
+ Confirm with the user before continuing.
97
+
98
+ ---
99
+
100
+ ## Phase 1: Connect to Cloud
101
+
102
+ Guide the user through connecting to the cloud provider. This swaps the
103
+ tier, stores the API key, and prepares the cloud mechanism skill.
104
+
105
+ **Step 1: Get API key.**
106
+
107
+ Ask the user for their FlyDocs API key (`fdk_...`). If `FLYDOCS_API_KEY`
108
+ is already set in the environment, confirm they want to use the existing
109
+ key or enter a new one.
110
+
111
+ If no key is available, instruct the user:
112
+
113
+ ```
114
+ You'll need a FlyDocs API key (fdk_...) from your dashboard at app.flydocs.ai.
115
+
116
+ Option A: Run `flydocs connect --here` in your terminal (handles everything)
117
+ Option B: Add FLYDOCS_API_KEY=fdk_... to your .env or .env.local file
118
+ ```
119
+
120
+ Wait for the user to confirm the key is set before proceeding.
121
+
122
+ **Step 2: Update config to cloud tier.**
123
+
124
+ Read `.flydocs/config.json`, update `tier` to `"cloud"`, and write it back.
125
+ Preserve all existing config values (detected stack, skills, etc.).
126
+
127
+ **Step 3: Swap mechanism skill.**
128
+
129
+ Instruct the user to run `flydocs connect --here` from their terminal if
130
+ they haven't already. This handles the mechanism skill swap (installs
131
+ `flydocs-cloud`, removes `flydocs-local`).
132
+
133
+ **Step 4: Verify connection.**
134
+
135
+ After the user confirms the swap, verify:
136
+
137
+ 1. Read `.flydocs/config.json` — `tier` should now be `cloud`
138
+ 2. Check that `.claude/skills/flydocs-cloud/scripts/` exists
139
+ 3. Run a test command to verify the connection:
140
+ ```bash
141
+ python3 .claude/skills/flydocs-cloud/scripts/list_issues.py --limit 1
142
+ ```
143
+
144
+ If any check fails, help the user troubleshoot before proceeding.
145
+
146
+ ---
147
+
148
+ ## Phase 2: Issue Migration
149
+
150
+ Migrate local issues to the cloud provider. After `flydocs connect` swaps
151
+ the mechanism skill, the local scripts are gone — read issue files directly.
152
+
153
+ **IMPORTANT:** The local mechanism scripts are no longer available after
154
+ Phase 1. Read the markdown files directly from `flydocs/issues/`.
155
+
156
+ **Step 1: Read local issue files.**
157
+
158
+ For each issue file in `flydocs/issues/{status}/*.md`, parse:
159
+
160
+ - **YAML frontmatter** — between `---` markers at the top of the file.
161
+ Fields: `title`, `type`, `priority`, `estimate`, `created`, `assigned`.
162
+ - **Body** — everything after the frontmatter closing `---`.
163
+ This is the issue description in markdown.
164
+ - **Comments** — look for `## Comments` section in the body.
165
+ Each comment has a timestamp header and content.
166
+ - **Status** — derived from the parent directory name. Map to cloud status:
167
+ - `backlog` -> `BACKLOG`
168
+ - `ready` -> `READY`
169
+ - `implementing` -> `IMPLEMENTING`
170
+ - `review` -> `REVIEW`
171
+ - `validating` -> `VALIDATING`
172
+ - `done` -> `DONE`
173
+ - `closed` -> `CLOSED`
174
+
175
+ **Step 2: Create issues in cloud.**
176
+
177
+ For each local issue, create it in the cloud provider. Read the cloud
178
+ mechanism skill's `SKILL.md` first for exact calling conventions.
179
+
180
+ For issues with long descriptions, write the description body to a temp file
181
+ and use `--description-file`:
182
+
183
+ ```bash
184
+ python3 .claude/skills/flydocs-cloud/scripts/create_issue.py \
185
+ --title "Issue title" \
186
+ --type feature \
187
+ --priority 3 \
188
+ --estimate 2 \
189
+ --description-file /tmp/flydocs-migrate-desc.md
190
+ ```
191
+
192
+ If the issue had comments in its local file, append them to the description
193
+ body under a `## Migration Notes` section:
194
+
195
+ ```markdown
196
+ ## Migration Notes
197
+
198
+ Migrated from local tier on YYYY-MM-DD.
199
+
200
+ ### Previous Comments
201
+
202
+ **YYYY-MM-DD HH:MM** — [comment content]
203
+ ```
204
+
205
+ **Step 3: Transition non-backlog issues.**
206
+
207
+ Issues created via `create_issue.py` start in BACKLOG status. For issues
208
+ that were in other statuses locally, transition them to match:
209
+
210
+ ```bash
211
+ python3 .claude/skills/flydocs-cloud/scripts/transition.py \
212
+ <new-issue-ref> <TARGET_STATUS> \
213
+ --comment "Migrated from local tier — original status was [status]"
214
+ ```
215
+
216
+ Status transitions must follow the workflow — you may need intermediate
217
+ transitions for some statuses. Read
218
+ `.claude/skills/flydocs-workflow/reference/status-workflow.md` for valid
219
+ transitions.
220
+
221
+ **Step 4: Track the mapping.**
222
+
223
+ Maintain and display an old-to-new ID mapping as issues are migrated:
224
+
225
+ ```
226
+ Migration Progress
227
+ ──────────────────
228
+ [1/N] local-1 "Setup auth" -> FLY-234 (BACKLOG)
229
+ [2/N] local-2 "Fix header" -> FLY-235 (IMPLEMENTING)
230
+ [3/N] local-3 "Add tests" -> FLY-236 (READY)
231
+ ...
232
+ ```
233
+
234
+ **Step 5: Handle failures.**
235
+
236
+ If any issue fails to create or transition:
237
+
238
+ - Log the error with the local issue reference
239
+ - Continue with remaining issues (don't abort the whole migration)
240
+ - Report all failures at the end with suggestions for manual resolution
241
+
242
+ ---
243
+
244
+ ## Phase 3: Content Disposition
245
+
246
+ After migration, handle the local issue files. Present three options
247
+ (same pattern as the uninstall command):
248
+
249
+ ```
250
+ All [N] issues have been migrated to Linear.
251
+
252
+ What would you like to do with the local issue files?
253
+
254
+ 1. Archive — Rename flydocs/issues/ to flydocs/issues-archive/
255
+ (keeps files as read-only reference)
256
+
257
+ 2. Delete — Remove flydocs/issues/ and .flydocs/issues.counter
258
+ (clean slate, issues live in Linear now)
259
+
260
+ 3. Keep — Leave files as-is
261
+ (local files remain alongside cloud issues)
262
+ ```
263
+
264
+ Execute the user's choice:
265
+
266
+ - **Archive**: Rename `flydocs/issues/` to `flydocs/issues-archive/`
267
+ - **Delete**: Remove `flydocs/issues/` directory and `.flydocs/issues.counter` file
268
+ - **Keep**: No action needed
269
+
270
+ ---
271
+
272
+ ## Phase 4: Completion
273
+
274
+ Summarize the migration and provide next steps.
275
+
276
+ **Step 1: Migration summary.**
277
+
278
+ ```
279
+ Migration Complete
280
+ ──────────────────
281
+ Tier: local -> cloud
282
+ Issues migrated: [N] ([success] succeeded, [fail] failed)
283
+ Local files: [archived / deleted / kept]
284
+
285
+ ID Mapping:
286
+ local-1 -> FLY-234
287
+ local-2 -> FLY-235
288
+ ...
289
+ ```
290
+
291
+ **Step 2: Next steps.**
292
+
293
+ ```
294
+ Next steps:
295
+ 1. Run /flydocs-setup to configure milestones and labels
296
+ 2. Review migrated issues in Linear
297
+ 3. Start working with /start-session
298
+ ```
299
+
300
+ **Step 3: Commit prompt.**
301
+
302
+ Offer to commit the configuration changes:
303
+
304
+ ```
305
+ The tier change and skill swap modified several files.
306
+ Want to commit these changes?
307
+ ```
308
+
309
+ If the user agrees, create a commit with message:
310
+ `Upgrade FlyDocs from local to cloud tier`
311
+
312
+ Stage: `.flydocs/config.json`, `.claude/skills/`, `.claude/CLAUDE.md`,
313
+ `.cursor/rules/`, and any archive/deletion changes.
314
+
315
+ ---
316
+
317
+ ## Error Handling
318
+
319
+ - **Already cloud tier** — Abort in Phase 0 with helpful message.
320
+ - **Zero local issues** — Skip Phase 2 entirely, proceed to Phase 4.
321
+ - **flydocs connect fails** — Help troubleshoot; do not proceed to Phase 2.
322
+ - **Partial migration failure** — Report which issues succeeded and which
323
+ failed. Offer to retry failed issues or proceed with what succeeded.
324
+ - **Cancel mid-migration** — Report current state: which issues were already
325
+ created in cloud, which local files remain. The user can re-run to
326
+ continue (Phase 0 will re-inventory remaining local issues).
327
+
328
+ ---
329
+
330
+ ## Key Rules
331
+
332
+ 1. **Always read the cloud mechanism skill's `SKILL.md`** before running
333
+ scripts in Phase 2. Calling conventions may have changed.
334
+ 2. **Never delete local files without explicit user consent** in Phase 3.
335
+ 3. **After `flydocs connect`, local scripts are gone.** Read issue files
336
+ directly — do not attempt to call `flydocs-local` scripts.
337
+ 4. **Status transitions must follow the workflow.** Read the status workflow
338
+ reference for valid transition paths.
339
+ 5. **Report progress continuously.** Show the mapping table after each
340
+ issue is migrated so the user can follow along.
341
+
342
+ $ARGUMENTS
@@ -0,0 +1,61 @@
1
+ # Knowledge (All Agents)
2
+
3
+ Create or update a knowledge document — decisions, notes, features, or product docs.
4
+
5
+ Read `flydocs/knowledge/README.md` for categories and guidance.
6
+ Read `flydocs/knowledge/INDEX.md` for existing entries.
7
+
8
+ ## Procedure
9
+
10
+ ### 1. Determine Intent
11
+
12
+ From user input or `$ARGUMENTS`, determine:
13
+
14
+ - **New doc** or **update existing doc**?
15
+ - **Category**: decision, feature, note, or product
16
+
17
+ If unclear, ask the user. Default to `note` for discoveries and learnings.
18
+
19
+ ### 2. For New Docs
20
+
21
+ 1. Read the template from `flydocs/knowledge/templates/<category>.md`
22
+ 2. Gather content from the user — ask clarifying questions if context is thin
23
+ 3. Fill in the frontmatter:
24
+ - `title`: Descriptive, specific title
25
+ - `created`: Today's date (`YYYY-MM-DD`)
26
+ - `lastUpdated`: Today's date
27
+ - `relatedIssues`: Any issue IDs discussed in this session
28
+ - Category-specific fields (see template)
29
+ 4. Write the doc to the correct directory:
30
+ - Decisions: `flydocs/knowledge/decisions/NNN-title.md` (auto-increment NNN)
31
+ - Features: `flydocs/knowledge/features/feature-name.md`
32
+ - Notes: `flydocs/knowledge/notes/topic-name.md`
33
+ - Product: `flydocs/knowledge/product/document-name.md`
34
+ 5. Update `flydocs/knowledge/INDEX.md`:
35
+ - Add entry to the appropriate table
36
+ - Update the Quick Reference count
37
+ - Use a concise description (helps agents assess relevance without loading the full doc)
38
+
39
+ ### 3. For Existing Docs
40
+
41
+ 1. Find the doc in INDEX.md or by searching `flydocs/knowledge/`
42
+ 2. Read the current content
43
+ 3. Apply the update
44
+ 4. Update the `lastUpdated` field in frontmatter
45
+ 5. Update the INDEX.md entry if the description changed
46
+
47
+ ### 4. Confirm
48
+
49
+ Report what was created or updated:
50
+
51
+ - File path
52
+ - Category and title
53
+ - INDEX.md entry added/updated
54
+
55
+ ## Triggers
56
+
57
+ - "document this" / "knowledge" / "add to knowledge base"
58
+ - "create an ADR" / "record this decision" / "capture this learning"
59
+ - "add a note about" / "document this discovery"
60
+
61
+ $ARGUMENTS
@@ -1,8 +1,9 @@
1
1
  ---
2
2
  name: flydocs-cloud
3
3
  description: |
4
- Connected issue management via Linear GraphQL API.
5
- Implements the FlyDocs mechanism contract with extended cloud-only operations.
4
+ Connected issue management via FlyDocs Relay API.
5
+ Implements the FlyDocs mechanism contract with extended cloud operations.
6
+ All provider translation (Linear, Jira) happens server-side.
6
7
  triggers:
7
8
  - create issue
8
9
  - transition
@@ -12,13 +13,14 @@ triggers:
12
13
  - update description
13
14
  - update issue
14
15
  - project update
15
- - Linear
16
16
  - cloud
17
17
  ---
18
18
 
19
19
  # FlyDocs Cloud Mechanism
20
20
 
21
- Issues managed in Linear. Reads config from `.flydocs/config.json` and API key from `.env`.
21
+ Issues managed via the FlyDocs Relay API. The relay handles provider translation server-side scripts are thin REST wrappers.
22
+
23
+ Reads config from `.flydocs/config.json` and API key (`FLYDOCS_API_KEY`) from `.env`.
22
24
 
23
25
  ## Script Catalog
24
26
 
@@ -26,42 +28,64 @@ All scripts: `python3 .claude/skills/flydocs-cloud/scripts/<script>`
26
28
 
27
29
  ### Shared Contract Scripts
28
30
 
29
- | Script | Usage | Output |
30
- |--------|-------|--------|
31
- | `create_issue.py` | `--title "..." --type feature [--description "..."] [--description-file PATH] [--priority 0-4] [--estimate 1-5] [--assignee STR] [--triage] \| stdin` | `{id, identifier, title, url}` |
32
- | `transition.py` | `<ref> <STATUS> "<comment>"` | `{success, issue, previousStatus, newStatus}` |
33
- | `comment.py` | `<ref> ["<comment>"] \| stdin` | `{success, commentId}` |
34
- | `list_issues.py` | `[--status STATUS[,STATUS]] [--active] [--project ID] [--milestone ID] [--assignee STR] [--mine] [--limit N]` | `[{id, identifier, title, status, assignee, priority, dueDate, milestone, milestoneId, milestoneSortOrder, project, projectId}]` |
35
- | `get_issue.py` | `<ref> [--fields basic\|full]` | `{id, identifier, title, description, status, assignee, priority, estimate, dueDate, milestone, milestoneId, project, projectId, comments[]}` |
36
- | `assign.py` | `<ref> <assignee>` | `{success, issue, assignee}` |
37
- | `update_description.py` | `<ref> --text "..." \| --file PATH \| stdin` | `{success, issue}` |
38
-
39
- ### Extended Scripts (cloud-only)
40
-
41
- | Script | Usage | Output |
42
- |--------|-------|--------|
43
- | `update_issue.py` | `<ref> [--title "..."] [--priority 0-4] [--estimate 1-5] [--assignee STR] [--state STATUS] [--description "..."] [--description-file PATH] [--comment "..."]` | `{success, issue, updated[]}` |
44
- | `estimate.py` | `<ref> <1-5>` | `{success, issue, estimate}` |
45
- | `priority.py` | `<ref> <0-4>` | `{success, issue, priority}` |
46
- | `link.py` | `<ref> <related_ref> <type>` | `{success, type}` |
47
- | `project_update.py` | `--health STATUS --body "..." [--body-file PATH]` | `{success, id}` |
48
- | `list_projects.py` | `[--active] [--all]` | `[{id, name, state}]` — `--all` bypasses product scope |
49
- | `create_project.py` | `--name "..." [--description "..."]` | `{id, name, url}` |
50
- | `assign_cycle.py` | `<ref> [cycle_id]` | `{success, issue, cycle}` |
51
- | `list_cycles.py` | `[--active]` | `[{id, name, number, startsAt, endsAt}]` |
52
- | `list_milestones.py` | `[--all]` | `[{id, name, targetDate}]` |
53
- | `create_milestone.py` | `--name "..." [--project ID] [--target-date DATE]` | `{id, name}` — defaults to first activeProject |
54
- | `assign_milestone.py` | `<ref> <milestone_id>` | `{success, issue, milestone}` |
31
+ | Script | Usage | Output |
32
+ | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
33
+ | `create_issue.py` | `--title "..." --type feature [--description "..."] [--description-file PATH] [--priority N] [--estimate N] [--assignee STR] [--project ID] [--labels "a,b"] [--milestone ID_OR_NAME] [--triage] \| stdin` | `{id, identifier, title, url}` |
34
+ | `transition.py` | `<ref> <STATUS> "<comment>"` | `{success, issue, previousStatus, newStatus}` |
35
+ | `comment.py` | `<ref> ["<comment>"] \| stdin` | `{success, commentId}` |
36
+ | `list_issues.py` | `[--status STATUS[,STATUS]] [--active] [--project ID] [--milestone ID] [--assignee STR] [--mine] [--limit N]` | `[{id, identifier, title, status, assignee, priority, dueDate, milestone, milestoneId, milestoneSortOrder, project, projectId}]` |
37
+ | `get_issue.py` | `<ref> [--fields basic\|full]` | `{id, identifier, title, description, status, assignee, priority, estimate, dueDate, milestone, milestoneId, project, projectId, comments[]}` |
38
+ | `assign.py` | `<ref> <assignee> \| --unassign` | `{success, issue, assignee}` |
39
+ | `update_description.py` | `<ref> --text "..." \| --file PATH \| stdin` | `{success, issue}` |
40
+
41
+ ### Extended Scripts
42
+
43
+ | Script | Usage | Output |
44
+ | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
45
+ | `update_issue.py` | `<ref> [--title "..."] [--priority N] [--estimate N] [--assignee STR] [--state STATUS] [--description "..."] [--description-file PATH] [--labels "a,b"] [--milestone ID_OR_NAME] [--comment "..."]` | `{success, issue, updated[]}` |
46
+ | `estimate.py` | `<ref> <points>` | `{success, issue, estimate}` — relay validates against provider scale |
47
+ | `priority.py` | `<ref> <0-4>` | `{success, issue, priority}` |
48
+ | `link.py` | `<ref> <related_ref> <type>` | `{success, type}` |
49
+ | `project_update.py` | `--health STATUS --body "..." [--body-file PATH]` | `{success, id}` |
50
+ | `list_projects.py` | `[--active] [--all]` | `[{id, name, state}]` — `--all` bypasses product scope |
51
+ | `create_project.py` | `--name "..." [--description "..."]` | `{id, name, url}` |
52
+ | `assign_cycle.py` | `<ref> [cycle_id]` | `{success, issue, cycle}` |
53
+ | `list_cycles.py` | `[--active]` | `[{id, name, number, startsAt, endsAt}]` |
54
+ | `list_milestones.py` | `[--all]` | `[{id, name, targetDate}]` |
55
+ | `create_milestone.py` | `--name "..." [--project ID] [--target-date DATE]` | `{id, name}` |
56
+ | `update_milestone.py` | `<milestone_id> [--name "..."] [--target-date DATE] [--description "..."]` | `{success, id, name}` |
57
+ | `delete_milestone.py` | `<milestone_id>` | `{success, id}` |
58
+ | `assign_milestone.py` | `<ref> <milestone_id>` | `{success, issue, milestone}` |
59
+
60
+ ### Workspace Scripts
61
+
62
+ | Script | Usage | Output |
63
+ | ----------------------- | --------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
64
+ | `list_providers.py` | (no args) | `[{type, name, connected}]` |
65
+ | `set_provider.py` | `<provider_type>` (`linear` or `jira`) | `{success}` — updates relay routing and local config `provider.type` |
66
+ | `list_teams.py` | (no args) | `[{id, name, key}]` — returns Linear teams or Jira projects (relay normalizes) |
67
+ | `create_team.py` | `--name "..." [--key KEY] [--description "..."] [--parent <team_id>]` | `{id, name, key}` — `--parent` is Linear-only (sub-teams) |
68
+ | `set_team.py` | `<team_id>` | `{success}` — updates relay preference and local config; for Jira, sets the active Jira project |
69
+ | `list_labels.py` | (no args) | `[{id, name, color}]` — requires team to be set first |
70
+ | `set_labels.py` | `--defaults '["a"]' --type-map '{"feature":["F"],...}' \| stdin` | `{success, validated, defaults, typeMap}` — stores label config on relay |
71
+ | `list_statuses.py` | (no args) | `{states, currentMapping, flydocsStatuses}` — provider workflow states and current mapping |
72
+ | `set_status_mapping.py` | `--auto \| --mapping '{"BACKLOG":"Backlog",...}' \| stdin` | `{success, mapping, matched, total}` — stores status mapping on relay |
73
+ | `set_identity.py` | `<provider> <provider-user-id>` | `{success, provider, providerId}` — binds provider user ID for `--mine` resolution |
74
+ | `set_preferences.py` | `[--workspace ID] [--assignee self\|ID] [--display JSON]` | `{success, preferences}` — no flags = GET current; with flags = POST update |
75
+ | `get_estimate_scale.py` | (no args) | `{scale, type}` — provider's valid estimate values (fixed or freeform) |
76
+ | `refresh_labels.py` | `[--fix]` | `{valid, stale, details}` — validates config label IDs against relay; `--fix` updates stale IDs |
77
+ | `validate_setup.py` | (no args) | `{valid, checks, missing[]}` — validates workspace config, caches result, sets setupComplete |
55
78
 
56
79
  ### Script Notes
57
80
 
58
- - **`list_issues.py` product scope**: Automatically scopes results using config cascade `activeProjects` `product.labelIds` team-wide. Explicit `--project` overrides. All flags (`--active`, `--status`, `--mine`, `--assignee`) filter within the scoped results.
59
- - **`list_issues.py --active`**: Returns all non-terminal issues (excludes Done, Archived, Canceled, Duplicate). Replaces `status_summary.py` — group results by status field instead.
60
- - **`list_issues.py --milestone`**: Filter issues by project milestone ID. Get IDs from `list_milestones.py`.
81
+ - **How it works**: Scripts call the FlyDocs Relay REST API, which translates to the provider (Linear, Jira) server-side. Same interface and output as before the transport changed from direct GraphQL to managed REST. For Jira, the relay handles Markdown-to-ADF (Atlassian Document Format) conversion automatically.
82
+ - **`list_issues.py --active`**: Returns all non-terminal issues (excludes Done, Archived, Canceled, Duplicate).
61
83
  - **`list_issues.py --status`**: Accepts comma-separated statuses: `--status READY,IMPLEMENTING,BLOCKED`
62
- - **`get_issue.py --fields basic`**: Skips comment fetch for faster responses when comments aren't needed.
63
- - **`update_issue.py`**: Bulk update — sets multiple fields in a single API call. Prefer over separate `estimate.py`/`priority.py`/`assign.py` calls when updating more than one field.
64
- - **Shell-safe text input**: For descriptions, comments, or any text with special characters (apostrophes, quotes, parentheses), pipe via stdin with a single-quoted heredoc instead of `--text`:
84
+ - **`get_issue.py --fields basic`**: Skips comment fetch for faster responses.
85
+ - **`update_issue.py`**: Bulk update — sets multiple fields in a single API call. Prefer over separate scripts when updating more than one field.
86
+ - **Estimate validation**: The relay validates estimates server-side against the provider's scale. Use `get_estimate_scale.py` to discover valid values before setting. Linear uses a fixed scale `[0, 1, 2, 3, 5, 8, 13, 21]`; Jira accepts freeform values.
87
+ - **Label staleness**: Label IDs are team-scoped and can go stale when switching teams or projects. Use `refresh_labels.py` to validate config label IDs, and `refresh_labels.py --fix` to auto-update stale ones.
88
+ - **Shell-safe text input**: For text with special characters, pipe via stdin with a single-quoted heredoc:
65
89
  ```bash
66
90
  python3 update_description.py ENG-123 <<'EOF'
67
91
  Description with 'apostrophes', (parens), and "quotes"
@@ -83,14 +107,17 @@ All scripts: `python3 .claude/skills/flydocs-cloud/scripts/<script>`
83
107
 
84
108
  ### Issue Reference
85
109
 
86
- `<ref>`: Provider identifier, e.g., `ENG-123`. Resolved via Linear search API.
110
+ `<ref>`: Provider identifier, e.g., `ENG-123`. Resolved server-side by the relay.
87
111
 
88
112
  ## Error Handling
89
113
 
90
114
  Exit 0 = success (JSON on stdout). Exit 1 = error (message on stderr).
91
115
  Network errors: exponential backoff, 3 retries, 2s base delay.
116
+ Relay errors include `code` and optional `provider_error` for debugging.
92
117
 
93
118
  ## Configuration
94
119
 
95
- Reads from `.flydocs/config.json`: tier, provider.teamId, statusMapping, issueLabels.
96
- Reads `LINEAR_API_KEY` from environment or `.env` / `.env.local`.
120
+ Reads from `.flydocs/config.json`: tier, relay URL override.
121
+ Reads `FLYDOCS_API_KEY` from environment or `.env` / `.env.local`.
122
+
123
+ Optional: `FLYDOCS_RELAY_URL` env var or `relay.url` in config to override the base URL (e.g., for local development).
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: Connected issue management via Linear — cloud mechanism for FlyDocs
2
+ description: Connected issue management via FlyDocs Relay API — cloud mechanism for FlyDocs
3
3
  alwaysApply: true
4
4
  ---
5
5
 
@@ -7,7 +7,7 @@ alwaysApply: true
7
7
 
8
8
  # FlyDocs Cloud Mechanism
9
9
 
10
- Issues managed in Linear. Reads config from `.flydocs/config.json` and API key from `.env`.
10
+ Issues managed via FlyDocs Relay API. Reads config from `.flydocs/config.json` and API key (`FLYDOCS_API_KEY`) from `.env`.
11
11
 
12
12
  ## Shared Contract Scripts
13
13
 
@@ -23,7 +23,7 @@ All scripts: `python3 .claude/skills/flydocs-cloud/scripts/<script>`
23
23
  | `assign.py` | `<ref> <assignee>` |
24
24
  | `update_description.py` | `<ref> --text "..." \| --file PATH` |
25
25
 
26
- ## Extended Scripts (cloud-only)
26
+ ## Extended Scripts
27
27
 
28
28
  | Script | Key Arguments |
29
29
  |--------|---------------|
@@ -46,5 +46,5 @@ Network errors: exponential backoff, 3 retries, 2s base delay.
46
46
 
47
47
  ## Configuration
48
48
 
49
- Reads from `.flydocs/config.json`: tier, provider.teamId, statusMapping, issueLabels.
50
- Reads `LINEAR_API_KEY` from environment or `.env` / `.env.local`.
49
+ Reads from `.flydocs/config.json`: tier, relay URL override.
50
+ Reads `FLYDOCS_API_KEY` from environment or `.env` / `.env.local`.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env python3
2
- """Assign an issue to a person."""
2
+ """Assign or unassign an issue via the FlyDocs Relay API."""
3
3
 
4
4
  import sys
5
5
  from pathlib import Path
@@ -7,32 +7,22 @@ from pathlib import Path
7
7
  sys.path.insert(0, str(Path(__file__).parent))
8
8
  from flydocs_api import get_client, output_json, fail
9
9
 
10
- if len(sys.argv) < 3:
11
- fail("Usage: assign.py <ref> <assignee>")
10
+ if len(sys.argv) < 2:
11
+ fail("Usage: assign.py <ref> <assignee> | assign.py <ref> --unassign")
12
12
 
13
- ref, assignee_query = sys.argv[1], sys.argv[2]
13
+ ref = sys.argv[1]
14
+ unassign = "--unassign" in sys.argv
15
+
16
+ if not unassign and len(sys.argv) < 3:
17
+ fail("Usage: assign.py <ref> <assignee> | assign.py <ref> --unassign")
18
+
19
+ assignee = None if unassign else sys.argv[2]
14
20
  client = get_client()
15
21
 
16
- issue_uuid = client.resolve_issue_id(ref)
17
- if not issue_uuid:
18
- fail(f"Issue not found: {ref}")
19
-
20
- user_id, user_name = client.resolve_user_id(assignee_query)
21
- if not user_id:
22
- fail(f"User not found: {assignee_query}")
23
-
24
- result = client.query(
25
- """mutation($id: String!, $assigneeId: String!) {
26
- issueUpdate(id: $id, input: { assigneeId: $assigneeId }) {
27
- success
28
- issue { identifier }
29
- }
30
- }""",
31
- {"id": issue_uuid, "assigneeId": user_id},
32
- )
33
-
34
- if not result.get("data", {}).get("issueUpdate", {}).get("success"):
35
- fail(f"Failed to assign: {result}")
36
-
37
- issue = result["data"]["issueUpdate"]["issue"]
38
- output_json({"success": True, "issue": issue["identifier"], "assignee": user_name})
22
+ result = client.post(f"/issues/{ref}/assign", {"assignee": assignee})
23
+
24
+ output_json({
25
+ "success": result.get("success", True),
26
+ "issue": result.get("issue", ref),
27
+ "assignee": result.get("assignee", assignee),
28
+ })