@fractary/faber-cli 1.1.0 → 1.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.
@@ -0,0 +1,50 @@
1
+ /**
2
+ * SDK Configuration Adapter
3
+ *
4
+ * Converts FABER CLI configuration to @fractary/core SDK configuration format
5
+ */
6
+ /**
7
+ * Create WorkConfig for WorkManager from FaberConfig
8
+ *
9
+ * @param faberConfig - FABER CLI configuration
10
+ * @returns WorkConfig for @fractary/core WorkManager
11
+ * @throws Error if required fields are missing
12
+ */
13
+ export function createWorkConfig(faberConfig) {
14
+ const token = faberConfig.github?.token;
15
+ const owner = faberConfig.github?.organization;
16
+ const repo = faberConfig.github?.project;
17
+ if (!token) {
18
+ throw new Error('GitHub token not found. Set GITHUB_TOKEN environment variable or configure in .fractary/settings.json');
19
+ }
20
+ if (!owner || !repo) {
21
+ throw new Error('GitHub organization and project must be configured in .fractary/settings.json');
22
+ }
23
+ return {
24
+ platform: 'github',
25
+ owner,
26
+ repo,
27
+ token,
28
+ };
29
+ }
30
+ /**
31
+ * Create RepoConfig for RepoManager from FaberConfig
32
+ *
33
+ * @param faberConfig - FABER CLI configuration
34
+ * @returns RepoConfig for @fractary/core RepoManager
35
+ * @throws Error if required fields are missing
36
+ */
37
+ export function createRepoConfig(faberConfig) {
38
+ const token = faberConfig.github?.token;
39
+ const owner = faberConfig.github?.organization;
40
+ const repo = faberConfig.github?.project;
41
+ if (!token) {
42
+ throw new Error('GitHub token not found. Set GITHUB_TOKEN environment variable or configure in .fractary/settings.json');
43
+ }
44
+ return {
45
+ platform: 'github',
46
+ owner,
47
+ repo,
48
+ token,
49
+ };
50
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * SDK Type Adapter
3
+ *
4
+ * Converts between @fractary/core SDK types and FABER CLI types
5
+ */
6
+ import type { Issue as SDKIssue, Worktree as SDKWorktree } from '@fractary/core';
7
+ interface CLIIssue {
8
+ id: string;
9
+ number: number;
10
+ title: string;
11
+ description: string;
12
+ labels: string[];
13
+ url: string;
14
+ state: string;
15
+ }
16
+ interface WorktreeResult {
17
+ path: string;
18
+ absolute_path: string;
19
+ branch: string;
20
+ created_at: string;
21
+ organization: string;
22
+ project: string;
23
+ work_id: string;
24
+ }
25
+ /**
26
+ * Convert SDK Issue to CLI Issue
27
+ *
28
+ * @param sdkIssue - Issue from @fractary/core SDK
29
+ * @returns CLI Issue format
30
+ */
31
+ export declare function sdkIssueToCLIIssue(sdkIssue: SDKIssue): CLIIssue;
32
+ /**
33
+ * Convert SDK Worktree to CLI WorktreeResult
34
+ *
35
+ * @param sdkWorktree - Worktree from @fractary/core SDK
36
+ * @param organization - GitHub organization
37
+ * @param project - GitHub project/repo name
38
+ * @param workId - Work/issue ID
39
+ * @returns CLI WorktreeResult format
40
+ */
41
+ export declare function sdkWorktreeToCLIWorktreeResult(sdkWorktree: SDKWorktree, organization: string, project: string, workId: string): WorktreeResult;
42
+ export {};
43
+ //# sourceMappingURL=sdk-type-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdk-type-adapter.d.ts","sourceRoot":"","sources":["../../src/lib/sdk-type-adapter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,KAAK,IAAI,QAAQ,EAAE,QAAQ,IAAI,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAGjF,UAAU,QAAQ;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,GAAG,QAAQ,CAU/D;AAED;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAC5C,WAAW,EAAE,WAAW,EACxB,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACb,cAAc,CAUhB"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * SDK Type Adapter
3
+ *
4
+ * Converts between @fractary/core SDK types and FABER CLI types
5
+ */
6
+ /**
7
+ * Convert SDK Issue to CLI Issue
8
+ *
9
+ * @param sdkIssue - Issue from @fractary/core SDK
10
+ * @returns CLI Issue format
11
+ */
12
+ export function sdkIssueToCLIIssue(sdkIssue) {
13
+ return {
14
+ id: sdkIssue.id,
15
+ number: sdkIssue.number,
16
+ title: sdkIssue.title,
17
+ description: sdkIssue.body, // Map 'body' to 'description'
18
+ labels: sdkIssue.labels.map(label => label.name), // Extract label names
19
+ url: sdkIssue.url,
20
+ state: sdkIssue.state,
21
+ };
22
+ }
23
+ /**
24
+ * Convert SDK Worktree to CLI WorktreeResult
25
+ *
26
+ * @param sdkWorktree - Worktree from @fractary/core SDK
27
+ * @param organization - GitHub organization
28
+ * @param project - GitHub project/repo name
29
+ * @param workId - Work/issue ID
30
+ * @returns CLI WorktreeResult format
31
+ */
32
+ export function sdkWorktreeToCLIWorktreeResult(sdkWorktree, organization, project, workId) {
33
+ return {
34
+ path: sdkWorktree.path,
35
+ absolute_path: sdkWorktree.path, // SDK path is already absolute
36
+ branch: sdkWorktree.branch || '',
37
+ created_at: new Date().toISOString(),
38
+ organization,
39
+ project,
40
+ work_id: workId,
41
+ };
42
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * FABER CLI Configuration Types
3
+ *
4
+ * Type definitions for configuration objects
5
+ */
6
+ export interface AnthropicConfig {
7
+ api_key?: string;
8
+ }
9
+ export interface GitHubConfig {
10
+ token?: string;
11
+ organization?: string;
12
+ project?: string;
13
+ repo?: string;
14
+ }
15
+ export interface WorktreeConfig {
16
+ location?: string;
17
+ inherit_from_claude?: boolean;
18
+ }
19
+ export interface WorkflowConfig {
20
+ default?: string;
21
+ config_path?: string;
22
+ }
23
+ export interface FaberConfig {
24
+ anthropic?: AnthropicConfig;
25
+ github?: GitHubConfig;
26
+ worktree?: WorktreeConfig;
27
+ workflow?: WorkflowConfig;
28
+ }
29
+ export interface ClaudeConfig {
30
+ worktree?: {
31
+ directory?: string;
32
+ };
33
+ }
34
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/types/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE;QACT,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;CACH"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * FABER CLI Configuration Types
3
+ *
4
+ * Type definitions for configuration objects
5
+ */
6
+ export {};
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Simple prompt utility for CLI input
3
+ */
4
+ /**
5
+ * Prompt user for input
6
+ */
7
+ export declare function prompt(question: string): Promise<string>;
8
+ //# sourceMappingURL=prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/utils/prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;GAEG;AACH,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAYxD"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Simple prompt utility for CLI input
3
+ */
4
+ import * as readline from 'readline';
5
+ /**
6
+ * Prompt user for input
7
+ */
8
+ export function prompt(question) {
9
+ const rl = readline.createInterface({
10
+ input: process.stdin,
11
+ output: process.stdout,
12
+ });
13
+ return new Promise((resolve) => {
14
+ rl.question(question, (answer) => {
15
+ rl.close();
16
+ resolve(answer.trim());
17
+ });
18
+ });
19
+ }
@@ -27,4 +27,75 @@ export declare function parseOptionalInteger(value: string | undefined, fieldNam
27
27
  * @throws Error if value is not a valid positive integer
28
28
  */
29
29
  export declare function parsePositiveInteger(value: string, fieldName: string): number;
30
+ /**
31
+ * Validates work ID format
32
+ * Work IDs must be numeric (GitHub issue numbers)
33
+ *
34
+ * @param workId - Work ID to validate
35
+ * @returns True if valid
36
+ * @throws Error if invalid
37
+ */
38
+ export declare function validateWorkId(workId: string): boolean;
39
+ /**
40
+ * Validates multiple comma-separated work IDs
41
+ *
42
+ * @param workIds - Comma-separated work IDs
43
+ * @returns Array of validated work IDs
44
+ * @throws Error if any ID is invalid
45
+ */
46
+ export declare function validateWorkIds(workIds: string): string[];
47
+ /**
48
+ * Validates label format
49
+ * Labels must be alphanumeric with hyphens, colons, and underscores only
50
+ *
51
+ * @param label - Label to validate
52
+ * @returns True if valid
53
+ * @throws Error if invalid
54
+ */
55
+ export declare function validateLabel(label: string): boolean;
56
+ /**
57
+ * Validates multiple comma-separated labels
58
+ *
59
+ * @param labels - Comma-separated labels
60
+ * @returns Array of validated labels
61
+ * @throws Error if any label is invalid
62
+ */
63
+ export declare function validateLabels(labels: string): string[];
64
+ /**
65
+ * Validates workflow name format
66
+ * Workflow names must be alphanumeric with hyphens and underscores
67
+ *
68
+ * @param workflowName - Workflow name to validate
69
+ * @returns True if valid
70
+ * @throws Error if invalid
71
+ */
72
+ export declare function validateWorkflowName(workflowName: string): boolean;
73
+ /**
74
+ * Validates and sanitizes file path to prevent path traversal
75
+ * Ensures path doesn't contain dangerous patterns like ../, absolute paths, etc.
76
+ *
77
+ * @param filePath - File path to validate
78
+ * @param baseDir - Base directory that path must be relative to (optional)
79
+ * @returns Sanitized path
80
+ * @throws Error if path is unsafe
81
+ */
82
+ export declare function validateSafePath(filePath: string, baseDir?: string): string;
83
+ /**
84
+ * Validates JSON response size to prevent DoS attacks
85
+ *
86
+ * @param jsonString - JSON string to validate
87
+ * @param maxSizeBytes - Maximum allowed size in bytes (default: 1MB)
88
+ * @returns True if valid
89
+ * @throws Error if too large
90
+ */
91
+ export declare function validateJsonSize(jsonString: string, maxSizeBytes?: number): boolean;
92
+ /**
93
+ * Validates plan ID format
94
+ * Plan IDs follow format: fractary-faber-{work-id}-{YYYYMMDD}-{HHMMSS}
95
+ *
96
+ * @param planId - Plan ID to validate
97
+ * @returns True if valid
98
+ * @throws Error if invalid
99
+ */
100
+ export declare function validatePlanId(planId: string): boolean;
30
101
  //# sourceMappingURL=validation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAY1E;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAMrG;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAQ7E"}
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAY1E;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAMrG;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAQ7E;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAWtD;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAiBzD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAYpD;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAiBvD;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAYlE;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAoC3E;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,GAAE,MAAoB,GAAG,OAAO,CAYhG;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAUtD"}
@@ -47,3 +47,160 @@ export function parsePositiveInteger(value, fieldName) {
47
47
  }
48
48
  return parsed;
49
49
  }
50
+ /**
51
+ * Validates work ID format
52
+ * Work IDs must be numeric (GitHub issue numbers)
53
+ *
54
+ * @param workId - Work ID to validate
55
+ * @returns True if valid
56
+ * @throws Error if invalid
57
+ */
58
+ export function validateWorkId(workId) {
59
+ // Work IDs must be numeric (1-8 digits for GitHub issue numbers)
60
+ const workIdPattern = /^\d{1,8}$/;
61
+ if (!workIdPattern.test(workId)) {
62
+ throw new Error(`Invalid work ID format: "${workId}". Work IDs must be numeric (e.g., "123", "456").`);
63
+ }
64
+ return true;
65
+ }
66
+ /**
67
+ * Validates multiple comma-separated work IDs
68
+ *
69
+ * @param workIds - Comma-separated work IDs
70
+ * @returns Array of validated work IDs
71
+ * @throws Error if any ID is invalid
72
+ */
73
+ export function validateWorkIds(workIds) {
74
+ const ids = workIds.split(',').map(id => id.trim()).filter(Boolean);
75
+ if (ids.length === 0) {
76
+ throw new Error('No work IDs provided');
77
+ }
78
+ if (ids.length > 50) {
79
+ throw new Error(`Too many work IDs (${ids.length}). Maximum is 50 to prevent API overload.`);
80
+ }
81
+ // Validate each ID
82
+ ids.forEach(id => validateWorkId(id));
83
+ return ids;
84
+ }
85
+ /**
86
+ * Validates label format
87
+ * Labels must be alphanumeric with hyphens, colons, and underscores only
88
+ *
89
+ * @param label - Label to validate
90
+ * @returns True if valid
91
+ * @throws Error if invalid
92
+ */
93
+ export function validateLabel(label) {
94
+ // Labels: alphanumeric, hyphens, colons, underscores (GitHub label format)
95
+ // Examples: "workflow:etl", "status:approved", "priority-high"
96
+ const labelPattern = /^[a-zA-Z0-9_:-]{1,50}$/;
97
+ if (!labelPattern.test(label)) {
98
+ throw new Error(`Invalid label format: "${label}". Labels must be alphanumeric with hyphens, colons, or underscores (max 50 chars).`);
99
+ }
100
+ return true;
101
+ }
102
+ /**
103
+ * Validates multiple comma-separated labels
104
+ *
105
+ * @param labels - Comma-separated labels
106
+ * @returns Array of validated labels
107
+ * @throws Error if any label is invalid
108
+ */
109
+ export function validateLabels(labels) {
110
+ const labelArray = labels.split(',').map(l => l.trim()).filter(Boolean);
111
+ if (labelArray.length === 0) {
112
+ throw new Error('No labels provided');
113
+ }
114
+ if (labelArray.length > 20) {
115
+ throw new Error(`Too many labels (${labelArray.length}). Maximum is 20.`);
116
+ }
117
+ // Validate each label
118
+ labelArray.forEach(label => validateLabel(label));
119
+ return labelArray;
120
+ }
121
+ /**
122
+ * Validates workflow name format
123
+ * Workflow names must be alphanumeric with hyphens and underscores
124
+ *
125
+ * @param workflowName - Workflow name to validate
126
+ * @returns True if valid
127
+ * @throws Error if invalid
128
+ */
129
+ export function validateWorkflowName(workflowName) {
130
+ // Workflow names: alphanumeric, hyphens, underscores
131
+ // Examples: "etl", "data-pipeline", "bugfix"
132
+ const workflowPattern = /^[a-zA-Z0-9_-]{1,50}$/;
133
+ if (!workflowPattern.test(workflowName)) {
134
+ throw new Error(`Invalid workflow name: "${workflowName}". Workflow names must be alphanumeric with hyphens or underscores (max 50 chars).`);
135
+ }
136
+ return true;
137
+ }
138
+ /**
139
+ * Validates and sanitizes file path to prevent path traversal
140
+ * Ensures path doesn't contain dangerous patterns like ../, absolute paths, etc.
141
+ *
142
+ * @param filePath - File path to validate
143
+ * @param baseDir - Base directory that path must be relative to (optional)
144
+ * @returns Sanitized path
145
+ * @throws Error if path is unsafe
146
+ */
147
+ export function validateSafePath(filePath, baseDir) {
148
+ // Remove any null bytes
149
+ if (filePath.includes('\0')) {
150
+ throw new Error('Path contains null bytes');
151
+ }
152
+ // Check for path traversal patterns
153
+ const dangerousPatterns = [
154
+ /\.\./, // Parent directory (..)
155
+ /^\//, // Absolute path
156
+ /^[a-zA-Z]:\\/, // Windows absolute path
157
+ /^~\//, // Home directory
158
+ ];
159
+ for (const pattern of dangerousPatterns) {
160
+ if (pattern.test(filePath)) {
161
+ throw new Error(`Unsafe path detected: "${filePath}". Paths must be relative and cannot contain "..", absolute paths, or home directory references.`);
162
+ }
163
+ }
164
+ // Normalize path (remove redundant separators, etc.)
165
+ const normalized = filePath.replace(/\/+/g, '/').replace(/\\/g, '/');
166
+ // If base directory provided, ensure path starts with it
167
+ if (baseDir) {
168
+ const normalizedBase = baseDir.replace(/\/+$/, '');
169
+ if (!normalized.startsWith(normalizedBase)) {
170
+ throw new Error(`Path "${filePath}" must be within base directory "${baseDir}"`);
171
+ }
172
+ }
173
+ return normalized;
174
+ }
175
+ /**
176
+ * Validates JSON response size to prevent DoS attacks
177
+ *
178
+ * @param jsonString - JSON string to validate
179
+ * @param maxSizeBytes - Maximum allowed size in bytes (default: 1MB)
180
+ * @returns True if valid
181
+ * @throws Error if too large
182
+ */
183
+ export function validateJsonSize(jsonString, maxSizeBytes = 1024 * 1024) {
184
+ const sizeBytes = Buffer.byteLength(jsonString, 'utf8');
185
+ if (sizeBytes > maxSizeBytes) {
186
+ const sizeMB = (sizeBytes / 1024 / 1024).toFixed(2);
187
+ const maxMB = (maxSizeBytes / 1024 / 1024).toFixed(2);
188
+ throw new Error(`JSON response too large: ${sizeMB}MB (maximum: ${maxMB}MB). This may indicate an API error or DoS attempt.`);
189
+ }
190
+ return true;
191
+ }
192
+ /**
193
+ * Validates plan ID format
194
+ * Plan IDs follow format: fractary-faber-{work-id}-{YYYYMMDD}-{HHMMSS}
195
+ *
196
+ * @param planId - Plan ID to validate
197
+ * @returns True if valid
198
+ * @throws Error if invalid
199
+ */
200
+ export function validatePlanId(planId) {
201
+ const planIdPattern = /^fractary-faber-\d+-\d{8}-\d{6}$/;
202
+ if (!planIdPattern.test(planId)) {
203
+ throw new Error(`Invalid plan ID format: "${planId}". Expected format: fractary-faber-{work-id}-{YYYYMMDD}-{HHMMSS}`);
204
+ }
205
+ return true;
206
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fractary/faber-cli",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "description": "FABER CLI - Command-line interface for FABER development toolkit",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -36,6 +36,7 @@
36
36
  "access": "public"
37
37
  },
38
38
  "dependencies": {
39
+ "@fractary/core": "^0.2.0",
39
40
  "@fractary/faber": "*",
40
41
  "chalk": "^5.0.0",
41
42
  "commander": "^12.0.0"