busy-cli 0.2.0 → 0.3.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.
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/types/schema.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/types/schema.ts"],"names":[],"mappings":"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAcrB,CAAC;AAGH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAS/B,CAAC;AAUH,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAChD,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAE9C,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAC1E,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AACtD,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAC9C,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAClD,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AACtD,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AACpE,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AACxD,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AACtD,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAC9C,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAC9C,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAC9C,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAGlE,MAAM,MAAM,YAAY,GAAG,kBAAkB,CAAC;AAC9C,MAAM,MAAM,SAAS,GAAG,eAAe,CAAC;AAOxC,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;EA2B5B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC"}
@@ -126,7 +126,7 @@ export const SectionSchema = z.lazy(() => z.object({
126
126
  }));
127
127
  // ConceptBase schema - need to keep as regular object schema to allow .extend()
128
128
  const ConceptBaseSchemaObject = z.object({
129
- kind: z.enum(['concept', 'document', 'operation', 'checklist', 'tool', 'playbook', 'localdef', 'importdef', 'setup']),
129
+ kind: z.enum(['concept', 'document', 'operation', 'checklist', 'tool', 'playbook', 'view', 'config', 'localdef', 'importdef', 'setup']),
130
130
  id: ConceptIdSchema,
131
131
  docId: DocIdSchema,
132
132
  slug: z.string(),
@@ -178,6 +178,16 @@ export const PlaybookSchema = LegacyBusyDocumentSchema.extend({
178
178
  kind: z.literal('playbook'),
179
179
  sequence: z.array(ConceptIdSchema), // Ordered array of operation references
180
180
  });
181
+ // View schema - extends LegacyBusyDocument with display section
182
+ // Views follow MVC: imports=Model, localDefs=ViewModel, template=View, operations=Controller
183
+ export const ViewSchema = LegacyBusyDocumentSchema.extend({
184
+ kind: z.literal('view'),
185
+ display: z.string().optional(), // Markdown template (optional — LORE can generate)
186
+ });
187
+ // Config schema - extends LegacyBusyDocument, semantically a singleton Model
188
+ export const ConfigSchema = LegacyBusyDocumentSchema.extend({
189
+ kind: z.literal('config'),
190
+ });
181
191
  // Edge schema
182
192
  export const EdgeRoleSchema = z.enum(['ref', 'calls', 'extends', 'imports']);
183
193
  export const EdgeSchema = z.object({
@@ -202,7 +212,7 @@ export const RepoSchema = z.object({
202
212
  byId: z.record(z.union([SectionSchema, LocalDefSchema, LegacyOperationSchema, ConceptBaseSchema])),
203
213
  byFile: z.record(// Renamed from byDoc for clarity
204
214
  z.object({
205
- concept: z.union([LegacyBusyDocumentSchema, PlaybookSchema]), // The concept defined in this file
215
+ concept: z.union([LegacyBusyDocumentSchema, PlaybookSchema, ViewSchema, ConfigSchema]), // The concept defined in this file
206
216
  bySlug: z.record(SectionSchema),
207
217
  })),
208
218
  edges: z.array(EdgeSchema),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "busy-cli",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "CLI for BUSY document framework - parse, validate, and manage BUSY workspaces",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -0,0 +1,277 @@
1
+ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
2
+ import { loadRepo } from '../loader.js';
3
+ import { join, dirname } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { writeFileSync, mkdirSync, rmSync } from 'node:fs';
6
+
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
8
+ const FIXTURES_DIR = join(__dirname, '__fixtures__', 'view-config');
9
+
10
+ // ── Fixtures ────────────────────────────────────────────────────────
11
+
12
+ const MODEL_DOC = `---
13
+ Name: Prospect
14
+ Type: [Model]
15
+ Description: An agent who has initiated contact
16
+ ---
17
+
18
+ # Imports
19
+
20
+ # Local Definitions
21
+
22
+ ## ProspectFields
23
+ - \`agent_name\` — Full name
24
+ - \`stage\` — discovery | trial | subscriber
25
+ - \`health_status\` — healthy | at_risk | churned
26
+
27
+ # Setup
28
+
29
+ A Prospect represents an agent in the early funnel.
30
+ `;
31
+
32
+ const VIEW_DOC = `---
33
+ Name: Prospect Pipeline
34
+ Type: [View]
35
+ Description: Dashboard view of all prospects in the conversion funnel
36
+ ---
37
+
38
+ # Imports
39
+ [Prospect]:./prospect.busy.md
40
+
41
+ # Local Definitions
42
+
43
+ ## ProspectRow
44
+ A summary row combining Prospect data.
45
+ - \`name\` — from [Prospect].agent_name
46
+ - \`stage\` — from [Prospect].stage
47
+ - \`health\` — from [Prospect].health_status
48
+
49
+ # Display
50
+
51
+ ## Pipeline Summary
52
+ | Stage | Count |
53
+ |-------|-------|
54
+ {{#each stageSummary}}
55
+ | {{stage}} | {{count}} |
56
+ {{/each}}
57
+
58
+ ## All Prospects
59
+ {{#each prospects}}
60
+ - **{{name}}** — {{stage}} ({{health}})
61
+ {{/each}}
62
+
63
+ # Operations
64
+
65
+ ## refreshView
66
+ Reload prospect data from the database.
67
+
68
+ ### Steps
69
+ 1. Query all active prospects
70
+ 2. Compute stage summary counts
71
+ 3. Sort by days in stage descending
72
+ `;
73
+
74
+ const VIEW_NO_TEMPLATE = `---
75
+ Name: Simple View
76
+ Type: [View]
77
+ Description: A view without an explicit display section
78
+ ---
79
+
80
+ # Imports
81
+ [Prospect]:./prospect.busy.md
82
+
83
+ # Local Definitions
84
+
85
+ ## SimpleRow
86
+ - \`name\` — from [Prospect].agent_name
87
+
88
+ # Operations
89
+
90
+ ## refresh
91
+ Reload data.
92
+ `;
93
+
94
+ const CONFIG_DOC = `---
95
+ Name: Canon SDLC
96
+ Type: [Config]
97
+ Description: Process configuration for the Canon SDLC wizard
98
+ ---
99
+
100
+ # Imports
101
+
102
+ # Local Definitions
103
+
104
+ ## PhaseDefinition
105
+ - \`id\` — Phase identifier
106
+ - \`title\` — Display title
107
+ - \`steps\` — Array of step definitions
108
+
109
+ ## StepDefinition
110
+ - \`id\` — Step identifier
111
+ - \`title\` — Display title
112
+ - \`content\` — Instructions markdown
113
+ - \`actions\` — Array of action definitions
114
+
115
+ # Setup
116
+
117
+ The Canon SDLC defines a 6-phase software development lifecycle.
118
+ Phases: Intake, Shape, Spec, Implement, Review, Ship.
119
+ `;
120
+
121
+ // ── Setup / Teardown ────────────────────────────────────────────────
122
+
123
+ function setupFixtures() {
124
+ mkdirSync(FIXTURES_DIR, { recursive: true });
125
+ writeFileSync(join(FIXTURES_DIR, 'prospect.busy.md'), MODEL_DOC);
126
+ writeFileSync(join(FIXTURES_DIR, 'prospect-pipeline.busy.md'), VIEW_DOC);
127
+ writeFileSync(join(FIXTURES_DIR, 'simple-view.busy.md'), VIEW_NO_TEMPLATE);
128
+ writeFileSync(join(FIXTURES_DIR, 'canon-sdlc.busy.md'), CONFIG_DOC);
129
+ }
130
+
131
+ function cleanFixtures() {
132
+ rmSync(FIXTURES_DIR, { recursive: true, force: true });
133
+ }
134
+
135
+ // ── Tests ───────────────────────────────────────────────────────────
136
+
137
+ describe('View and Config Types', () => {
138
+ let repo: Awaited<ReturnType<typeof loadRepo>>;
139
+
140
+ beforeAll(async () => {
141
+ setupFixtures();
142
+ repo = await loadRepo([join(FIXTURES_DIR, '*.busy.md')]);
143
+ });
144
+
145
+ afterAll(() => {
146
+ cleanFixtures();
147
+ });
148
+
149
+ describe('Loading', () => {
150
+ it('loads all 4 fixture documents', () => {
151
+ expect(repo.concepts.length).toBe(4);
152
+ });
153
+
154
+ it('classifies Model as document', () => {
155
+ const prospect = repo.concepts.find(c => c.name === 'Prospect');
156
+ expect(prospect).toBeDefined();
157
+ expect(prospect!.kind).toBe('document');
158
+ });
159
+
160
+ it('classifies View as view', () => {
161
+ const pipeline = repo.concepts.find(c => c.name === 'Prospect Pipeline');
162
+ expect(pipeline).toBeDefined();
163
+ expect(pipeline!.kind).toBe('view');
164
+ });
165
+
166
+ it('classifies Config as config', () => {
167
+ const config = repo.concepts.find(c => c.name === 'Canon SDLC');
168
+ expect(config).toBeDefined();
169
+ expect(config!.kind).toBe('config');
170
+ });
171
+ });
172
+
173
+ describe('View Document', () => {
174
+ it('has display content when Display section exists', () => {
175
+ const viewDocId = Object.keys(repo.byFile).find(id =>
176
+ repo.byFile[id].concept.name === 'Prospect Pipeline'
177
+ )!;
178
+ const viewDoc = repo.byFile[viewDocId].concept;
179
+ expect(viewDoc.kind).toBe('view');
180
+ if (viewDoc.kind === 'view') {
181
+ expect(viewDoc.display).toBeDefined();
182
+ expect(viewDoc.display).toContain('{{#each stageSummary}}');
183
+ expect(viewDoc.display).toContain('{{#each prospects}}');
184
+ }
185
+ });
186
+
187
+ it('has undefined display when no Display section', () => {
188
+ const viewDocId = Object.keys(repo.byFile).find(id =>
189
+ repo.byFile[id].concept.name === 'Simple View'
190
+ )!;
191
+ const viewDoc = repo.byFile[viewDocId].concept;
192
+ expect(viewDoc.kind).toBe('view');
193
+ if (viewDoc.kind === 'view') {
194
+ expect(viewDoc.display).toBeUndefined();
195
+ }
196
+ });
197
+
198
+ it('has imports resolved', () => {
199
+ const viewDocId = Object.keys(repo.byFile).find(id =>
200
+ repo.byFile[id].concept.name === 'Prospect Pipeline'
201
+ )!;
202
+ const viewDoc = repo.byFile[viewDocId].concept;
203
+ expect(viewDoc.imports.length).toBeGreaterThan(0);
204
+ expect(viewDoc.imports[0].label).toBe('Prospect');
205
+ });
206
+
207
+ it('has local definitions (ViewModel)', () => {
208
+ const viewDocId = Object.keys(repo.byFile).find(id =>
209
+ repo.byFile[id].concept.name === 'Prospect Pipeline'
210
+ )!;
211
+ const viewDoc = repo.byFile[viewDocId].concept;
212
+ expect(viewDoc.localdefs.length).toBeGreaterThan(0);
213
+ expect(viewDoc.localdefs[0].name).toBe('ProspectRow');
214
+ });
215
+
216
+ it('has operations (Controller)', () => {
217
+ const viewDocId = Object.keys(repo.byFile).find(id =>
218
+ repo.byFile[id].concept.name === 'Prospect Pipeline'
219
+ )!;
220
+ const viewDoc = repo.byFile[viewDocId].concept;
221
+ expect(viewDoc.operations.length).toBeGreaterThan(0);
222
+ expect(viewDoc.operations[0].name).toBe('refreshView');
223
+ });
224
+
225
+ it('creates import edges', () => {
226
+ const viewDocId = Object.keys(repo.byFile).find(id =>
227
+ repo.byFile[id].concept.name === 'Prospect Pipeline'
228
+ )!;
229
+ const importEdges = repo.edges.filter(
230
+ e => e.from === viewDocId && e.role === 'imports'
231
+ );
232
+ expect(importEdges.length).toBeGreaterThan(0);
233
+ });
234
+ });
235
+
236
+ describe('Config Document', () => {
237
+ it('has local definitions', () => {
238
+ const configDocId = Object.keys(repo.byFile).find(id =>
239
+ repo.byFile[id].concept.name === 'Canon SDLC'
240
+ )!;
241
+ const configDoc = repo.byFile[configDocId].concept;
242
+ expect(configDoc.localdefs.length).toBe(2);
243
+ });
244
+
245
+ it('has setup section', () => {
246
+ const configDocId = Object.keys(repo.byFile).find(id =>
247
+ repo.byFile[id].concept.name === 'Canon SDLC'
248
+ )!;
249
+ const configDoc = repo.byFile[configDocId].concept;
250
+ expect(configDoc.setup).toBeDefined();
251
+ expect(configDoc.setup.content).toContain('6-phase');
252
+ });
253
+
254
+ it('is distinct from regular document', () => {
255
+ const configConcept = repo.concepts.find(c => c.name === 'Canon SDLC');
256
+ const modelConcept = repo.concepts.find(c => c.name === 'Prospect');
257
+ expect(configConcept!.kind).toBe('config');
258
+ expect(modelConcept!.kind).toBe('document');
259
+ });
260
+ });
261
+
262
+ describe('Graph Integrity', () => {
263
+ it('view and config appear in byId', () => {
264
+ const viewConcept = repo.concepts.find(c => c.name === 'Prospect Pipeline');
265
+ const configConcept = repo.concepts.find(c => c.name === 'Canon SDLC');
266
+ expect(repo.byId[viewConcept!.id]).toBeDefined();
267
+ expect(repo.byId[configConcept!.id]).toBeDefined();
268
+ });
269
+
270
+ it('all four document types coexist', () => {
271
+ const kinds = new Set(repo.concepts.map(c => c.kind));
272
+ expect(kinds.has('document')).toBe(true);
273
+ expect(kinds.has('view')).toBe(true);
274
+ expect(kinds.has('config')).toBe(true);
275
+ });
276
+ });
277
+ });
package/src/cli/index.ts CHANGED
@@ -352,16 +352,17 @@ const packageCmd = program
352
352
  // Package add
353
353
  packageCmd
354
354
  .command('add')
355
- .description('Add a package from URL')
356
- .argument('<url>', 'URL to the BUSY document')
355
+ .description('Add a package from URL or local folder')
356
+ .argument('<url>', 'URL or local path to the BUSY document or folder')
357
357
  .option('-d, --dir <directory>', 'Workspace directory', '.')
358
+ .option('-r, --recursive', 'Recursively add all files from a local folder')
358
359
  .action(async (url: string, options) => {
359
360
  try {
360
361
  const workspaceRoot = resolve(options.dir);
361
362
 
362
363
  console.log(`\nAdding package from: ${url}\n`);
363
364
 
364
- const result = await addPackage(workspaceRoot, url);
365
+ const result = await addPackage(workspaceRoot, url, { recursive: options.recursive });
365
366
 
366
367
  console.log(` ID: ${result.id}`);
367
368
  console.log(` Provider: ${result.provider}`);
@@ -9,7 +9,7 @@ import * as path from 'node:path';
9
9
  import { CacheManager, calculateIntegrity, deriveCachePath } from '../cache/index.js';
10
10
  import { PackageRegistry, PackageEntry, deriveEntryId, deriveCategory } from '../registry/index.js';
11
11
  import { providerRegistry } from '../providers/index.js';
12
- import { isPackageManifestUrl, fetchPackageFromManifest } from '../package/manifest.js';
12
+ import { isPackageManifestUrl, fetchPackageFromManifest, fetchPackageFromLocalFolder } from '../package/manifest.js';
13
13
 
14
14
  // Ensure providers are registered
15
15
  import '../providers/local.js';
@@ -166,12 +166,41 @@ export async function checkWorkspace(workspaceRoot: string, options?: { skipExte
166
166
  }
167
167
 
168
168
  /**
169
- * Add a package from URL
169
+ * Add a package from URL or local folder
170
170
  *
171
171
  * If the URL points to a package.busy.md manifest, fetches the entire package.
172
+ * If it's a local directory with --recursive (or without a manifest), copies all files.
172
173
  * Otherwise, fetches a single file.
173
174
  */
174
- export async function addPackage(workspaceRoot: string, url: string): Promise<AddResult> {
175
+ export async function addPackage(workspaceRoot: string, url: string, options?: { recursive?: boolean }): Promise<AddResult> {
176
+ // Check if this is a local directory that should use folder-based discovery
177
+ if (url.startsWith('./') || url.startsWith('../') || url.startsWith('/') || (!url.includes('://') && !url.startsWith('http'))) {
178
+ const resolvedPath = path.isAbsolute(url) ? url : path.resolve(process.cwd(), url);
179
+ try {
180
+ const stat = await fs.stat(resolvedPath);
181
+ if (stat.isDirectory()) {
182
+ const manifestExists = await fs.stat(path.join(resolvedPath, 'package.busy.md'))
183
+ .then(() => true).catch(() => false);
184
+
185
+ if (options?.recursive || !manifestExists) {
186
+ // Use folder-based discovery: --recursive flag or no manifest available
187
+ const result = await fetchPackageFromLocalFolder(workspaceRoot, resolvedPath);
188
+ return {
189
+ id: result.name,
190
+ source: resolvedPath,
191
+ provider: 'local',
192
+ cached: result.cached,
193
+ version: result.version,
194
+ integrity: result.integrity,
195
+ };
196
+ }
197
+ // Has manifest and not --recursive: fall through to manifest-based flow
198
+ }
199
+ } catch {
200
+ // Not a directory or doesn't exist - fall through to normal handling
201
+ }
202
+ }
203
+
175
204
  // Check if this is a package manifest URL
176
205
  if (isPackageManifestUrl(url)) {
177
206
  // Use manifest-based package installation
package/src/index.ts CHANGED
@@ -10,6 +10,9 @@ export type {
10
10
  Section,
11
11
  ConceptBase,
12
12
  BusyDocument,
13
+ Playbook,
14
+ View,
15
+ Config,
13
16
  LocalDef,
14
17
  Operation,
15
18
  ImportDef,
package/src/loader.ts CHANGED
@@ -5,6 +5,8 @@ import {
5
5
  Repo,
6
6
  BusyDocument,
7
7
  Playbook,
8
+ View,
9
+ Config,
8
10
  ConceptBase,
9
11
  LocalDef,
10
12
  Operation,
@@ -13,6 +15,13 @@ import {
13
15
  Section,
14
16
  File,
15
17
  } from './types/schema.js';
18
+
19
+ /**
20
+ * Union of all top-level document variants the loader produces.
21
+ * Note: BusyDocument covers the generic `document` kind, including plain
22
+ * Document/Model-style docs that don't get a more specific classifier.
23
+ */
24
+ type AnyDocument = BusyDocument | Playbook | View | Config;
16
25
  import { parseFrontMatter } from './parsers/frontmatter.js';
17
26
  import { parseSections, getAllSections, findSection } from './parsers/sections.js';
18
27
  import { extractLocalDefs } from './parsers/localdefs.js';
@@ -67,7 +76,7 @@ export async function loadRepo(globs: string[]): Promise<Repo> {
67
76
 
68
77
  // Second pass: parse documents
69
78
  const files: File[] = []; // Lightweight file representations
70
- const docs: (BusyDocument | Playbook)[] = []; // Full concept definitions
79
+ const docs: AnyDocument[] = []; // Full concept definitions
71
80
  const allLocaldefs = new Map<string, LocalDef>();
72
81
  const allOperations = new Map<string, Operation>();
73
82
  const allImports: ImportDef[] = [];
@@ -215,51 +224,57 @@ export async function loadRepo(globs: string[]): Promise<Repo> {
215
224
 
216
225
  // Build final document structures with inline arrays
217
226
  for (const [docId, parts] of docParts) {
218
- const isPlaybook = parts.types.some((t) => t.toLowerCase() === 'playbook');
227
+ const typesLower = parts.types.map((t) => t.toLowerCase());
228
+ const isPlaybook = typesLower.includes('playbook');
229
+ const isView = typesLower.includes('view');
230
+ const isConfig = typesLower.includes('config');
231
+
232
+ // Base fields shared across all document kinds
233
+ const baseFields = {
234
+ id: parts.docId,
235
+ docId: parts.docId,
236
+ slug: parts.docId.toLowerCase(),
237
+ name: parts.frontmatter.Name,
238
+ content: parts.content,
239
+ types: parts.types,
240
+ extends: parts.extends,
241
+ sectionRef: `${parts.docId}#`, // Root reference
242
+ imports: parts.imports,
243
+ localdefs: parts.localdefs,
244
+ setup: parts.setup!,
245
+ operations: parts.operations,
246
+ };
219
247
 
220
248
  if (isPlaybook) {
221
249
  // Extract sequence from ExecutePlaybook operation
222
250
  const sequence = extractPlaybookSequence(parts.sections);
223
-
224
- const doc: Playbook = {
225
- kind: 'playbook',
226
- id: parts.docId,
227
- docId: parts.docId,
228
- slug: parts.docId.toLowerCase(),
229
- name: parts.frontmatter.Name,
230
- content: parts.content,
231
- types: parts.types,
232
- extends: parts.extends,
233
- sectionRef: `${parts.docId}#`, // Root reference
234
- imports: parts.imports,
235
- localdefs: parts.localdefs,
236
- setup: parts.setup!,
237
- operations: parts.operations,
238
- sequence,
251
+ const doc: Playbook = { ...baseFields, kind: 'playbook', sequence };
252
+ docs.push(doc);
253
+ } else if (isView) {
254
+ // Extract template section with full content (including children)
255
+ const displaySection = findSection(parts.sections, 'display');
256
+ let displayContent: string | undefined;
257
+ if (displaySection) {
258
+ // Reconstruct full template from section + children content
259
+ displayContent = getSectionFullContent(displaySection);
260
+ }
261
+ const doc: View = {
262
+ ...baseFields,
263
+ kind: 'view',
264
+ display: displayContent,
239
265
  };
240
266
  docs.push(doc);
267
+ } else if (isConfig) {
268
+ const doc: Config = { ...baseFields, kind: 'config' };
269
+ docs.push(doc);
241
270
  } else {
242
- const doc: BusyDocument = {
243
- kind: 'document',
244
- id: parts.docId,
245
- docId: parts.docId,
246
- slug: parts.docId.toLowerCase(),
247
- name: parts.frontmatter.Name,
248
- content: parts.content,
249
- types: parts.types,
250
- extends: parts.extends,
251
- sectionRef: `${parts.docId}#`, // Root reference
252
- imports: parts.imports,
253
- localdefs: parts.localdefs,
254
- setup: parts.setup!,
255
- operations: parts.operations,
256
- };
271
+ const doc: BusyDocument = { ...baseFields, kind: 'document' };
257
272
  docs.push(doc);
258
273
  }
259
274
  }
260
275
 
261
276
  // Inherit operations from parent documents
262
- inheritOperations(docs, allOperations);
277
+ inheritOperations(docs as (BusyDocument | Playbook)[], allOperations);
263
278
 
264
279
  // Build concepts array (includes all documents as ConceptBase)
265
280
  const concepts: ConceptBase[] = docs.map((doc) => ({
@@ -306,7 +321,7 @@ export async function loadRepo(globs: string[]): Promise<Repo> {
306
321
  }
307
322
 
308
323
  // Build byFile index
309
- const byFile: Record<string, { concept: BusyDocument | Playbook; bySlug: Record<string, Section> }> = {};
324
+ const byFile: Record<string, { concept: AnyDocument; bySlug: Record<string, Section> }> = {};
310
325
 
311
326
  for (const doc of docs) {
312
327
  const bySlug: Record<string, Section> = {};
@@ -352,11 +367,11 @@ export async function loadRepo(globs: string[]): Promise<Repo> {
352
367
  * 2. Documents in the 'types' array (implicit type-based inheritance)
353
368
  */
354
369
  function inheritOperations(
355
- docs: (BusyDocument | Playbook)[],
370
+ docs: AnyDocument[],
356
371
  allOperations: Map<string, Operation>
357
372
  ): void {
358
373
  // Build doc lookup by name
359
- const docByName = new Map<string, BusyDocument | Playbook>();
374
+ const docByName = new Map<string, BusyDocument | Playbook | View | Config>();
360
375
  for (const doc of docs) {
361
376
  docByName.set(doc.name, doc);
362
377
  }
@@ -416,7 +431,7 @@ function resolveSymbol(
416
431
  nameOrLabel: string,
417
432
  currentDocId: string,
418
433
  localdefs: Map<string, LocalDef>,
419
- docs: (BusyDocument | Playbook)[],
434
+ docs: AnyDocument[],
420
435
  symbols: Record<string, { docId?: string; slug?: string }>
421
436
  ): string | undefined {
422
437
  // 1. Check for LocalDef in same doc
@@ -440,6 +455,19 @@ function resolveSymbol(
440
455
  return undefined;
441
456
  }
442
457
 
458
+ /**
459
+ * Get the full content of a section including all nested children.
460
+ * Reconstructs the original markdown by walking the section tree.
461
+ */
462
+ function getSectionFullContent(section: Section): string {
463
+ let content = section.content;
464
+ for (const child of section.children) {
465
+ const prefix = '#'.repeat(child.depth);
466
+ content += `\n${prefix} ${child.title}\n${getSectionFullContent(child)}`;
467
+ }
468
+ return content.trim();
469
+ }
470
+
443
471
  /**
444
472
  * Extract sequence of operations from a playbook's ExecutePlaybook operation
445
473
  * Looks for sections with "Step" in the title and extracts Target metadata