@gonovus-ai/spec-flow-cli 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +807 -2
- package/dist/authentication-command-topology.d.ts +7 -0
- package/dist/authentication-command-topology.js +9 -0
- package/dist/authentication-command-topology.js.map +1 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +52 -0
- package/dist/bin.js.map +1 -0
- package/dist/cli.d.ts +16 -0
- package/dist/cli.js +3339 -0
- package/dist/cli.js.map +1 -0
- package/dist/client-identity.d.ts +12 -0
- package/dist/client-identity.js +29 -0
- package/dist/client-identity.js.map +1 -0
- package/dist/credential-store.d.ts +20 -0
- package/dist/credential-store.js +146 -0
- package/dist/credential-store.js.map +1 -0
- package/dist/default-api-origin.d.ts +1 -0
- package/dist/default-api-origin.js +1 -0
- package/dist/default-api-origin.js.map +1 -0
- package/dist/github-account-commands.d.ts +25 -0
- package/dist/github-account-commands.js +117 -0
- package/dist/github-account-commands.js.map +1 -0
- package/dist/github-connection-commands.d.ts +4 -0
- package/dist/github-connection-commands.js +95 -0
- package/dist/github-connection-commands.js.map +1 -0
- package/dist/github-import-commands.d.ts +3 -0
- package/dist/github-import-commands.js +59 -0
- package/dist/github-import-commands.js.map +1 -0
- package/dist/http-origin.d.ts +13 -0
- package/dist/http-origin.js +39 -0
- package/dist/http-origin.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +238 -0
- package/dist/index.js.map +1 -0
- package/dist/node-version.d.ts +1 -0
- package/dist/node-version.js +8 -0
- package/dist/node-version.js.map +1 -0
- package/dist/safe-cli-error.d.ts +2 -0
- package/dist/safe-cli-error.js +3 -0
- package/dist/safe-cli-error.js.map +1 -0
- package/dist/user-agent.d.ts +3 -0
- package/dist/user-agent.js +10 -0
- package/dist/user-agent.js.map +1 -0
- package/dist/user-api-key-commands.d.ts +29 -0
- package/dist/user-api-key-commands.js +128 -0
- package/dist/user-api-key-commands.js.map +1 -0
- package/dist/work-item-asset-commands.d.ts +24 -0
- package/dist/work-item-asset-commands.js +211 -0
- package/dist/work-item-asset-commands.js.map +1 -0
- package/dist/work-item-exchange-file.d.ts +4 -0
- package/dist/work-item-exchange-file.js +66 -0
- package/dist/work-item-exchange-file.js.map +1 -0
- package/dist/work-item-resource-link-commands.d.ts +23 -0
- package/dist/work-item-resource-link-commands.js +85 -0
- package/dist/work-item-resource-link-commands.js.map +1 -0
- package/dist/work-item-time-entry-input.d.ts +4 -0
- package/dist/work-item-time-entry-input.js +27 -0
- package/dist/work-item-time-entry-input.js.map +1 -0
- package/package.json +53 -3
package/README.md
CHANGED
|
@@ -1,3 +1,808 @@
|
|
|
1
|
-
#
|
|
1
|
+
# SpecFlow CLI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The next CLI contract is **0.2.0**, coordinated with the official Skill's exact
|
|
4
|
+
pin. Directory, Spec and Product Map results can return `capabilityId: null`;
|
|
5
|
+
unassigned search results have `capabilityPath: []`. Consumers of 0.1.x must
|
|
6
|
+
handle these absent placements before upgrading. Omit `--capability-id` on
|
|
7
|
+
creation, and use `--capability-id none` on `spec update` to clear placement;
|
|
8
|
+
omitting that update option preserves the current placement. Existing grouped
|
|
9
|
+
requests and nested Capability paths retain their meaning. The HTTP service
|
|
10
|
+
continues under `/v1` with regenerated OpenAPI inputs; clients must update their
|
|
11
|
+
nullable response handling together. This source change does not publish either
|
|
12
|
+
artifact or change already released Skill tags.
|
|
13
|
+
|
|
14
|
+
`@gonovus-ai/spec-flow-cli` uses OAuth Device Authorization to create an independent
|
|
15
|
+
seven-day Better Auth CLI Session. It supports the Node.js 24 runtime line;
|
|
16
|
+
Node.js 22 and unverified future major versions are intentionally unsupported.
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install --global @gonovus-ai/spec-flow-cli@0.2.0
|
|
20
|
+
specflow auth login
|
|
21
|
+
specflow auth status
|
|
22
|
+
specflow auth logout
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The published package's default service origin comes from the GitHub repository
|
|
26
|
+
Actions variable `SPEC_FLOW_DEFAULT_API_URL`, embedded at build time. Both authentication
|
|
27
|
+
and resource commands resolve `--server` first, then runtime `SPEC_FLOW_API_URL`, then
|
|
28
|
+
that packaged default. Keep the same origin for login and subsequent commands.
|
|
29
|
+
Credentials are isolated by origin; a different environment requires its own login.
|
|
30
|
+
|
|
31
|
+
Changing the repository variable requires publishing a new CLI version; existing
|
|
32
|
+
installations keep their packaged default. The release workflow rejects a missing,
|
|
33
|
+
empty or invalid origin. Skill instructions do not need a deployment address.
|
|
34
|
+
|
|
35
|
+
Local builds without `SPEC_FLOW_DEFAULT_API_URL` have no implicit service target;
|
|
36
|
+
pass `--server` or set runtime `SPEC_FLOW_API_URL`. To build a local package with a
|
|
37
|
+
default, provide `SPEC_FLOW_DEFAULT_API_URL` to the CLI build command. The packed
|
|
38
|
+
installation smoke uses an isolated `.invalid` test origin when no build value is
|
|
39
|
+
provided; it never substitutes a deployment URL into source.
|
|
40
|
+
|
|
41
|
+
After login, resource commands reuse the stored CLI Session and emit structured JSON
|
|
42
|
+
on stdout. Existing-Project commands always require an explicit `--project-id`:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
SPEC_FLOW_API_URL=https://specflow.example specflow workspace list
|
|
46
|
+
SPEC_FLOW_API_URL=https://specflow.example specflow workspace create --name "Core Platform"
|
|
47
|
+
SPEC_FLOW_API_URL=https://specflow.example specflow project list
|
|
48
|
+
SPEC_FLOW_API_URL=https://specflow.example specflow project list --workspace-id <workspace-id>
|
|
49
|
+
SPEC_FLOW_API_URL=https://specflow.example specflow project list --status Archived
|
|
50
|
+
SPEC_FLOW_API_URL=https://specflow.example specflow project list --status Trashed
|
|
51
|
+
SPEC_FLOW_API_URL=https://specflow.example specflow project create --name "Payments" --project-id PAY --workspace-id <workspace-id>
|
|
52
|
+
SPEC_FLOW_API_URL=https://specflow.example specflow project create --name "Payments" --project-id PAY --workspace-id <workspace-id> --spec-language zh-CN
|
|
53
|
+
SPEC_FLOW_API_URL=https://specflow.example specflow project archive --project-id <project-id> --expected-version '"1"'
|
|
54
|
+
SPEC_FLOW_API_URL=https://specflow.example specflow project restore --project-id <project-id> --expected-version '"2"'
|
|
55
|
+
SPEC_FLOW_API_URL=https://specflow.example specflow project trash --project-id <project-id> --expected-version '"2"'
|
|
56
|
+
SPEC_FLOW_API_URL=https://specflow.example specflow project directory --project-id <project-id>
|
|
57
|
+
SPEC_FLOW_API_URL=https://specflow.example specflow spec read --project-id <project-id> --spec-id <spec-id>
|
|
58
|
+
SPEC_FLOW_API_URL=https://specflow.example specflow spec current --project-id <project-id> --spec-id <spec-id>
|
|
59
|
+
SPEC_FLOW_API_URL=https://specflow.example specflow spec revision --project-id <project-id> --spec-id <spec-id> --revision-id <revision-id>
|
|
60
|
+
SPEC_FLOW_API_URL=https://specflow.example specflow spec changelog --project-id <project-id> --spec-id <spec-id>
|
|
61
|
+
SPEC_FLOW_API_URL=https://specflow.example specflow spec edit --project-id <project-id> --spec-id <spec-id> --content "$(cat payments.md)"
|
|
62
|
+
SPEC_FLOW_API_URL=https://specflow.example specflow spec assign-scenario-ids --project-id <project-id> --spec-id <spec-id>
|
|
63
|
+
SPEC_FLOW_API_URL=https://specflow.example specflow spec publish --project-id <project-id> --spec-id <spec-id>
|
|
64
|
+
SPEC_FLOW_API_URL=https://specflow.example specflow glossary edit --project-id <project-id> --entries '[{"id":"payment","canonicalTerm":"Payment","definition":"A completed transfer.","usageNote":null}]'
|
|
65
|
+
SPEC_FLOW_API_URL=https://specflow.example specflow proposal create-spec --project-id <project-id> --spec-id <spec-id> --baseline-content "$(cat payments.md)" --proposed-content "$(cat payments.md)" --agent-revision <revision> --agent-model <model> --source-reference-ids '["source-id"]'
|
|
66
|
+
SPEC_FLOW_API_URL=https://specflow.example specflow proposal list --project-id <project-id> --target-kind Spec --spec-id <spec-id> --status Open
|
|
67
|
+
SPEC_FLOW_API_URL=https://specflow.example specflow proposal apply --project-id <project-id> --proposal-id <proposal-id> --change-ids '["hunk-1"]'
|
|
68
|
+
SPEC_FLOW_API_URL=https://specflow.example specflow proposal discard --project-id <project-id> --proposal-id <proposal-id>
|
|
69
|
+
SPEC_FLOW_API_URL=https://specflow.example specflow authoring-history --project-id <project-id>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Every official CLI service request sends the versioned `@gonovus-ai/spec-flow-cli/<version>`
|
|
73
|
+
User-Agent. Diagnostics use stderr, and stable Skill Errors use documented reason and
|
|
74
|
+
exit-status categories.
|
|
75
|
+
|
|
76
|
+
## Optional Task resource links
|
|
77
|
+
|
|
78
|
+
Use `work-item resource-link list --project-id PAY --work-item-id PAY-7` to read
|
|
79
|
+
current authorized references. Add a stable Spec with `add --kind spec --spec-id
|
|
80
|
+
PAY-8`; `--spec-project-id` selects another accessible Project in the same Workspace
|
|
81
|
+
and otherwise defaults to the Task Project. Add a document or other locator with
|
|
82
|
+
`add --kind document|other --title <name> --url <http-or-https-url>`. Every add requires
|
|
83
|
+
`--idempotency-key <uuid>` and the owning Project/Task flags. Retain that key for an
|
|
84
|
+
ambiguous retry of the same input.
|
|
85
|
+
|
|
86
|
+
Unlink with `remove --link-id <uuid> --expected-version <opaque-version>
|
|
87
|
+
--idempotency-key <uuid>` and the Project/Task flags. The target and Task remain
|
|
88
|
+
independent. `spec work-items --project-id <Spec-project> --spec-id <id> [--limit <n>]
|
|
89
|
+
[--cursor <opaque-cursor>]` reads paged authorized reverse Task references.
|
|
90
|
+
These commands read current metadata without pinning a Revision, importing content,
|
|
91
|
+
or changing Task completion or Spec publication. External locator names are
|
|
92
|
+
user-authored Task data; opening a destination uses that destination's authorization.
|
|
93
|
+
|
|
94
|
+
## Machine contract
|
|
95
|
+
|
|
96
|
+
Resource-command success writes exactly one newline-terminated JSON object to stdout.
|
|
97
|
+
stderr is newline-delimited JSON (NDJSON): zero or more diagnostics use
|
|
98
|
+
`{ "diagnostic": { "level": "warning", "message": string } }`. These
|
|
99
|
+
command/result pairs are the supported schemas:
|
|
100
|
+
|
|
101
|
+
| Command | Success object |
|
|
102
|
+
| ------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
|
|
103
|
+
| `workspace list` | `{ workspaces: WorkspaceSummary[] }` |
|
|
104
|
+
| `workspace create` | `{ workspace: WorkspaceSummary }` |
|
|
105
|
+
| `workspace member list --workspace-id <id>` | `{ members: WorkspaceMember[] }` |
|
|
106
|
+
| `workspace member search --workspace-id <id> --query <q>` | `{ candidates: WorkspaceDirectoryCandidate[] }` |
|
|
107
|
+
| `workspace member add --workspace-id <id> --user-id <userId> --role <role>` | `{ member: WorkspaceMember }` |
|
|
108
|
+
| `workspace member set-role --workspace-id <id> --user-id <userId> --role <role> --expected-version <v>` | `{ member: WorkspaceMember }` |
|
|
109
|
+
| `workspace member remove --workspace-id <id> --user-id <userId> --expected-version <v>` | `{ removed: { userId: string } }` |
|
|
110
|
+
| `workspace role list --workspace-id <id>` | `{ roles: WorkspaceRole[] }` |
|
|
111
|
+
| `workspace role create --workspace-id <id> --name <name> --statements <json>` | `{ role: WorkspaceRole }` |
|
|
112
|
+
| `workspace role update --workspace-id <id> --name <name> --statements <json> --expected-version <v>` | `{ role: WorkspaceRole }` |
|
|
113
|
+
| `workspace role delete --workspace-id <id> --name <name> --expected-version <v>` | `{ deleted: { name: string } }` |
|
|
114
|
+
| `project list [--status Active\|Archived\|Trashed] [--workspace-id <workspace-id>]` | `{ projects: ProjectSummary[] }` |
|
|
115
|
+
| `project create` | `{ project: ProjectSummary }` |
|
|
116
|
+
| `project archive` | `{ project: ProjectSummary }` |
|
|
117
|
+
| `project restore` | `{ project: ProjectSummary }` |
|
|
118
|
+
| `project trash` | `{ project: ProjectSummary }` |
|
|
119
|
+
| `project context` | `{ project: ProjectContext, publishedGlossary: PublishedGlossary \| null }` |
|
|
120
|
+
| `project directory` | `{ capabilities: Capability[], permissions: Permissions, specs: SpecSummary[] }` |
|
|
121
|
+
| `spec search` | `{ nextCursor: string \| null, results: SearchResult[], totalCount: number }` |
|
|
122
|
+
| `work-item resource-link list` | `{ links: WorkItemResourceLink[], canCreateLink: boolean, canReadSpecs: boolean }` |
|
|
123
|
+
| `work-item resource-link add` | `{ linkId: string, link: WorkItemResourceLink \| null, replayed: boolean }` |
|
|
124
|
+
| `work-item resource-link remove` | `{ deleted: true, replayed: boolean }` |
|
|
125
|
+
| `spec work-items` | `{ workItems: SpecWorkItemReference[], nextCursor: string \| null, canReadWorkItems: boolean }` |
|
|
126
|
+
| `spec read` | `{ currentRevision: SpecRevision \| null, permissions: Permissions, spec: SpecDetails }` |
|
|
127
|
+
| `spec current` | `{ revision: SpecRevision, spec: SpecSummary }` |
|
|
128
|
+
| `spec revision` | `{ revision: SpecRevision }` |
|
|
129
|
+
| `spec changelog` | `{ entries: SpecChangelogEntry[] }` |
|
|
130
|
+
| `spec create` | `{ spec: SpecDetails }` |
|
|
131
|
+
| `spec update` | `{ spec: SpecDetails }` |
|
|
132
|
+
| `spec draft` | `{ spec: SpecDetails }` |
|
|
133
|
+
| `spec edit` | `{ draft: { draftSessionId: string, content: string, specId: string } }` |
|
|
134
|
+
| `spec assign-scenario-ids` | `{ assignedScenarioIds: string[], draft: { draftSessionId: string, content: string, specId: string } }` |
|
|
135
|
+
| `spec publish` | `{ revision: SpecRevision, spec: SpecSummary }` |
|
|
136
|
+
| `spec state` | `{ spec: SpecSummary }` |
|
|
137
|
+
| `spec rollback` | `{ revision: SpecRevision, spec: SpecSummary }` |
|
|
138
|
+
| `spec delete` | `{ deleted: { specId: string } }` |
|
|
139
|
+
| `glossary read` | `{ currentRevision: GlossaryRevision \| null, draftSession: GlossaryDraftSession \| null, permissions: Permissions }` |
|
|
140
|
+
| `glossary changelog` | `{ entries: GlossaryChangelogEntry[] }` |
|
|
141
|
+
| `glossary revision` | `{ revision: GlossaryRevision }` |
|
|
142
|
+
| `glossary draft` | `{ glossary: GlossaryDetails }` |
|
|
143
|
+
| `glossary edit` | `{ draft: { draftSessionId: string, entries: GlossaryEntry[] } }` |
|
|
144
|
+
| `glossary publish` | `{ revision: GlossaryRevision }` |
|
|
145
|
+
| `glossary rollback` | `{ revision: GlossaryRevision }` |
|
|
146
|
+
| `proposal create-spec\|create-glossary` | `{ proposal: DraftProposal }` |
|
|
147
|
+
| `proposal list` | `{ proposals: DraftProposal[] }` |
|
|
148
|
+
| `proposal apply` | `{ mergeOutcome: "Applied", proposal: DraftProposal }` |
|
|
149
|
+
| `proposal discard` | `{ proposal: DraftProposal }` |
|
|
150
|
+
| `authoring-history` | `{ operations: AuthoringOperation[] }` |
|
|
151
|
+
| `capability create` | `{ capability: Capability }` |
|
|
152
|
+
| `capability update` | `{ capability: Capability }` |
|
|
153
|
+
| `capability delete` | `{ deleted: { capabilityId: string } }` |
|
|
154
|
+
| `token issue` | `{ credential: string, token: ProjectReadToken }` |
|
|
155
|
+
| `token list` | `{ tokens: ProjectReadToken[] }` |
|
|
156
|
+
| `token revoke` | `{ revoked: { tokenId: string } }` |
|
|
157
|
+
| `review request` | `{ review: ManualReviewRecord }` |
|
|
158
|
+
| `review read` | `{ review: ManualReviewRecord }` |
|
|
159
|
+
| `finding list` | `{ findings: ReviewFinding[], nextCursor: string \| null, permissions: FindingPermissions }` |
|
|
160
|
+
| `finding read` | `{ finding: ReviewFinding, permissions: FindingPermissions }` |
|
|
161
|
+
| `finding create` | `{ finding: ReviewFinding, permissions: FindingPermissions }` |
|
|
162
|
+
| `finding confirm\|dismiss\|resolve` | `{ finding: ReviewFinding, permissions: FindingPermissions }` |
|
|
163
|
+
|
|
164
|
+
The named JSON shapes are:
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
type WorkItemResourceLink = {
|
|
168
|
+
id: string;
|
|
169
|
+
version: string; // opaque ETag
|
|
170
|
+
createdAt: string;
|
|
171
|
+
target:
|
|
172
|
+
| {
|
|
173
|
+
kind: "spec";
|
|
174
|
+
projectId: string;
|
|
175
|
+
specId: string;
|
|
176
|
+
title: string;
|
|
177
|
+
state: "Draft" | "Ready" | "Unavailable";
|
|
178
|
+
unavailabilityReason: string | null;
|
|
179
|
+
}
|
|
180
|
+
| { kind: "document" | "other"; title: string; url: string };
|
|
181
|
+
};
|
|
182
|
+
type SpecWorkItemReference = {
|
|
183
|
+
linkId: string;
|
|
184
|
+
projectId: string;
|
|
185
|
+
workItemId: string;
|
|
186
|
+
title: string;
|
|
187
|
+
status: string;
|
|
188
|
+
};
|
|
189
|
+
type WorkspaceSummary = {
|
|
190
|
+
capabilities: {
|
|
191
|
+
canReadMembers: boolean;
|
|
192
|
+
canReadRoles: boolean;
|
|
193
|
+
};
|
|
194
|
+
id: string;
|
|
195
|
+
name: string;
|
|
196
|
+
role: string;
|
|
197
|
+
};
|
|
198
|
+
type WorkspaceMember = {
|
|
199
|
+
accessStatus: "Enabled" | "Disabled";
|
|
200
|
+
email: string | null;
|
|
201
|
+
image: string | null;
|
|
202
|
+
name: string;
|
|
203
|
+
role: string;
|
|
204
|
+
userId: string;
|
|
205
|
+
version: string; // opaque ETag
|
|
206
|
+
};
|
|
207
|
+
type WorkspaceDirectoryCandidate = {
|
|
208
|
+
eligible: boolean;
|
|
209
|
+
ineligibleReason: string | null;
|
|
210
|
+
issuer: string;
|
|
211
|
+
name: string;
|
|
212
|
+
subject: string;
|
|
213
|
+
userId: string | null;
|
|
214
|
+
};
|
|
215
|
+
type WorkspaceRole = {
|
|
216
|
+
name: string;
|
|
217
|
+
statements: Record<string, string[]>;
|
|
218
|
+
version: string; // opaque ETag
|
|
219
|
+
};
|
|
220
|
+
type ProjectSummary = {
|
|
221
|
+
effectiveCapabilities: {
|
|
222
|
+
canAdministerGitHubConnection: boolean;
|
|
223
|
+
canAdministerProject: boolean;
|
|
224
|
+
canEditProject: boolean;
|
|
225
|
+
canReadProject: boolean;
|
|
226
|
+
};
|
|
227
|
+
specLanguage: string;
|
|
228
|
+
id: string;
|
|
229
|
+
name: string;
|
|
230
|
+
role: string;
|
|
231
|
+
status: "Active" | "Archived" | "Trashed";
|
|
232
|
+
version: string; // opaque ETag
|
|
233
|
+
workspaceId: string;
|
|
234
|
+
workspaceName: string;
|
|
235
|
+
};
|
|
236
|
+
type ProjectContext = {
|
|
237
|
+
specLanguage: string;
|
|
238
|
+
id: string;
|
|
239
|
+
name: string;
|
|
240
|
+
status: "Active" | "Archived";
|
|
241
|
+
version: string; // opaque ETag
|
|
242
|
+
};
|
|
243
|
+
type GlossaryEntry = {
|
|
244
|
+
canonicalTerm: string;
|
|
245
|
+
definition: string;
|
|
246
|
+
id: string;
|
|
247
|
+
usageNote: string | null;
|
|
248
|
+
};
|
|
249
|
+
type PublishedGlossary = {
|
|
250
|
+
entries: GlossaryEntry[];
|
|
251
|
+
id: string;
|
|
252
|
+
publishedAt: string; // ISO 8601 date-time
|
|
253
|
+
};
|
|
254
|
+
type Capability = {
|
|
255
|
+
id: string;
|
|
256
|
+
name: string;
|
|
257
|
+
parentId: string | null;
|
|
258
|
+
version: string; // opaque ETag, for example: "\"1\""
|
|
259
|
+
};
|
|
260
|
+
type Permissions = { canEdit: boolean };
|
|
261
|
+
type FindingPermissions = { canWrite: boolean };
|
|
262
|
+
type SourceReference = {
|
|
263
|
+
externalRevision?: string;
|
|
264
|
+
id: string;
|
|
265
|
+
section?: string;
|
|
266
|
+
title: string;
|
|
267
|
+
url: string;
|
|
268
|
+
};
|
|
269
|
+
type SpecSummary = {
|
|
270
|
+
capabilityId: string;
|
|
271
|
+
featureName: string;
|
|
272
|
+
id: string;
|
|
273
|
+
sourceReferences: SourceReference[];
|
|
274
|
+
state: "Draft" | "Ready" | "Unavailable";
|
|
275
|
+
unavailabilityReason: string | null;
|
|
276
|
+
version: string; // opaque ETag
|
|
277
|
+
};
|
|
278
|
+
type SpecDetails = SpecSummary & {
|
|
279
|
+
draftSession: {
|
|
280
|
+
documentName: string;
|
|
281
|
+
id: string;
|
|
282
|
+
rootName: "spec-outline";
|
|
283
|
+
} | null;
|
|
284
|
+
};
|
|
285
|
+
type SpecRevision = {
|
|
286
|
+
content: string;
|
|
287
|
+
id: string;
|
|
288
|
+
publishedAt: string; // ISO 8601 date-time
|
|
289
|
+
};
|
|
290
|
+
type CapabilityPathEntry = { id: string; name: string };
|
|
291
|
+
type SearchResult = {
|
|
292
|
+
capabilityPath: CapabilityPathEntry[];
|
|
293
|
+
spec: SpecSummary;
|
|
294
|
+
};
|
|
295
|
+
type SourceReferenceInput = Omit<SourceReference, "id">;
|
|
296
|
+
type SpecChangelogEntry = {
|
|
297
|
+
acceptedAt: string; // ISO 8601 date-time
|
|
298
|
+
action:
|
|
299
|
+
| "Published"
|
|
300
|
+
| "RolledBack"
|
|
301
|
+
| "StateChanged"
|
|
302
|
+
| "MetadataChanged"
|
|
303
|
+
| "FindingCreated"
|
|
304
|
+
| "FindingConfirmed"
|
|
305
|
+
| "FindingDismissed"
|
|
306
|
+
| "FindingResolved"
|
|
307
|
+
| "FindingStale";
|
|
308
|
+
actorSessionId: string;
|
|
309
|
+
actorUserId: string;
|
|
310
|
+
changes: {
|
|
311
|
+
content: { from: string | null; to: string } | null;
|
|
312
|
+
finding: {
|
|
313
|
+
findingId: string;
|
|
314
|
+
status: "Confirmed" | "Dismissed" | "Proposed" | "Resolved" | "Stale";
|
|
315
|
+
} | null;
|
|
316
|
+
metadata: {
|
|
317
|
+
capabilityId?: { from: string; to: string };
|
|
318
|
+
sourceReferences?: {
|
|
319
|
+
from: SourceReferenceInput[];
|
|
320
|
+
to: SourceReferenceInput[];
|
|
321
|
+
};
|
|
322
|
+
} | null;
|
|
323
|
+
state: {
|
|
324
|
+
from: "Draft" | "Ready" | "Unavailable";
|
|
325
|
+
fromUnavailabilityReason: string | null;
|
|
326
|
+
to: "Draft" | "Ready" | "Unavailable";
|
|
327
|
+
toUnavailabilityReason: string | null;
|
|
328
|
+
} | null;
|
|
329
|
+
};
|
|
330
|
+
id: string;
|
|
331
|
+
previousRevisionId: string | null;
|
|
332
|
+
revisionId: string | null;
|
|
333
|
+
};
|
|
334
|
+
type GlossaryRevision = {
|
|
335
|
+
entries: GlossaryEntry[];
|
|
336
|
+
id: string;
|
|
337
|
+
publishedAt: string; // ISO 8601 date-time
|
|
338
|
+
};
|
|
339
|
+
type GlossaryDraftSession = {
|
|
340
|
+
documentName: string;
|
|
341
|
+
entriesName: "entries";
|
|
342
|
+
id: string;
|
|
343
|
+
};
|
|
344
|
+
type GlossaryDetails = {
|
|
345
|
+
currentRevision: GlossaryRevision | null;
|
|
346
|
+
draftSession: GlossaryDraftSession;
|
|
347
|
+
};
|
|
348
|
+
type GlossaryChangelogEntry = {
|
|
349
|
+
acceptedAt: string; // ISO 8601 date-time
|
|
350
|
+
action: "Published" | "RolledBack";
|
|
351
|
+
actorSessionId: string;
|
|
352
|
+
actorUserId: string;
|
|
353
|
+
changes: {
|
|
354
|
+
added: GlossaryEntry[];
|
|
355
|
+
removed: GlossaryEntry[];
|
|
356
|
+
updated: { from: GlossaryEntry; to: GlossaryEntry }[];
|
|
357
|
+
};
|
|
358
|
+
id: string;
|
|
359
|
+
previousRevisionId: string | null;
|
|
360
|
+
revisionId: string;
|
|
361
|
+
};
|
|
362
|
+
type ProjectReadToken = {
|
|
363
|
+
createdAt: string; // ISO 8601 date-time
|
|
364
|
+
expiresAt: string | null; // ISO 8601 date-time
|
|
365
|
+
id: string;
|
|
366
|
+
issuer: { id: string; name: string };
|
|
367
|
+
lastUsedAt: string | null; // ISO 8601 date-time
|
|
368
|
+
name: string;
|
|
369
|
+
revokedAt: string | null; // ISO 8601 date-time
|
|
370
|
+
};
|
|
371
|
+
type FindingType =
|
|
372
|
+
| "Contradiction"
|
|
373
|
+
| "Conflict"
|
|
374
|
+
| "Duplicate"
|
|
375
|
+
| "Ambiguity"
|
|
376
|
+
| "Terminology"
|
|
377
|
+
| "Unverifiable";
|
|
378
|
+
type ManualReviewRecord = {
|
|
379
|
+
agentRevision: string;
|
|
380
|
+
completedAt: string | null; // ISO 8601 date-time
|
|
381
|
+
createdAt: string; // ISO 8601 date-time
|
|
382
|
+
draft: { contentHash: string; draftSessionId: string; specId: string };
|
|
383
|
+
enabledFindingTypes: FindingType[];
|
|
384
|
+
failureCategory:
|
|
385
|
+
| "InvalidOutput"
|
|
386
|
+
| "ProjectInactive"
|
|
387
|
+
| "TerminalExecutionFailure"
|
|
388
|
+
| "Timeout"
|
|
389
|
+
| null;
|
|
390
|
+
findingIds: string[];
|
|
391
|
+
glossaryRevisionId: string | null;
|
|
392
|
+
id: string;
|
|
393
|
+
knownFindingIds: string[];
|
|
394
|
+
mastraExecutionVersion: string;
|
|
395
|
+
model: string | null;
|
|
396
|
+
projectId: string;
|
|
397
|
+
requestedBy: { sessionId: string; userId: string };
|
|
398
|
+
reviewContractVersion: string;
|
|
399
|
+
startedAt: string | null; // ISO 8601 date-time
|
|
400
|
+
status:
|
|
401
|
+
| "Queued"
|
|
402
|
+
| "Running"
|
|
403
|
+
| "ProposedFindings"
|
|
404
|
+
| "Superseded"
|
|
405
|
+
| "Cancelled"
|
|
406
|
+
| "Failed";
|
|
407
|
+
trigger: "ManualDraft";
|
|
408
|
+
updatedAt: string; // ISO 8601 date-time
|
|
409
|
+
};
|
|
410
|
+
type FindingReference = {
|
|
411
|
+
kind: "Feature" | "Rule" | "Background" | "Scenario" | "Examples" | "Step";
|
|
412
|
+
text: string;
|
|
413
|
+
};
|
|
414
|
+
type FindingTarget = {
|
|
415
|
+
binding:
|
|
416
|
+
| { kind: "Revision"; revisionId: string }
|
|
417
|
+
| {
|
|
418
|
+
contentHash: string;
|
|
419
|
+
draftSessionId: string;
|
|
420
|
+
kind: "WorkingDraftSnapshot";
|
|
421
|
+
};
|
|
422
|
+
references: FindingReference[];
|
|
423
|
+
specId: string;
|
|
424
|
+
};
|
|
425
|
+
type FindingEvidence =
|
|
426
|
+
| { incompatibleClaims: [string, string]; kind: "Contradiction" }
|
|
427
|
+
| { incompatibleRequirements: [string, string]; kind: "Conflict" }
|
|
428
|
+
| { duplicatedBehavior: string; kind: "Duplicate" }
|
|
429
|
+
| {
|
|
430
|
+
interpretations: [
|
|
431
|
+
{ behavior: string; meaning: string },
|
|
432
|
+
{ behavior: string; meaning: string },
|
|
433
|
+
];
|
|
434
|
+
kind: "Ambiguity";
|
|
435
|
+
}
|
|
436
|
+
| {
|
|
437
|
+
glossaryEntryIds: string[];
|
|
438
|
+
issue: "MissingDefinition" | "GlossaryConflict" | "MultipleMeanings";
|
|
439
|
+
kind: "Terminology";
|
|
440
|
+
term: string;
|
|
441
|
+
}
|
|
442
|
+
| { kind: "Unverifiable"; missingCriterion: string };
|
|
443
|
+
type ReviewFinding = {
|
|
444
|
+
affectedScenarios: string[];
|
|
445
|
+
author: { sessionId: string; userId: string };
|
|
446
|
+
conclusion: string;
|
|
447
|
+
createdAt: string; // ISO 8601 date-time
|
|
448
|
+
evidence: FindingEvidence;
|
|
449
|
+
explanation: string;
|
|
450
|
+
glossaryReferences: {
|
|
451
|
+
entry: GlossaryEntry;
|
|
452
|
+
entryId: string;
|
|
453
|
+
revisionId: string;
|
|
454
|
+
}[];
|
|
455
|
+
id: string;
|
|
456
|
+
projectId: string;
|
|
457
|
+
reviewRecordId: string | null;
|
|
458
|
+
status: "Proposed" | "Confirmed" | "Dismissed" | "Resolved" | "Stale";
|
|
459
|
+
targets: FindingTarget[];
|
|
460
|
+
type: FindingType;
|
|
461
|
+
updatedAt: string; // ISO 8601 date-time
|
|
462
|
+
version: string; // opaque ETag
|
|
463
|
+
};
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
A failed resource command writes nothing to stdout. After any diagnostic lines, the
|
|
467
|
+
final stderr line is exactly `{ "error": { "message": string, "reason":
|
|
468
|
+
SkillErrorReason, "retryAfter"?: string, "retryable": boolean,
|
|
469
|
+
"diagnostics"?: SkillErrorDiagnostic[] } }` where
|
|
470
|
+
`type SkillErrorDiagnostic = { column?: number; line?: number; message: string;
|
|
471
|
+
reason: string }`. `diagnostics` is present whenever the server reports
|
|
472
|
+
positioned source problems: Spec Publish and Rollback rejections from the Spec Content
|
|
473
|
+
Publish Gate carry one entry per `feature-count`, `language-mismatch`,
|
|
474
|
+
`parse-error`, `scenario-required`, or `scenario-id-*` reason,
|
|
475
|
+
`spec assign-scenario-ids` carries the same shape when the Working Draft source is
|
|
476
|
+
invalid, and other Invalid Operation rejections may carry it too. `SkillErrorReason` is `Authentication Failed`,
|
|
477
|
+
`Project Not Accessible`, `Permission Denied`, `Resource Not Found`,
|
|
478
|
+
`Resource Changed`, `Invalid Operation`, or `Temporary Failure`. Exit status `2`
|
|
479
|
+
covers authentication, validation, inaccessible/not-found resources, conflicts, and
|
|
480
|
+
invalid operations; `3` is permission denial; `4` is a `Temporary Failure`, whose
|
|
481
|
+
`retryable` field determines whether automatic retry is safe. Exit status `0` is
|
|
482
|
+
success. Exit status `1` is reserved for startup/runtime failure before a
|
|
483
|
+
resource-command contract can run.
|
|
484
|
+
|
|
485
|
+
HTTP `429` is a retryable `Temporary Failure`. When the server supplies
|
|
486
|
+
`Retry-After`, the CLI copies its exact value to `retryAfter` and does not retry the
|
|
487
|
+
request automatically. Generated `--help` is a separate controlled success path:
|
|
488
|
+
top-level help includes authentication and every resource group, nested help includes
|
|
489
|
+
the selected group's operations and options, and all help writes to stdout, exits
|
|
490
|
+
zero, and does not resolve credentials or call the service.
|
|
491
|
+
|
|
492
|
+
`ProjectSummary.effectiveCapabilities` incorporates lifecycle status. Archived
|
|
493
|
+
Projects always report `canEditProject: false`, including for Admins and Editors; an
|
|
494
|
+
Archived Admin still reports `canAdministerProject: true` for Restore and access
|
|
495
|
+
reduction. A Trashed Project reports `canReadProject: false` even for its Admin:
|
|
496
|
+
it appears only in the explicit `--status Trashed` list, and every read or write
|
|
497
|
+
path rejects it; its only accepted mutation is `project restore`, which lands it
|
|
498
|
+
on Archived, so reaching Active again takes a second explicit restore.
|
|
499
|
+
|
|
500
|
+
Workspace membership is the only source of Project access. `ProjectSummary.role`
|
|
501
|
+
is the caller's Role in the owning Workspace, and `workspace create` grants the
|
|
502
|
+
creator the `Owner` Workspace Role. `project create` requires the owning
|
|
503
|
+
Workspace's ID and at least the `Editor` Role inside it.
|
|
504
|
+
|
|
505
|
+
`workspace member` and `workspace role` administer that source. `member search`
|
|
506
|
+
queries the bound identity directory and reports each candidate's eligibility;
|
|
507
|
+
`member add` provisions the selected User — including before first login — and
|
|
508
|
+
`member set-role`/`member remove` require the Membership's opaque `version` as
|
|
509
|
+
`--expected-version`. `role` commands manage the Workspace's statement sets:
|
|
510
|
+
`--statements` takes a JSON object mapping resources to action arrays, a Role
|
|
511
|
+
never grants statements the caller does not hold, `Owner` is immutable, and a
|
|
512
|
+
Role still assigned to a member cannot be deleted. Role updates and deletes
|
|
513
|
+
require the Role's `version` as `--expected-version`.
|
|
514
|
+
|
|
515
|
+
`project list` stays stateless: pass `--workspace-id <workspace-id>` — from
|
|
516
|
+
`workspace list` or `project create` output — to select one Workspace and list
|
|
517
|
+
only its Projects, combinable with `--status`. The CLI keeps no implicit
|
|
518
|
+
current Workspace. An unknown or inaccessible Workspace returns an empty list
|
|
519
|
+
rather than revealing that it exists, and a CLI Session approved for a Project
|
|
520
|
+
subset only ever returns Projects inside that scope, even when the filter names
|
|
521
|
+
a Workspace that contains no scoped Project.
|
|
522
|
+
|
|
523
|
+
Every non-idempotent create, Draft-session, Publish, Rollback,
|
|
524
|
+
token issuance, Finding disposition, Manual Review request, and Project lifecycle
|
|
525
|
+
command performs at most one fetch-transport retry. It clones the request and reuses
|
|
526
|
+
the same `Idempotency-Key`; an HTTP response, including a response whose body cannot
|
|
527
|
+
be decoded, is never dispatched again. Archive, Restore, and Trash require the opaque
|
|
528
|
+
Project
|
|
529
|
+
version returned by discovery or context. If neither transport attempt yields a usable
|
|
530
|
+
response, the final `Temporary Failure` has `retryable: false` and directs the caller
|
|
531
|
+
to inspect the resource or Changelog before deciding whether another logical mutation
|
|
532
|
+
is appropriate.
|
|
533
|
+
|
|
534
|
+
Token issuance returns the plaintext credential only for the first committed
|
|
535
|
+
response. If a same-key retry confirms the token with `credential: null`, the CLI
|
|
536
|
+
exits nonzero, prints no success payload, and directs the caller to list or revoke the
|
|
537
|
+
token before deliberately issuing another.
|
|
538
|
+
|
|
539
|
+
Source Reference URLs accept only HTTP or HTTPS and must not contain URL userinfo
|
|
540
|
+
(`username` or `password`). Keep external credentials in the Agent's own authorized
|
|
541
|
+
source-reading tool; never embed them in SpecFlow metadata.
|
|
542
|
+
|
|
543
|
+
The repository-owned official Skill is `skills/specflow/SKILL.md`. It pins this exact
|
|
544
|
+
CLI release, requires explicit User confirmation immediately before Spec or Glossary
|
|
545
|
+
Publish and Rollback, and does not send proof of that confirmation to the CLI or API.
|
|
546
|
+
|
|
547
|
+
The CLI stores its Session credential in macOS Keychain, Windows Credential
|
|
548
|
+
Manager, or Linux Secret Service. It does not print or persist the credential in
|
|
549
|
+
environment variables. If the system store is unavailable on a POSIX platform,
|
|
550
|
+
local-file storage is used only after `--allow-file-fallback` is explicitly
|
|
551
|
+
selected; the CLI warns and enforces directory mode `0700` and file mode `0600`.
|
|
552
|
+
|
|
553
|
+
## Work Item creation labels
|
|
554
|
+
|
|
555
|
+
`specflow work-item create --project-id PAY --title "Retry alert" --label <definitionId>`
|
|
556
|
+
sets existing Workspace labels in the same transaction as creation. Repeat `--label`
|
|
557
|
+
for multiple labels; duplicate IDs are ignored. The response includes
|
|
558
|
+
`workItem.labels`. Missing, foreign-Workspace, copy, or deleting labels reject the
|
|
559
|
+
entire creation with `INVALID_WORK_ITEM_LABEL`.
|
|
560
|
+
|
|
561
|
+
## Work Item JSON exchange
|
|
562
|
+
|
|
563
|
+
```bash
|
|
564
|
+
specflow work-item export --project-id PAY --status done > tasks.json
|
|
565
|
+
specflow work-item import --project-id OPS --file tasks.json --idempotency-key release-tasks-1
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
Export supports the same selection flags as `work-item list` and returns a JSON
|
|
569
|
+
`{ project: { name, slug, description, exportedAt }, tasks: [...] }` document on
|
|
570
|
+
stdout. Each task contains `title`, `description`, `status`, `priority`,
|
|
571
|
+
`startDate`, `dueDate`, `userId`, and `labels: [{ name, color }]`. Dates are ISO
|
|
572
|
+
strings or null. Only readable tasks from the explicit Project are included.
|
|
573
|
+
An export over 1000 tasks or 1 MiB fails; narrow the selection instead of expecting
|
|
574
|
+
a truncated document.
|
|
575
|
+
|
|
576
|
+
Import accepts a JSON file with a `tasks` array, at most 1000 tasks and 1 MiB.
|
|
577
|
+
File Project metadata is descriptive; `--project-id` always selects the target.
|
|
578
|
+
The server applies ordinary creation and assignment authorization, membership,
|
|
579
|
+
workflow, default Custom Field, and identity rules. Unknown statuses become
|
|
580
|
+
`planned`; unknown priorities become `no-priority`; absent or empty priority
|
|
581
|
+
becomes `low`. Labels are exported but not imported, matching pinned Kaneo;
|
|
582
|
+
nonempty imported labels produce an explicit warning.
|
|
583
|
+
|
|
584
|
+
Import stdout contains `importedAt`, target `project`, and `results` with
|
|
585
|
+
`total`, `successful`, `failed`, and indexed `tasks`. Each row has `success` and
|
|
586
|
+
`warnings`; successful rows include `workItemId` and opaque `version`, while
|
|
587
|
+
failed rows include an error code. If any row fails, the CLI retains this complete
|
|
588
|
+
receipt on stdout, emits a nonretryable `Invalid Operation` on stderr, and exits
|
|
589
|
+
`2`. Correct and import only failed rows with a new key. Successful rows and
|
|
590
|
+
business refusals commit together; an unexpected database error rolls back the
|
|
591
|
+
whole batch.
|
|
592
|
+
|
|
593
|
+
Retry the same file with the same `--idempotency-key` after an interrupted request.
|
|
594
|
+
Within the existing 24-hour replay window it returns the original receipt without
|
|
595
|
+
duplicating tasks. A changed task payload with that key conflicts. Read Tokens may
|
|
596
|
+
export their single Project; they cannot import. No CSV or legacy migration format
|
|
597
|
+
is provided.
|
|
598
|
+
|
|
599
|
+
### Task relations
|
|
600
|
+
|
|
601
|
+
Relations link two tasks in the same Workspace, including across Projects.
|
|
602
|
+
`subtask` means source parent → target child; `blocks` means source blocker →
|
|
603
|
+
blocked target; `related` is symmetric. Reading either endpoint returns both task
|
|
604
|
+
identities and their current Projects. Self-links and duplicate pairs of the same
|
|
605
|
+
relation type in either direction are rejected; longer cycles are allowed, as in
|
|
606
|
+
the pinned Kaneo contract. These links are separate from Spec/document links.
|
|
607
|
+
|
|
608
|
+
```bash
|
|
609
|
+
specflow work-item relation list --project-id PAY --work-item-id PAY-7
|
|
610
|
+
specflow work-item relation create --project-id PAY --work-item-id PAY-7 \
|
|
611
|
+
--target-project-id OPS --target-work-item-id OPS-2 --type blocks \
|
|
612
|
+
--idempotency-key relation-command-1
|
|
613
|
+
specflow work-item relation delete --project-id OPS --work-item-id OPS-2 \
|
|
614
|
+
--peer-project-id PAY --relation-id <relation-id> --expected-version '"1"' \
|
|
615
|
+
--idempotency-key remove-relation-command-1
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
Keep the same command key and inputs after an interrupted response. Receipts
|
|
619
|
+
contain only the relation identifier; a create replay returns `relation: null`
|
|
620
|
+
when the relation has been deleted or its current endpoints are outside the
|
|
621
|
+
original authority. It never restores a deleted link. After a task transfer,
|
|
622
|
+
reread to obtain the endpoint's new task identity and Project before removing its
|
|
623
|
+
relation. Both endpoints require current task update permission for writes;
|
|
624
|
+
Archived endpoints are read-only. Lists omit inaccessible peers and their counts.
|
|
625
|
+
Project Read Tokens can read only relations wholly inside their single Project
|
|
626
|
+
and cannot create or delete relations.
|
|
627
|
+
|
|
628
|
+
### Task comments and activity
|
|
629
|
+
|
|
630
|
+
Read comments oldest first, or read the mixed discussion/activity feed newest
|
|
631
|
+
first. Both commands return an opaque `nextCursor`; pass it back with `--cursor`.
|
|
632
|
+
Pages accept `--limit` from 1 through 100.
|
|
633
|
+
|
|
634
|
+
```bash
|
|
635
|
+
specflow work-item comment list --project-id PAY --work-item-id PAY-7 --limit 20
|
|
636
|
+
specflow work-item discussion --project-id PAY --work-item-id PAY-7 --limit 20
|
|
637
|
+
specflow work-item comment create --project-id PAY --work-item-id PAY-7 \
|
|
638
|
+
--content '**Review** the rollout' --idempotency-key <uuid>
|
|
639
|
+
specflow work-item comment update --project-id PAY --work-item-id PAY-7 \
|
|
640
|
+
--comment-id <comment-uuid> --content 'Updated review' \
|
|
641
|
+
--expected-version '"1"' --idempotency-key <uuid>
|
|
642
|
+
specflow work-item comment delete --project-id PAY --work-item-id PAY-7 \
|
|
643
|
+
--comment-id <comment-uuid> --expected-version '"2"' --idempotency-key <uuid>
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
Comment mutations require a CLI Session, current task update permission, and a
|
|
647
|
+
UUID command key. Only the comment's author may edit or delete it, including
|
|
648
|
+
when another Member is an Admin. Reuse the same command key and inputs after a
|
|
649
|
+
lost response; receipts retain only the comment identifier and resolve its
|
|
650
|
+
current content. A replay after deletion returns `comment: null`.
|
|
651
|
+
|
|
652
|
+
Take the opaque comment `version` from the read result. An edit or deletion
|
|
653
|
+
against an older version reports `Resource Changed`; reread before deciding
|
|
654
|
+
whether to resubmit. Project Read Tokens may read comments and activity under
|
|
655
|
+
`WorkItemRead`, and cannot mutate comments. Activities are produced by the
|
|
656
|
+
server's actual task operations; there is no activity creation command.
|
|
657
|
+
|
|
658
|
+
### Task time recording
|
|
659
|
+
|
|
660
|
+
List entries oldest first with an opaque `nextCursor`, or retrieve one entry:
|
|
661
|
+
|
|
662
|
+
```bash
|
|
663
|
+
specflow work-item time-entry list --project-id PAY --work-item-id PAY-7 --limit 20
|
|
664
|
+
specflow work-item time-entry get --project-id PAY --work-item-id PAY-7 --entry-id <uuid>
|
|
665
|
+
specflow work-item time-entry create --project-id PAY --work-item-id PAY-7 \
|
|
666
|
+
--start-time '2026-07-01T10:00:00+08:00' --end-time '2026-07-01T11:00:00+08:00' \
|
|
667
|
+
--description 'Reviewed rollout' --idempotency-key <uuid>
|
|
668
|
+
specflow work-item time-entry update --project-id PAY --work-item-id PAY-7 \
|
|
669
|
+
--entry-id <uuid> --start-time '2026-07-01T10:00:00+08:00' \
|
|
670
|
+
--end-time '2026-07-01T11:30:00+08:00' --expected-version '"1"' --idempotency-key <uuid>
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
Timestamps require an ISO 8601 offset. Omit `--end-time` on creation to record an
|
|
674
|
+
unfinished entry; on update, omission preserves the existing end time. Omitted
|
|
675
|
+
descriptions are preserved on update. The server computes whole duration seconds;
|
|
676
|
+
unfinished entries have no duration and are excluded from `closedDurationSeconds`.
|
|
677
|
+
The list returns that exact cumulative value as a decimal string plus `runningCount`.
|
|
678
|
+
|
|
679
|
+
Writes require a CLI Session, current task update permission and a UUID command
|
|
680
|
+
key. Only the author may update an entry, including when another Member is an
|
|
681
|
+
Admin. Reuse the same key and inputs after an interrupted response. Updates require
|
|
682
|
+
the read result's opaque `version`; a conflict requires a deliberate reread.
|
|
683
|
+
Project Read Tokens can list and retrieve entries but cannot write. Archived
|
|
684
|
+
Projects are read-only. There is no time-entry deletion command.
|
|
685
|
+
|
|
686
|
+
### Personal notifications
|
|
687
|
+
|
|
688
|
+
Use the existing User Session; a Project Read Token cannot access this inbox.
|
|
689
|
+
|
|
690
|
+
```bash
|
|
691
|
+
specflow notification list
|
|
692
|
+
specflow notification read --notification-id <uuid> --idempotency-key <uuid>
|
|
693
|
+
specflow notification read-all --idempotency-key <uuid>
|
|
694
|
+
specflow notification clear --idempotency-key <uuid>
|
|
695
|
+
specflow notification preferences get
|
|
696
|
+
specflow notification preferences update --expected-version <version> --preferences '{"taskCommentEnabled":false}' --idempotency-key <uuid>
|
|
697
|
+
specflow notification create --type info --title "Review ready" --message "Evidence attached" --idempotency-key <uuid>
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
Task or Workspace creation targets use paired `--related-entity-id` and
|
|
701
|
+
`--related-entity-type task|workspace` options; Task identifiers are current public
|
|
702
|
+
IDs such as `PAY-7`. Optional `--event-data` accepts a bounded JSON object. Manual
|
|
703
|
+
creation is for the current User only and returns a null notification when the
|
|
704
|
+
category is muted or the target is inaccessible.
|
|
705
|
+
|
|
706
|
+
The feed returns the latest 50 currently accessible entries and their unread
|
|
707
|
+
count. A read command returns the fresh target after a transfer. Reuse identical
|
|
708
|
+
inputs and the same UUID key after an ambiguous write outcome, particularly for
|
|
709
|
+
read-all and clear, so a retry cannot alter later arrivals. A CLI Session restricted
|
|
710
|
+
to Projects can read only admitted targets; read-all, clear, and preferences require
|
|
711
|
+
an unrestricted Session. Preference reads return an opaque version; saves require `--expected-version`. A
|
|
712
|
+
stale save returns Resource Changed and requires a deliberate reread and reapply.
|
|
713
|
+
Preferences accept partial assignment/comment/status/due
|
|
714
|
+
booleans and `dueDateReminderMinutes` from 5 to 43200. No command schedules reminders
|
|
715
|
+
or configures external delivery channels.
|
|
716
|
+
|
|
717
|
+
### Public task sharing
|
|
718
|
+
|
|
719
|
+
```bash
|
|
720
|
+
specflow project sharing read --project-id PAY
|
|
721
|
+
specflow project sharing set --project-id PAY --public true \
|
|
722
|
+
--expected-version '"1"' --idempotency-key <uuid>
|
|
723
|
+
specflow project sharing set --project-id PAY --public false \
|
|
724
|
+
--expected-version '"2"' --idempotency-key <uuid>
|
|
725
|
+
```
|
|
726
|
+
|
|
727
|
+
Use the sharing read's opaque version, which is independent of the Project's
|
|
728
|
+
lifecycle version. Changes require a CLI Session with current `project:share`
|
|
729
|
+
permission on an Active Project. Reuse the same UUID key, boolean and expected
|
|
730
|
+
version after a lost response; a replay returns its original command result without
|
|
731
|
+
changing current sharing. Read the settings again to obtain the current state. A stale fresh command requires a
|
|
732
|
+
reread and an explicit decision. Project Read Tokens cannot manage sharing.
|
|
733
|
+
|
|
734
|
+
Public sharing exposes only Task/workflow fields and finalized assets currently
|
|
735
|
+
referenced by Task descriptions. It creates no Workspace membership and grants
|
|
736
|
+
no Spec, Glossary, resource association, comment or private attachment access.
|
|
737
|
+
Archive and Trash close sharing; Restore does not reopen it. The anonymous Web
|
|
738
|
+
entry is `/public/projects/<PROJECT>`.
|
|
739
|
+
|
|
740
|
+
## User API Keys in the current checkout
|
|
741
|
+
|
|
742
|
+
Use an authenticated CLI Session to manage the current User’s explicitly scoped
|
|
743
|
+
keys. Creating a key saves its one-time secret directly to the origin-scoped system
|
|
744
|
+
credential store; stdout contains metadata and `credentialStored`, never the secret.
|
|
745
|
+
The warned owner-only file fallback remains opt-in with `--allow-file-fallback`.
|
|
746
|
+
These commands describe the repository implementation; a published npm release
|
|
747
|
+
must be verified separately.
|
|
748
|
+
|
|
749
|
+
```bash
|
|
750
|
+
specflow --server https://specflow.example api-key create --name "Task automation" --project-ids PAY --scopes '{"workItem":["read","create"]}' --expires-at never --idempotency-key <uuid>
|
|
751
|
+
specflow --server https://specflow.example api-key list --limit 50
|
|
752
|
+
specflow --server https://specflow.example api-key list --cursor <nextCursor>
|
|
753
|
+
specflow --server https://specflow.example --api-key-id <key-id> work-item list --project-id PAY
|
|
754
|
+
specflow --server https://specflow.example api-key revoke --key-id <key-id> --expected-version '"1"' --idempotency-key <uuid>
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
An expiry can instead be an explicit UTC ISO timestamp. Creation requires explicit
|
|
758
|
+
Project IDs and resource-to-actions scope statements. Spec/Glossary `publish` is a
|
|
759
|
+
separate grant; unknown or ungranted scopes fail closed. Every business request
|
|
760
|
+
checks current User eligibility, membership, Role, explicit key scope and lifecycle.
|
|
761
|
+
Global account/Workspace and credential-management routes require a User Session.
|
|
762
|
+
|
|
763
|
+
Keep the same creation command ID and intent when recovering an uncertain response.
|
|
764
|
+
A replay cannot redisclose a lost secret; revoke that key before deliberately issuing
|
|
765
|
+
a replacement. Saving failure triggers a versioned compensating revoke; an uncertain
|
|
766
|
+
revoke reports the key ID for operator reconciliation. Revocation removes only the
|
|
767
|
+
selected local key slot after the server confirms success. Session credentials stay
|
|
768
|
+
independent.
|
|
769
|
+
|
|
770
|
+
`SPEC_FLOW_API_KEY` accepts an explicitly provided key for CI. Do not place raw
|
|
771
|
+
secrets in command arguments or use multiple credential selectors. An absent selected
|
|
772
|
+
key never falls back to the Session. API Keys and Project Read Tokens cannot manage
|
|
773
|
+
credentials.
|
|
774
|
+
|
|
775
|
+
## Explicit GitHub import in the current checkout
|
|
776
|
+
|
|
777
|
+
```bash
|
|
778
|
+
specflow github connection status --project-id PAY
|
|
779
|
+
specflow github import status --project-id PAY
|
|
780
|
+
specflow github import run --project-id PAY --expected-version '"1"' --idempotency-key <uuid>
|
|
781
|
+
specflow github import run --project-id PAY --expected-version '"1"' --idempotency-key <new-uuid> --run-id <saved-run-id>
|
|
782
|
+
```
|
|
783
|
+
|
|
784
|
+
Use the connected repository's observed version. Starting and reading import progress
|
|
785
|
+
require a real User Session with current GitHub connection management permission on
|
|
786
|
+
an Active Project. Each page separately checks the connection's current delegated
|
|
787
|
+
API Key and the Task/label operations it needs. Passing `--api-key-id` cannot grant
|
|
788
|
+
connection management.
|
|
789
|
+
|
|
790
|
+
The command processes bounded batches until completion, retrying rate limits up to
|
|
791
|
+
five times with the same command identity. Stdout contains the final run identity and
|
|
792
|
+
new/updated/skipped counts. A failed batch leaves committed progress intact; retry a
|
|
793
|
+
lost initial response with the same UUID and identical options. Once a run ID is known,
|
|
794
|
+
resume it explicitly. A completed explicit run returns its saved counts; starting
|
|
795
|
+
without a run ID after completion begins a new import.
|
|
796
|
+
|
|
797
|
+
Import reads open Issues, copies ordinary labels and non-bot historical comments, and
|
|
798
|
+
associates matching Pull Requests. Historical comments remain read-only. Explicit
|
|
799
|
+
import refreshes existing linked Tasks without applying webhook workflow rules; PR
|
|
800
|
+
association does not move a Task. The Project settings Web surface offers the same
|
|
801
|
+
start/resume capability. Closing it stops future batches; an in-flight batch may still
|
|
802
|
+
commit before the pause takes effect.
|
|
803
|
+
|
|
804
|
+
Specs may be created without `--capability-id`. They appear in Unassigned and retain
|
|
805
|
+
the same editing and publication contract. To move a Spec to Unassigned, use
|
|
806
|
+
`specflow spec update --project-id <id> --spec-id <id> --capability-id none
|
|
807
|
+
--expected-version <version>`. Capability deletion rejects child Capabilities;
|
|
808
|
+
deleting a leaf moves its Specs to Unassigned and records their placement changes.
|