@sudosandwich/limps 0.2.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.
- package/LICENSE +21 -0
- package/README.md +190 -0
- package/dist/agent-parser.d.ts +146 -0
- package/dist/agent-parser.d.ts.map +1 -0
- package/dist/agent-parser.js +448 -0
- package/dist/agent-parser.js.map +1 -0
- package/dist/config.d.ts +54 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +146 -0
- package/dist/config.js.map +1 -0
- package/dist/coordination.d.ts +102 -0
- package/dist/coordination.d.ts.map +1 -0
- package/dist/coordination.js +157 -0
- package/dist/coordination.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +256 -0
- package/dist/index.js.map +1 -0
- package/dist/indexer.d.ts +83 -0
- package/dist/indexer.d.ts.map +1 -0
- package/dist/indexer.js +467 -0
- package/dist/indexer.js.map +1 -0
- package/dist/resources/agents-status.d.ts +32 -0
- package/dist/resources/agents-status.d.ts.map +1 -0
- package/dist/resources/agents-status.js +73 -0
- package/dist/resources/agents-status.js.map +1 -0
- package/dist/resources/decisions-log.d.ts +21 -0
- package/dist/resources/decisions-log.d.ts.map +1 -0
- package/dist/resources/decisions-log.js +146 -0
- package/dist/resources/decisions-log.js.map +1 -0
- package/dist/resources/index.d.ts +10 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +74 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/resources/plans-full.d.ts +11 -0
- package/dist/resources/plans-full.d.ts.map +1 -0
- package/dist/resources/plans-full.js +71 -0
- package/dist/resources/plans-full.js.map +1 -0
- package/dist/resources/plans-index.d.ts +30 -0
- package/dist/resources/plans-index.d.ts.map +1 -0
- package/dist/resources/plans-index.js +177 -0
- package/dist/resources/plans-index.js.map +1 -0
- package/dist/resources/plans-summary.d.ts +33 -0
- package/dist/resources/plans-summary.d.ts.map +1 -0
- package/dist/resources/plans-summary.js +238 -0
- package/dist/resources/plans-summary.js.map +1 -0
- package/dist/rlm/extractors.d.ts +39 -0
- package/dist/rlm/extractors.d.ts.map +1 -0
- package/dist/rlm/extractors.js +291 -0
- package/dist/rlm/extractors.js.map +1 -0
- package/dist/rlm/helpers-inject.d.ts +13 -0
- package/dist/rlm/helpers-inject.d.ts.map +1 -0
- package/dist/rlm/helpers-inject.js +586 -0
- package/dist/rlm/helpers-inject.js.map +1 -0
- package/dist/rlm/helpers.d.ts +124 -0
- package/dist/rlm/helpers.d.ts.map +1 -0
- package/dist/rlm/helpers.js +381 -0
- package/dist/rlm/helpers.js.map +1 -0
- package/dist/rlm/index.d.ts +12 -0
- package/dist/rlm/index.d.ts.map +1 -0
- package/dist/rlm/index.js +19 -0
- package/dist/rlm/index.js.map +1 -0
- package/dist/rlm/parallel.d.ts +45 -0
- package/dist/rlm/parallel.d.ts.map +1 -0
- package/dist/rlm/parallel.js +76 -0
- package/dist/rlm/parallel.js.map +1 -0
- package/dist/rlm/recursion.d.ts +96 -0
- package/dist/rlm/recursion.d.ts.map +1 -0
- package/dist/rlm/recursion.js +113 -0
- package/dist/rlm/recursion.js.map +1 -0
- package/dist/rlm/sampling.d.ts +100 -0
- package/dist/rlm/sampling.d.ts.map +1 -0
- package/dist/rlm/sampling.js +96 -0
- package/dist/rlm/sampling.js.map +1 -0
- package/dist/rlm/sandbox.d.ts +73 -0
- package/dist/rlm/sandbox.d.ts.map +1 -0
- package/dist/rlm/sandbox.js +160 -0
- package/dist/rlm/sandbox.js.map +1 -0
- package/dist/rlm/security.d.ts +28 -0
- package/dist/rlm/security.d.ts.map +1 -0
- package/dist/rlm/security.js +154 -0
- package/dist/rlm/security.js.map +1 -0
- package/dist/server.d.ts +21 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +107 -0
- package/dist/server.js.map +1 -0
- package/dist/task-parser.d.ts +47 -0
- package/dist/task-parser.d.ts.map +1 -0
- package/dist/task-parser.js +112 -0
- package/dist/task-parser.js.map +1 -0
- package/dist/test-setup.d.ts +6 -0
- package/dist/test-setup.d.ts.map +1 -0
- package/dist/test-setup.js +37 -0
- package/dist/test-setup.js.map +1 -0
- package/dist/tools/claim-task.d.ts +28 -0
- package/dist/tools/claim-task.d.ts.map +1 -0
- package/dist/tools/claim-task.js +288 -0
- package/dist/tools/claim-task.js.map +1 -0
- package/dist/tools/create-doc.d.ts +47 -0
- package/dist/tools/create-doc.d.ts.map +1 -0
- package/dist/tools/create-doc.js +137 -0
- package/dist/tools/create-doc.js.map +1 -0
- package/dist/tools/create-plan.d.ts +25 -0
- package/dist/tools/create-plan.d.ts.map +1 -0
- package/dist/tools/create-plan.js +179 -0
- package/dist/tools/create-plan.js.map +1 -0
- package/dist/tools/delete-doc.d.ts +51 -0
- package/dist/tools/delete-doc.d.ts.map +1 -0
- package/dist/tools/delete-doc.js +194 -0
- package/dist/tools/delete-doc.js.map +1 -0
- package/dist/tools/get-next-task.d.ts +49 -0
- package/dist/tools/get-next-task.d.ts.map +1 -0
- package/dist/tools/get-next-task.js +204 -0
- package/dist/tools/get-next-task.js.map +1 -0
- package/dist/tools/index.d.ts +10 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +122 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/list-docs.d.ts +53 -0
- package/dist/tools/list-docs.d.ts.map +1 -0
- package/dist/tools/list-docs.js +236 -0
- package/dist/tools/list-docs.js.map +1 -0
- package/dist/tools/open-document-in-cursor.d.ts +62 -0
- package/dist/tools/open-document-in-cursor.d.ts.map +1 -0
- package/dist/tools/open-document-in-cursor.js +211 -0
- package/dist/tools/open-document-in-cursor.js.map +1 -0
- package/dist/tools/read-doc.d.ts +44 -0
- package/dist/tools/read-doc.d.ts.map +1 -0
- package/dist/tools/read-doc.js +174 -0
- package/dist/tools/read-doc.js.map +1 -0
- package/dist/tools/release-task.d.ts +28 -0
- package/dist/tools/release-task.d.ts.map +1 -0
- package/dist/tools/release-task.js +154 -0
- package/dist/tools/release-task.js.map +1 -0
- package/dist/tools/rlm-multi-query.d.ts +110 -0
- package/dist/tools/rlm-multi-query.d.ts.map +1 -0
- package/dist/tools/rlm-multi-query.js +348 -0
- package/dist/tools/rlm-multi-query.js.map +1 -0
- package/dist/tools/rlm-query.d.ts +56 -0
- package/dist/tools/rlm-query.d.ts.map +1 -0
- package/dist/tools/rlm-query.js +228 -0
- package/dist/tools/rlm-query.js.map +1 -0
- package/dist/tools/search-docs.d.ts +34 -0
- package/dist/tools/search-docs.d.ts.map +1 -0
- package/dist/tools/search-docs.js +292 -0
- package/dist/tools/search-docs.js.map +1 -0
- package/dist/tools/update-doc.d.ts +149 -0
- package/dist/tools/update-doc.d.ts.map +1 -0
- package/dist/tools/update-doc.js +195 -0
- package/dist/tools/update-doc.js.map +1 -0
- package/dist/tools/update-task-status.d.ts +31 -0
- package/dist/tools/update-task-status.d.ts.map +1 -0
- package/dist/tools/update-task-status.js +303 -0
- package/dist/tools/update-task-status.js.map +1 -0
- package/dist/types.d.ts +50 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/backup.d.ts +76 -0
- package/dist/utils/backup.d.ts.map +1 -0
- package/dist/utils/backup.js +172 -0
- package/dist/utils/backup.js.map +1 -0
- package/dist/utils/errors.d.ts +93 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +125 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +9 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/os-paths.d.ts +45 -0
- package/dist/utils/os-paths.d.ts.map +1 -0
- package/dist/utils/os-paths.js +81 -0
- package/dist/utils/os-paths.js.map +1 -0
- package/dist/utils/paths.d.ts +71 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +165 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/watcher.d.ts +19 -0
- package/dist/watcher.d.ts.map +1 -0
- package/dist/watcher.js +109 -0
- package/dist/watcher.js.map +1 -0
- package/package.json +85 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* update_doc tool: Update existing documents with full replacement or patch operations.
|
|
3
|
+
*/
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import type { ToolContext, ToolResult } from '../types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Patch operation schema.
|
|
8
|
+
*/
|
|
9
|
+
export declare const PatchSchema: z.ZodObject<{
|
|
10
|
+
search: z.ZodString;
|
|
11
|
+
replace: z.ZodString;
|
|
12
|
+
all: z.ZodDefault<z.ZodBoolean>;
|
|
13
|
+
}, "strip", z.ZodTypeAny, {
|
|
14
|
+
replace: string;
|
|
15
|
+
search: string;
|
|
16
|
+
all: boolean;
|
|
17
|
+
}, {
|
|
18
|
+
replace: string;
|
|
19
|
+
search: string;
|
|
20
|
+
all?: boolean | undefined;
|
|
21
|
+
}>;
|
|
22
|
+
/**
|
|
23
|
+
* Base input schema for update_doc tool (for registration).
|
|
24
|
+
*/
|
|
25
|
+
export declare const UpdateDocInputBaseSchema: z.ZodObject<{
|
|
26
|
+
path: z.ZodString;
|
|
27
|
+
content: z.ZodOptional<z.ZodString>;
|
|
28
|
+
patch: z.ZodOptional<z.ZodObject<{
|
|
29
|
+
search: z.ZodString;
|
|
30
|
+
replace: z.ZodString;
|
|
31
|
+
all: z.ZodDefault<z.ZodBoolean>;
|
|
32
|
+
}, "strip", z.ZodTypeAny, {
|
|
33
|
+
replace: string;
|
|
34
|
+
search: string;
|
|
35
|
+
all: boolean;
|
|
36
|
+
}, {
|
|
37
|
+
replace: string;
|
|
38
|
+
search: string;
|
|
39
|
+
all?: boolean | undefined;
|
|
40
|
+
}>>;
|
|
41
|
+
createBackup: z.ZodDefault<z.ZodBoolean>;
|
|
42
|
+
force: z.ZodDefault<z.ZodBoolean>;
|
|
43
|
+
}, "strip", z.ZodTypeAny, {
|
|
44
|
+
path: string;
|
|
45
|
+
force: boolean;
|
|
46
|
+
createBackup: boolean;
|
|
47
|
+
content?: string | undefined;
|
|
48
|
+
patch?: {
|
|
49
|
+
replace: string;
|
|
50
|
+
search: string;
|
|
51
|
+
all: boolean;
|
|
52
|
+
} | undefined;
|
|
53
|
+
}, {
|
|
54
|
+
path: string;
|
|
55
|
+
content?: string | undefined;
|
|
56
|
+
force?: boolean | undefined;
|
|
57
|
+
patch?: {
|
|
58
|
+
replace: string;
|
|
59
|
+
search: string;
|
|
60
|
+
all?: boolean | undefined;
|
|
61
|
+
} | undefined;
|
|
62
|
+
createBackup?: boolean | undefined;
|
|
63
|
+
}>;
|
|
64
|
+
/**
|
|
65
|
+
* Input schema for update_doc tool (with validation).
|
|
66
|
+
*/
|
|
67
|
+
export declare const UpdateDocInputSchema: z.ZodEffects<z.ZodObject<{
|
|
68
|
+
path: z.ZodString;
|
|
69
|
+
content: z.ZodOptional<z.ZodString>;
|
|
70
|
+
patch: z.ZodOptional<z.ZodObject<{
|
|
71
|
+
search: z.ZodString;
|
|
72
|
+
replace: z.ZodString;
|
|
73
|
+
all: z.ZodDefault<z.ZodBoolean>;
|
|
74
|
+
}, "strip", z.ZodTypeAny, {
|
|
75
|
+
replace: string;
|
|
76
|
+
search: string;
|
|
77
|
+
all: boolean;
|
|
78
|
+
}, {
|
|
79
|
+
replace: string;
|
|
80
|
+
search: string;
|
|
81
|
+
all?: boolean | undefined;
|
|
82
|
+
}>>;
|
|
83
|
+
createBackup: z.ZodDefault<z.ZodBoolean>;
|
|
84
|
+
force: z.ZodDefault<z.ZodBoolean>;
|
|
85
|
+
}, "strip", z.ZodTypeAny, {
|
|
86
|
+
path: string;
|
|
87
|
+
force: boolean;
|
|
88
|
+
createBackup: boolean;
|
|
89
|
+
content?: string | undefined;
|
|
90
|
+
patch?: {
|
|
91
|
+
replace: string;
|
|
92
|
+
search: string;
|
|
93
|
+
all: boolean;
|
|
94
|
+
} | undefined;
|
|
95
|
+
}, {
|
|
96
|
+
path: string;
|
|
97
|
+
content?: string | undefined;
|
|
98
|
+
force?: boolean | undefined;
|
|
99
|
+
patch?: {
|
|
100
|
+
replace: string;
|
|
101
|
+
search: string;
|
|
102
|
+
all?: boolean | undefined;
|
|
103
|
+
} | undefined;
|
|
104
|
+
createBackup?: boolean | undefined;
|
|
105
|
+
}>, {
|
|
106
|
+
path: string;
|
|
107
|
+
force: boolean;
|
|
108
|
+
createBackup: boolean;
|
|
109
|
+
content?: string | undefined;
|
|
110
|
+
patch?: {
|
|
111
|
+
replace: string;
|
|
112
|
+
search: string;
|
|
113
|
+
all: boolean;
|
|
114
|
+
} | undefined;
|
|
115
|
+
}, {
|
|
116
|
+
path: string;
|
|
117
|
+
content?: string | undefined;
|
|
118
|
+
force?: boolean | undefined;
|
|
119
|
+
patch?: {
|
|
120
|
+
replace: string;
|
|
121
|
+
search: string;
|
|
122
|
+
all?: boolean | undefined;
|
|
123
|
+
} | undefined;
|
|
124
|
+
createBackup?: boolean | undefined;
|
|
125
|
+
}>;
|
|
126
|
+
export type UpdateDocInput = z.infer<typeof UpdateDocInputSchema>;
|
|
127
|
+
/**
|
|
128
|
+
* Output interface for update_doc tool.
|
|
129
|
+
*/
|
|
130
|
+
export interface UpdateDocOutput {
|
|
131
|
+
path: string;
|
|
132
|
+
updated: true;
|
|
133
|
+
size: number;
|
|
134
|
+
backup?: string;
|
|
135
|
+
changes?: {
|
|
136
|
+
additions: number;
|
|
137
|
+
deletions: number;
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Handle update_doc tool request.
|
|
142
|
+
* Updates an existing file with full replacement or patch operation.
|
|
143
|
+
*
|
|
144
|
+
* @param input - Tool input
|
|
145
|
+
* @param context - Tool context
|
|
146
|
+
* @returns Tool result
|
|
147
|
+
*/
|
|
148
|
+
export declare function handleUpdateDoc(input: UpdateDocInput, context: ToolContext): Promise<ToolResult>;
|
|
149
|
+
//# sourceMappingURL=update-doc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-doc.d.ts","sourceRoot":"","sources":["../../src/tools/update-doc.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE3D;;GAEG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;EAItB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAMnC,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGhC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,IAAI,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE;QACR,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AA8CD;;;;;;;GAOG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,cAAc,EACrB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,CAAC,CAsJrB"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* update_doc tool: Update existing documents with full replacement or patch operations.
|
|
3
|
+
*/
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { existsSync, readFileSync, writeFileSync, statSync } from 'fs';
|
|
6
|
+
import { dirname } from 'path';
|
|
7
|
+
import { validatePath, isProtectedPlanFile } from '../utils/paths.js';
|
|
8
|
+
import { notFound } from '../utils/errors.js';
|
|
9
|
+
import { createBackup } from '../utils/backup.js';
|
|
10
|
+
import { indexDocument } from '../indexer.js';
|
|
11
|
+
/**
|
|
12
|
+
* Patch operation schema.
|
|
13
|
+
*/
|
|
14
|
+
export const PatchSchema = z.object({
|
|
15
|
+
search: z.string().min(1).describe('Text to find'),
|
|
16
|
+
replace: z.string().describe('Replacement text'),
|
|
17
|
+
all: z.boolean().default(false).describe('Replace all occurrences'),
|
|
18
|
+
});
|
|
19
|
+
/**
|
|
20
|
+
* Base input schema for update_doc tool (for registration).
|
|
21
|
+
*/
|
|
22
|
+
export const UpdateDocInputBaseSchema = z.object({
|
|
23
|
+
path: z.string().min(1).describe('Path to existing file'),
|
|
24
|
+
content: z.string().optional().describe('Full replacement content'),
|
|
25
|
+
patch: PatchSchema.optional().describe('Search/replace patch'),
|
|
26
|
+
createBackup: z.boolean().default(true).describe('Create backup before update'),
|
|
27
|
+
force: z.boolean().default(false).describe('Skip validation warnings'),
|
|
28
|
+
});
|
|
29
|
+
/**
|
|
30
|
+
* Input schema for update_doc tool (with validation).
|
|
31
|
+
*/
|
|
32
|
+
export const UpdateDocInputSchema = UpdateDocInputBaseSchema.refine((data) => data.content !== undefined || data.patch !== undefined, { message: 'Either content or patch must be provided' });
|
|
33
|
+
/**
|
|
34
|
+
* Get repository root from config.
|
|
35
|
+
*/
|
|
36
|
+
function getRepoRoot(config) {
|
|
37
|
+
return dirname(config.plansPath);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Check if content has frontmatter (YAML or TOML).
|
|
41
|
+
*/
|
|
42
|
+
function hasFrontmatter(content) {
|
|
43
|
+
return /^---\s*\n/.test(content) || /^\+\+\+\s*\n/.test(content);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Calculate line count differences between old and new content.
|
|
47
|
+
*/
|
|
48
|
+
function calculateChanges(oldContent, newContent) {
|
|
49
|
+
const oldLines = oldContent.split('\n').length;
|
|
50
|
+
const newLines = newContent.split('\n').length;
|
|
51
|
+
const additions = Math.max(0, newLines - oldLines);
|
|
52
|
+
const deletions = Math.max(0, oldLines - newLines);
|
|
53
|
+
return { additions, deletions };
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Apply patch operation to content.
|
|
57
|
+
*/
|
|
58
|
+
function applyPatch(content, patch) {
|
|
59
|
+
if (patch.all) {
|
|
60
|
+
return content.replaceAll(patch.search, patch.replace);
|
|
61
|
+
}
|
|
62
|
+
return content.replace(patch.search, patch.replace);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Handle update_doc tool request.
|
|
66
|
+
* Updates an existing file with full replacement or patch operation.
|
|
67
|
+
*
|
|
68
|
+
* @param input - Tool input
|
|
69
|
+
* @param context - Tool context
|
|
70
|
+
* @returns Tool result
|
|
71
|
+
*/
|
|
72
|
+
export async function handleUpdateDoc(input, context) {
|
|
73
|
+
const { path, content, patch, createBackup: shouldBackup, force } = input;
|
|
74
|
+
const repoRoot = getRepoRoot(context.config);
|
|
75
|
+
try {
|
|
76
|
+
// Validate path
|
|
77
|
+
const validated = validatePath(path, repoRoot);
|
|
78
|
+
// Check if file exists
|
|
79
|
+
if (!existsSync(validated.absolute)) {
|
|
80
|
+
throw notFound(path);
|
|
81
|
+
}
|
|
82
|
+
// Check if this is a protected plan file
|
|
83
|
+
if (isProtectedPlanFile(validated.relative) && !force) {
|
|
84
|
+
return {
|
|
85
|
+
content: [
|
|
86
|
+
{
|
|
87
|
+
type: 'text',
|
|
88
|
+
text: JSON.stringify({
|
|
89
|
+
warning: 'Protected plan file - confirm with force: true',
|
|
90
|
+
path: validated.relative,
|
|
91
|
+
}, null, 2),
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
isError: true,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
// Read existing content
|
|
98
|
+
const oldContent = readFileSync(validated.absolute, 'utf-8');
|
|
99
|
+
const hadFrontmatter = hasFrontmatter(oldContent);
|
|
100
|
+
// Determine new content
|
|
101
|
+
let newContent;
|
|
102
|
+
if (content !== undefined) {
|
|
103
|
+
// Full replacement
|
|
104
|
+
newContent = content;
|
|
105
|
+
// Warn if frontmatter was removed (unless force is true)
|
|
106
|
+
if (hadFrontmatter && !hasFrontmatter(newContent) && !force) {
|
|
107
|
+
return {
|
|
108
|
+
content: [
|
|
109
|
+
{
|
|
110
|
+
type: 'text',
|
|
111
|
+
text: JSON.stringify({
|
|
112
|
+
warning: 'Frontmatter removed - confirm with force: true',
|
|
113
|
+
path: validated.relative,
|
|
114
|
+
}, null, 2),
|
|
115
|
+
},
|
|
116
|
+
],
|
|
117
|
+
isError: true,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
else if (patch !== undefined) {
|
|
122
|
+
// Patch operation
|
|
123
|
+
newContent = applyPatch(oldContent, patch);
|
|
124
|
+
// Warn if patch had no matches
|
|
125
|
+
if (newContent === oldContent) {
|
|
126
|
+
return {
|
|
127
|
+
content: [
|
|
128
|
+
{
|
|
129
|
+
type: 'text',
|
|
130
|
+
text: JSON.stringify({
|
|
131
|
+
warning: 'Patch had no matches - file unchanged',
|
|
132
|
+
path: validated.relative,
|
|
133
|
+
search: patch.search,
|
|
134
|
+
}, null, 2),
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
isError: true,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
// This should never happen due to schema validation
|
|
143
|
+
throw new Error('Either content or patch must be provided');
|
|
144
|
+
}
|
|
145
|
+
// Create backup if requested
|
|
146
|
+
let backupPath;
|
|
147
|
+
if (shouldBackup) {
|
|
148
|
+
const backupResult = await createBackup(validated.absolute, repoRoot);
|
|
149
|
+
backupPath = backupResult.backupPath;
|
|
150
|
+
}
|
|
151
|
+
// Write new content
|
|
152
|
+
writeFileSync(validated.absolute, newContent, 'utf-8');
|
|
153
|
+
// Get file size
|
|
154
|
+
const stats = statSync(validated.absolute);
|
|
155
|
+
const size = stats.size;
|
|
156
|
+
// Calculate changes
|
|
157
|
+
const changes = calculateChanges(oldContent, newContent);
|
|
158
|
+
// Re-index the file
|
|
159
|
+
await indexDocument(context.db, validated.absolute);
|
|
160
|
+
const output = {
|
|
161
|
+
path: validated.relative,
|
|
162
|
+
updated: true,
|
|
163
|
+
size,
|
|
164
|
+
backup: backupPath,
|
|
165
|
+
changes,
|
|
166
|
+
};
|
|
167
|
+
return {
|
|
168
|
+
content: [
|
|
169
|
+
{
|
|
170
|
+
type: 'text',
|
|
171
|
+
text: JSON.stringify(output, null, 2),
|
|
172
|
+
},
|
|
173
|
+
],
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
// Re-throw DocumentError as-is
|
|
178
|
+
if (error instanceof Error && 'code' in error) {
|
|
179
|
+
throw error;
|
|
180
|
+
}
|
|
181
|
+
// Wrap other errors
|
|
182
|
+
return {
|
|
183
|
+
content: [
|
|
184
|
+
{
|
|
185
|
+
type: 'text',
|
|
186
|
+
text: JSON.stringify({
|
|
187
|
+
error: error instanceof Error ? error.message : String(error),
|
|
188
|
+
}, null, 2),
|
|
189
|
+
},
|
|
190
|
+
],
|
|
191
|
+
isError: true,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=update-doc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-doc.js","sourceRoot":"","sources":["../../src/tools/update-doc.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { ToolContext, ToolResult } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Input schema for update_task_status tool.
|
|
5
|
+
*/
|
|
6
|
+
export declare const UpdateTaskStatusInputSchema: z.ZodObject<{
|
|
7
|
+
taskId: z.ZodString;
|
|
8
|
+
status: z.ZodEnum<["GAP", "WIP", "PASS", "BLOCKED"]>;
|
|
9
|
+
agentId: z.ZodOptional<z.ZodString>;
|
|
10
|
+
notes: z.ZodOptional<z.ZodString>;
|
|
11
|
+
}, "strip", z.ZodTypeAny, {
|
|
12
|
+
status: "GAP" | "WIP" | "PASS" | "BLOCKED";
|
|
13
|
+
taskId: string;
|
|
14
|
+
agentId?: string | undefined;
|
|
15
|
+
notes?: string | undefined;
|
|
16
|
+
}, {
|
|
17
|
+
status: "GAP" | "WIP" | "PASS" | "BLOCKED";
|
|
18
|
+
taskId: string;
|
|
19
|
+
agentId?: string | undefined;
|
|
20
|
+
notes?: string | undefined;
|
|
21
|
+
}>;
|
|
22
|
+
/**
|
|
23
|
+
* Handle update_task_status tool request.
|
|
24
|
+
* Updates task status in planning documents (GAP → WIP → PASS/BLOCKED).
|
|
25
|
+
*
|
|
26
|
+
* @param input - Tool input
|
|
27
|
+
* @param context - Tool context
|
|
28
|
+
* @returns Tool result
|
|
29
|
+
*/
|
|
30
|
+
export declare function handleUpdateTaskStatus(input: z.infer<typeof UpdateTaskStatusInputSchema>, context: ToolContext): Promise<ToolResult>;
|
|
31
|
+
//# sourceMappingURL=update-task-status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-task-status.d.ts","sourceRoot":"","sources":["../../src/tools/update-task-status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAWxB,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE3D;;GAEG;AACH,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;EAKtC,CAAC;AAyLH;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,EAClD,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,CAAC,CA0JrB"}
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { readFileSync, writeFileSync } from 'fs';
|
|
3
|
+
import { readCoordination, writeCoordination, } from '../coordination.js';
|
|
4
|
+
import { indexDocument } from '../indexer.js';
|
|
5
|
+
import { extractPlanId, parseTasksFromDocument, findTaskById } from '../task-parser.js';
|
|
6
|
+
/**
|
|
7
|
+
* Input schema for update_task_status tool.
|
|
8
|
+
*/
|
|
9
|
+
export const UpdateTaskStatusInputSchema = z.object({
|
|
10
|
+
taskId: z.string(),
|
|
11
|
+
status: z.enum(['GAP', 'WIP', 'PASS', 'BLOCKED']),
|
|
12
|
+
agentId: z.string().optional(),
|
|
13
|
+
notes: z.string().optional(),
|
|
14
|
+
});
|
|
15
|
+
/**
|
|
16
|
+
* Valid status transitions.
|
|
17
|
+
*/
|
|
18
|
+
const VALID_TRANSITIONS = {
|
|
19
|
+
GAP: ['WIP'],
|
|
20
|
+
WIP: ['PASS', 'BLOCKED'],
|
|
21
|
+
PASS: [], // Terminal state
|
|
22
|
+
BLOCKED: ['GAP', 'WIP'], // Can be unblocked
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Check if a status transition is valid.
|
|
26
|
+
*/
|
|
27
|
+
function isValidTransition(from, to) {
|
|
28
|
+
const allowed = VALID_TRANSITIONS[from] || [];
|
|
29
|
+
return allowed.includes(to);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Find task in document by feature number.
|
|
33
|
+
* Returns the content section for the task.
|
|
34
|
+
*/
|
|
35
|
+
function findTaskSection(content, featureNumber) {
|
|
36
|
+
const featureRegex = new RegExp(`^###\\s+#${featureNumber}:`, 'm');
|
|
37
|
+
const match = content.match(featureRegex);
|
|
38
|
+
if (!match || match.index === undefined) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
const start = match.index;
|
|
42
|
+
// Find next feature or end of document
|
|
43
|
+
const nextFeatureMatch = content.indexOf('### #', start + 1);
|
|
44
|
+
const end = nextFeatureMatch > 0 ? nextFeatureMatch : content.length;
|
|
45
|
+
const section = content.substring(start, end);
|
|
46
|
+
return { start, end, section };
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Update status in task section.
|
|
50
|
+
* Preserves formatting and other content.
|
|
51
|
+
*/
|
|
52
|
+
function updateStatusInSection(section, newStatus) {
|
|
53
|
+
// Match status line: "Status: `GAP`" or "Status: `WIP`" etc.
|
|
54
|
+
const statusRegex = /Status:\s*`?(\w+)`?/i;
|
|
55
|
+
const match = section.match(statusRegex);
|
|
56
|
+
if (match) {
|
|
57
|
+
// Replace existing status
|
|
58
|
+
return section.replace(statusRegex, `Status: \`${newStatus}\``);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
// Add status line if not found (shouldn't happen, but handle gracefully)
|
|
62
|
+
// Insert after feature title
|
|
63
|
+
const titleMatch = section.match(/^###\s+#\d+:\s+(.+)$/m);
|
|
64
|
+
if (titleMatch) {
|
|
65
|
+
const titleEnd = section.indexOf('\n', titleMatch.index || 0);
|
|
66
|
+
return (section.substring(0, titleEnd + 1) +
|
|
67
|
+
`\nStatus: \`${newStatus}\`\n` +
|
|
68
|
+
section.substring(titleEnd + 1));
|
|
69
|
+
}
|
|
70
|
+
return section;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Parse task ID to extract plan ID and feature number.
|
|
75
|
+
* Format: "<planId>#<featureNumber>"
|
|
76
|
+
*/
|
|
77
|
+
function parseTaskId(taskId) {
|
|
78
|
+
const match = taskId.match(/^(.+)#(\d+)$/);
|
|
79
|
+
if (!match) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
planId: match[1],
|
|
84
|
+
featureNumber: parseInt(match[2], 10),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Find document path for a plan.
|
|
89
|
+
*/
|
|
90
|
+
async function findPlanDocument(db, plansPath, planId) {
|
|
91
|
+
// Query database for plan documents
|
|
92
|
+
// Match planId in path (could be "0001-plan-name" or just "0001")
|
|
93
|
+
const plans = db
|
|
94
|
+
.prepare(`
|
|
95
|
+
SELECT path
|
|
96
|
+
FROM documents
|
|
97
|
+
WHERE path LIKE ?
|
|
98
|
+
AND path LIKE '%/plan.md'
|
|
99
|
+
`)
|
|
100
|
+
.all(`${plansPath}%${planId}%`);
|
|
101
|
+
if (plans.length === 0) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
// Find exact match (plan directory should contain planId)
|
|
105
|
+
for (const plan of plans) {
|
|
106
|
+
if (plan.path.includes(planId)) {
|
|
107
|
+
return plan.path;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return plans[0]?.path || null;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Try to auto-create a task entry from the plan document.
|
|
114
|
+
* Returns the task state if found in the plan, null otherwise.
|
|
115
|
+
*
|
|
116
|
+
* @param taskId - Task identifier
|
|
117
|
+
* @param context - Tool context
|
|
118
|
+
* @returns Task state or null if not found
|
|
119
|
+
*/
|
|
120
|
+
async function tryAutoCreateTaskFromPlan(taskId, context) {
|
|
121
|
+
const parsed = parseTaskId(taskId);
|
|
122
|
+
if (!parsed) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
const { planId } = parsed;
|
|
126
|
+
const { plansPath } = context.config;
|
|
127
|
+
// Query database for plan documents matching this plan ID
|
|
128
|
+
const plans = context.db
|
|
129
|
+
.prepare(`
|
|
130
|
+
SELECT path, content
|
|
131
|
+
FROM documents
|
|
132
|
+
WHERE path LIKE ?
|
|
133
|
+
AND path LIKE '%/plan.md'
|
|
134
|
+
`)
|
|
135
|
+
.all(`${plansPath}%${planId}%`);
|
|
136
|
+
if (plans.length === 0) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
// Find the plan document and parse tasks
|
|
140
|
+
for (const plan of plans) {
|
|
141
|
+
const extractedPlanId = extractPlanId(plan.path);
|
|
142
|
+
if (!extractedPlanId || !extractedPlanId.includes(planId)) {
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
const tasks = parseTasksFromDocument(plan.path, plan.content, extractedPlanId);
|
|
146
|
+
const task = findTaskById(tasks, taskId);
|
|
147
|
+
if (task) {
|
|
148
|
+
// Create TaskState from parsed task
|
|
149
|
+
return {
|
|
150
|
+
status: task.status,
|
|
151
|
+
claimedBy: undefined,
|
|
152
|
+
dependencies: task.dependencies,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Handle update_task_status tool request.
|
|
160
|
+
* Updates task status in planning documents (GAP → WIP → PASS/BLOCKED).
|
|
161
|
+
*
|
|
162
|
+
* @param input - Tool input
|
|
163
|
+
* @param context - Tool context
|
|
164
|
+
* @returns Tool result
|
|
165
|
+
*/
|
|
166
|
+
export async function handleUpdateTaskStatus(input, context) {
|
|
167
|
+
const { taskId, status, agentId, notes } = input;
|
|
168
|
+
const { plansPath, coordinationPath } = context.config;
|
|
169
|
+
// Parse task ID
|
|
170
|
+
const parsed = parseTaskId(taskId);
|
|
171
|
+
if (!parsed) {
|
|
172
|
+
return {
|
|
173
|
+
content: [
|
|
174
|
+
{
|
|
175
|
+
type: 'text',
|
|
176
|
+
text: `Invalid task ID format: ${taskId}. Expected format: "<planId>#<featureNumber>"`,
|
|
177
|
+
},
|
|
178
|
+
],
|
|
179
|
+
isError: true,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
const { planId, featureNumber } = parsed;
|
|
183
|
+
// Find plan document
|
|
184
|
+
const documentPath = await findPlanDocument(context.db, plansPath, planId);
|
|
185
|
+
if (!documentPath) {
|
|
186
|
+
return {
|
|
187
|
+
content: [
|
|
188
|
+
{
|
|
189
|
+
type: 'text',
|
|
190
|
+
text: `Plan document not found for task ${taskId}`,
|
|
191
|
+
},
|
|
192
|
+
],
|
|
193
|
+
isError: true,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
// Read current coordination state
|
|
197
|
+
const coordination = await readCoordination(coordinationPath);
|
|
198
|
+
let task = coordination.tasks[taskId];
|
|
199
|
+
// Auto-create task entry if found in plan but not in coordination
|
|
200
|
+
if (!task) {
|
|
201
|
+
const autoCreatedTask = await tryAutoCreateTaskFromPlan(taskId, context);
|
|
202
|
+
if (!autoCreatedTask) {
|
|
203
|
+
return {
|
|
204
|
+
content: [
|
|
205
|
+
{
|
|
206
|
+
type: 'text',
|
|
207
|
+
text: `Task ${taskId} not found in coordination state or plan documents`,
|
|
208
|
+
},
|
|
209
|
+
],
|
|
210
|
+
isError: true,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
// Add the auto-created task to coordination state
|
|
214
|
+
coordination.tasks[taskId] = autoCreatedTask;
|
|
215
|
+
task = autoCreatedTask;
|
|
216
|
+
}
|
|
217
|
+
// Validate status transition
|
|
218
|
+
if (!isValidTransition(task.status, status)) {
|
|
219
|
+
return {
|
|
220
|
+
content: [
|
|
221
|
+
{
|
|
222
|
+
type: 'text',
|
|
223
|
+
text: `Invalid status transition from ${task.status} to ${status}. Valid transitions: ${VALID_TRANSITIONS[task.status]?.join(', ') || 'none'}`,
|
|
224
|
+
},
|
|
225
|
+
],
|
|
226
|
+
isError: true,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
// Read document
|
|
230
|
+
const content = readFileSync(documentPath, 'utf-8');
|
|
231
|
+
// Find task section
|
|
232
|
+
const taskSection = findTaskSection(content, featureNumber);
|
|
233
|
+
if (!taskSection) {
|
|
234
|
+
return {
|
|
235
|
+
content: [
|
|
236
|
+
{
|
|
237
|
+
type: 'text',
|
|
238
|
+
text: `Feature #${featureNumber} not found in document`,
|
|
239
|
+
},
|
|
240
|
+
],
|
|
241
|
+
isError: true,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
// Update status in section
|
|
245
|
+
const updatedSection = updateStatusInSection(taskSection.section, status);
|
|
246
|
+
// Replace section in document
|
|
247
|
+
const updatedContent = content.substring(0, taskSection.start) + updatedSection + content.substring(taskSection.end);
|
|
248
|
+
// Write updated document
|
|
249
|
+
writeFileSync(documentPath, updatedContent, 'utf-8');
|
|
250
|
+
// Update coordination state if agentId provided
|
|
251
|
+
if (agentId) {
|
|
252
|
+
const maxRetries = 5;
|
|
253
|
+
let retries = 0;
|
|
254
|
+
while (retries < maxRetries) {
|
|
255
|
+
try {
|
|
256
|
+
const currentCoordination = await readCoordination(coordinationPath);
|
|
257
|
+
const expectedVersion = currentCoordination.version;
|
|
258
|
+
// Update task status and claim
|
|
259
|
+
const updatedCoordination = {
|
|
260
|
+
...currentCoordination,
|
|
261
|
+
version: currentCoordination.version + 1,
|
|
262
|
+
tasks: {
|
|
263
|
+
...currentCoordination.tasks,
|
|
264
|
+
[taskId]: {
|
|
265
|
+
...currentCoordination.tasks[taskId],
|
|
266
|
+
status: status,
|
|
267
|
+
claimedBy: status === 'WIP' ? agentId : undefined,
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
};
|
|
271
|
+
await writeCoordination(coordinationPath, updatedCoordination, expectedVersion);
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
catch (error) {
|
|
275
|
+
retries++;
|
|
276
|
+
if (retries >= maxRetries) {
|
|
277
|
+
return {
|
|
278
|
+
content: [
|
|
279
|
+
{
|
|
280
|
+
type: 'text',
|
|
281
|
+
text: `Failed to update coordination state after ${maxRetries} retries: ${error instanceof Error ? error.message : String(error)}`,
|
|
282
|
+
},
|
|
283
|
+
],
|
|
284
|
+
isError: true,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
// Wait a bit before retry
|
|
288
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
// Re-index document
|
|
293
|
+
await indexDocument(context.db, documentPath);
|
|
294
|
+
return {
|
|
295
|
+
content: [
|
|
296
|
+
{
|
|
297
|
+
type: 'text',
|
|
298
|
+
text: `Task ${taskId} status updated to ${status}${agentId ? ` by agent ${agentId}` : ''}${notes ? `. Notes: ${notes}` : ''}`,
|
|
299
|
+
},
|
|
300
|
+
],
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
//# sourceMappingURL=update-task-status.js.map
|