@caiqueoak/flow 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -5
- package/package.json +1 -1
- package/skills/flow/SKILL.md +25 -9
- package/skills/flow/references/build.md +3 -1
- package/skills/flow/references/discovery.md +3 -1
- package/skills/flow/references/planning.md +3 -1
- package/skills/flow/references/reconcile.md +3 -1
- package/skills/flow/references/review.md +3 -1
- package/src/cli.mjs +119 -15
- package/skills/flow/references/artifact-guidance.md +0 -5
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ npx flow init
|
|
|
11
11
|
|
|
12
12
|
`flow init` is interactive, or use `--runtime codex,claude` in automation. Built-in adapters install the public `/flow` skill in `.codex/skills/flow/` or `.claude/skills/flow/`; a custom project-local skills directory is also available interactively.
|
|
13
13
|
|
|
14
|
-
Skills are always installed inside the current project. Runtime integration directories never contain project state. If `.flow/` already exists, `flow init` only adds coding-agent integrations and updates `.flow/config.yaml
|
|
14
|
+
Skills are always installed inside the current project. Runtime integration directories never contain project state. If `.flow/` already exists, `flow init` only adds missing coding-agent integrations and updates `.flow/config.yaml`. If all built-in integrations are already configured, it exits without prompting. It does not modify canonical project artifacts.
|
|
15
15
|
|
|
16
16
|
## Project bootstrap
|
|
17
17
|
|
|
@@ -22,7 +22,7 @@ Skills are always installed inside the current project. Runtime integration dire
|
|
|
22
22
|
└── config.yaml
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
It does not create a PRD, engineering guide, backlog, state, decisions, work items, gates, or templates.
|
|
25
|
+
It does not create a PRD, engineering guide, backlog, graph, state, decisions, work items, gates, or templates. During `/flow`, new project documents and artifacts are created only when the developer explicitly requests or authorizes them. Flow updates existing approved artifacts instead of inventing ad-hoc progress, summary, handoff, or status documents.
|
|
26
26
|
|
|
27
27
|
## Workflow
|
|
28
28
|
|
|
@@ -34,17 +34,31 @@ There is one public skill:
|
|
|
34
34
|
|
|
35
35
|
Use `/flow <intent>` to start or change work, for example `/flow I want to build a diet app`. Use `/flow` with no extra input to continue from `.flow/STATE.md`.
|
|
36
36
|
|
|
37
|
-
Flow internally loads only the guidance needed for discovery, planning, build, review, or reconciliation. It asks only for consequential decisions and uses the largest safe degree of parallelism.
|
|
37
|
+
Flow internally loads only the guidance needed for discovery, planning, build, review, or reconciliation. It asks only for consequential decisions and uses the largest safe degree of parallelism. Once execution is underway, it does not stop merely to announce completed tasks, progress, or next steps; it continues automatically until developer input, external approval, an unrecoverable blocker, or no ready work requires a real stop.
|
|
38
|
+
|
|
39
|
+
When authorized, Flow keeps a concise artifact model: product truth in `PRD.md`, engineering truth in `ENGINEERING.md`, decisions in `DECISIONS.md`, execution context in `STATE.md`, the canonical work-item DAG in `BACKLOG.yaml`, and a human-readable derived projection in `GRAPH.md`. Work items use `SPEC.md` plus `TASKS.yaml`. `SUMMARY.md` is not part of the model.
|
|
40
|
+
|
|
41
|
+
In `GRAPH.md`, work-item states are consistent: complete is green, in progress is blue, blocked is red when unfinished dependencies remain, and pending is yellow when all dependencies are complete and the item is ready to execute.
|
|
38
42
|
|
|
39
43
|
## Update
|
|
40
44
|
|
|
41
45
|
Updates are explicit:
|
|
42
46
|
|
|
43
47
|
```bash
|
|
44
|
-
|
|
48
|
+
flow update
|
|
45
49
|
```
|
|
46
50
|
|
|
47
|
-
`flow update` updates the
|
|
51
|
+
`flow update` detects how the active Flow CLI is installed. If the project contains `@caiqueoak/flow`, it updates that project dependency; if the CLI is globally installed, it updates the global package instead. It then refreshes `/flow` for every coding agent configured in `.flow/config.yaml` without modifying canonical project state.
|
|
52
|
+
|
|
53
|
+
On Windows, npm is invoked through the command shell so `npm.cmd` can be executed correctly. When Flow is installed as a project dependency, `npx flow update` is equivalent.
|
|
54
|
+
|
|
55
|
+
There is no background update check or automatic update mechanism.
|
|
56
|
+
|
|
57
|
+
## Releases
|
|
58
|
+
|
|
59
|
+
Merges to `main` are released automatically after the test matrix passes. The release pipeline uses npm Trusted Publishing (OIDC), creates a signed npm provenance record, and tags the release; no npm token or manual version bump is needed.
|
|
60
|
+
|
|
61
|
+
Use Conventional Commit prefixes in the PR title (and retained commits): `fix:` produces a patch, `feat:` a minor, and `feat!:` or a `BREAKING CHANGE:` footer a major release. `docs:`, `test:`, `chore:`, and `ci:` do not publish a package.
|
|
48
62
|
|
|
49
63
|
## CLI
|
|
50
64
|
|
package/package.json
CHANGED
package/skills/flow/SKILL.md
CHANGED
|
@@ -19,31 +19,35 @@ Do not require the developer to know or invoke internal workflow phases.
|
|
|
19
19
|
|
|
20
20
|
1. **Readability first.** Canonical artifacts must be understandable without Flow internals.
|
|
21
21
|
2. **Decision ownership.** The developer owns consequential product and engineering decisions; the agent executes within approved rules and obvious conventions.
|
|
22
|
-
3. **Autonomy by default.** Continue until a consequential decision, external approval, unrecoverable blocker, or no-ready-work condition.
|
|
22
|
+
3. **Autonomy by default.** Continue until a consequential decision requiring developer input, external approval, unrecoverable blocker, or no-ready-work condition.
|
|
23
23
|
4. **Just-in-time detail.** Resolve global decisions during discovery and work-item detail only when that item becomes active.
|
|
24
24
|
5. **Production-aware MVP.** MVP includes product capability plus the technical, infrastructure, quality, deployment, and operational work needed to run it.
|
|
25
25
|
6. **Parallelism first.** Execute the largest safe independent set while preserving correctness and token efficiency.
|
|
26
|
-
7. **Automatic synchronization.** Keep state, decisions, PRD, engineering definition, backlog, specs, and
|
|
26
|
+
7. **Automatic synchronization.** Keep state, decisions, PRD, engineering definition, backlog, graph, specs, and tasks aligned.
|
|
27
|
+
8. **Artifact restraint.** Never create a new project document or artifact unless the developer explicitly requests or authorizes it. Update existing approved artifacts instead whenever possible.
|
|
28
|
+
9. **Execution continuity.** Do not pause execution merely to report progress, completion, or next steps. Continue automatically while ready work exists. Surface status only when execution has actually stopped or when developer input is required.
|
|
27
29
|
|
|
28
30
|
## Canonical project artifacts
|
|
29
31
|
|
|
30
|
-
Create artifacts only when they become valid. `flow init` creates only `.flow/config.yaml`.
|
|
32
|
+
Create artifacts only when they become valid and only when the developer has explicitly requested or authorized their creation. `flow init` creates only `.flow/config.yaml`.
|
|
31
33
|
|
|
32
34
|
Developer-facing knowledge is Markdown:
|
|
33
35
|
|
|
34
36
|
- `.flow/PRD.md` - current global product truth and MVP boundary.
|
|
35
37
|
- `.flow/ENGINEERING.md` - global engineering truth.
|
|
36
|
-
- `.flow/SUMMARY.md` - concise project overview derived from canonical state.
|
|
37
38
|
- `.flow/DECISIONS.md` - consequential decision record and rationale.
|
|
38
|
-
- `.flow/STATE.md` - concise navigation
|
|
39
|
+
- `.flow/STATE.md` - concise current execution/navigation checkpoint and resume context.
|
|
40
|
+
- `.flow/GRAPH.md` - human-readable derived projection of the work-item dependency graph and current readiness state.
|
|
39
41
|
- `.flow/work-items/<folder>/SPEC.md` - readable lifecycle/specification of one work item.
|
|
40
42
|
|
|
41
43
|
Graph/control data is YAML:
|
|
42
44
|
|
|
43
|
-
- `.flow/BACKLOG.yaml` - work-item DAG.
|
|
45
|
+
- `.flow/BACKLOG.yaml` - canonical work-item DAG and work-item state.
|
|
44
46
|
- `.flow/work-items/<folder>/TASKS.yaml` - task DAG and execution ownership.
|
|
45
47
|
|
|
46
|
-
Do not create completion logs. Completed `SPEC.md` files retain concise Overview and Validation sections.
|
|
48
|
+
Do not create `SUMMARY.md`, completion logs, ad-hoc progress documents, handoff documents, reports, or any other new project artifact unless the developer explicitly requests or authorizes them. Completed `SPEC.md` files retain concise Overview and Validation sections.
|
|
49
|
+
|
|
50
|
+
`GRAPH.md` is derived only. It must never become an independent source of truth and must be reconciled whenever work-item existence, dependencies, or status change. Preserve its established visual style and conventions while updating it.
|
|
47
51
|
|
|
48
52
|
## Work item model
|
|
49
53
|
|
|
@@ -53,6 +57,15 @@ Do not create completion logs. Completed `SPEC.md` files retain concise Overview
|
|
|
53
57
|
|
|
54
58
|
Folder format is `<three-digit-sequence><kind-code>-<slug>` (for example, `001F-user-profile`). The sequence is a stable readability aid, never execution order. Dependencies determine readiness.
|
|
55
59
|
|
|
60
|
+
Work-item states are derived consistently:
|
|
61
|
+
|
|
62
|
+
- `complete` (`✅`, green) - the item is completed.
|
|
63
|
+
- `in_progress` (`🔵`, blue) - the item has active execution.
|
|
64
|
+
- `blocked` (`🔴`, red) - the item is neither complete nor in progress and at least one work-item dependency is not complete.
|
|
65
|
+
- `pending` (`🟡`, yellow) - the item is neither complete nor in progress and every work-item dependency is complete; it is ready to execute.
|
|
66
|
+
|
|
67
|
+
The graph must use these meanings consistently for nodes and outgoing dependency-line styling.
|
|
68
|
+
|
|
56
69
|
## Decision authority
|
|
57
70
|
|
|
58
71
|
Apply low-impact and conventional choices automatically. A decision requires developer approval when materially different choices affect product behavior or scope; architecture/public contracts; production infrastructure or cost; persistent data; security/privacy; testing strategy or gates; project-wide conventions; or other work-item assumptions.
|
|
@@ -112,13 +125,16 @@ Load only the reference needed for current state:
|
|
|
112
125
|
## Orchestration loop
|
|
113
126
|
|
|
114
127
|
1. Read `.flow/config.yaml`.
|
|
115
|
-
2. Read only the minimum navigation context from `.flow/STATE.md`
|
|
128
|
+
2. Read only the minimum navigation context from `.flow/STATE.md` when present.
|
|
116
129
|
3. Classify new intent and its impact on canonical truth, backlog, active work, or execution detail.
|
|
117
130
|
4. Respect work/tasks already `in_progress` under another execution ID.
|
|
118
131
|
5. Route to the minimal internal reference.
|
|
119
132
|
6. Claim selected work before parallel execution.
|
|
120
133
|
7. Continue planning, build, gates, review, fixes/reconciliation, and completion without another invocation.
|
|
121
|
-
8. Recompute readiness after
|
|
134
|
+
8. Recompute work-item states and readiness after every meaningful transition, synchronize `BACKLOG.yaml`, `STATE.md`, and `GRAPH.md`, and continue if ready work exists.
|
|
135
|
+
9. Do not stop or return control merely to announce that a task/work item completed or to describe the next step. Stop only when developer input is required for a consequential decision, an external approval is required, an unrecoverable blocker prevents useful progress, or no ready work remains.
|
|
136
|
+
|
|
137
|
+
When execution stops, report the stopping reason and the smallest relevant status summary. During uninterrupted execution, avoid progress-only messages.
|
|
122
138
|
|
|
123
139
|
## Parallelism and gates
|
|
124
140
|
|
|
@@ -2,4 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
Compute ready tasks, exclude claims by another execution ID, select the largest safe set, and mark it `in_progress` before editing or delegating. Load only relevant specs, decisions, code, and gates. Follow approved conventions, avoid unrelated refactors, run the cheapest relevant deterministic checks, make atomic commits, and mark tasks complete only after acceptance checks pass.
|
|
4
4
|
|
|
5
|
-
Synchronize TASKS
|
|
5
|
+
Synchronize `TASKS.yaml`, `BACKLOG.yaml`, `STATE.md`, `GRAPH.md`, and other affected approved canonical artifacts at each meaningful transition. Never create a new document or artifact unless the developer explicitly requested or authorized it. If a consequential new choice emerges, stop only the affected path and present the decision while independent paths continue when safe.
|
|
6
|
+
|
|
7
|
+
Do not pause or return control merely to report that a task or work item completed, to announce progress, or to state the next step. Recompute readiness and continue automatically while useful ready work exists. Surface execution status only when developer input is required or execution has actually stopped.
|
|
@@ -10,4 +10,6 @@ Resolve only consequential global decisions affecting the problem, users, MVP, b
|
|
|
10
10
|
|
|
11
11
|
## Outputs
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Update valid canonical artifacts when their truth changes. Create `PRD.md`, `ENGINEERING.md`, `DECISIONS.md`, `BACKLOG.yaml`, `STATE.md`, `GRAPH.md`, work-item artifacts, or gate definitions only when the developer explicitly requested or authorized creation of that artifact class. Never create substitute, progress, summary, handoff, or ad-hoc documents to capture information that belongs in an existing approved artifact.
|
|
14
|
+
|
|
15
|
+
`GRAPH.md` is a derived human-readable projection of `BACKLOG.yaml`, not an independent source of truth. Discovery ends when no unresolved global decision is needed for a coherent production-capable MVP and initial work-item DAG.
|
|
@@ -2,4 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
Read only relevant global decisions, backlog context, existing spec/tasks, and source. Ask consequential work-item decisions only when viable answers materially change behavior, contracts, data semantics, technical boundaries, security, UX, or gates.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
For an already authorized work-item artifact class, create or update `.flow/work-items/<id>/SPEC.md` with goal, scope/non-goals, relevant decisions, approach, requirements, acceptance criteria, gates, dependencies/impacts, and validation. Create or update `TASKS.yaml` with bounded, testable, independently executable tasks, real blocking dependencies only, and concise acceptance/validation expectations.
|
|
6
|
+
|
|
7
|
+
If the required `SPEC.md` or `TASKS.yaml` does not yet exist and the developer has not explicitly requested or authorized creation of that artifact class, request authorization before creating it. Do not create substitute planning documents. After planning, continue automatically into ready execution instead of stopping to report the plan unless a consequential developer decision is required.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
# Reconciliation
|
|
2
2
|
|
|
3
|
-
Keep canonical truth and active plans aligned when new intent or accepted decisions affect work. Reconcile pending/planned work before execution, preserve unaffected in-progress work, and create maintenance work for completed work that must change. Preserve superseded decisions with links to their replacements. Update only artifacts whose current truth changed.
|
|
3
|
+
Keep canonical truth and active plans aligned when new intent or accepted decisions affect work. Reconcile pending/planned work before execution, preserve unaffected in-progress work, and create maintenance work for completed work that must change. Preserve superseded decisions with links to their replacements. Update only approved artifacts whose current truth changed, including the derived `GRAPH.md` whenever work-item existence, dependencies, or status change.
|
|
4
|
+
|
|
5
|
+
Never create a new document or artifact during reconciliation unless the developer explicitly requested or authorized it. After reconciliation, recompute readiness and continue execution automatically when safe rather than pausing to report status.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
# Review
|
|
2
2
|
|
|
3
|
-
Verify completed work against its spec and applicable gates: inspect task completion and diff, validate requirements and acceptance criteria, run deterministic blocking gates, then applicable agentic gates, and check integration/regressions. Create targeted fix tasks within approved scope; request a decision only for consequential new choices. On success, update the spec Overview and Validation, then synchronize
|
|
3
|
+
Verify completed work against its spec and applicable gates: inspect task completion and diff, validate requirements and acceptance criteria, run deterministic blocking gates, then applicable agentic gates, and check integration/regressions. Create targeted fix tasks within approved scope; request a decision only for consequential new choices. On success, update the spec Overview and Validation, then synchronize `BACKLOG.yaml`, `STATE.md`, `GRAPH.md`, and other affected approved canonical artifacts.
|
|
4
|
+
|
|
5
|
+
Never create a new document or artifact during review unless the developer explicitly requested or authorized it. Do not stop merely to announce successful validation or the next ready work item; return to orchestration and continue while useful ready work exists.
|
package/src/cli.mjs
CHANGED
|
@@ -27,6 +27,38 @@ function valueAfter(name) { const i = args.indexOf(name); return i >= 0 ? args[i
|
|
|
27
27
|
function npmCommand() { return process.platform === 'win32' ? 'npm.cmd' : 'npm'; }
|
|
28
28
|
function projectRoot() { return path.resolve(valueAfter('--path') || process.cwd()); }
|
|
29
29
|
function configPath(root) { return path.join(root, '.flow', 'config.yaml'); }
|
|
30
|
+
function packagePath(root) { return path.join(root, 'node_modules', '@caiqueoak', 'flow'); }
|
|
31
|
+
|
|
32
|
+
function abortedPromptError() {
|
|
33
|
+
const error = new Error('Prompt aborted.');
|
|
34
|
+
error.code = 'ABORT_ERR';
|
|
35
|
+
return error;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function question(rl, message) {
|
|
39
|
+
return new Promise((resolve, reject) => {
|
|
40
|
+
let settled = false;
|
|
41
|
+
const finish = (callback, value) => {
|
|
42
|
+
if (settled) return;
|
|
43
|
+
settled = true;
|
|
44
|
+
rl.removeListener('close', onClose);
|
|
45
|
+
callback(value);
|
|
46
|
+
};
|
|
47
|
+
const onClose = () => finish(reject, abortedPromptError());
|
|
48
|
+
rl.once('close', onClose);
|
|
49
|
+
rl.question(message).then(
|
|
50
|
+
(answer) => finish(resolve, answer),
|
|
51
|
+
(error) => finish(reject, error)
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function runNpm(npmArgs, options = {}) {
|
|
57
|
+
return execFileSync(npmCommand(), npmArgs, {
|
|
58
|
+
...options,
|
|
59
|
+
shell: process.platform === 'win32'
|
|
60
|
+
});
|
|
61
|
+
}
|
|
30
62
|
|
|
31
63
|
function copyDir(source, target) {
|
|
32
64
|
fs.mkdirSync(target, { recursive: true });
|
|
@@ -82,6 +114,11 @@ function parseRuntimeFlag() {
|
|
|
82
114
|
return raw ? raw.split(',').map((x) => x.trim().toLowerCase()).filter(Boolean) : null;
|
|
83
115
|
}
|
|
84
116
|
|
|
117
|
+
function missingBuiltinRuntimes(existing) {
|
|
118
|
+
const existingTypes = new Set(existing.map((r) => r.type));
|
|
119
|
+
return Object.keys(RUNTIME_DEFINITIONS).filter((type) => !existingTypes.has(type));
|
|
120
|
+
}
|
|
121
|
+
|
|
85
122
|
async function promptMultiSelect(existing) {
|
|
86
123
|
const existingTypes = new Set(existing.map((r) => r.type));
|
|
87
124
|
const options = Object.entries(RUNTIME_DEFINITIONS).filter(([type]) => !existingTypes.has(type)).map(([value, def]) => ({ value, label: def.label }));
|
|
@@ -92,7 +129,7 @@ async function promptMultiSelect(existing) {
|
|
|
92
129
|
const rl = readline.createInterface({ input: inputStream, output: outputStream });
|
|
93
130
|
try {
|
|
94
131
|
while (true) {
|
|
95
|
-
const answer = (await
|
|
132
|
+
const answer = (await question(rl, 'Selection: ')).trim();
|
|
96
133
|
const indices = [...new Set(answer.split(',').map((v) => Number.parseInt(v.trim(), 10)).filter(Number.isInteger))];
|
|
97
134
|
if (indices.length && indices.every((n) => n >= 1 && n <= options.length)) return indices.map((n) => options[n - 1].value);
|
|
98
135
|
info('Choose one or more valid numbers.');
|
|
@@ -103,7 +140,7 @@ async function promptMultiSelect(existing) {
|
|
|
103
140
|
async function promptText(message, defaultValue = '') {
|
|
104
141
|
const rl = readline.createInterface({ input: inputStream, output: outputStream });
|
|
105
142
|
try {
|
|
106
|
-
const answer = (await
|
|
143
|
+
const answer = (await question(rl, `${message}${defaultValue ? ` [${defaultValue}]` : ''}: `)).trim();
|
|
107
144
|
return answer || defaultValue;
|
|
108
145
|
} finally { rl.close(); }
|
|
109
146
|
}
|
|
@@ -129,7 +166,15 @@ async function initProject() {
|
|
|
129
166
|
info('Flow project already exists. Canonical project artifacts will not be created or modified.');
|
|
130
167
|
if (config.runtimes.length) info(`Configured coding agents: ${config.runtimes.map((r) => r.type).join(', ')}`);
|
|
131
168
|
}
|
|
132
|
-
|
|
169
|
+
|
|
170
|
+
const requested = parseRuntimeFlag();
|
|
171
|
+
if (existed && !requested && missingBuiltinRuntimes(config.runtimes).length === 0) {
|
|
172
|
+
info('All built-in coding agents are already configured. Nothing to add.');
|
|
173
|
+
info('Use --runtime custom only when you intentionally want to add a custom coding agent.');
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const selected = requested || await promptMultiSelect(config.runtimes);
|
|
133
178
|
const knownTypes = new Set(config.runtimes.map((r) => r.type));
|
|
134
179
|
const added = [];
|
|
135
180
|
for (const type of selected) {
|
|
@@ -156,29 +201,88 @@ function dependencySection(root) {
|
|
|
156
201
|
return '--save-dev';
|
|
157
202
|
}
|
|
158
203
|
|
|
204
|
+
function containingNodeModules(packageRoot) {
|
|
205
|
+
let current = path.resolve(packageRoot);
|
|
206
|
+
while (true) {
|
|
207
|
+
if (path.basename(current).toLowerCase() === 'node_modules') return current;
|
|
208
|
+
const parent = path.dirname(current);
|
|
209
|
+
if (parent === current) return null;
|
|
210
|
+
current = parent;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function updatePlan(root) {
|
|
215
|
+
const projectPackageRoot = packagePath(root);
|
|
216
|
+
if (fs.existsSync(path.join(projectPackageRoot, 'package.json'))) {
|
|
217
|
+
return {
|
|
218
|
+
npmArgs: ['install', dependencySection(root), `${PACKAGE_NAME}@latest`],
|
|
219
|
+
cwd: root,
|
|
220
|
+
packageRoot: projectPackageRoot,
|
|
221
|
+
mode: 'project'
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
try {
|
|
226
|
+
const globalNodeModules = path.resolve(runNpm(['root', '--global'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim());
|
|
227
|
+
const globalPackageRoot = path.join(globalNodeModules, '@caiqueoak', 'flow');
|
|
228
|
+
if (path.resolve(ROOT).startsWith(`${globalNodeModules}${path.sep}`) && fs.existsSync(path.join(globalPackageRoot, 'package.json'))) {
|
|
229
|
+
return {
|
|
230
|
+
npmArgs: ['install', '--global', `${PACKAGE_NAME}@latest`],
|
|
231
|
+
cwd: root,
|
|
232
|
+
packageRoot: globalPackageRoot,
|
|
233
|
+
mode: 'global'
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
} catch { /* fall through to local installation detection */ }
|
|
237
|
+
|
|
238
|
+
const nodeModules = containingNodeModules(ROOT);
|
|
239
|
+
if (nodeModules) {
|
|
240
|
+
const installRoot = path.dirname(nodeModules);
|
|
241
|
+
return {
|
|
242
|
+
npmArgs: ['install', dependencySection(installRoot), `${PACKAGE_NAME}@latest`],
|
|
243
|
+
cwd: installRoot,
|
|
244
|
+
packageRoot: ROOT,
|
|
245
|
+
mode: 'local'
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
fail('cannot determine how this Flow CLI was installed. Reinstall @caiqueoak/flow with npm, then run flow update again.');
|
|
250
|
+
}
|
|
251
|
+
|
|
159
252
|
function update() {
|
|
160
253
|
const root = projectRoot();
|
|
161
254
|
const config = readConfig(root);
|
|
162
255
|
if (!config) fail('this project is not initialized. Run flow init first.');
|
|
163
256
|
if (!config.runtimes.length) fail('no coding agents are configured. Run flow init to add one.');
|
|
164
|
-
|
|
165
|
-
|
|
257
|
+
|
|
258
|
+
const plan = updatePlan(root);
|
|
259
|
+
info(`Updating ${PACKAGE_NAME} (${plan.mode} installation)...`);
|
|
260
|
+
try { runNpm(plan.npmArgs, { cwd: plan.cwd, stdio: 'inherit' }); }
|
|
166
261
|
catch { fail('npm update failed. Existing project state and installed skills were not intentionally removed.'); }
|
|
167
|
-
|
|
168
|
-
if (!fs.existsSync(path.join(packageRoot, 'package.json'))) fail(`updated package not found at ${
|
|
169
|
-
const latest = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'));
|
|
170
|
-
for (const runtime of config.runtimes) info(`✓ ${runtime.type}: ${path.relative(root, installRuntimeSkill(root, runtime, packageRoot))}`);
|
|
262
|
+
|
|
263
|
+
if (!fs.existsSync(path.join(plan.packageRoot, 'package.json'))) fail(`updated package not found at ${plan.packageRoot}.`);
|
|
264
|
+
const latest = JSON.parse(fs.readFileSync(path.join(plan.packageRoot, 'package.json'), 'utf8'));
|
|
265
|
+
for (const runtime of config.runtimes) info(`✓ ${runtime.type}: ${path.relative(root, installRuntimeSkill(root, runtime, plan.packageRoot))}`);
|
|
171
266
|
const text = fs.readFileSync(configPath(root), 'utf8');
|
|
172
267
|
fs.writeFileSync(configPath(root), text.replace(/(^framework:\s*\n(?:.*\n)*?\s+version:\s*)[^\n]+/m, `$1${latest.version}`), 'utf8');
|
|
173
268
|
info(`Flow updated to ${latest.version}.`);
|
|
174
269
|
}
|
|
175
270
|
|
|
176
271
|
function help() {
|
|
177
|
-
info(`Flow ${VERSION}\n\nUsage:\n flow init [--path <project>] [--runtime codex,claude]\n flow update [--path <project>]\n flow --version\n\nflow init creates only .flow/config.yaml and installs the project-local /flow skill for selected coding agents.\nIf .flow already exists, init only adds coding-agent integrations.\nThere is no flow install command and no automatic/background update mechanism.`);
|
|
272
|
+
info(`Flow ${VERSION}\n\nUsage:\n flow init [--path <project>] [--runtime codex,claude]\n flow update [--path <project>]\n flow --version\n\nflow init creates only .flow/config.yaml and installs the project-local /flow skill for selected coding agents.\nIf .flow already exists, init only adds coding-agent integrations and exits without prompting when all built-in integrations are already configured.\nflow update updates the installation that provides the Flow CLI (project-local or global) and refreshes every configured project-local skill.\nThere is no flow install command and no automatic/background update mechanism.`);
|
|
178
273
|
}
|
|
179
274
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
else if (
|
|
183
|
-
else if (args[0] === '
|
|
184
|
-
else
|
|
275
|
+
try {
|
|
276
|
+
if (!args.length || hasFlag('--help') || hasFlag('-h')) help();
|
|
277
|
+
else if (hasFlag('--version') || hasFlag('-v')) info(VERSION);
|
|
278
|
+
else if (args[0] === 'init') await initProject();
|
|
279
|
+
else if (args[0] === 'update') update();
|
|
280
|
+
else fail(`unknown command '${args[0]}'. Run flow --help.`);
|
|
281
|
+
} catch (error) {
|
|
282
|
+
if (error?.code === 'ABORT_ERR') {
|
|
283
|
+
info('\nFlow command canceled.');
|
|
284
|
+
process.exitCode = 130;
|
|
285
|
+
} else {
|
|
286
|
+
throw error;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
# Canonical Artifact Guidance
|
|
2
|
-
|
|
3
|
-
Create canonical project files only when they become valid. `PRD.md` holds global product truth; `ENGINEERING.md` holds current global engineering truth; `SUMMARY.md` is a concise derived orientation view; `STATE.md` is a concise navigation/status view; and `DECISIONS.md` preserves consequential decisions, options, rationale, and impacts.
|
|
4
|
-
|
|
5
|
-
`BACKLOG.yaml` is the work-item DAG. Each work item has a readable `SPEC.md` and a `TASKS.yaml` task DAG with status, dependencies, acceptance/validation, and optional ownership areas. Do not create a separate completion log: keep delivered behavior and validation in the completed spec.
|