maskweaver 0.9.4 → 0.9.6
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/README.ko.md +638 -592
- package/README.md +671 -667
- package/dist/cli/doctor.js +5 -21
- package/dist/cli/install.d.ts +0 -8
- package/dist/cli/install.js +0 -39
- package/dist/context/config.d.ts +0 -22
- package/dist/context/config.js +0 -28
- package/dist/context/feature.d.ts +0 -39
- package/dist/context/feature.js +0 -77
- package/dist/context/files.d.ts +0 -13
- package/dist/context/files.js +1 -24
- package/dist/context/index.d.ts +0 -7
- package/dist/context/index.js +0 -12
- package/dist/context/project.d.ts +0 -21
- package/dist/context/project.js +0 -30
- package/dist/context/types.d.ts +0 -48
- package/dist/context/types.js +0 -12
- package/dist/context/utils.d.ts +0 -18
- package/dist/context/utils.js +0 -27
- package/dist/core/engine/promptBuilder.d.ts +0 -17
- package/dist/core/engine/promptBuilder.js +0 -28
- package/dist/core/index.d.ts +0 -6
- package/dist/core/index.js +0 -9
- package/dist/core/loader/MaskLoader.d.ts +0 -23
- package/dist/core/loader/MaskLoader.js +0 -29
- package/dist/core/schema/types.d.ts +0 -47
- package/dist/core/schema/types.js +0 -6
- package/dist/core/schema/validator.d.ts +0 -14
- package/dist/core/schema/validator.js +0 -18
- package/dist/i18n/index.d.ts +0 -18
- package/dist/i18n/index.js +4 -23
- package/dist/index.d.ts +0 -8
- package/dist/index.js +0 -8
- package/dist/lib.d.ts +0 -5
- package/dist/lib.js +0 -12
- package/dist/memory/chunking.d.ts +0 -22
- package/dist/memory/chunking.js +2 -37
- package/dist/memory/core.d.ts +0 -29
- package/dist/memory/core.js +1 -52
- package/dist/memory/index.d.ts +0 -5
- package/dist/memory/index.js +0 -10
- package/dist/memory/indexer.d.ts +0 -21
- package/dist/memory/indexer.js +0 -44
- package/dist/memory/providers/examples.d.ts +0 -5
- package/dist/memory/providers/examples.js +4 -64
- package/dist/memory/providers/factory.d.ts +0 -44
- package/dist/memory/providers/factory.js +0 -46
- package/dist/memory/providers/index.d.ts +0 -26
- package/dist/memory/providers/index.js +0 -28
- package/dist/memory/providers/ollama.d.ts +0 -6
- package/dist/memory/providers/ollama.js +1 -8
- package/dist/memory/providers/openai.d.ts +0 -6
- package/dist/memory/providers/openai.js +1 -8
- package/dist/memory/providers/openrouter.d.ts +0 -6
- package/dist/memory/providers/openrouter.js +0 -8
- package/dist/memory/providers/text-only.d.ts +0 -13
- package/dist/memory/providers/text-only.js +0 -17
- package/dist/memory/providers/types.d.ts +0 -39
- package/dist/memory/providers/types.js +0 -7
- package/dist/memory/providers/voyage.d.ts +0 -22
- package/dist/memory/providers/voyage.js +1 -24
- package/dist/memory/search/hybrid.d.ts +0 -12
- package/dist/memory/search/hybrid.js +1 -22
- package/dist/memory/store/sqlite.d.ts +0 -72
- package/dist/memory/store/sqlite.js +4 -127
- package/dist/plugin/config/index.d.ts +0 -112
- package/dist/plugin/config/index.js +0 -115
- package/dist/plugin/index.d.ts +0 -13
- package/dist/plugin/index.js +1 -123
- package/dist/plugin/tools/command-registry.d.ts +0 -6
- package/dist/plugin/tools/command-registry.js +0 -14
- package/dist/plugin/tools/context.d.ts +0 -12
- package/dist/plugin/tools/context.js +0 -58
- package/dist/plugin/tools/maskSave.d.ts +0 -3
- package/dist/plugin/tools/maskSave.js +0 -3
- package/dist/plugin/tools/memoryGet.d.ts +0 -3
- package/dist/plugin/tools/memoryGet.js +0 -3
- package/dist/plugin/tools/memoryIndexer.d.ts +0 -3
- package/dist/plugin/tools/memoryIndexer.js +0 -10
- package/dist/plugin/tools/memorySearch.d.ts +0 -31
- package/dist/plugin/tools/memorySearch.js +0 -79
- package/dist/plugin/tools/memoryWrite.d.ts +0 -8
- package/dist/plugin/tools/memoryWrite.js +0 -32
- package/dist/plugin/tools/retrospect.d.ts +0 -3
- package/dist/plugin/tools/retrospect.js +0 -3
- package/dist/plugin/tools/slashcommand.d.ts +0 -11
- package/dist/plugin/tools/slashcommand.js +0 -38
- package/dist/plugin/tools/squad.d.ts +0 -12
- package/dist/plugin/tools/squad.js +11 -83
- package/dist/plugin/tools/weave.d.ts +0 -6
- package/dist/plugin/tools/weave.js +0 -78
- package/dist/plugin/types.d.ts +0 -20
- package/dist/plugin/types.js +0 -7
- package/dist/retrospect/index.d.ts +0 -7
- package/dist/retrospect/index.js +0 -9
- package/dist/retrospect/mask-save.d.ts +0 -12
- package/dist/retrospect/mask-save.js +1 -80
- package/dist/retrospect/retrospect.d.ts +0 -18
- package/dist/retrospect/retrospect.js +0 -63
- package/dist/retrospect/strategies/base.d.ts +0 -15
- package/dist/retrospect/strategies/base.js +0 -7
- package/dist/retrospect/strategies/deep.d.ts +0 -12
- package/dist/retrospect/strategies/deep.js +0 -24
- package/dist/retrospect/strategies/index.d.ts +0 -12
- package/dist/retrospect/strategies/index.js +0 -12
- package/dist/retrospect/strategies/quick.d.ts +0 -12
- package/dist/retrospect/strategies/quick.js +0 -19
- package/dist/retrospect/strategies/standard.d.ts +0 -12
- package/dist/retrospect/strategies/standard.js +0 -15
- package/dist/retrospect/types.d.ts +0 -7
- package/dist/retrospect/types.js +0 -7
- package/dist/shared/config.d.ts +0 -105
- package/dist/shared/config.js +0 -33
- package/dist/shared/errors.d.ts +0 -18
- package/dist/shared/errors.js +0 -19
- package/dist/shared/generate-agents.d.ts +0 -69
- package/dist/shared/generate-agents.js +2 -86
- package/dist/shared/image.d.ts +0 -67
- package/dist/shared/image.js +6 -104
- package/dist/shared/index.d.ts +0 -5
- package/dist/shared/index.js +0 -7
- package/dist/shared/model-registry.d.ts +0 -72
- package/dist/shared/model-registry.js +5 -95
- package/dist/shared/types.d.ts +0 -15
- package/dist/shared/types.js +0 -3
- package/dist/shared-context/dag.d.ts +0 -105
- package/dist/shared-context/dag.js +3 -114
- package/dist/shared-context/index.d.ts +0 -5
- package/dist/shared-context/index.js +0 -15
- package/dist/shared-context/logger.d.ts +0 -37
- package/dist/shared-context/logger.js +0 -41
- package/dist/shared-context/parallel-executor.d.ts +0 -54
- package/dist/shared-context/parallel-executor.js +4 -56
- package/dist/shared-context/session.d.ts +0 -56
- package/dist/shared-context/session.js +0 -47
- package/dist/shared-context/squad.d.ts +0 -68
- package/dist/shared-context/squad.js +0 -63
- package/dist/shared-context/storage.d.ts +0 -132
- package/dist/shared-context/storage.js +0 -116
- package/dist/shared-context/task.d.ts +0 -120
- package/dist/shared-context/task.js +0 -152
- package/dist/shared-context/test/dag.test.js +9 -14
- package/dist/shared-context/test/logger.test.d.ts +0 -8
- package/dist/shared-context/test/logger.test.js +0 -52
- package/dist/shared-context/test/session.test.d.ts +0 -7
- package/dist/shared-context/test/session.test.js +0 -63
- package/dist/shared-context/test/squad.test.d.ts +0 -10
- package/dist/shared-context/test/squad.test.js +2 -68
- package/dist/shared-context/test/storage.test.d.ts +0 -8
- package/dist/shared-context/test/storage.test.js +0 -68
- package/dist/shared-context/test/task.test.d.ts +0 -7
- package/dist/shared-context/test/task.test.js +0 -54
- package/dist/shared-context/test/watchdog.test.d.ts +0 -7
- package/dist/shared-context/test/watchdog.test.js +3 -58
- package/dist/shared-context/types.d.ts +0 -215
- package/dist/shared-context/types.js +0 -125
- package/dist/shared-context/watchdog.d.ts +0 -127
- package/dist/shared-context/watchdog.js +0 -148
- package/dist/shared-context/worktree.d.ts +0 -68
- package/dist/shared-context/worktree.js +2 -34
- package/dist/verify/budget.d.ts +0 -29
- package/dist/verify/budget.js +0 -34
- package/dist/verify/critical-files.d.ts +0 -17
- package/dist/verify/critical-files.js +0 -37
- package/dist/verify/escalation.d.ts +0 -20
- package/dist/verify/escalation.js +0 -22
- package/dist/verify/index.d.ts +0 -5
- package/dist/verify/index.js +0 -11
- package/dist/verify/prompts.d.ts +0 -20
- package/dist/verify/prompts.js +0 -20
- package/dist/verify/types.d.ts +0 -26
- package/dist/verify/types.js +1 -12
- package/dist/verify/verifier.d.ts +0 -29
- package/dist/verify/verifier.js +0 -54
- package/dist/version.d.ts +1 -16
- package/dist/version.js +1 -16
- package/dist/weave/bridge.d.ts +0 -35
- package/dist/weave/bridge.js +0 -51
- package/dist/weave/environment/detector.d.ts +0 -6
- package/dist/weave/environment/detector.js +4 -45
- package/dist/weave/environment/index.d.ts +0 -19
- package/dist/weave/environment/index.js +1 -39
- package/dist/weave/environment/issues.d.ts +0 -35
- package/dist/weave/environment/issues.js +0 -59
- package/dist/weave/git.d.ts +0 -8
- package/dist/weave/git.js +0 -8
- package/dist/weave/index.d.ts +0 -13
- package/dist/weave/index.js +2 -28
- package/dist/weave/knowledge/global.d.ts +0 -39
- package/dist/weave/knowledge/global.js +2 -78
- package/dist/weave/loop.js +0 -3
- package/dist/weave/orchestrator.d.ts +0 -69
- package/dist/weave/orchestrator.js +1 -101
- package/dist/weave/phase-manager.d.ts +0 -64
- package/dist/weave/phase-manager.js +0 -89
- package/dist/weave/security/secret-scan.d.ts +0 -14
- package/dist/weave/security/secret-scan.js +0 -19
- package/dist/weave/stages/build.js +0 -15
- package/dist/weave/stages/execute.d.ts +0 -42
- package/dist/weave/stages/execute.js +4 -86
- package/dist/weave/stages/handoff.d.ts +0 -7
- package/dist/weave/stages/handoff.js +0 -43
- package/dist/weave/stages/index.d.ts +0 -3
- package/dist/weave/stages/index.js +0 -3
- package/dist/weave/stages/intake.d.ts +0 -8
- package/dist/weave/stages/intake.js +5 -65
- package/dist/weave/stages/map.d.ts +0 -1
- package/dist/weave/stages/openspec.d.ts +0 -1
- package/dist/weave/stages/plan.d.ts +0 -11
- package/dist/weave/stages/plan.js +1 -53
- package/dist/weave/stages/refine.d.ts +0 -7
- package/dist/weave/stages/refine.js +0 -7
- package/dist/weave/stages/research.d.ts +0 -6
- package/dist/weave/stages/research.js +0 -6
- package/dist/weave/stages/spec.d.ts +0 -12
- package/dist/weave/stages/spec.js +0 -17
- package/dist/weave/types.d.ts +0 -20
- package/dist/weave/types.js +0 -5
- package/dist/weave/verification/commands.d.ts +0 -12
- package/dist/weave/verification/commands.js +0 -19
- package/dist/weave/verification/index.d.ts +0 -6
- package/dist/weave/verification/index.js +1 -19
- package/dist/weave/verification/playwright.d.ts +0 -47
- package/dist/weave/verification/playwright.js +1 -90
- package/dist/weave/worktree.d.ts +0 -16
- package/dist/weave/worktree.js +0 -23
- package/dist/weave/yaml-repair.d.ts +0 -39
- package/dist/weave/yaml-repair.js +13 -116
- package/package.json +1 -1
package/dist/weave/worktree.js
CHANGED
|
@@ -1,22 +1,9 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Weave Worktree Utilities
|
|
3
|
-
*
|
|
4
|
-
* Provides git worktree helpers tailored for Weave workflows.
|
|
5
|
-
*
|
|
6
|
-
* Goals:
|
|
7
|
-
* - Enable parallel feature/phase work on isolated working directories
|
|
8
|
-
* - Bootstrap .opencode/weave artifacts into newly created worktrees
|
|
9
|
-
* - Keep "weave init once" principle by copying/creating required files
|
|
10
|
-
*/
|
|
11
1
|
import * as fs from 'node:fs';
|
|
12
2
|
import * as path from 'node:path';
|
|
13
3
|
import { execFile } from 'node:child_process';
|
|
14
4
|
import { promisify } from 'node:util';
|
|
15
5
|
import { createWorktreeManager } from '../shared-context/worktree.js';
|
|
16
6
|
const execFileAsync = promisify(execFile);
|
|
17
|
-
// ============================================================================
|
|
18
|
-
// Git helpers
|
|
19
|
-
// ============================================================================
|
|
20
7
|
async function git(cwd, args) {
|
|
21
8
|
try {
|
|
22
9
|
const { stdout } = await execFileAsync('git', args, { cwd });
|
|
@@ -44,9 +31,6 @@ function toKebabCase(input) {
|
|
|
44
31
|
.replace(/[^a-z0-9]+/g, '-')
|
|
45
32
|
.replace(/^-+|-+$/g, '');
|
|
46
33
|
}
|
|
47
|
-
// ============================================================================
|
|
48
|
-
// Bootstrap helpers
|
|
49
|
-
// ============================================================================
|
|
50
34
|
export function ensureIgnoreOverride(projectRoot) {
|
|
51
35
|
const ignorePath = path.join(projectRoot, '.ignore');
|
|
52
36
|
const allowLine = '!.opencode/weave/';
|
|
@@ -148,7 +132,6 @@ function copyDirectoryRecursive(srcDir, destDir) {
|
|
|
148
132
|
export function bootstrapWeaveArtifacts(fromRoot, toRoot) {
|
|
149
133
|
ensureIgnoreOverride(toRoot);
|
|
150
134
|
ensureWeaveState(toRoot);
|
|
151
|
-
// Copy weave artifacts if they exist in the source worktree.
|
|
152
135
|
copyIfExists(path.join(fromRoot, '.opencode', 'weave', 'state.yaml'), path.join(toRoot, '.opencode', 'weave', 'state.yaml'));
|
|
153
136
|
copyYamlDirIfExists(path.join(fromRoot, '.opencode', 'weave', 'plans'), path.join(toRoot, '.opencode', 'weave', 'plans'));
|
|
154
137
|
copyYamlDirIfExists(path.join(fromRoot, '.opencode', 'weave', 'specs'), path.join(toRoot, '.opencode', 'weave', 'specs'));
|
|
@@ -162,9 +145,6 @@ export function bootstrapGdcArtifacts(fromRoot, toRoot) {
|
|
|
162
145
|
const destNodes = path.join(toRoot, '.gdc', 'nodes');
|
|
163
146
|
copyGdcNodesRecursive(srcNodes, destNodes);
|
|
164
147
|
}
|
|
165
|
-
// ============================================================================
|
|
166
|
-
// Public API
|
|
167
|
-
// ============================================================================
|
|
168
148
|
export async function createWeaveWorktree(options) {
|
|
169
149
|
const basePath = path.resolve(options.basePath);
|
|
170
150
|
const slug = toKebabCase(options.name);
|
|
@@ -230,9 +210,6 @@ export async function removeWeaveWorktree(options) {
|
|
|
230
210
|
worktreeBase: path.join('.worktrees', 'weave'),
|
|
231
211
|
branchPrefix: 'weave/',
|
|
232
212
|
});
|
|
233
|
-
// Remove worktree directory via git.
|
|
234
|
-
// NOTE: The shared worktree manager also deletes the branch. For user-facing
|
|
235
|
-
// flows we make branch deletion optional.
|
|
236
213
|
const info = await manager.get(slug);
|
|
237
214
|
if (!info)
|
|
238
215
|
return;
|
|
@@ -1,19 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* YAML Repair Utility
|
|
3
|
-
*
|
|
4
|
-
* Provides YAML string escaping, corruption detection, and auto-repair
|
|
5
|
-
* for Weave plan files. Handles common YAML corruption patterns:
|
|
6
|
-
* - Unclosed/mismatched quotes
|
|
7
|
-
* - Unescaped special characters in string values
|
|
8
|
-
* - Tab→space conversion
|
|
9
|
-
* - Truncated files
|
|
10
|
-
*/
|
|
11
1
|
export interface RepairResult {
|
|
12
2
|
file: string;
|
|
13
3
|
status: 'ok' | 'repaired' | 'unrecoverable';
|
|
14
4
|
error?: string;
|
|
15
5
|
details?: string;
|
|
16
|
-
/** Structured info about what's missing for user-assisted repair */
|
|
17
6
|
missingInfo?: MissingInfo[];
|
|
18
7
|
}
|
|
19
8
|
export interface MissingInfo {
|
|
@@ -21,31 +10,13 @@ export interface MissingInfo {
|
|
|
21
10
|
description: string;
|
|
22
11
|
lineHint?: number;
|
|
23
12
|
}
|
|
24
|
-
/**
|
|
25
|
-
* Properly escape a string value for YAML double-quoted format.
|
|
26
|
-
* Handles all YAML special characters that would break parsing.
|
|
27
|
-
*/
|
|
28
13
|
export declare function yamlEscapeString(value: string): string;
|
|
29
|
-
/**
|
|
30
|
-
* Attempt to repair corrupted YAML content.
|
|
31
|
-
* Returns the repaired content or null if unrecoverable.
|
|
32
|
-
*/
|
|
33
14
|
export declare function repairYamlContent(content: string): {
|
|
34
15
|
repaired: string | null;
|
|
35
16
|
changes: string[];
|
|
36
17
|
missingInfo: MissingInfo[];
|
|
37
18
|
};
|
|
38
|
-
/**
|
|
39
|
-
* Write a file atomically with backup.
|
|
40
|
-
* 1. Copy existing file to .bak
|
|
41
|
-
* 2. Write to .tmp
|
|
42
|
-
* 3. Rename .tmp to target
|
|
43
|
-
*/
|
|
44
19
|
export declare function safeWriteFile(filePath: string, content: string): void;
|
|
45
|
-
/**
|
|
46
|
-
* Safely read and parse a YAML file with auto-repair on failure.
|
|
47
|
-
* Returns the parsed object, or an error message.
|
|
48
|
-
*/
|
|
49
20
|
export declare function safeReadYaml(filePath: string): Promise<{
|
|
50
21
|
data: any | null;
|
|
51
22
|
repaired: boolean;
|
|
@@ -53,19 +24,9 @@ export declare function safeReadYaml(filePath: string): Promise<{
|
|
|
53
24
|
changes?: string[];
|
|
54
25
|
missingInfo?: MissingInfo[];
|
|
55
26
|
}>;
|
|
56
|
-
/**
|
|
57
|
-
* Repair a single plan YAML file.
|
|
58
|
-
*/
|
|
59
27
|
export declare function repairPlanFile(filePath: string): Promise<RepairResult>;
|
|
60
|
-
/**
|
|
61
|
-
* Scan and repair all plan YAML files in the plans/ directory.
|
|
62
|
-
*/
|
|
63
28
|
export declare function repairAllPlans(basePath?: string): Promise<{
|
|
64
29
|
results: RepairResult[];
|
|
65
30
|
summary: string;
|
|
66
31
|
}>;
|
|
67
|
-
/**
|
|
68
|
-
* Validate and sanitize plan structure after parsing.
|
|
69
|
-
* Filters out invalid phases and ensures required fields exist.
|
|
70
|
-
*/
|
|
71
32
|
export declare function validatePlanStructure(raw: any): any;
|
|
@@ -1,27 +1,9 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* YAML Repair Utility
|
|
3
|
-
*
|
|
4
|
-
* Provides YAML string escaping, corruption detection, and auto-repair
|
|
5
|
-
* for Weave plan files. Handles common YAML corruption patterns:
|
|
6
|
-
* - Unclosed/mismatched quotes
|
|
7
|
-
* - Unescaped special characters in string values
|
|
8
|
-
* - Tab→space conversion
|
|
9
|
-
* - Truncated files
|
|
10
|
-
*/
|
|
11
1
|
import * as fs from 'node:fs';
|
|
12
2
|
import * as path from 'node:path';
|
|
13
|
-
// ============================================================================
|
|
14
|
-
// YAML String Escaping
|
|
15
|
-
// ============================================================================
|
|
16
|
-
/**
|
|
17
|
-
* Properly escape a string value for YAML double-quoted format.
|
|
18
|
-
* Handles all YAML special characters that would break parsing.
|
|
19
|
-
*/
|
|
20
3
|
export function yamlEscapeString(value) {
|
|
21
4
|
if (value === undefined || value === null)
|
|
22
5
|
return '""';
|
|
23
6
|
const str = String(value);
|
|
24
|
-
// If the string is simple (no special chars), return as-is with quotes
|
|
25
7
|
if (/^[a-zA-Z0-9가-힣ぁ-んァ-ヶ\s.,;:!?@#%^&*()_+=\-\[\]{}/<>~`|']+$/.test(str)
|
|
26
8
|
&& !str.includes('"')
|
|
27
9
|
&& !str.includes('\\')
|
|
@@ -29,40 +11,30 @@ export function yamlEscapeString(value) {
|
|
|
29
11
|
&& !str.endsWith(' ')) {
|
|
30
12
|
return `"${str}"`;
|
|
31
13
|
}
|
|
32
|
-
// Escape special characters for YAML double-quoted strings
|
|
33
14
|
const escaped = str
|
|
34
|
-
.replace(/\\/g, '\\\\')
|
|
35
|
-
.replace(/"/g, '\\"')
|
|
36
|
-
.replace(/\n/g, '\\n')
|
|
37
|
-
.replace(/\r/g, '\\r')
|
|
38
|
-
.replace(/\t/g, '\\t')
|
|
39
|
-
.replace(/\0/g, '\\0');
|
|
15
|
+
.replace(/\\/g, '\\\\')
|
|
16
|
+
.replace(/"/g, '\\"')
|
|
17
|
+
.replace(/\n/g, '\\n')
|
|
18
|
+
.replace(/\r/g, '\\r')
|
|
19
|
+
.replace(/\t/g, '\\t')
|
|
20
|
+
.replace(/\0/g, '\\0');
|
|
40
21
|
return `"${escaped}"`;
|
|
41
22
|
}
|
|
42
|
-
// ============================================================================
|
|
43
|
-
// YAML Corruption Detection
|
|
44
|
-
// ============================================================================
|
|
45
|
-
/**
|
|
46
|
-
* Detect common YAML corruption patterns and return error details.
|
|
47
|
-
*/
|
|
48
23
|
function detectCorruption(content) {
|
|
49
24
|
const issues = [];
|
|
50
25
|
const lines = content.split('\n');
|
|
51
26
|
for (let i = 0; i < lines.length; i++) {
|
|
52
27
|
const line = lines[i];
|
|
53
28
|
const lineNum = i + 1;
|
|
54
|
-
// Check for unclosed double quotes in value positions
|
|
55
29
|
const valueMatch = line.match(/^(\s*[\w_-]+:\s*)"(.*)/);
|
|
56
30
|
if (valueMatch) {
|
|
57
31
|
const afterColon = valueMatch[2];
|
|
58
|
-
// Count unescaped quotes
|
|
59
32
|
const unescaped = afterColon.replace(/\\"/g, '');
|
|
60
33
|
const quoteCount = (unescaped.match(/"/g) || []).length;
|
|
61
34
|
if (quoteCount % 2 !== 0) {
|
|
62
35
|
issues.push(`Line ${lineNum}: Unclosed double quote in value`);
|
|
63
36
|
}
|
|
64
37
|
}
|
|
65
|
-
// Check for array items with unclosed quotes
|
|
66
38
|
const arrayMatch = line.match(/^(\s*-\s*)"(.*)/);
|
|
67
39
|
if (arrayMatch && !line.match(/^(\s*-\s*\w+:\s*)/)) {
|
|
68
40
|
const afterDash = arrayMatch[2];
|
|
@@ -72,7 +44,6 @@ function detectCorruption(content) {
|
|
|
72
44
|
issues.push(`Line ${lineNum}: Unclosed double quote in array item`);
|
|
73
45
|
}
|
|
74
46
|
}
|
|
75
|
-
// Check for tabs (YAML requires spaces)
|
|
76
47
|
if (line.includes('\t') && !line.match(/:\s*".*\t.*"/)) {
|
|
77
48
|
issues.push(`Line ${lineNum}: Tab character in indentation`);
|
|
78
49
|
}
|
|
@@ -82,23 +53,14 @@ function detectCorruption(content) {
|
|
|
82
53
|
issues,
|
|
83
54
|
};
|
|
84
55
|
}
|
|
85
|
-
// ============================================================================
|
|
86
|
-
// YAML Content Repair
|
|
87
|
-
// ============================================================================
|
|
88
|
-
/**
|
|
89
|
-
* Attempt to repair corrupted YAML content.
|
|
90
|
-
* Returns the repaired content or null if unrecoverable.
|
|
91
|
-
*/
|
|
92
56
|
export function repairYamlContent(content) {
|
|
93
57
|
const changes = [];
|
|
94
58
|
const missingInfo = [];
|
|
95
59
|
let repaired = content;
|
|
96
|
-
// 1. Convert tabs to spaces (YAML requires spaces)
|
|
97
60
|
if (repaired.includes('\t')) {
|
|
98
61
|
repaired = repaired.replace(/\t/g, ' ');
|
|
99
62
|
changes.push('Converted tabs to spaces');
|
|
100
63
|
}
|
|
101
|
-
// 2. Normalize line endings
|
|
102
64
|
if (repaired.includes('\r\n')) {
|
|
103
65
|
repaired = repaired.replace(/\r\n/g, '\n');
|
|
104
66
|
changes.push('Normalized line endings (CRLF→LF)');
|
|
@@ -107,27 +69,22 @@ export function repairYamlContent(content) {
|
|
|
107
69
|
repaired = repaired.replace(/\r/g, '\n');
|
|
108
70
|
changes.push('Normalized line endings (CR→LF)');
|
|
109
71
|
}
|
|
110
|
-
// 3. Fix unclosed quotes in key-value pairs
|
|
111
72
|
const lines = repaired.split('\n');
|
|
112
73
|
const fixedLines = [];
|
|
113
74
|
for (let i = 0; i < lines.length; i++) {
|
|
114
75
|
let line = lines[i];
|
|
115
76
|
const lineNum = i + 1;
|
|
116
|
-
// Pattern: key: "value with "embedded" quotes or unclosed
|
|
117
77
|
const kvMatch = line.match(/^(\s*)([\w_-]+):\s*"(.*)$/);
|
|
118
78
|
if (kvMatch) {
|
|
119
79
|
const [, indent, key, rest] = kvMatch;
|
|
120
|
-
// Check if the rest ends with a properly closed quote
|
|
121
80
|
if (!rest.endsWith('"') || hasUnbalancedQuotes(rest)) {
|
|
122
|
-
// Fix: escape internal quotes and ensure closure
|
|
123
81
|
const fixedValue = rest
|
|
124
|
-
.replace(/"$/g, '')
|
|
125
|
-
.replace(/(?<!\\)"/g, '\\"');
|
|
82
|
+
.replace(/"$/g, '')
|
|
83
|
+
.replace(/(?<!\\)"/g, '\\"');
|
|
126
84
|
line = `${indent}${key}: "${fixedValue}"`;
|
|
127
85
|
changes.push(`Line ${lineNum}: Fixed unclosed/mismatched quotes in '${key}'`);
|
|
128
86
|
}
|
|
129
87
|
}
|
|
130
|
-
// Pattern: array item - "value with unclosed quotes
|
|
131
88
|
const arrayMatch = line.match(/^(\s*-\s*)"(.*)$/);
|
|
132
89
|
if (arrayMatch && !line.match(/^(\s*-\s*\w+:\s*)/)) {
|
|
133
90
|
const [, prefix, rest] = arrayMatch;
|
|
@@ -139,7 +96,6 @@ export function repairYamlContent(content) {
|
|
|
139
96
|
changes.push(`Line ${lineNum}: Fixed unclosed quotes in array item`);
|
|
140
97
|
}
|
|
141
98
|
}
|
|
142
|
-
// Pattern: array item key: "value with unclosed quotes
|
|
143
99
|
const arrayKvMatch = line.match(/^(\s*-?\s*)([\w_-]+):\s*"(.*)$/);
|
|
144
100
|
if (arrayKvMatch) {
|
|
145
101
|
const [, indent, key, rest] = arrayKvMatch;
|
|
@@ -154,9 +110,7 @@ export function repairYamlContent(content) {
|
|
|
154
110
|
fixedLines.push(line);
|
|
155
111
|
}
|
|
156
112
|
repaired = fixedLines.join('\n');
|
|
157
|
-
// 4. Validate the repaired content by attempting a parse
|
|
158
113
|
try {
|
|
159
|
-
// Dynamic import would be async, so we do a basic structural check
|
|
160
114
|
if (!hasBasicYamlStructure(repaired)) {
|
|
161
115
|
missingInfo.push({
|
|
162
116
|
field: 'structure',
|
|
@@ -165,78 +119,48 @@ export function repairYamlContent(content) {
|
|
|
165
119
|
}
|
|
166
120
|
}
|
|
167
121
|
catch {
|
|
168
|
-
// ignore validation errors at this stage
|
|
169
122
|
}
|
|
170
123
|
if (changes.length === 0 && missingInfo.length > 0) {
|
|
171
124
|
return { repaired: null, changes, missingInfo };
|
|
172
125
|
}
|
|
173
126
|
return { repaired, changes, missingInfo };
|
|
174
127
|
}
|
|
175
|
-
/**
|
|
176
|
-
* Check if a string (after the opening quote) has unbalanced quotes.
|
|
177
|
-
*/
|
|
178
128
|
function hasUnbalancedQuotes(str) {
|
|
179
|
-
// Remove escaped quotes
|
|
180
129
|
const cleaned = str.replace(/\\"/g, '');
|
|
181
|
-
// Count remaining quotes (should be odd number since the opening was already stripped)
|
|
182
130
|
const count = (cleaned.match(/"/g) || []).length;
|
|
183
|
-
// After opening quote was stripped, remaining should have odd count
|
|
184
|
-
// (one for closing). Even count means unbalanced.
|
|
185
131
|
return count % 2 === 0;
|
|
186
132
|
}
|
|
187
|
-
/**
|
|
188
|
-
* Basic structural validation for a Weave plan YAML.
|
|
189
|
-
*/
|
|
190
133
|
function hasBasicYamlStructure(content) {
|
|
191
134
|
return content.includes('project_name:') && content.includes('phases:');
|
|
192
135
|
}
|
|
193
|
-
// ============================================================================
|
|
194
|
-
// Safe File I/O
|
|
195
|
-
// ============================================================================
|
|
196
|
-
/**
|
|
197
|
-
* Write a file atomically with backup.
|
|
198
|
-
* 1. Copy existing file to .bak
|
|
199
|
-
* 2. Write to .tmp
|
|
200
|
-
* 3. Rename .tmp to target
|
|
201
|
-
*/
|
|
202
136
|
export function safeWriteFile(filePath, content) {
|
|
203
|
-
// Create backup of existing file
|
|
204
137
|
if (fs.existsSync(filePath)) {
|
|
205
138
|
try {
|
|
206
139
|
fs.copyFileSync(filePath, `${filePath}.bak`);
|
|
207
140
|
}
|
|
208
141
|
catch {
|
|
209
|
-
// Backup failed, continue anyway
|
|
210
142
|
}
|
|
211
143
|
}
|
|
212
144
|
const tmpPath = `${filePath}.tmp`;
|
|
213
145
|
try {
|
|
214
146
|
fs.writeFileSync(tmpPath, content, 'utf-8');
|
|
215
|
-
// Atomic rename
|
|
216
147
|
try {
|
|
217
148
|
fs.renameSync(tmpPath, filePath);
|
|
218
149
|
}
|
|
219
150
|
catch {
|
|
220
|
-
// Windows fallback: rename can fail if target exists
|
|
221
151
|
fs.writeFileSync(filePath, content, 'utf-8');
|
|
222
152
|
try {
|
|
223
153
|
fs.unlinkSync(tmpPath);
|
|
224
154
|
}
|
|
225
|
-
catch {
|
|
155
|
+
catch { }
|
|
226
156
|
}
|
|
227
157
|
}
|
|
228
158
|
catch (e) {
|
|
229
|
-
// Last resort: direct write
|
|
230
159
|
fs.writeFileSync(filePath, content, 'utf-8');
|
|
231
160
|
}
|
|
232
161
|
}
|
|
233
|
-
/**
|
|
234
|
-
* Safely read and parse a YAML file with auto-repair on failure.
|
|
235
|
-
* Returns the parsed object, or an error message.
|
|
236
|
-
*/
|
|
237
162
|
export async function safeReadYaml(filePath) {
|
|
238
163
|
const { parse } = await import('yaml');
|
|
239
|
-
// 1. Try normal read + parse
|
|
240
164
|
try {
|
|
241
165
|
const content = fs.readFileSync(filePath, 'utf-8');
|
|
242
166
|
const data = parse(content);
|
|
@@ -244,18 +168,16 @@ export async function safeReadYaml(filePath) {
|
|
|
244
168
|
}
|
|
245
169
|
catch (parseError) {
|
|
246
170
|
const errorMsg = parseError instanceof Error ? parseError.message : String(parseError);
|
|
247
|
-
// 2. Try auto-repair
|
|
248
171
|
try {
|
|
249
172
|
const rawContent = fs.readFileSync(filePath, 'utf-8');
|
|
250
173
|
const repair = repairYamlContent(rawContent);
|
|
251
174
|
if (repair.repaired) {
|
|
252
175
|
try {
|
|
253
176
|
const data = parse(repair.repaired);
|
|
254
|
-
// Save corrupted backup and write repaired content
|
|
255
177
|
try {
|
|
256
178
|
fs.copyFileSync(filePath, `${filePath}.corrupted`);
|
|
257
179
|
}
|
|
258
|
-
catch {
|
|
180
|
+
catch { }
|
|
259
181
|
safeWriteFile(filePath, repair.repaired);
|
|
260
182
|
console.log(`[PhaseManager] Auto-repaired ${path.basename(filePath)}: ${repair.changes.join(', ')}`);
|
|
261
183
|
return {
|
|
@@ -266,29 +188,25 @@ export async function safeReadYaml(filePath) {
|
|
|
266
188
|
};
|
|
267
189
|
}
|
|
268
190
|
catch (repairParseError) {
|
|
269
|
-
// Repair didn't fix the parse error
|
|
270
191
|
}
|
|
271
192
|
}
|
|
272
193
|
}
|
|
273
|
-
catch {
|
|
274
|
-
// 3. Try .bak file
|
|
194
|
+
catch { }
|
|
275
195
|
const bakPath = `${filePath}.bak`;
|
|
276
196
|
if (fs.existsSync(bakPath)) {
|
|
277
197
|
try {
|
|
278
198
|
const bakContent = fs.readFileSync(bakPath, 'utf-8');
|
|
279
199
|
const data = parse(bakContent);
|
|
280
|
-
// Save corrupted file and restore from backup
|
|
281
200
|
try {
|
|
282
201
|
fs.copyFileSync(filePath, `${filePath}.corrupted`);
|
|
283
202
|
}
|
|
284
|
-
catch {
|
|
203
|
+
catch { }
|
|
285
204
|
fs.copyFileSync(bakPath, filePath);
|
|
286
205
|
console.log(`[PhaseManager] Restored ${path.basename(filePath)} from backup`);
|
|
287
206
|
return { data, repaired: true, changes: ['Restored from .bak backup'] };
|
|
288
207
|
}
|
|
289
|
-
catch {
|
|
208
|
+
catch { }
|
|
290
209
|
}
|
|
291
|
-
// 4. Unrecoverable
|
|
292
210
|
return {
|
|
293
211
|
data: null,
|
|
294
212
|
repaired: false,
|
|
@@ -300,12 +218,6 @@ export async function safeReadYaml(filePath) {
|
|
|
300
218
|
};
|
|
301
219
|
}
|
|
302
220
|
}
|
|
303
|
-
// ============================================================================
|
|
304
|
-
// Plan File Repair
|
|
305
|
-
// ============================================================================
|
|
306
|
-
/**
|
|
307
|
-
* Repair a single plan YAML file.
|
|
308
|
-
*/
|
|
309
221
|
export async function repairPlanFile(filePath) {
|
|
310
222
|
const fileName = path.basename(filePath);
|
|
311
223
|
if (!fs.existsSync(filePath)) {
|
|
@@ -330,24 +242,18 @@ export async function repairPlanFile(filePath) {
|
|
|
330
242
|
missingInfo: result.missingInfo,
|
|
331
243
|
};
|
|
332
244
|
}
|
|
333
|
-
/**
|
|
334
|
-
* Scan and repair all plan YAML files in the plans/ directory.
|
|
335
|
-
*/
|
|
336
245
|
export async function repairAllPlans(basePath = process.cwd()) {
|
|
337
246
|
const weaveDir = path.join(basePath, '.opencode', 'weave');
|
|
338
247
|
const plansDir = path.join(weaveDir, 'plans');
|
|
339
248
|
const results = [];
|
|
340
|
-
// Check legacy PLAN.yaml
|
|
341
249
|
const legacyPath = path.join(weaveDir, 'PLAN.yaml');
|
|
342
250
|
if (fs.existsSync(legacyPath)) {
|
|
343
251
|
results.push(await repairPlanFile(legacyPath));
|
|
344
252
|
}
|
|
345
|
-
// Check state.yaml
|
|
346
253
|
const statePath = path.join(weaveDir, 'state.yaml');
|
|
347
254
|
if (fs.existsSync(statePath)) {
|
|
348
255
|
results.push(await repairPlanFile(statePath));
|
|
349
256
|
}
|
|
350
|
-
// Scan plans/ directory
|
|
351
257
|
if (fs.existsSync(plansDir)) {
|
|
352
258
|
try {
|
|
353
259
|
const files = fs.readdirSync(plansDir).filter(f => f.endsWith('.yaml'));
|
|
@@ -360,7 +266,6 @@ export async function repairAllPlans(basePath = process.cwd()) {
|
|
|
360
266
|
console.error('[YamlRepair] Failed to scan plans directory:', e);
|
|
361
267
|
}
|
|
362
268
|
}
|
|
363
|
-
// Generate summary
|
|
364
269
|
const ok = results.filter(r => r.status === 'ok').length;
|
|
365
270
|
const repaired = results.filter(r => r.status === 'repaired').length;
|
|
366
271
|
const unrecoverable = results.filter(r => r.status === 'unrecoverable').length;
|
|
@@ -391,7 +296,6 @@ export async function repairAllPlans(basePath = process.cwd()) {
|
|
|
391
296
|
lines.push('');
|
|
392
297
|
}
|
|
393
298
|
}
|
|
394
|
-
// Advice for unrecoverable files
|
|
395
299
|
if (unrecoverable > 0) {
|
|
396
300
|
lines.push('---');
|
|
397
301
|
lines.push('### Recovery Options for Unrecoverable Files\n');
|
|
@@ -401,18 +305,12 @@ export async function repairAllPlans(basePath = process.cwd()) {
|
|
|
401
305
|
}
|
|
402
306
|
return { results, summary: lines.join('\n') };
|
|
403
307
|
}
|
|
404
|
-
/**
|
|
405
|
-
* Validate and sanitize plan structure after parsing.
|
|
406
|
-
* Filters out invalid phases and ensures required fields exist.
|
|
407
|
-
*/
|
|
408
308
|
export function validatePlanStructure(raw) {
|
|
409
309
|
if (!raw || typeof raw !== 'object')
|
|
410
310
|
return null;
|
|
411
|
-
// Ensure required fields
|
|
412
311
|
if (!raw.project_name && !raw.projectName) {
|
|
413
312
|
raw.project_name = 'Unknown (recovered)';
|
|
414
313
|
}
|
|
415
|
-
// Filter invalid phases
|
|
416
314
|
if (Array.isArray(raw.phases)) {
|
|
417
315
|
raw.phases = raw.phases.filter((p) => {
|
|
418
316
|
if (!p || typeof p !== 'object')
|
|
@@ -421,7 +319,6 @@ export function validatePlanStructure(raw) {
|
|
|
421
319
|
return false;
|
|
422
320
|
return true;
|
|
423
321
|
});
|
|
424
|
-
// Sanitize each phase
|
|
425
322
|
for (const phase of raw.phases) {
|
|
426
323
|
if (!phase.name)
|
|
427
324
|
phase.name = phase.id;
|