task-o-matic 0.0.13 → 0.0.14
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/dist/commands/init.js +41 -8
- package/dist/commands/tasks/document/add.js +3 -3
- package/dist/commands/tasks/list.js +2 -2
- package/dist/commands/tasks/next.js +4 -4
- package/dist/commands/tasks/status.js +2 -2
- package/dist/lib/ai-service/ai-operations.d.ts +1 -1
- package/dist/lib/ai-service/ai-operations.d.ts.map +1 -1
- package/dist/lib/ai-service/base-operations.d.ts +22 -0
- package/dist/lib/ai-service/base-operations.d.ts.map +1 -1
- package/dist/lib/ai-service/base-operations.js +29 -1
- package/dist/lib/ai-service/task-operations.d.ts +1 -1
- package/dist/lib/ai-service/task-operations.d.ts.map +1 -1
- package/dist/lib/better-t-stack-cli.d.ts +36 -21
- package/dist/lib/better-t-stack-cli.d.ts.map +1 -1
- package/dist/lib/better-t-stack-cli.js +212 -33
- package/dist/lib/bootstrap/cli-bootstrap.d.ts +14 -0
- package/dist/lib/bootstrap/cli-bootstrap.d.ts.map +1 -0
- package/dist/lib/bootstrap/cli-bootstrap.js +325 -0
- package/dist/lib/bootstrap/index.d.ts +4 -0
- package/dist/lib/bootstrap/index.d.ts.map +1 -0
- package/dist/lib/bootstrap/index.js +19 -0
- package/dist/lib/bootstrap/medusa-bootstrap.d.ts +14 -0
- package/dist/lib/bootstrap/medusa-bootstrap.d.ts.map +1 -0
- package/dist/lib/bootstrap/medusa-bootstrap.js +218 -0
- package/dist/lib/bootstrap/opentui-bootstrap.d.ts +11 -0
- package/dist/lib/bootstrap/opentui-bootstrap.d.ts.map +1 -0
- package/dist/lib/bootstrap/opentui-bootstrap.js +342 -0
- package/dist/lib/config.d.ts +14 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +18 -0
- package/dist/services/prd.d.ts.map +1 -1
- package/dist/services/prd.js +18 -45
- package/dist/services/tasks.d.ts +2 -2
- package/dist/services/tasks.d.ts.map +1 -1
- package/dist/services/tasks.js +55 -85
- package/dist/types/index.d.ts +36 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/results.d.ts +60 -6
- package/dist/types/results.d.ts.map +1 -1
- package/dist/utils/error-utils.d.ts +70 -0
- package/dist/utils/error-utils.d.ts.map +1 -0
- package/dist/utils/error-utils.js +103 -0
- package/dist/utils/file-utils.d.ts +49 -0
- package/dist/utils/file-utils.d.ts.map +1 -0
- package/dist/utils/file-utils.js +77 -0
- package/dist/utils/id-generator.d.ts +92 -0
- package/dist/utils/id-generator.d.ts.map +1 -0
- package/dist/utils/id-generator.js +140 -0
- package/dist/utils/stack-formatter.d.ts +2 -1
- package/dist/utils/stack-formatter.d.ts.map +1 -1
- package/dist/utils/stack-formatter.js +8 -2
- package/dist/utils/storage-utils.d.ts +49 -0
- package/dist/utils/storage-utils.d.ts.map +1 -0
- package/dist/utils/storage-utils.js +79 -0
- package/dist/utils/streaming-utils.d.ts +38 -0
- package/dist/utils/streaming-utils.d.ts.map +1 -0
- package/dist/utils/streaming-utils.js +56 -0
- package/docs/agents/cli.md +58 -149
- package/package.json +1 -1
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validates that a file exists at the given path (synchronous).
|
|
3
|
+
* Throws an error with a custom message if the file doesn't exist.
|
|
4
|
+
*
|
|
5
|
+
* @param filePath - Path to the file to validate
|
|
6
|
+
* @param customMessage - Optional custom error message
|
|
7
|
+
* @throws Error if file doesn't exist
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* validateFileExists("./config.json", "Configuration file not found");
|
|
12
|
+
* // Throws: Error("Configuration file not found") if file doesn't exist
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare function validateFileExists(filePath: string, customMessage?: string): void;
|
|
16
|
+
/**
|
|
17
|
+
* Validates that a file exists at the given path (asynchronous).
|
|
18
|
+
* Throws an error with a custom message if the file doesn't exist.
|
|
19
|
+
*
|
|
20
|
+
* @param filePath - Path to the file to validate
|
|
21
|
+
* @param customMessage - Optional custom error message
|
|
22
|
+
* @throws Error if file doesn't exist
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* await validateFileExistsAsync("./data.json");
|
|
27
|
+
* // Throws: Error("File not found: ./data.json") if file doesn't exist
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare function validateFileExistsAsync(filePath: string, customMessage?: string): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Checks if a file exists at the given path (synchronous).
|
|
33
|
+
* Returns true if file exists, false otherwise.
|
|
34
|
+
* Unlike validateFileExists, this doesn't throw an error.
|
|
35
|
+
*
|
|
36
|
+
* @param filePath - Path to check
|
|
37
|
+
* @returns true if file exists, false otherwise
|
|
38
|
+
*/
|
|
39
|
+
export declare function fileExists(filePath: string): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Checks if a file exists at the given path (asynchronous).
|
|
42
|
+
* Returns true if file exists, false otherwise.
|
|
43
|
+
* Unlike validateFileExistsAsync, this doesn't throw an error.
|
|
44
|
+
*
|
|
45
|
+
* @param filePath - Path to check
|
|
46
|
+
* @returns Promise resolving to true if file exists, false otherwise
|
|
47
|
+
*/
|
|
48
|
+
export declare function fileExistsAsync(filePath: string): Promise<boolean>;
|
|
49
|
+
//# sourceMappingURL=file-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-utils.d.ts","sourceRoot":"","sources":["../../src/utils/file-utils.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,aAAa,CAAC,EAAE,MAAM,GACrB,IAAI,CAIN;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,IAAI,CAAC,CAMf;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOxE"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateFileExists = validateFileExists;
|
|
4
|
+
exports.validateFileExistsAsync = validateFileExistsAsync;
|
|
5
|
+
exports.fileExists = fileExists;
|
|
6
|
+
exports.fileExistsAsync = fileExistsAsync;
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
const promises_1 = require("fs/promises");
|
|
9
|
+
/**
|
|
10
|
+
* Validates that a file exists at the given path (synchronous).
|
|
11
|
+
* Throws an error with a custom message if the file doesn't exist.
|
|
12
|
+
*
|
|
13
|
+
* @param filePath - Path to the file to validate
|
|
14
|
+
* @param customMessage - Optional custom error message
|
|
15
|
+
* @throws Error if file doesn't exist
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* validateFileExists("./config.json", "Configuration file not found");
|
|
20
|
+
* // Throws: Error("Configuration file not found") if file doesn't exist
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
function validateFileExists(filePath, customMessage) {
|
|
24
|
+
if (!(0, fs_1.existsSync)(filePath)) {
|
|
25
|
+
throw new Error(customMessage || `File not found: ${filePath}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Validates that a file exists at the given path (asynchronous).
|
|
30
|
+
* Throws an error with a custom message if the file doesn't exist.
|
|
31
|
+
*
|
|
32
|
+
* @param filePath - Path to the file to validate
|
|
33
|
+
* @param customMessage - Optional custom error message
|
|
34
|
+
* @throws Error if file doesn't exist
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* await validateFileExistsAsync("./data.json");
|
|
39
|
+
* // Throws: Error("File not found: ./data.json") if file doesn't exist
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
async function validateFileExistsAsync(filePath, customMessage) {
|
|
43
|
+
try {
|
|
44
|
+
await (0, promises_1.access)(filePath, promises_1.constants.F_OK);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
throw new Error(customMessage || `File not found: ${filePath}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Checks if a file exists at the given path (synchronous).
|
|
52
|
+
* Returns true if file exists, false otherwise.
|
|
53
|
+
* Unlike validateFileExists, this doesn't throw an error.
|
|
54
|
+
*
|
|
55
|
+
* @param filePath - Path to check
|
|
56
|
+
* @returns true if file exists, false otherwise
|
|
57
|
+
*/
|
|
58
|
+
function fileExists(filePath) {
|
|
59
|
+
return (0, fs_1.existsSync)(filePath);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Checks if a file exists at the given path (asynchronous).
|
|
63
|
+
* Returns true if file exists, false otherwise.
|
|
64
|
+
* Unlike validateFileExistsAsync, this doesn't throw an error.
|
|
65
|
+
*
|
|
66
|
+
* @param filePath - Path to check
|
|
67
|
+
* @returns Promise resolving to true if file exists, false otherwise
|
|
68
|
+
*/
|
|
69
|
+
async function fileExistsAsync(filePath) {
|
|
70
|
+
try {
|
|
71
|
+
await (0, promises_1.access)(filePath, promises_1.constants.F_OK);
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates unique task IDs with consistent format.
|
|
3
|
+
* Uses timestamp + random hex for uniqueness.
|
|
4
|
+
*/
|
|
5
|
+
export declare class TaskIDGenerator {
|
|
6
|
+
/**
|
|
7
|
+
* Generates a unique task ID with format: prefix-timestamp-random
|
|
8
|
+
*
|
|
9
|
+
* @param prefix - Prefix for the ID (default: "task")
|
|
10
|
+
* @returns Unique task ID
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const id = TaskIDGenerator.generate();
|
|
15
|
+
* // Returns: "task-1733750400000-a1b2c3d4"
|
|
16
|
+
*
|
|
17
|
+
* const customId = TaskIDGenerator.generate("subtask");
|
|
18
|
+
* // Returns: "subtask-1733750400000-e5f6g7h8"
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
static generate(prefix?: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Validates a task ID format.
|
|
24
|
+
* Accepts three formats:
|
|
25
|
+
* - Timestamped: "task-1234567890-abcd1234"
|
|
26
|
+
* - Hierarchical: "1.2.3"
|
|
27
|
+
* - Numeric: "123"
|
|
28
|
+
*
|
|
29
|
+
* @param id - Task ID to validate
|
|
30
|
+
* @returns true if ID format is valid
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* TaskIDGenerator.validate("task-1234-abcd"); // true
|
|
35
|
+
* TaskIDGenerator.validate("1.2.3"); // true
|
|
36
|
+
* TaskIDGenerator.validate("123"); // true
|
|
37
|
+
* TaskIDGenerator.validate("invalid!"); // false
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
static validate(id: string): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Checks if an ID is unique within a set of existing IDs.
|
|
43
|
+
*
|
|
44
|
+
* @param id - ID to check
|
|
45
|
+
* @param existingIds - Set of existing IDs
|
|
46
|
+
* @returns true if ID is unique
|
|
47
|
+
*/
|
|
48
|
+
static isUnique(id: string, existingIds: Set<string>): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Generates a unique ID that doesn't exist in the provided set.
|
|
51
|
+
* Retries up to maxAttempts times if collisions occur.
|
|
52
|
+
*
|
|
53
|
+
* @param existingIds - Set of existing IDs to avoid
|
|
54
|
+
* @param prefix - Prefix for the ID
|
|
55
|
+
* @param maxAttempts - Maximum number of generation attempts
|
|
56
|
+
* @returns Unique task ID
|
|
57
|
+
* @throws Error if unable to generate unique ID after maxAttempts
|
|
58
|
+
*/
|
|
59
|
+
static generateUnique(existingIds: Set<string>, prefix?: string, maxAttempts?: number): string;
|
|
60
|
+
/**
|
|
61
|
+
* Generates a hierarchical child ID from a parent ID.
|
|
62
|
+
* If parent is "1.2", generates "1.2.1", "1.2.2", etc.
|
|
63
|
+
*
|
|
64
|
+
* @param parentId - Parent task ID
|
|
65
|
+
* @param childIndex - Index of the child (1-based)
|
|
66
|
+
* @returns Child task ID
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* TaskIDGenerator.generateChildId("1", 1); // "1.1"
|
|
71
|
+
* TaskIDGenerator.generateChildId("1.2", 3); // "1.2.3"
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
static generateChildId(parentId: string, childIndex: number): string;
|
|
75
|
+
/**
|
|
76
|
+
* Parses a hierarchical ID to extract parent ID and child index.
|
|
77
|
+
*
|
|
78
|
+
* @param id - Hierarchical task ID
|
|
79
|
+
* @returns Object with parentId and childIndex, or null if not hierarchical
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```typescript
|
|
83
|
+
* TaskIDGenerator.parseHierarchicalId("1.2.3");
|
|
84
|
+
* // Returns: { parentId: "1.2", childIndex: 3 }
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
static parseHierarchicalId(id: string): {
|
|
88
|
+
parentId: string;
|
|
89
|
+
childIndex: number;
|
|
90
|
+
} | null;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=id-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"id-generator.d.ts","sourceRoot":"","sources":["../../src/utils/id-generator.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,qBAAa,eAAe;IAC1B;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAE,MAAe,GAAG,MAAM;IAMhD;;;;;;;;;;;;;;;;;OAiBG;IACH,MAAM,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IA0BpC;;;;;;OAMG;IACH,MAAM,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,OAAO;IAI9D;;;;;;;;;OASG;IACH,MAAM,CAAC,cAAc,CACnB,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EACxB,MAAM,GAAE,MAAe,EACvB,WAAW,GAAE,MAAW,GACvB,MAAM;IAaT;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM;IAIpE;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,mBAAmB,CACxB,EAAE,EAAE,MAAM,GACT;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;CAcnD"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TaskIDGenerator = void 0;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
5
|
+
/**
|
|
6
|
+
* Generates unique task IDs with consistent format.
|
|
7
|
+
* Uses timestamp + random hex for uniqueness.
|
|
8
|
+
*/
|
|
9
|
+
class TaskIDGenerator {
|
|
10
|
+
/**
|
|
11
|
+
* Generates a unique task ID with format: prefix-timestamp-random
|
|
12
|
+
*
|
|
13
|
+
* @param prefix - Prefix for the ID (default: "task")
|
|
14
|
+
* @returns Unique task ID
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const id = TaskIDGenerator.generate();
|
|
19
|
+
* // Returns: "task-1733750400000-a1b2c3d4"
|
|
20
|
+
*
|
|
21
|
+
* const customId = TaskIDGenerator.generate("subtask");
|
|
22
|
+
* // Returns: "subtask-1733750400000-e5f6g7h8"
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
static generate(prefix = "task") {
|
|
26
|
+
const timestamp = Date.now();
|
|
27
|
+
const random = (0, crypto_1.randomBytes)(4).toString("hex");
|
|
28
|
+
return `${prefix}-${timestamp}-${random}`;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Validates a task ID format.
|
|
32
|
+
* Accepts three formats:
|
|
33
|
+
* - Timestamped: "task-1234567890-abcd1234"
|
|
34
|
+
* - Hierarchical: "1.2.3"
|
|
35
|
+
* - Numeric: "123"
|
|
36
|
+
*
|
|
37
|
+
* @param id - Task ID to validate
|
|
38
|
+
* @returns true if ID format is valid
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```typescript
|
|
42
|
+
* TaskIDGenerator.validate("task-1234-abcd"); // true
|
|
43
|
+
* TaskIDGenerator.validate("1.2.3"); // true
|
|
44
|
+
* TaskIDGenerator.validate("123"); // true
|
|
45
|
+
* TaskIDGenerator.validate("invalid!"); // false
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
static validate(id) {
|
|
49
|
+
if (!id || typeof id !== "string") {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
// Format 1: Timestamped (task-timestamp-random)
|
|
53
|
+
const timestampedPattern = /^[a-z]+-\d+-[a-f0-9]{8}$/;
|
|
54
|
+
if (timestampedPattern.test(id)) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
// Format 2: Hierarchical (1.2.3)
|
|
58
|
+
const hierarchicalPattern = /^[\d.]+$/;
|
|
59
|
+
if (hierarchicalPattern.test(id)) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
// Format 3: Numeric (123)
|
|
63
|
+
const numericPattern = /^\d+$/;
|
|
64
|
+
if (numericPattern.test(id)) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Checks if an ID is unique within a set of existing IDs.
|
|
71
|
+
*
|
|
72
|
+
* @param id - ID to check
|
|
73
|
+
* @param existingIds - Set of existing IDs
|
|
74
|
+
* @returns true if ID is unique
|
|
75
|
+
*/
|
|
76
|
+
static isUnique(id, existingIds) {
|
|
77
|
+
return !existingIds.has(id);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Generates a unique ID that doesn't exist in the provided set.
|
|
81
|
+
* Retries up to maxAttempts times if collisions occur.
|
|
82
|
+
*
|
|
83
|
+
* @param existingIds - Set of existing IDs to avoid
|
|
84
|
+
* @param prefix - Prefix for the ID
|
|
85
|
+
* @param maxAttempts - Maximum number of generation attempts
|
|
86
|
+
* @returns Unique task ID
|
|
87
|
+
* @throws Error if unable to generate unique ID after maxAttempts
|
|
88
|
+
*/
|
|
89
|
+
static generateUnique(existingIds, prefix = "task", maxAttempts = 10) {
|
|
90
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
91
|
+
const id = this.generate(prefix);
|
|
92
|
+
if (this.isUnique(id, existingIds)) {
|
|
93
|
+
return id;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
throw new Error(`Failed to generate unique ID after ${maxAttempts} attempts`);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Generates a hierarchical child ID from a parent ID.
|
|
100
|
+
* If parent is "1.2", generates "1.2.1", "1.2.2", etc.
|
|
101
|
+
*
|
|
102
|
+
* @param parentId - Parent task ID
|
|
103
|
+
* @param childIndex - Index of the child (1-based)
|
|
104
|
+
* @returns Child task ID
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```typescript
|
|
108
|
+
* TaskIDGenerator.generateChildId("1", 1); // "1.1"
|
|
109
|
+
* TaskIDGenerator.generateChildId("1.2", 3); // "1.2.3"
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
static generateChildId(parentId, childIndex) {
|
|
113
|
+
return `${parentId}.${childIndex}`;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Parses a hierarchical ID to extract parent ID and child index.
|
|
117
|
+
*
|
|
118
|
+
* @param id - Hierarchical task ID
|
|
119
|
+
* @returns Object with parentId and childIndex, or null if not hierarchical
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```typescript
|
|
123
|
+
* TaskIDGenerator.parseHierarchicalId("1.2.3");
|
|
124
|
+
* // Returns: { parentId: "1.2", childIndex: 3 }
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
static parseHierarchicalId(id) {
|
|
128
|
+
const parts = id.split(".");
|
|
129
|
+
if (parts.length < 2) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
const childIndex = parseInt(parts[parts.length - 1], 10);
|
|
133
|
+
if (isNaN(childIndex)) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
const parentId = parts.slice(0, -1).join(".");
|
|
137
|
+
return { parentId, childIndex };
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
exports.TaskIDGenerator = TaskIDGenerator;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stack-formatter.d.ts","sourceRoot":"","sources":["../../src/utils/stack-formatter.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"stack-formatter.d.ts","sourceRoot":"","sources":["../../src/utils/stack-formatter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,WAAW,GAAG,WAAW,EAAE,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CA6B3E;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAUjF"}
|
|
@@ -6,8 +6,11 @@ function formatStackInfo(stack) {
|
|
|
6
6
|
if (!stack) {
|
|
7
7
|
return "Not detected";
|
|
8
8
|
}
|
|
9
|
+
const frontendStr = Array.isArray(stack.frontend)
|
|
10
|
+
? stack.frontend.join(", ")
|
|
11
|
+
: stack.frontend;
|
|
9
12
|
const parts = [
|
|
10
|
-
`Frontend: ${
|
|
13
|
+
`Frontend: ${frontendStr}`,
|
|
11
14
|
`Backend: ${stack.backend}`
|
|
12
15
|
];
|
|
13
16
|
if (stack.database !== 'none') {
|
|
@@ -26,5 +29,8 @@ function formatStackForContext(stack) {
|
|
|
26
29
|
if (!stack) {
|
|
27
30
|
return "";
|
|
28
31
|
}
|
|
29
|
-
|
|
32
|
+
const frontendStr = Array.isArray(stack.frontend)
|
|
33
|
+
? stack.frontend.join(" + ")
|
|
34
|
+
: stack.frontend;
|
|
35
|
+
return `Technology Stack: ${frontendStr} + ${stack.backend} + ${stack.database}`;
|
|
30
36
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Task } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Ensures a task is not null, throwing an error if it is.
|
|
4
|
+
* Useful for enforcing null checks after storage operations.
|
|
5
|
+
*
|
|
6
|
+
* @param task - Task that may be null
|
|
7
|
+
* @param taskId - ID of the task for error message
|
|
8
|
+
* @returns The task if not null
|
|
9
|
+
* @throws Error if task is null
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const task = await storage.getTask(taskId);
|
|
14
|
+
* const validTask = requireTask(task, taskId);
|
|
15
|
+
* console.log(validTask.title); // Safe - never null
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare function requireTask(task: Task | null, taskId: string): Task;
|
|
19
|
+
/**
|
|
20
|
+
* Ensures multiple tasks are not null, throwing an error if any is null.
|
|
21
|
+
*
|
|
22
|
+
* @param tasks - Array of tasks that may contain nulls
|
|
23
|
+
* @param context - Context for error message (e.g., "subtasks", "dependencies")
|
|
24
|
+
* @returns Array of tasks with nulls filtered out
|
|
25
|
+
* @throws Error if any task is null
|
|
26
|
+
*/
|
|
27
|
+
export declare function requireTasks(tasks: (Task | null)[], context?: string): Task[];
|
|
28
|
+
/**
|
|
29
|
+
* Filters out null tasks from an array, with type narrowing.
|
|
30
|
+
*
|
|
31
|
+
* @param tasks - Array of tasks that may contain nulls
|
|
32
|
+
* @returns Array of tasks with nulls removed
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* const tasks = await Promise.all(ids.map(id => storage.getTask(id)));
|
|
37
|
+
* const validTasks = filterNullTasks(tasks);
|
|
38
|
+
* // validTasks has type Task[] (no null)
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export declare function filterNullTasks(tasks: (Task | null)[]): Task[];
|
|
42
|
+
/**
|
|
43
|
+
* Validates that a task ID is a non-empty string.
|
|
44
|
+
*
|
|
45
|
+
* @param taskId - Task ID to validate
|
|
46
|
+
* @throws Error if task ID is invalid
|
|
47
|
+
*/
|
|
48
|
+
export declare function validateTaskId(taskId: string): void;
|
|
49
|
+
//# sourceMappingURL=storage-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-utils.d.ts","sourceRoot":"","sources":["../../src/utils/storage-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEzC;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAKnE;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,EACtB,OAAO,GAAE,MAAgB,GACxB,IAAI,EAAE,CAiBR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,CAE9D;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAInD"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.requireTask = requireTask;
|
|
4
|
+
exports.requireTasks = requireTasks;
|
|
5
|
+
exports.filterNullTasks = filterNullTasks;
|
|
6
|
+
exports.validateTaskId = validateTaskId;
|
|
7
|
+
/**
|
|
8
|
+
* Ensures a task is not null, throwing an error if it is.
|
|
9
|
+
* Useful for enforcing null checks after storage operations.
|
|
10
|
+
*
|
|
11
|
+
* @param task - Task that may be null
|
|
12
|
+
* @param taskId - ID of the task for error message
|
|
13
|
+
* @returns The task if not null
|
|
14
|
+
* @throws Error if task is null
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const task = await storage.getTask(taskId);
|
|
19
|
+
* const validTask = requireTask(task, taskId);
|
|
20
|
+
* console.log(validTask.title); // Safe - never null
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
function requireTask(task, taskId) {
|
|
24
|
+
if (!task) {
|
|
25
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
26
|
+
}
|
|
27
|
+
return task;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Ensures multiple tasks are not null, throwing an error if any is null.
|
|
31
|
+
*
|
|
32
|
+
* @param tasks - Array of tasks that may contain nulls
|
|
33
|
+
* @param context - Context for error message (e.g., "subtasks", "dependencies")
|
|
34
|
+
* @returns Array of tasks with nulls filtered out
|
|
35
|
+
* @throws Error if any task is null
|
|
36
|
+
*/
|
|
37
|
+
function requireTasks(tasks, context = "tasks") {
|
|
38
|
+
const validTasks = [];
|
|
39
|
+
const missingIds = [];
|
|
40
|
+
tasks.forEach((task, index) => {
|
|
41
|
+
if (!task) {
|
|
42
|
+
missingIds.push(`index ${index}`);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
validTasks.push(task);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
if (missingIds.length > 0) {
|
|
49
|
+
throw new Error(`Missing ${context}: ${missingIds.join(", ")}`);
|
|
50
|
+
}
|
|
51
|
+
return validTasks;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Filters out null tasks from an array, with type narrowing.
|
|
55
|
+
*
|
|
56
|
+
* @param tasks - Array of tasks that may contain nulls
|
|
57
|
+
* @returns Array of tasks with nulls removed
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* const tasks = await Promise.all(ids.map(id => storage.getTask(id)));
|
|
62
|
+
* const validTasks = filterNullTasks(tasks);
|
|
63
|
+
* // validTasks has type Task[] (no null)
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
function filterNullTasks(tasks) {
|
|
67
|
+
return tasks.filter((task) => task !== null);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Validates that a task ID is a non-empty string.
|
|
71
|
+
*
|
|
72
|
+
* @param taskId - Task ID to validate
|
|
73
|
+
* @throws Error if task ID is invalid
|
|
74
|
+
*/
|
|
75
|
+
function validateTaskId(taskId) {
|
|
76
|
+
if (!taskId || typeof taskId !== "string" || !taskId.trim()) {
|
|
77
|
+
throw new Error("Invalid task ID: must be a non-empty string");
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { StreamingOptions } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Token usage metrics from AI operations
|
|
4
|
+
*/
|
|
5
|
+
export interface TokenUsage {
|
|
6
|
+
prompt: number;
|
|
7
|
+
completion: number;
|
|
8
|
+
total: number;
|
|
9
|
+
}
|
|
10
|
+
export interface MetricsTracker {
|
|
11
|
+
tokenUsage: TokenUsage;
|
|
12
|
+
timeToFirstToken: number | undefined;
|
|
13
|
+
}
|
|
14
|
+
export interface MetricsStreamingResult {
|
|
15
|
+
options: StreamingOptions;
|
|
16
|
+
getMetrics: () => MetricsTracker;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Creates streaming options with automatic metrics tracking.
|
|
20
|
+
* Wraps provided streaming callbacks to capture token usage and timing metrics.
|
|
21
|
+
*
|
|
22
|
+
* @param streamingOptions - Optional base streaming options to wrap
|
|
23
|
+
* @param aiStartTime - Optional timestamp when AI operation started (for measuring time to first token)
|
|
24
|
+
* @returns Object containing wrapped streaming options and metrics getter
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* const aiStartTime = Date.now();
|
|
29
|
+
* const { options, getMetrics } = createMetricsStreamingOptions(userCallbacks, aiStartTime);
|
|
30
|
+
*
|
|
31
|
+
* await generateText({ model, prompt, ...options });
|
|
32
|
+
*
|
|
33
|
+
* const { tokenUsage, timeToFirstToken } = getMetrics();
|
|
34
|
+
* console.log(`Used ${tokenUsage.total} tokens in ${timeToFirstToken}ms`);
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare function createMetricsStreamingOptions(streamingOptions?: StreamingOptions, aiStartTime?: number): MetricsStreamingResult;
|
|
38
|
+
//# sourceMappingURL=streaming-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streaming-utils.d.ts","sourceRoot":"","sources":["../../src/utils/streaming-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,UAAU,CAAC;IACvB,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,gBAAgB,CAAC;IAC1B,UAAU,EAAE,MAAM,cAAc,CAAC;CAClC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,6BAA6B,CAC3C,gBAAgB,CAAC,EAAE,gBAAgB,EACnC,WAAW,CAAC,EAAE,MAAM,GACnB,sBAAsB,CAsCxB"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createMetricsStreamingOptions = createMetricsStreamingOptions;
|
|
4
|
+
/**
|
|
5
|
+
* Creates streaming options with automatic metrics tracking.
|
|
6
|
+
* Wraps provided streaming callbacks to capture token usage and timing metrics.
|
|
7
|
+
*
|
|
8
|
+
* @param streamingOptions - Optional base streaming options to wrap
|
|
9
|
+
* @param aiStartTime - Optional timestamp when AI operation started (for measuring time to first token)
|
|
10
|
+
* @returns Object containing wrapped streaming options and metrics getter
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const aiStartTime = Date.now();
|
|
15
|
+
* const { options, getMetrics } = createMetricsStreamingOptions(userCallbacks, aiStartTime);
|
|
16
|
+
*
|
|
17
|
+
* await generateText({ model, prompt, ...options });
|
|
18
|
+
*
|
|
19
|
+
* const { tokenUsage, timeToFirstToken } = getMetrics();
|
|
20
|
+
* console.log(`Used ${tokenUsage.total} tokens in ${timeToFirstToken}ms`);
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
function createMetricsStreamingOptions(streamingOptions, aiStartTime) {
|
|
24
|
+
let tokenUsage = { prompt: 0, completion: 0, total: 0 };
|
|
25
|
+
let timeToFirstToken = undefined;
|
|
26
|
+
const wrappedOptions = {
|
|
27
|
+
onFinish: async (result) => {
|
|
28
|
+
// Extract token usage from result
|
|
29
|
+
if (result.usage) {
|
|
30
|
+
tokenUsage = {
|
|
31
|
+
prompt: result.usage.inputTokens || result.usage.promptTokens || 0,
|
|
32
|
+
completion: result.usage.outputTokens || result.usage.completionTokens || 0,
|
|
33
|
+
total: result.usage.totalTokens || 0,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
// Call original onFinish callback if provided
|
|
37
|
+
await streamingOptions?.onFinish?.(result);
|
|
38
|
+
},
|
|
39
|
+
onChunk: (chunk) => {
|
|
40
|
+
// Measure time to first token (ignore empty/whitespace chunks)
|
|
41
|
+
if (chunk && chunk.trim() && !timeToFirstToken && aiStartTime) {
|
|
42
|
+
timeToFirstToken = Date.now() - aiStartTime;
|
|
43
|
+
}
|
|
44
|
+
// Call original onChunk callback if provided
|
|
45
|
+
streamingOptions?.onChunk?.(chunk);
|
|
46
|
+
},
|
|
47
|
+
onError: (error) => {
|
|
48
|
+
// Pass through error callback
|
|
49
|
+
streamingOptions?.onError?.(error);
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
return {
|
|
53
|
+
options: wrappedOptions,
|
|
54
|
+
getMetrics: () => ({ tokenUsage, timeToFirstToken }),
|
|
55
|
+
};
|
|
56
|
+
}
|