@flydocs/cli 0.6.0-alpha.10 → 0.6.0-alpha.11
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.
- package/dist/cli.js +1 -1
- package/package.json +1 -1
- package/template/.claude/skills/flydocs-cloud/SKILL.md +29 -17
- package/template/.claude/skills/flydocs-cloud/scripts/flydocs_api.py +20 -0
- package/template/.claude/skills/flydocs-cloud/scripts/validate_setup.py +46 -65
- package/template/.flydocs/config.json +1 -1
- package/template/.flydocs/version +1 -1
- package/template/manifest.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -15,7 +15,7 @@ var CLI_VERSION, CLI_NAME, PACKAGE_NAME, POSTHOG_API_KEY;
|
|
|
15
15
|
var init_constants = __esm({
|
|
16
16
|
"src/lib/constants.ts"() {
|
|
17
17
|
"use strict";
|
|
18
|
-
CLI_VERSION = "0.6.0-alpha.
|
|
18
|
+
CLI_VERSION = "0.6.0-alpha.11";
|
|
19
19
|
CLI_NAME = "flydocs";
|
|
20
20
|
PACKAGE_NAME = "@flydocs/cli";
|
|
21
21
|
POSTHOG_API_KEY = "phc_v1MSJTQDFkMS90CBh3mxIz3v8bYCCnKU6v1ir6bz0Xn";
|
package/package.json
CHANGED
|
@@ -59,22 +59,22 @@ All scripts: `python3 .claude/skills/flydocs-cloud/scripts/<script>`
|
|
|
59
59
|
|
|
60
60
|
### Workspace Scripts
|
|
61
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[]}` —
|
|
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, passed[], missing[], warnings[]}` — reads relay validation, caches result, sets setupComplete |
|
|
78
78
|
|
|
79
79
|
### Script Notes
|
|
80
80
|
|
|
@@ -117,7 +117,19 @@ Relay errors include `code` and optional `provider_error` for debugging.
|
|
|
117
117
|
|
|
118
118
|
## Configuration
|
|
119
119
|
|
|
120
|
-
Reads from `.flydocs/config.json`: tier, relay URL override.
|
|
120
|
+
Reads from `.flydocs/config.json`: tier, workspaceId, relay URL override.
|
|
121
121
|
Reads `FLYDOCS_API_KEY` from environment or `.env` / `.env.local`.
|
|
122
122
|
|
|
123
123
|
Optional: `FLYDOCS_RELAY_URL` env var or `relay.url` in config to override the base URL (e.g., for local development).
|
|
124
|
+
|
|
125
|
+
### Header Contract
|
|
126
|
+
|
|
127
|
+
Every relay request includes:
|
|
128
|
+
|
|
129
|
+
| Header | Required | Source |
|
|
130
|
+
| --------------- | -------- | --------------------------------------------------- |
|
|
131
|
+
| `Authorization` | Yes | `Bearer fdk_...` from `FLYDOCS_API_KEY` |
|
|
132
|
+
| `X-Workspace` | Yes\* | `workspaceId` from `.flydocs/config.json` |
|
|
133
|
+
| `X-Repo` | No | Git remote slug (auto-detected, e.g., `owner/repo`) |
|
|
134
|
+
|
|
135
|
+
\*Required for all endpoints except `POST /auth/validate`.
|
|
@@ -11,6 +11,7 @@ Usage:
|
|
|
11
11
|
|
|
12
12
|
import json
|
|
13
13
|
import os
|
|
14
|
+
import subprocess
|
|
14
15
|
import sys
|
|
15
16
|
import time
|
|
16
17
|
from pathlib import Path
|
|
@@ -43,6 +44,7 @@ class FlyDocsClient:
|
|
|
43
44
|
print("Run 'flydocs setup' to configure your workspace", file=sys.stderr)
|
|
44
45
|
sys.exit(1)
|
|
45
46
|
|
|
47
|
+
self.repo_slug = self._detect_repo_slug()
|
|
46
48
|
self.base_url = self._resolve_base_url()
|
|
47
49
|
|
|
48
50
|
def _load_config(self) -> dict:
|
|
@@ -74,6 +76,22 @@ class FlyDocsClient:
|
|
|
74
76
|
return v if v else None
|
|
75
77
|
return None
|
|
76
78
|
|
|
79
|
+
def _detect_repo_slug(self) -> Optional[str]:
|
|
80
|
+
"""Derive owner/repo slug from git remote origin URL."""
|
|
81
|
+
try:
|
|
82
|
+
url = subprocess.check_output(
|
|
83
|
+
["git", "remote", "get-url", "origin"],
|
|
84
|
+
stderr=subprocess.DEVNULL,
|
|
85
|
+
timeout=5,
|
|
86
|
+
).decode().strip()
|
|
87
|
+
if url.endswith(".git"):
|
|
88
|
+
url = url[:-4]
|
|
89
|
+
if ":" in url and "@" in url:
|
|
90
|
+
return url.split(":")[-1] # SSH: git@github.com:owner/repo
|
|
91
|
+
return "/".join(url.split("/")[-2:]) # HTTPS
|
|
92
|
+
except Exception:
|
|
93
|
+
return None
|
|
94
|
+
|
|
77
95
|
def _resolve_base_url(self) -> str:
|
|
78
96
|
"""Resolve base URL: env var > config > default."""
|
|
79
97
|
env_url = os.environ.get("FLYDOCS_RELAY_URL")
|
|
@@ -103,6 +121,8 @@ class FlyDocsClient:
|
|
|
103
121
|
"Content-Type": "application/json",
|
|
104
122
|
"Accept": "application/json",
|
|
105
123
|
}
|
|
124
|
+
if self.repo_slug:
|
|
125
|
+
headers["X-Repo"] = self.repo_slug
|
|
106
126
|
|
|
107
127
|
data = json.dumps(body).encode("utf-8") if body else None
|
|
108
128
|
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""Validate workspace setup via the FlyDocs Relay API.
|
|
3
3
|
|
|
4
|
-
Read-only validation that
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
Read-only validation that calls GET /auth/config. The relay returns:
|
|
5
|
+
- valid: bool (all required checks pass)
|
|
6
|
+
- missing: ["provider", "statusMapping", ...] (required, blocks setup)
|
|
7
|
+
- warnings: ["repos", ...] (optional, informational)
|
|
8
|
+
|
|
9
|
+
Writes result to .flydocs/validation-cache.json and sets
|
|
10
|
+
setupComplete: true in config when valid is true.
|
|
7
11
|
"""
|
|
8
12
|
|
|
9
13
|
import json
|
|
@@ -15,71 +19,48 @@ sys.path.insert(0, str(Path(__file__).parent))
|
|
|
15
19
|
from flydocs_api import get_client, output_json, fail
|
|
16
20
|
|
|
17
21
|
|
|
18
|
-
#
|
|
19
|
-
|
|
20
|
-
"provider":
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
"
|
|
29
|
-
"test": lambda cfg: cfg.get("statusMapping", {}).get("configured") is True,
|
|
30
|
-
"message": "Status mapping not configured — configure in FlyDocs dashboard",
|
|
31
|
-
},
|
|
32
|
-
"labelConfig": {
|
|
33
|
-
"test": lambda cfg: cfg.get("labelConfig", {}).get("configured") is True,
|
|
34
|
-
"message": "Label config not configured — configure in FlyDocs dashboard",
|
|
35
|
-
},
|
|
22
|
+
# Human-readable messages for missing/warning items
|
|
23
|
+
CHECK_MESSAGES: dict[str, str] = {
|
|
24
|
+
"provider": "No provider connected — configure in FlyDocs dashboard",
|
|
25
|
+
"team": "No team selected — configure in FlyDocs dashboard",
|
|
26
|
+
"statusMapping": "Status mapping not configured — configure in FlyDocs dashboard",
|
|
27
|
+
"labelConfig": "Label config not configured — configure in FlyDocs dashboard",
|
|
28
|
+
"userIdentity": (
|
|
29
|
+
"Provider identity not linked — run: "
|
|
30
|
+
"python3 .claude/skills/flydocs-cloud/scripts/set_identity.py <provider> <id>"
|
|
31
|
+
),
|
|
32
|
+
"repos": "No repos linked — GitHub features won't work until you push and link a repo",
|
|
36
33
|
}
|
|
37
34
|
|
|
38
|
-
|
|
39
|
-
OPTIONAL_CHECKS = {
|
|
40
|
-
"userIdentity": {
|
|
41
|
-
"test": lambda cfg: cfg.get("userIdentity", {}).get("linked") is True,
|
|
42
|
-
"message": (
|
|
43
|
-
"Provider identity not linked — run: "
|
|
44
|
-
"python3 .claude/skills/flydocs-cloud/scripts/set_identity.py <provider> <id>"
|
|
45
|
-
),
|
|
46
|
-
},
|
|
47
|
-
"repos": {
|
|
48
|
-
"test": lambda cfg: (cfg.get("repos", {}).get("count", 0) or 0) > 0,
|
|
49
|
-
"message": "No repos linked — link a repo in FlyDocs dashboard settings",
|
|
50
|
-
},
|
|
51
|
-
}
|
|
35
|
+
DEFAULT_MESSAGE = "Not configured — check FlyDocs dashboard"
|
|
52
36
|
|
|
53
37
|
|
|
54
38
|
def main() -> None:
|
|
55
39
|
client = get_client()
|
|
56
40
|
|
|
57
|
-
# Fetch workspace config from relay
|
|
41
|
+
# Fetch workspace config from relay — relay does the validation
|
|
58
42
|
config_response = client.get("/auth/config")
|
|
59
43
|
|
|
60
|
-
#
|
|
44
|
+
# Read relay-computed validation results
|
|
45
|
+
is_valid = config_response.get("valid", False)
|
|
46
|
+
missing_keys: list[str] = config_response.get("missing", [])
|
|
47
|
+
warning_keys: list[str] = config_response.get("warnings", [])
|
|
48
|
+
|
|
49
|
+
# Build structured missing/warning lists with messages
|
|
50
|
+
missing = [
|
|
51
|
+
{"check": k, "action": CHECK_MESSAGES.get(k, DEFAULT_MESSAGE)}
|
|
52
|
+
for k in missing_keys
|
|
53
|
+
]
|
|
54
|
+
warnings = [
|
|
55
|
+
{"check": k, "action": CHECK_MESSAGES.get(k, DEFAULT_MESSAGE)}
|
|
56
|
+
for k in warning_keys
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
# Build checks map for cache
|
|
60
|
+
all_keys = set(CHECK_MESSAGES.keys())
|
|
61
61
|
checks: dict[str, bool] = {}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
warnings: list[dict[str, str]] = []
|
|
65
|
-
|
|
66
|
-
for name, check in REQUIRED_CHECKS.items():
|
|
67
|
-
passed = check["test"](config_response)
|
|
68
|
-
checks[name] = passed
|
|
69
|
-
if passed:
|
|
70
|
-
valid.append(name)
|
|
71
|
-
else:
|
|
72
|
-
missing.append({"check": name, "action": check["message"]})
|
|
73
|
-
|
|
74
|
-
for name, check in OPTIONAL_CHECKS.items():
|
|
75
|
-
passed = check["test"](config_response)
|
|
76
|
-
checks[name] = passed
|
|
77
|
-
if passed:
|
|
78
|
-
valid.append(name)
|
|
79
|
-
else:
|
|
80
|
-
warnings.append({"check": name, "action": check["message"]})
|
|
81
|
-
|
|
82
|
-
all_required_pass = len(missing) == 0
|
|
62
|
+
for k in all_keys:
|
|
63
|
+
checks[k] = k not in missing_keys and k not in warning_keys
|
|
83
64
|
|
|
84
65
|
# Build workspace info from response
|
|
85
66
|
workspace = config_response.get("workspace", {})
|
|
@@ -88,15 +69,15 @@ def main() -> None:
|
|
|
88
69
|
# Write validation cache
|
|
89
70
|
cache = {
|
|
90
71
|
"timestamp": datetime.now(timezone.utc).isoformat().replace("+00:00", "Z"),
|
|
91
|
-
"valid":
|
|
72
|
+
"valid": is_valid,
|
|
92
73
|
"workspace": {
|
|
93
74
|
"id": workspace.get("id", ""),
|
|
94
75
|
"name": workspace.get("name", ""),
|
|
95
76
|
},
|
|
96
77
|
"provider": provider_type,
|
|
97
78
|
"checks": checks,
|
|
98
|
-
"missing":
|
|
99
|
-
"warnings":
|
|
79
|
+
"missing": missing_keys,
|
|
80
|
+
"warnings": warning_keys,
|
|
100
81
|
}
|
|
101
82
|
|
|
102
83
|
cache_path = client.project_root / ".flydocs" / "validation-cache.json"
|
|
@@ -106,7 +87,7 @@ def main() -> None:
|
|
|
106
87
|
f.write("\n")
|
|
107
88
|
|
|
108
89
|
# If all required checks pass, set setupComplete in config
|
|
109
|
-
if
|
|
90
|
+
if is_valid:
|
|
110
91
|
config_path = client.config_path
|
|
111
92
|
if config_path.exists():
|
|
112
93
|
with open(config_path, "r") as f:
|
|
@@ -121,15 +102,15 @@ def main() -> None:
|
|
|
121
102
|
|
|
122
103
|
# Output structured report
|
|
123
104
|
report: dict = {
|
|
124
|
-
"valid":
|
|
105
|
+
"valid": is_valid,
|
|
125
106
|
"checks": checks,
|
|
126
|
-
"passed":
|
|
107
|
+
"passed": [k for k, v in checks.items() if v],
|
|
127
108
|
}
|
|
128
109
|
if missing:
|
|
129
110
|
report["missing"] = missing
|
|
130
111
|
if warnings:
|
|
131
112
|
report["warnings"] = warnings
|
|
132
|
-
if
|
|
113
|
+
if is_valid:
|
|
133
114
|
report["setupComplete"] = True
|
|
134
115
|
|
|
135
116
|
output_json(report)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.6.0-alpha.
|
|
1
|
+
0.6.0-alpha.11
|
package/template/manifest.json
CHANGED