@brainfile/cli 0.15.0 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +10 -0
  3. package/dist/cli.js +5 -5
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/add.js +5 -4
  6. package/dist/commands/add.js.map +1 -1
  7. package/dist/commands/adr.js +1 -1
  8. package/dist/commands/adr.js.map +1 -1
  9. package/dist/commands/init.d.ts +0 -1
  10. package/dist/commands/init.d.ts.map +1 -1
  11. package/dist/commands/init.js +19 -33
  12. package/dist/commands/init.js.map +1 -1
  13. package/dist/commands/list.d.ts.map +1 -1
  14. package/dist/commands/list.js +5 -4
  15. package/dist/commands/list.js.map +1 -1
  16. package/dist/commands/log.js +2 -2
  17. package/dist/commands/log.js.map +1 -1
  18. package/dist/commands/mcp.js +2 -2
  19. package/dist/commands/mcp.js.map +1 -1
  20. package/dist/commands/migrate.d.ts +3 -3
  21. package/dist/commands/migrate.d.ts.map +1 -1
  22. package/dist/commands/migrate.js +124 -87
  23. package/dist/commands/migrate.js.map +1 -1
  24. package/dist/commands/show.js +5 -4
  25. package/dist/commands/show.js.map +1 -1
  26. package/dist/commands/tui.d.ts.map +1 -1
  27. package/dist/commands/tui.js +10 -0
  28. package/dist/commands/tui.js.map +1 -1
  29. package/dist/schemas/board.json +105 -18
  30. package/dist/utils/v2-detect.d.ts +5 -5
  31. package/dist/utils/v2-detect.d.ts.map +1 -1
  32. package/dist/utils/v2-detect.js +22 -19
  33. package/dist/utils/v2-detect.js.map +1 -1
  34. package/dist/utils/workspace-format.d.ts +25 -0
  35. package/dist/utils/workspace-format.d.ts.map +1 -0
  36. package/dist/utils/workspace-format.js +106 -0
  37. package/dist/utils/workspace-format.js.map +1 -0
  38. package/package.json +1 -1
@@ -2,10 +2,9 @@
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
3
  "$id": "https://brainfile.md/v1/board.json",
4
4
  "title": "Brainfile Board Schema",
5
- "description": "Schema for Kanban-style task boards with columns and tasks",
5
+ "description": "Schema for Kanban-style task boards. In v2 (per-task file architecture), the board file is config-only: it defines columns, rules, and project metadata. Tasks are standalone .md files in .brainfile/tasks/ (active) and .brainfile/logs/ (completed), each validated against task.json. In v1 (legacy), tasks are embedded in column arrays within this file.",
6
6
  "x-brainfile-renderer": "kanban",
7
7
  "x-brainfile-columns-path": "$.columns",
8
- "x-brainfile-items-path": "$.columns[*].tasks",
9
8
  "x-brainfile-title-field": "title",
10
9
  "x-brainfile-status-field": "priority",
11
10
  "allOf": [
@@ -14,19 +13,47 @@
14
13
  },
15
14
  {
16
15
  "type": "object",
17
- "required": ["columns"],
16
+ "required": [
17
+ "columns"
18
+ ],
18
19
  "properties": {
19
20
  "type": {
20
21
  "const": "board"
21
22
  },
22
23
  "columns": {
23
24
  "type": "array",
24
- "description": "Task columns (e.g., To Do, In Progress, Done)",
25
+ "description": "Board columns defining workflow stages. In v2, columns are config-only (no embedded tasks). In v1 (legacy), columns may contain a tasks array.",
25
26
  "minItems": 1,
26
27
  "items": {
27
28
  "$ref": "#/definitions/column"
28
29
  }
29
30
  },
31
+ "types": {
32
+ "type": "object",
33
+ "description": "Optional map of document type definitions. Keys are type identifiers (e.g., 'epic', 'adr') that match the type field in task.json. In strict mode, this map is the allowlist for non-task types; the built-in task type is always implicitly valid. When omitted, all items are standard tasks.",
34
+ "additionalProperties": {
35
+ "$ref": "#/definitions/typeEntry"
36
+ },
37
+ "examples": [
38
+ {
39
+ "epic": {
40
+ "idPrefix": "epic",
41
+ "completable": false,
42
+ "schema": "https://brainfile.md/v1/examples/epic.json"
43
+ },
44
+ "adr": {
45
+ "idPrefix": "adr",
46
+ "completable": false,
47
+ "schema": "https://brainfile.md/v1/examples/adr.json"
48
+ }
49
+ }
50
+ ]
51
+ },
52
+ "strict": {
53
+ "type": "boolean",
54
+ "description": "Enables strict validation for CLI operations. When true, add rejects unknown task types and move rejects unknown columns. When false (default), unknown types and columns are allowed for backward compatibility. The task type is always implicitly valid even if not listed in types.",
55
+ "default": false
56
+ },
30
57
  "statsConfig": {
31
58
  "type": "object",
32
59
  "description": "Configuration for statistics calculation",
@@ -43,7 +70,8 @@
43
70
  },
44
71
  "archive": {
45
72
  "type": "array",
46
- "description": "Archived tasks removed from active columns",
73
+ "description": "Deprecated in v2. In v1, holds archived tasks removed from active columns. In v2, completed tasks live as individual files in .brainfile/logs/.",
74
+ "x-brainfile-deprecated": true,
47
75
  "items": {
48
76
  "$ref": "#/definitions/task"
49
77
  }
@@ -53,13 +81,46 @@
53
81
  }
54
82
  ],
55
83
  "definitions": {
84
+ "typeEntry": {
85
+ "type": "object",
86
+ "description": "Configuration for a custom document type. Defines how items of this type behave within the board.",
87
+ "required": [
88
+ "idPrefix"
89
+ ],
90
+ "properties": {
91
+ "idPrefix": {
92
+ "type": "string",
93
+ "description": "Prefix for auto-generated IDs of this type (e.g., 'epic' produces 'epic-1', 'epic-2'). Must be unique across all type entries.",
94
+ "pattern": "^[a-z]+(-[a-z]+)*$",
95
+ "minLength": 1
96
+ },
97
+ "completable": {
98
+ "type": "boolean",
99
+ "description": "Whether items of this type can be completed (moved to completion columns and logs/). Defaults to true. Set to false for reference documents like ADRs or epics that are not completable tasks.",
100
+ "default": true
101
+ },
102
+ "schema": {
103
+ "type": "string",
104
+ "description": "Optional JSON Schema URL for validating the extended fields of this type. Can be a remote URI (https://) or a local file path relative to the project root.",
105
+ "format": "uri-reference",
106
+ "examples": [
107
+ "https://brainfile.md/v1/examples/epic.json",
108
+ ".brainfile/schemas/adr.json"
109
+ ]
110
+ }
111
+ },
112
+ "additionalProperties": true
113
+ },
56
114
  "column": {
57
115
  "type": "object",
58
- "required": ["id", "title", "tasks"],
116
+ "required": [
117
+ "id",
118
+ "title"
119
+ ],
59
120
  "properties": {
60
121
  "id": {
61
122
  "type": "string",
62
- "description": "Unique column identifier in kebab-case (e.g., 'todo', 'in-progress')",
123
+ "description": "Unique column identifier in kebab-case (e.g., 'todo', 'in-progress'). Referenced by task.column in per-task files.",
63
124
  "pattern": "^[a-z]+(-[a-z]+)*$",
64
125
  "minLength": 1
65
126
  },
@@ -80,7 +141,8 @@
80
141
  },
81
142
  "tasks": {
82
143
  "type": "array",
83
- "description": "Tasks in this column",
144
+ "description": "Deprecated in v2. In v1, holds tasks embedded in this column. In v2, task membership is declared via the column field in each task's frontmatter (see task.json).",
145
+ "x-brainfile-deprecated": true,
84
146
  "items": {
85
147
  "$ref": "#/definitions/task"
86
148
  }
@@ -90,12 +152,18 @@
90
152
  },
91
153
  "task": {
92
154
  "type": "object",
93
- "required": ["id", "title"],
155
+ "description": "Deprecated in v2. Inline task definition for v1 backward compatibility. In v2, use the standalone task.json schema instead.",
156
+ "x-brainfile-deprecated": true,
157
+ "x-brainfile-see": "https://brainfile.md/v1/task.json",
158
+ "required": [
159
+ "id",
160
+ "title"
161
+ ],
94
162
  "properties": {
95
163
  "id": {
96
164
  "type": "string",
97
- "description": "Unique task identifier following pattern 'task-N'",
98
- "pattern": "^task-[0-9]+$"
165
+ "description": "Unique identifier following pattern '{type}-N'",
166
+ "pattern": "^[a-z][a-z0-9]*-[0-9]+$"
99
167
  },
100
168
  "title": {
101
169
  "type": "string",
@@ -120,19 +188,30 @@
120
188
  "priority": {
121
189
  "type": "string",
122
190
  "description": "Optional task priority",
123
- "enum": ["low", "medium", "high", "critical"]
191
+ "enum": [
192
+ "low",
193
+ "medium",
194
+ "high",
195
+ "critical"
196
+ ]
124
197
  },
125
198
  "effort": {
126
199
  "type": "string",
127
200
  "description": "Optional effort estimation for AI planning",
128
- "enum": ["trivial", "small", "medium", "large", "xlarge"]
201
+ "enum": [
202
+ "trivial",
203
+ "small",
204
+ "medium",
205
+ "large",
206
+ "xlarge"
207
+ ]
129
208
  },
130
209
  "blockedBy": {
131
210
  "type": "array",
132
- "description": "Optional list of task IDs that block this task",
211
+ "description": "Optional list of item IDs that block this task",
133
212
  "items": {
134
213
  "type": "string",
135
- "pattern": "^task-[0-9]+$"
214
+ "pattern": "^[a-z][a-z0-9]*-[0-9]+$"
136
215
  }
137
216
  },
138
217
  "dueDate": {
@@ -165,7 +244,11 @@
165
244
  "template": {
166
245
  "type": "string",
167
246
  "description": "Optional task template type",
168
- "enum": ["bug", "feature", "refactor"]
247
+ "enum": [
248
+ "bug",
249
+ "feature",
250
+ "refactor"
251
+ ]
169
252
  },
170
253
  "contract": {
171
254
  "$ref": "https://brainfile.md/v1/contract.json"
@@ -175,7 +258,11 @@
175
258
  },
176
259
  "subtask": {
177
260
  "type": "object",
178
- "required": ["id", "title", "completed"],
261
+ "required": [
262
+ "id",
263
+ "title",
264
+ "completed"
265
+ ],
179
266
  "properties": {
180
267
  "id": {
181
268
  "type": "string",
@@ -195,4 +282,4 @@
195
282
  "additionalProperties": true
196
283
  }
197
284
  }
198
- }
285
+ }
@@ -9,16 +9,16 @@
9
9
  */
10
10
  export { type V2Dirs, getV2Dirs, isV2, ensureV2Dirs, getTaskFilePath, getLogFilePath, findV2Task, extractDescription, extractLog, composeBody, readV2BoardConfig, buildBoardFromV2, } from '@brainfile/core';
11
11
  /**
12
- * Check whether we should show the one-time v2 migration suggestion.
12
+ * Check whether we should show the one-time migration suggestion.
13
13
  *
14
14
  * Returns true when ALL of these hold:
15
- * a. The brainfile is v1 format (no board/ directory next to it)
16
- * b. The brainfile has at least one task in any column
17
- * c. This process has not already shown the hint for this brainfile path
15
+ * a. The workspace appears to be in a legacy or mixed layout, OR this file
16
+ * itself looks like a legacy board file.
17
+ * b. This process has not already shown the hint for this brainfile path.
18
18
  */
19
19
  export declare function shouldSuggestV2Migration(brainfilePath: string): boolean;
20
20
  /**
21
- * Record that the v2 migration hint has been shown so it won't appear again.
21
+ * Record that the migration hint has been shown so it won't appear again.
22
22
  *
23
23
  * This is intentionally in-memory only; Brainfile no longer persists state.json.
24
24
  */
@@ -1 +1 @@
1
- {"version":3,"file":"v2-detect.d.ts","sourceRoot":"","sources":["../../src/utils/v2-detect.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAQH,OAAO,EACL,KAAK,MAAM,EACX,SAAS,EACT,IAAI,EACJ,YAAY,EACZ,eAAe,EACf,cAAc,EACd,UAAU,EACV,kBAAkB,EAClB,UAAU,EACV,WAAW,EACX,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,iBAAiB,CAAC;AAQzB;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAsBvE;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAEpE;AAED,4BAA4B;AAC5B,wBAAgB,2BAA2B,IAAI,IAAI,CAElD"}
1
+ {"version":3,"file":"v2-detect.d.ts","sourceRoot":"","sources":["../../src/utils/v2-detect.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAQH,OAAO,EACL,KAAK,MAAM,EACX,SAAS,EACT,IAAI,EACJ,YAAY,EACZ,eAAe,EACf,cAAc,EACd,UAAU,EACV,kBAAkB,EAClB,UAAU,EACV,WAAW,EACX,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,iBAAiB,CAAC;AAYzB;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAuBvE;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAEpE;AAED,4BAA4B;AAC5B,wBAAgB,2BAA2B,IAAI,IAAI,CAElD"}
@@ -64,38 +64,41 @@ Object.defineProperty(exports, "readV2BoardConfig", { enumerable: true, get: fun
64
64
  Object.defineProperty(exports, "buildBoardFromV2", { enumerable: true, get: function () { return core_2.buildBoardFromV2; } });
65
65
  // ── CLI-specific migration hint helpers ──────────────────────────────
66
66
  const core_3 = require("@brainfile/core");
67
+ const workspace_format_1 = require("./workspace-format");
67
68
  const v2MigrationHintShown = new Set();
68
69
  /**
69
- * Check whether we should show the one-time v2 migration suggestion.
70
+ * Check whether we should show the one-time migration suggestion.
70
71
  *
71
72
  * Returns true when ALL of these hold:
72
- * a. The brainfile is v1 format (no board/ directory next to it)
73
- * b. The brainfile has at least one task in any column
74
- * c. This process has not already shown the hint for this brainfile path
73
+ * a. The workspace appears to be in a legacy or mixed layout, OR this file
74
+ * itself looks like a legacy board file.
75
+ * b. This process has not already shown the hint for this brainfile path.
75
76
  */
76
77
  function shouldSuggestV2Migration(brainfilePath) {
77
78
  const resolved = path.resolve(brainfilePath);
78
- // (a) Must be v1 format
79
- if ((0, core_3.isV2)(resolved))
80
- return false;
81
- // (c) One-time guard for this process
82
79
  if (v2MigrationHintShown.has(resolved))
83
80
  return false;
84
- // (b) Parse brainfile and check for at least one task
85
- try {
86
- const content = fs.readFileSync(resolved, 'utf-8');
87
- const result = core_1.Brainfile.parseWithErrors(content);
88
- if (!result.board)
89
- return false;
90
- const hasTasks = result.board.columns.some((col) => col.tasks && col.tasks.length > 0);
91
- return hasTasks;
81
+ const probe = (0, workspace_format_1.probeWorkspaceForBrainfile)(resolved);
82
+ if ((0, workspace_format_1.shouldSuggestMigration)(probe)) {
83
+ return true;
92
84
  }
93
- catch {
94
- return false;
85
+ // Fallback: explicit non-standard board files (e.g. fixtures/test-board.md)
86
+ // should still receive a migration suggestion when they parse as v1 board files.
87
+ if (!(0, core_3.isV2)(resolved) && fs.existsSync(resolved)) {
88
+ try {
89
+ const content = fs.readFileSync(resolved, 'utf-8');
90
+ const parsed = core_1.Brainfile.parseWithErrors(content);
91
+ if (parsed.board)
92
+ return true;
93
+ }
94
+ catch {
95
+ // Ignore parse/read errors and suppress hint.
96
+ }
95
97
  }
98
+ return false;
96
99
  }
97
100
  /**
98
- * Record that the v2 migration hint has been shown so it won't appear again.
101
+ * Record that the migration hint has been shown so it won't appear again.
99
102
  *
100
103
  * This is intentionally in-memory only; Brainfile no longer persists state.json.
101
104
  */
@@ -1 +1 @@
1
- {"version":3,"file":"v2-detect.js","sourceRoot":"","sources":["../../src/utils/v2-detect.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCH,4DAsBC;AAOD,4DAEC;AAGD,kEAEC;AAvED,uCAAyB;AACzB,2CAA6B;AAC7B,0CAA4C;AAE5C,wEAAwE;AAExE,wCAayB;AAXvB,iGAAA,SAAS,OAAA;AACT,4FAAA,IAAI,OAAA;AACJ,oGAAA,YAAY,OAAA;AACZ,uGAAA,eAAe,OAAA;AACf,sGAAA,cAAc,OAAA;AACd,kGAAA,UAAU,OAAA;AACV,0GAAA,kBAAkB,OAAA;AAClB,kGAAA,UAAU,OAAA;AACV,mGAAA,WAAW,OAAA;AACX,yGAAA,iBAAiB,OAAA;AACjB,wGAAA,gBAAgB,OAAA;AAGlB,wEAAwE;AAExE,0CAAuC;AAEvC,MAAM,oBAAoB,GAAG,IAAI,GAAG,EAAU,CAAC;AAE/C;;;;;;;GAOG;AACH,SAAgB,wBAAwB,CAAC,aAAqB;IAC5D,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IAE7C,wBAAwB;IACxB,IAAI,IAAA,WAAI,EAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IAEjC,sCAAsC;IACtC,IAAI,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IAErD,sDAAsD;IACtD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,gBAAS,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM,CAAC,KAAK;YAAE,OAAO,KAAK,CAAC;QAEhC,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CACxC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAC3C,CAAC;QACF,OAAO,QAAQ,CAAC;IAClB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAgB,wBAAwB,CAAC,aAAqB;IAC5D,oBAAoB,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;AACxD,CAAC;AAED,4BAA4B;AAC5B,SAAgB,2BAA2B;IACzC,oBAAoB,CAAC,KAAK,EAAE,CAAC;AAC/B,CAAC"}
1
+ {"version":3,"file":"v2-detect.js","sourceRoot":"","sources":["../../src/utils/v2-detect.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCH,4DAuBC;AAOD,4DAEC;AAGD,kEAEC;AA5ED,uCAAyB;AACzB,2CAA6B;AAC7B,0CAA4C;AAE5C,wEAAwE;AAExE,wCAayB;AAXvB,iGAAA,SAAS,OAAA;AACT,4FAAA,IAAI,OAAA;AACJ,oGAAA,YAAY,OAAA;AACZ,uGAAA,eAAe,OAAA;AACf,sGAAA,cAAc,OAAA;AACd,kGAAA,UAAU,OAAA;AACV,0GAAA,kBAAkB,OAAA;AAClB,kGAAA,UAAU,OAAA;AACV,mGAAA,WAAW,OAAA;AACX,yGAAA,iBAAiB,OAAA;AACjB,wGAAA,gBAAgB,OAAA;AAGlB,wEAAwE;AAExE,0CAAuC;AACvC,yDAG4B;AAE5B,MAAM,oBAAoB,GAAG,IAAI,GAAG,EAAU,CAAC;AAE/C;;;;;;;GAOG;AACH,SAAgB,wBAAwB,CAAC,aAAqB;IAC5D,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IAE7C,IAAI,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IAErD,MAAM,KAAK,GAAG,IAAA,6CAA0B,EAAC,QAAQ,CAAC,CAAC;IACnD,IAAI,IAAA,yCAAsB,EAAC,KAAK,CAAC,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,4EAA4E;IAC5E,iFAAiF;IACjF,IAAI,CAAC,IAAA,WAAI,EAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/C,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACnD,MAAM,MAAM,GAAG,gBAAS,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;YAClD,IAAI,MAAM,CAAC,KAAK;gBAAE,OAAO,IAAI,CAAC;QAChC,CAAC;QAAC,MAAM,CAAC;YACP,8CAA8C;QAChD,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,SAAgB,wBAAwB,CAAC,aAAqB;IAC5D,oBAAoB,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;AACxD,CAAC;AAED,4BAA4B;AAC5B,SAAgB,2BAA2B;IACzC,oBAAoB,CAAC,KAAK,EAAE,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,25 @@
1
+ export type WorkspaceFormat = 'v2' | 'legacy-root' | 'legacy-dotbrainfile' | 'mixed' | 'empty';
2
+ export interface WorkspacePaths {
3
+ rootDir: string;
4
+ rootBrainfilePath: string;
5
+ dotDir: string;
6
+ dotBrainfilePath: string;
7
+ boardDir: string;
8
+ logsDir: string;
9
+ }
10
+ export interface WorkspacePresence {
11
+ rootBrainfile: boolean;
12
+ dotBrainfile: boolean;
13
+ boardDir: boolean;
14
+ logsDir: boolean;
15
+ }
16
+ export interface WorkspaceProbe {
17
+ format: WorkspaceFormat;
18
+ paths: WorkspacePaths;
19
+ presence: WorkspacePresence;
20
+ }
21
+ export declare function workspaceRootFromBrainfilePath(brainfilePath: string): string;
22
+ export declare function probeWorkspaceFormat(rootDir?: string): WorkspaceProbe;
23
+ export declare function probeWorkspaceForBrainfile(brainfilePath: string): WorkspaceProbe;
24
+ export declare function shouldSuggestMigration(probe: WorkspaceProbe): boolean;
25
+ //# sourceMappingURL=workspace-format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-format.d.ts","sourceRoot":"","sources":["../../src/utils/workspace-format.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,eAAe,GACvB,IAAI,GACJ,aAAa,GACb,qBAAqB,GACrB,OAAO,GACP,OAAO,CAAC;AAEZ,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,eAAe,CAAC;IACxB,KAAK,EAAE,cAAc,CAAC;IACtB,QAAQ,EAAE,iBAAiB,CAAC;CAC7B;AAkBD,wBAAgB,8BAA8B,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAI5E;AAED,wBAAgB,oBAAoB,CAAC,OAAO,GAAE,MAAsB,GAAG,cAAc,CAqCpF;AAED,wBAAgB,0BAA0B,CAAC,aAAa,EAAE,MAAM,GAAG,cAAc,CAEhF;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAErE"}
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.workspaceRootFromBrainfilePath = workspaceRootFromBrainfilePath;
37
+ exports.probeWorkspaceFormat = probeWorkspaceFormat;
38
+ exports.probeWorkspaceForBrainfile = probeWorkspaceForBrainfile;
39
+ exports.shouldSuggestMigration = shouldSuggestMigration;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ function existsFile(filePath) {
43
+ try {
44
+ return fs.statSync(filePath).isFile();
45
+ }
46
+ catch {
47
+ return false;
48
+ }
49
+ }
50
+ function existsDir(dirPath) {
51
+ try {
52
+ return fs.statSync(dirPath).isDirectory();
53
+ }
54
+ catch {
55
+ return false;
56
+ }
57
+ }
58
+ function workspaceRootFromBrainfilePath(brainfilePath) {
59
+ const absolute = path.resolve(brainfilePath);
60
+ const dir = path.dirname(absolute);
61
+ return path.basename(dir) === '.brainfile' ? path.dirname(dir) : dir;
62
+ }
63
+ function probeWorkspaceFormat(rootDir = process.cwd()) {
64
+ const resolvedRoot = path.resolve(rootDir);
65
+ const dotDir = path.join(resolvedRoot, '.brainfile');
66
+ const paths = {
67
+ rootDir: resolvedRoot,
68
+ rootBrainfilePath: path.join(resolvedRoot, 'brainfile.md'),
69
+ dotDir,
70
+ dotBrainfilePath: path.join(dotDir, 'brainfile.md'),
71
+ boardDir: path.join(dotDir, 'board'),
72
+ logsDir: path.join(dotDir, 'logs'),
73
+ };
74
+ const presence = {
75
+ rootBrainfile: existsFile(paths.rootBrainfilePath),
76
+ dotBrainfile: existsFile(paths.dotBrainfilePath),
77
+ boardDir: existsDir(paths.boardDir),
78
+ logsDir: existsDir(paths.logsDir),
79
+ };
80
+ const hasAnyV2Artifacts = presence.boardDir || presence.logsDir;
81
+ const hasFullV2 = presence.dotBrainfile && presence.boardDir && presence.logsDir;
82
+ let format;
83
+ if (!presence.rootBrainfile && !presence.dotBrainfile && !hasAnyV2Artifacts) {
84
+ format = 'empty';
85
+ }
86
+ else if (hasFullV2 && !presence.rootBrainfile) {
87
+ format = 'v2';
88
+ }
89
+ else if (presence.rootBrainfile && !presence.dotBrainfile && !hasAnyV2Artifacts) {
90
+ format = 'legacy-root';
91
+ }
92
+ else if (!presence.rootBrainfile && presence.dotBrainfile && !hasAnyV2Artifacts) {
93
+ format = 'legacy-dotbrainfile';
94
+ }
95
+ else {
96
+ format = 'mixed';
97
+ }
98
+ return { format, paths, presence };
99
+ }
100
+ function probeWorkspaceForBrainfile(brainfilePath) {
101
+ return probeWorkspaceFormat(workspaceRootFromBrainfilePath(brainfilePath));
102
+ }
103
+ function shouldSuggestMigration(probe) {
104
+ return probe.format === 'legacy-root' || probe.format === 'legacy-dotbrainfile' || probe.format === 'mixed';
105
+ }
106
+ //# sourceMappingURL=workspace-format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-format.js","sourceRoot":"","sources":["../../src/utils/workspace-format.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainfile/cli",
3
- "version": "0.15.0",
3
+ "version": "0.15.1",
4
4
  "description": "Command-line interface for Brainfile task management",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",