open-wiki-spec 0.1.0 → 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 +14 -12
- package/bin/open-wiki-spec.js +0 -0
- package/dist/cli/commands/apply.d.ts.map +1 -1
- package/dist/cli/commands/apply.js +26 -5
- package/dist/cli/commands/apply.js.map +1 -1
- package/dist/cli/commands/archive.d.ts +1 -0
- package/dist/cli/commands/archive.d.ts.map +1 -1
- package/dist/cli/commands/archive.js +12 -4
- package/dist/cli/commands/archive.js.map +1 -1
- package/dist/cli/commands/continue.d.ts.map +1 -1
- package/dist/cli/commands/continue.js +8 -4
- package/dist/cli/commands/continue.js.map +1 -1
- package/dist/cli/commands/error-handler.d.ts +6 -0
- package/dist/cli/commands/error-handler.d.ts.map +1 -0
- package/dist/cli/commands/error-handler.js +15 -0
- package/dist/cli/commands/error-handler.js.map +1 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +12 -3
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/list.d.ts.map +1 -1
- package/dist/cli/commands/list.js +3 -3
- package/dist/cli/commands/list.js.map +1 -1
- package/dist/cli/commands/migrate.d.ts.map +1 -1
- package/dist/cli/commands/migrate.js +5 -1
- package/dist/cli/commands/migrate.js.map +1 -1
- package/dist/cli/commands/propose.d.ts.map +1 -1
- package/dist/cli/commands/propose.js +20 -3
- package/dist/cli/commands/propose.js.map +1 -1
- package/dist/cli/commands/query.d.ts.map +1 -1
- package/dist/cli/commands/query.js +25 -20
- package/dist/cli/commands/query.js.map +1 -1
- package/dist/cli/commands/status.d.ts +7 -2
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +123 -53
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/verify.d.ts +3 -0
- package/dist/cli/commands/verify.d.ts.map +1 -1
- package/dist/cli/commands/verify.js +6 -8
- package/dist/cli/commands/verify.js.map +1 -1
- package/dist/cli/index.js +3 -6
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init/init-engine.d.ts.map +1 -1
- package/dist/cli/init/init-engine.js +65 -0
- package/dist/cli/init/init-engine.js.map +1 -1
- package/dist/cli/init/meta-files.d.ts.map +1 -1
- package/dist/cli/init/meta-files.js +8 -12
- package/dist/cli/init/meta-files.js.map +1 -1
- package/dist/cli/init/skill-generator.d.ts.map +1 -1
- package/dist/cli/init/skill-generator.js +78 -19
- package/dist/cli/init/skill-generator.js.map +1 -1
- package/dist/cli/init/types.d.ts +3 -0
- package/dist/cli/init/types.d.ts.map +1 -1
- package/dist/core/embedding/cache.d.ts +28 -0
- package/dist/core/embedding/cache.d.ts.map +1 -0
- package/dist/core/embedding/cache.js +53 -0
- package/dist/core/embedding/cache.js.map +1 -0
- package/dist/core/embedding/embedder.d.ts +26 -0
- package/dist/core/embedding/embedder.d.ts.map +1 -0
- package/dist/core/embedding/embedder.js +51 -0
- package/dist/core/embedding/embedder.js.map +1 -0
- package/dist/core/embedding/index.d.ts +5 -0
- package/dist/core/embedding/index.d.ts.map +1 -0
- package/dist/core/embedding/index.js +5 -0
- package/dist/core/embedding/index.js.map +1 -0
- package/dist/core/embedding/semantic-recall.d.ts +18 -0
- package/dist/core/embedding/semantic-recall.d.ts.map +1 -0
- package/dist/core/embedding/semantic-recall.js +37 -0
- package/dist/core/embedding/semantic-recall.js.map +1 -0
- package/dist/core/embedding/similarity.d.ts +5 -0
- package/dist/core/embedding/similarity.d.ts.map +1 -0
- package/dist/core/embedding/similarity.js +21 -0
- package/dist/core/embedding/similarity.js.map +1 -0
- package/dist/core/index/build.d.ts.map +1 -1
- package/dist/core/index/build.js +38 -3
- package/dist/core/index/build.js.map +1 -1
- package/dist/core/index/resolve.d.ts +2 -1
- package/dist/core/index/resolve.d.ts.map +1 -1
- package/dist/core/index/resolve.js +17 -4
- package/dist/core/index/resolve.js.map +1 -1
- package/dist/core/index/scan.js +1 -1
- package/dist/core/index/scan.js.map +1 -1
- package/dist/core/index/validate.d.ts +2 -1
- package/dist/core/index/validate.d.ts.map +1 -1
- package/dist/core/index/validate.js +23 -2
- package/dist/core/index/validate.js.map +1 -1
- package/dist/core/migrate/change-converter.js +5 -5
- package/dist/core/migrate/change-converter.js.map +1 -1
- package/dist/core/migrate/migrate.js +1 -1
- package/dist/core/migrate/migrate.js.map +1 -1
- package/dist/core/migrate/spec-converter.js +1 -2
- package/dist/core/migrate/spec-converter.js.map +1 -1
- package/dist/core/parser/wikilink-parser.d.ts.map +1 -1
- package/dist/core/parser/wikilink-parser.js +13 -1
- package/dist/core/parser/wikilink-parser.js.map +1 -1
- package/dist/core/retrieval/constants.d.ts +4 -1
- package/dist/core/retrieval/constants.d.ts.map +1 -1
- package/dist/core/retrieval/constants.js +3 -0
- package/dist/core/retrieval/constants.js.map +1 -1
- package/dist/core/retrieval/retrieve.d.ts +6 -0
- package/dist/core/retrieval/retrieve.d.ts.map +1 -1
- package/dist/core/retrieval/retrieve.js +17 -4
- package/dist/core/retrieval/retrieve.js.map +1 -1
- package/dist/core/retrieval/scoring.d.ts +3 -2
- package/dist/core/retrieval/scoring.d.ts.map +1 -1
- package/dist/core/retrieval/scoring.js +42 -3
- package/dist/core/retrieval/scoring.js.map +1 -1
- package/dist/core/schema/base.schema.js +1 -1
- package/dist/core/schema/base.schema.js.map +1 -1
- package/dist/core/schema/requirement.d.ts +2 -2
- package/dist/core/workflow/apply/apply.d.ts.map +1 -1
- package/dist/core/workflow/apply/apply.js +265 -15
- package/dist/core/workflow/apply/apply.js.map +1 -1
- package/dist/core/workflow/apply/feature-updater.d.ts +9 -5
- package/dist/core/workflow/apply/feature-updater.d.ts.map +1 -1
- package/dist/core/workflow/apply/feature-updater.js +130 -8
- package/dist/core/workflow/apply/feature-updater.js.map +1 -1
- package/dist/core/workflow/apply/types.d.ts +5 -0
- package/dist/core/workflow/apply/types.d.ts.map +1 -1
- package/dist/core/workflow/continue/continue.d.ts +1 -0
- package/dist/core/workflow/continue/continue.d.ts.map +1 -1
- package/dist/core/workflow/continue/continue.js +94 -34
- package/dist/core/workflow/continue/continue.js.map +1 -1
- package/dist/core/workflow/continue/types.d.ts +1 -1
- package/dist/core/workflow/continue/types.d.ts.map +1 -1
- package/dist/core/workflow/propose/note-creator.d.ts +2 -0
- package/dist/core/workflow/propose/note-creator.d.ts.map +1 -1
- package/dist/core/workflow/propose/note-creator.js +33 -10
- package/dist/core/workflow/propose/note-creator.js.map +1 -1
- package/dist/core/workflow/propose/propose.d.ts.map +1 -1
- package/dist/core/workflow/propose/propose.js +131 -14
- package/dist/core/workflow/propose/propose.js.map +1 -1
- package/dist/core/workflow/propose/query-normalizer.d.ts +7 -1
- package/dist/core/workflow/propose/query-normalizer.d.ts.map +1 -1
- package/dist/core/workflow/propose/query-normalizer.js +52 -2
- package/dist/core/workflow/propose/query-normalizer.js.map +1 -1
- package/dist/core/workflow/propose/types.d.ts +7 -3
- package/dist/core/workflow/propose/types.d.ts.map +1 -1
- package/dist/core/workflow/query/query-note-creator.js +1 -1
- package/dist/core/workflow/query/query-note-creator.js.map +1 -1
- package/dist/core/workflow/query/query-search.d.ts +3 -1
- package/dist/core/workflow/query/query-search.d.ts.map +1 -1
- package/dist/core/workflow/query/query-search.js +6 -2
- package/dist/core/workflow/query/query-search.js.map +1 -1
- package/dist/core/workflow/verify/completeness.d.ts +2 -2
- package/dist/core/workflow/verify/completeness.d.ts.map +1 -1
- package/dist/core/workflow/verify/completeness.js +101 -5
- package/dist/core/workflow/verify/completeness.js.map +1 -1
- package/dist/core/workflow/verify/correctness.d.ts +6 -0
- package/dist/core/workflow/verify/correctness.d.ts.map +1 -1
- package/dist/core/workflow/verify/correctness.js +35 -0
- package/dist/core/workflow/verify/correctness.js.map +1 -1
- package/dist/core/workflow/verify/index.d.ts +2 -2
- package/dist/core/workflow/verify/index.d.ts.map +1 -1
- package/dist/core/workflow/verify/index.js +2 -2
- package/dist/core/workflow/verify/index.js.map +1 -1
- package/dist/core/workflow/verify/vault-integrity.d.ts +11 -0
- package/dist/core/workflow/verify/vault-integrity.d.ts.map +1 -1
- package/dist/core/workflow/verify/vault-integrity.js +47 -2
- package/dist/core/workflow/verify/vault-integrity.js.map +1 -1
- package/dist/core/workflow/verify/verify.d.ts.map +1 -1
- package/dist/core/workflow/verify/verify.js +6 -2
- package/dist/core/workflow/verify/verify.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/dist/types/index-record.d.ts +2 -1
- package/dist/types/index-record.d.ts.map +1 -1
- package/dist/types/retrieval.d.ts +2 -0
- package/dist/types/retrieval.d.ts.map +1 -1
- package/dist/utils/path-safety.d.ts +8 -0
- package/dist/utils/path-safety.d.ts.map +1 -0
- package/dist/utils/path-safety.js +15 -0
- package/dist/utils/path-safety.js.map +1 -0
- package/package.json +4 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retrieve.d.ts","sourceRoot":"","sources":["../../../src/core/retrieval/retrieve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAqB,MAAM,0BAA0B,CAAC;AACnG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,KAAK,EAAE,cAAc,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAS/E,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IAClC,UAAU,CAAC,EAAE,OAAO,CAAC,wBAAwB,CAAC,CAAC;IAC/C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"retrieve.d.ts","sourceRoot":"","sources":["../../../src/core/retrieval/retrieve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAqB,MAAM,0BAA0B,CAAC;AACnG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,KAAK,EAAE,cAAc,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAS/E,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IAClC,UAAU,CAAC,EAAE,OAAO,CAAC,wBAAwB,CAAC,CAAC;IAC/C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B;;;;OAIG;IACH,cAAc,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9C;AAuBD;;;GAGG;AACH,wBAAgB,QAAQ,CACtB,KAAK,EAAE,UAAU,EACjB,KAAK,EAAE,cAAc,EACrB,OAAO,CAAC,EAAE,gBAAgB,GACzB,eAAe,CAwDjB"}
|
|
@@ -29,11 +29,24 @@ export function retrieve(index, query, options) {
|
|
|
29
29
|
const thresholds = mergeThresholds(DEFAULT_THRESHOLDS, options?.thresholds);
|
|
30
30
|
const maxCandidates = options?.maxCandidates ?? 10;
|
|
31
31
|
// Step 1: Lexical retrieval
|
|
32
|
-
const
|
|
33
|
-
// Step
|
|
32
|
+
const lexicalCandidates = lexicalRetrieval(query, index);
|
|
33
|
+
// Step 1b: Merge semantic candidates (if available) before graph expansion
|
|
34
|
+
const semanticScores = options?.semanticScores;
|
|
35
|
+
const firstPass = new Set(lexicalCandidates);
|
|
36
|
+
if (semanticScores) {
|
|
37
|
+
for (const id of semanticScores.keys()) {
|
|
38
|
+
if (index.records.has(id)) {
|
|
39
|
+
firstPass.add(id);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Step 2: Graph expansion (semantic candidates get graph neighbors too)
|
|
34
44
|
const expanded = graphExpand(firstPass, index);
|
|
35
|
-
// Step 3: Score all expanded candidates
|
|
36
|
-
const
|
|
45
|
+
// Step 3: Score all expanded candidates (with embedding scores for Signal 10)
|
|
46
|
+
const embeddingScores = semanticScores
|
|
47
|
+
? new Map(semanticScores)
|
|
48
|
+
: undefined;
|
|
49
|
+
const scored = scoreCandidates(expanded, query, index, weights, embeddingScores);
|
|
37
50
|
// Trim to max candidates
|
|
38
51
|
const topCandidates = scored.slice(0, maxCandidates);
|
|
39
52
|
// Step 4: Classify
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retrieve.js","sourceRoot":"","sources":["../../../src/core/retrieval/retrieve.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"retrieve.js","sourceRoot":"","sources":["../../../src/core/retrieval/retrieve.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,7 +8,8 @@ export interface ScoredCandidateInternal extends ScoredCandidate {
|
|
|
8
8
|
signals: ScoringSignal[];
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
|
-
* Score all candidates using the
|
|
11
|
+
* Score all candidates using the additive signal model (section 9.1 + 9.2).
|
|
12
|
+
* Optional embeddingScores map provides pre-computed cosine similarities for Signal 10.
|
|
12
13
|
*/
|
|
13
|
-
export declare function scoreCandidates(candidateIds: Set<string>, query: RetrievalQuery, index: VaultIndex, weights?: ScoringWeights): ScoredCandidate[];
|
|
14
|
+
export declare function scoreCandidates(candidateIds: Set<string>, query: RetrievalQuery, index: VaultIndex, weights?: ScoringWeights, embeddingScores?: Map<string, number>): ScoredCandidate[];
|
|
14
15
|
//# sourceMappingURL=scoring.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scoring.d.ts","sourceRoot":"","sources":["../../../src/core/retrieval/scoring.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAChF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAIpE;;GAEG;AACH,MAAM,WAAW,uBAAwB,SAAQ,eAAe;IAC9D,OAAO,EAAE,aAAa,EAAE,CAAC;CAC1B;AAED
|
|
1
|
+
{"version":3,"file":"scoring.d.ts","sourceRoot":"","sources":["../../../src/core/retrieval/scoring.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAChF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAIpE;;GAEG;AACH,MAAM,WAAW,uBAAwB,SAAQ,eAAe;IAC9D,OAAO,EAAE,aAAa,EAAE,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,EACzB,KAAK,EAAE,cAAc,EACrB,KAAK,EAAE,UAAU,EACjB,OAAO,GAAE,cAAgC,EACzC,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GACpC,eAAe,EAAE,CAmNnB"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { DEFAULT_WEIGHTS } from './constants.js';
|
|
2
2
|
import { findSystemByTerm, isActiveChangeStatus } from './helpers.js';
|
|
3
3
|
/**
|
|
4
|
-
* Score all candidates using the
|
|
4
|
+
* Score all candidates using the additive signal model (section 9.1 + 9.2).
|
|
5
|
+
* Optional embeddingScores map provides pre-computed cosine similarities for Signal 10.
|
|
5
6
|
*/
|
|
6
|
-
export function scoreCandidates(candidateIds, query, index, weights = DEFAULT_WEIGHTS) {
|
|
7
|
+
export function scoreCandidates(candidateIds, query, index, weights = DEFAULT_WEIGHTS, embeddingScores) {
|
|
7
8
|
const allTerms = [...query.feature_terms, ...query.system_terms, ...query.entity_terms];
|
|
8
9
|
const searchTerms = allTerms.map((t) => t.toLowerCase());
|
|
9
10
|
const summaryLower = query.summary.toLowerCase();
|
|
@@ -13,8 +14,9 @@ export function scoreCandidates(candidateIds, query, index, weights = DEFAULT_WE
|
|
|
13
14
|
if (!record)
|
|
14
15
|
continue;
|
|
15
16
|
const signals = [];
|
|
16
|
-
// Signal 1:
|
|
17
|
+
// Signal 1: Title match (exact, prefix-stripped, or partial)
|
|
17
18
|
const titleLower = record.title.toLowerCase();
|
|
19
|
+
const titleWithoutPrefix = titleLower.replace(/^(feature|change|system|decision|source|query):\s*/i, '');
|
|
18
20
|
if (titleLower === summaryLower || searchTerms.some((t) => titleLower === t)) {
|
|
19
21
|
signals.push({
|
|
20
22
|
signal: 'exact_title',
|
|
@@ -22,6 +24,22 @@ export function scoreCandidates(candidateIds, query, index, weights = DEFAULT_WE
|
|
|
22
24
|
reason: `exact title match: "${record.title}"`,
|
|
23
25
|
});
|
|
24
26
|
}
|
|
27
|
+
else if (searchTerms.some((t) => titleWithoutPrefix === t)) {
|
|
28
|
+
// Search term matches title minus type prefix (+30)
|
|
29
|
+
signals.push({
|
|
30
|
+
signal: 'exact_title',
|
|
31
|
+
points: 30,
|
|
32
|
+
reason: `prefix-stripped title match: "${record.title}"`,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
else if (searchTerms.some((t) => titleLower.includes(t) || titleWithoutPrefix.includes(t))) {
|
|
36
|
+
// Title contains any search term (+20)
|
|
37
|
+
signals.push({
|
|
38
|
+
signal: 'title_partial',
|
|
39
|
+
points: weights.title_partial,
|
|
40
|
+
reason: `partial title match: "${record.title}"`,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
25
43
|
// Signal 2: Alias match (at most once)
|
|
26
44
|
for (const alias of record.aliases) {
|
|
27
45
|
const aliasLower = alias.toLowerCase();
|
|
@@ -146,6 +164,25 @@ export function scoreCandidates(candidateIds, query, index, weights = DEFAULT_WE
|
|
|
146
164
|
reason: `strong full-text hit: ${matchedTerms.join(', ')}`,
|
|
147
165
|
});
|
|
148
166
|
}
|
|
167
|
+
else if (matchedTerms.length === 1) {
|
|
168
|
+
signals.push({
|
|
169
|
+
signal: 'full_text_weak',
|
|
170
|
+
points: weights.full_text_weak,
|
|
171
|
+
reason: `weak full-text hit: ${matchedTerms.join(', ')}`,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
// Signal 10: Semantic similarity (embedding-based, section 9.2)
|
|
175
|
+
if (embeddingScores && weights.semantic_similarity) {
|
|
176
|
+
const similarity = embeddingScores.get(id);
|
|
177
|
+
if (similarity !== undefined && similarity > 0.7) {
|
|
178
|
+
const points = Math.round(similarity * weights.semantic_similarity);
|
|
179
|
+
signals.push({
|
|
180
|
+
signal: 'semantic_similarity',
|
|
181
|
+
points,
|
|
182
|
+
reason: `semantic match: ${similarity.toFixed(2)}`,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
149
186
|
// Compute total score
|
|
150
187
|
let totalScore = signals.reduce((sum, s) => sum + s.points, 0);
|
|
151
188
|
// Status bias bonus (minor tiebreaker)
|
|
@@ -159,6 +196,8 @@ export function scoreCandidates(candidateIds, query, index, weights = DEFAULT_WE
|
|
|
159
196
|
title: record.title,
|
|
160
197
|
score: totalScore,
|
|
161
198
|
reasons: signals.map((s) => s.reason),
|
|
199
|
+
status: record.status,
|
|
200
|
+
path: record.path,
|
|
162
201
|
});
|
|
163
202
|
}
|
|
164
203
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scoring.js","sourceRoot":"","sources":["../../../src/core/retrieval/scoring.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAStE
|
|
1
|
+
{"version":3,"file":"scoring.js","sourceRoot":"","sources":["../../../src/core/retrieval/scoring.ts"],"names":[],"mappings":"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"}
|
|
@@ -25,7 +25,7 @@ export const BaseFrontmatterSchema = z.object({
|
|
|
25
25
|
type: NoteTypeEnum,
|
|
26
26
|
id: z.string()
|
|
27
27
|
.min(1, 'id is required')
|
|
28
|
-
.regex(/^[
|
|
28
|
+
.regex(/^[\p{Ll}\p{Lo}\p{N}-]+$/u, 'id must be lowercase alphanumeric (Unicode) with hyphens'),
|
|
29
29
|
status: NoteStatusEnum,
|
|
30
30
|
tags: z.array(z.string()).default([]),
|
|
31
31
|
}).passthrough();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.schema.js","sourceRoot":"","sources":["../../../src/core/schema/base.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,IAAI,CAAC;IACjC,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO;CAC7D,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,IAAI,CAAC;IACnC,QAAQ;IACR,YAAY;IACZ,OAAO;IACP,UAAU;IACV,UAAU;IACV,SAAS;IACT,aAAa;IACb,SAAS;CACV,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC,CAAC;AAC1F,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC;AAClE,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;AAEzE,4CAA4C;AAC5C,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,4BAA4B,CAAC,CAAC;AAEhG;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,IAAI,EAAE,YAAY;IAClB,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;SACX,GAAG,CAAC,CAAC,EAAE,gBAAgB,CAAC;SACxB,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"base.schema.js","sourceRoot":"","sources":["../../../src/core/schema/base.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,IAAI,CAAC;IACjC,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO;CAC7D,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,IAAI,CAAC;IACnC,QAAQ;IACR,YAAY;IACZ,OAAO;IACP,UAAU;IACV,UAAU;IACV,SAAS;IACT,aAAa;IACb,SAAS;CACV,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC,CAAC;AAC1F,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC;AAClE,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;AAEzE,4CAA4C;AAC5C,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,4BAA4B,CAAC,CAAC;AAEhG;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,IAAI,EAAE,YAAY;IAClB,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;SACX,GAAG,CAAC,CAAC,EAAE,gBAAgB,CAAC;SACxB,KAAK,CAAC,0BAA0B,EAAE,0DAA0D,CAAC;IAChG,MAAM,EAAE,cAAc;IACtB,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;CACtC,CAAC,CAAC,WAAW,EAAE,CAAC"}
|
|
@@ -47,8 +47,8 @@ export declare const RequirementSchema: z.ZodObject<{
|
|
|
47
47
|
/** SHA-256 of normalized content */
|
|
48
48
|
content_hash: z.ZodString;
|
|
49
49
|
}, "strip", z.ZodTypeAny, {
|
|
50
|
-
content_hash: string;
|
|
51
50
|
key: string;
|
|
51
|
+
content_hash: string;
|
|
52
52
|
name: string;
|
|
53
53
|
normative: string;
|
|
54
54
|
scenarios: {
|
|
@@ -56,8 +56,8 @@ export declare const RequirementSchema: z.ZodObject<{
|
|
|
56
56
|
raw_text: string;
|
|
57
57
|
}[];
|
|
58
58
|
}, {
|
|
59
|
-
content_hash: string;
|
|
60
59
|
key: string;
|
|
60
|
+
content_hash: string;
|
|
61
61
|
name: string;
|
|
62
62
|
normative: string;
|
|
63
63
|
scenarios: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../../src/core/workflow/apply/apply.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,YAAY,EACZ,WAAW,EACX,SAAS,EAOT,cAAc,EACd,aAAa,EACd,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,UAAU,EAAe,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../../src/core/workflow/apply/apply.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,YAAY,EACZ,WAAW,EACX,SAAS,EAOT,cAAc,EACd,aAAa,EACd,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,UAAU,EAAe,MAAM,gCAAgC,CAAC;AAwE9E;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,YAAY,EACrB,KAAK,EAAE,UAAU,EACjB,IAAI,EAAE,SAAS,GACd,WAAW,CAuZb;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,UAAU,EACjB,IAAI,EAAE,SAAS,GACd,aAAa,CA0Cf"}
|
|
@@ -2,8 +2,65 @@ import { join, basename, resolve } from 'node:path';
|
|
|
2
2
|
import { parseDeltaSummary, validateDeltaConflicts } from './delta-parser.js';
|
|
3
3
|
import { detectStale, computeRequirementHash } from './stale-checker.js';
|
|
4
4
|
import { applyDeltaToFeature } from './feature-updater.js';
|
|
5
|
+
import { assertInsideVault } from '../../../utils/path-safety.js';
|
|
5
6
|
const PROGRAMMATIC_OPS = new Set(['RENAMED', 'REMOVED']);
|
|
6
7
|
const AGENT_DRIVEN_OPS = new Set(['MODIFIED', 'ADDED']);
|
|
8
|
+
const LOCK_FILENAME = '.ows-lock';
|
|
9
|
+
const LOCK_STALE_MS = 5 * 60 * 1000; // 5 minutes
|
|
10
|
+
function acquireLock(vaultRoot, deps) {
|
|
11
|
+
const lockPath = join(vaultRoot, 'wiki', LOCK_FILENAME);
|
|
12
|
+
if (deps.fileExists(lockPath)) {
|
|
13
|
+
// Check if lock is stale (PID dead or timestamp > 5 minutes old)
|
|
14
|
+
try {
|
|
15
|
+
const content = deps.readFile(lockPath);
|
|
16
|
+
const parsed = JSON.parse(content);
|
|
17
|
+
const lockTime = parsed.timestamp ? new Date(parsed.timestamp).getTime() : 0;
|
|
18
|
+
const isStaleByTime = Date.now() - lockTime > LOCK_STALE_MS;
|
|
19
|
+
let isStaleByPid = false;
|
|
20
|
+
if (parsed.pid) {
|
|
21
|
+
try {
|
|
22
|
+
// process.kill(pid, 0) throws if process doesn't exist
|
|
23
|
+
process.kill(parsed.pid, 0);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
isStaleByPid = true;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (isStaleByTime || isStaleByPid) {
|
|
30
|
+
// Force-remove stale lock and retry
|
|
31
|
+
if (deps.deleteFile) {
|
|
32
|
+
deps.deleteFile(lockPath);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// If we can't parse the lock, treat as stale and recover
|
|
41
|
+
if (deps.deleteFile) {
|
|
42
|
+
try {
|
|
43
|
+
deps.deleteFile(lockPath);
|
|
44
|
+
}
|
|
45
|
+
catch { /* swallow */ }
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const lockContent = JSON.stringify({ pid: process.pid, timestamp: new Date().toISOString() });
|
|
50
|
+
deps.writeFile(lockPath, lockContent);
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
function releaseLock(vaultRoot, deps) {
|
|
54
|
+
const lockPath = join(vaultRoot, 'wiki', LOCK_FILENAME);
|
|
55
|
+
try {
|
|
56
|
+
if (deps.deleteFile) {
|
|
57
|
+
deps.deleteFile(lockPath);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Best-effort release — swallow errors
|
|
62
|
+
}
|
|
63
|
+
}
|
|
7
64
|
function getAtomicPriority(op) {
|
|
8
65
|
switch (op) {
|
|
9
66
|
case 'RENAMED': return 1;
|
|
@@ -134,13 +191,16 @@ export function applyChange(options, index, deps) {
|
|
|
134
191
|
}
|
|
135
192
|
if (errors.length > 0)
|
|
136
193
|
continue;
|
|
137
|
-
// Apply
|
|
194
|
+
// Apply all requirement operations (programmatic + agent-driven markers)
|
|
138
195
|
const mechEntries = reqEntries.filter((e) => PROGRAMMATIC_OPS.has(e.op));
|
|
139
196
|
const agentEntries = reqEntries.filter((e) => AGENT_DRIVEN_OPS.has(e.op));
|
|
197
|
+
const allReqEntries = [...mechEntries, ...agentEntries];
|
|
140
198
|
const resolvedNotePath = resolve(options.vaultRoot, noteRecord.path);
|
|
141
|
-
|
|
199
|
+
// Read Feature file content for programmatic editing
|
|
200
|
+
const featureContent = deps.readFile(resolvedNotePath);
|
|
201
|
+
const result = applyDeltaToFeature(noteKey, resolvedNotePath, reqMap, allReqEntries, featureContent, options.changeId);
|
|
142
202
|
featureResults.push(result);
|
|
143
|
-
// Collect agent-driven ops
|
|
203
|
+
// Collect agent-driven ops (MODIFIED/ADDED need agent to fill content)
|
|
144
204
|
for (const entry of agentEntries) {
|
|
145
205
|
pendingAgentOps.push({
|
|
146
206
|
entry,
|
|
@@ -171,7 +231,7 @@ export function applyChange(options, index, deps) {
|
|
|
171
231
|
preEditSnapshots.set(op.featureId, hashMap);
|
|
172
232
|
}
|
|
173
233
|
}
|
|
174
|
-
// Handle section operations
|
|
234
|
+
// Handle section operations — currently unsupported; hard-fail
|
|
175
235
|
const sectionResults = [];
|
|
176
236
|
for (const [noteKey, entries] of deltaPlan.byTargetNote) {
|
|
177
237
|
const secEntries = entries.filter((e) => e.targetType === 'section');
|
|
@@ -184,28 +244,201 @@ export function applyChange(options, index, deps) {
|
|
|
184
244
|
notePath: resolve(options.vaultRoot, secNoteRecord.path),
|
|
185
245
|
sectionName: entry.targetName,
|
|
186
246
|
op: entry.op,
|
|
187
|
-
success:
|
|
247
|
+
success: false,
|
|
248
|
+
error: 'Section-level operations are not yet supported. Use requirement-level operations.',
|
|
188
249
|
});
|
|
189
250
|
}
|
|
190
251
|
}
|
|
252
|
+
// Block apply if ANY section-level operations exist
|
|
253
|
+
if (sectionResults.length > 0) {
|
|
254
|
+
errors.push('Cannot apply: contains section-level operations which are not yet supported');
|
|
255
|
+
return {
|
|
256
|
+
changeId: options.changeId,
|
|
257
|
+
changeName: changeRecord.title,
|
|
258
|
+
success: false,
|
|
259
|
+
staleReport,
|
|
260
|
+
featureResults,
|
|
261
|
+
sectionResults,
|
|
262
|
+
postValidation: allPostValidations,
|
|
263
|
+
pendingAgentOps,
|
|
264
|
+
preEditSnapshots,
|
|
265
|
+
statusTransitioned: false,
|
|
266
|
+
modifiedFiles: [],
|
|
267
|
+
warnings,
|
|
268
|
+
errors,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
191
271
|
// === PHASE 2: Write (only if Phase 1 passed) ===
|
|
272
|
+
// Uses atomic temp-file pattern: write to .ows-tmp first, then rename all at once.
|
|
192
273
|
let statusTransitioned = false;
|
|
274
|
+
const modifiedFiles = [];
|
|
275
|
+
// When noAutoTransition is set and there are pending agent ops, skip auto-transition.
|
|
276
|
+
// The agent must fill markers first, then run apply again (or verifyApply).
|
|
277
|
+
const skipTransition = options.noAutoTransition && pendingAgentOps.length > 0;
|
|
193
278
|
if (!options.dryRun) {
|
|
194
|
-
//
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
279
|
+
// Acquire vault-level lock
|
|
280
|
+
if (!acquireLock(options.vaultRoot, deps)) {
|
|
281
|
+
errors.push('Cannot apply: another apply operation is in progress (wiki/.ows-lock exists)');
|
|
282
|
+
return {
|
|
283
|
+
changeId: options.changeId,
|
|
284
|
+
changeName: changeRecord.title,
|
|
285
|
+
success: false,
|
|
286
|
+
staleReport,
|
|
287
|
+
featureResults,
|
|
288
|
+
sectionResults,
|
|
289
|
+
postValidation: allPostValidations,
|
|
290
|
+
pendingAgentOps,
|
|
291
|
+
preEditSnapshots,
|
|
292
|
+
statusTransitioned: false,
|
|
293
|
+
modifiedFiles: [],
|
|
294
|
+
warnings,
|
|
295
|
+
errors,
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
try {
|
|
299
|
+
// Collect all pending writes as {path, content} pairs
|
|
300
|
+
const pendingWrites = [];
|
|
301
|
+
for (const featureResult of featureResults) {
|
|
302
|
+
if (featureResult.requiresWrite && featureResult.updatedContent) {
|
|
303
|
+
pendingWrites.push({ path: featureResult.featurePath, content: featureResult.updatedContent });
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
// Status transition content — skip if noAutoTransition with pending ops
|
|
307
|
+
const changeContent = deps.readFile(resolvedChangePath);
|
|
308
|
+
const updatedChangeContent = skipTransition
|
|
309
|
+
? changeContent // keep current status (in_progress)
|
|
310
|
+
: changeContent.replace(/^(status:\s*).+$/m, '$1applied');
|
|
311
|
+
pendingWrites.push({ path: resolvedChangePath, content: updatedChangeContent });
|
|
312
|
+
// Use unique temp suffix to avoid collisions
|
|
313
|
+
const tmpSuffix = `.ows-tmp-${Date.now()}`;
|
|
314
|
+
// Phase 2a: Write all to temp files
|
|
315
|
+
const tmpPaths = [];
|
|
316
|
+
let writeFailed = false;
|
|
317
|
+
for (const { path, content } of pendingWrites) {
|
|
318
|
+
assertInsideVault(path, options.vaultRoot);
|
|
319
|
+
const tmpPath = `${path}${tmpSuffix}`;
|
|
320
|
+
try {
|
|
321
|
+
deps.writeFile(tmpPath, content);
|
|
322
|
+
tmpPaths.push(tmpPath);
|
|
323
|
+
}
|
|
324
|
+
catch (err) {
|
|
325
|
+
errors.push(`Failed to write temp file ${tmpPath}: ${err.message}`);
|
|
326
|
+
writeFailed = true;
|
|
327
|
+
break;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
if (writeFailed) {
|
|
331
|
+
// Cleanup: remove any temp files already written
|
|
332
|
+
cleanupTempFiles(tmpPaths, deps);
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
// Phase 2b: Backup originals, then rename temp files to final paths (atomic swap)
|
|
336
|
+
const backupSuffix = `.ows-backup-${Date.now()}`;
|
|
337
|
+
const backedUpPaths = [];
|
|
338
|
+
let backupFailed = false;
|
|
339
|
+
// Backup existing originals before overwriting
|
|
340
|
+
for (const { path } of pendingWrites) {
|
|
341
|
+
if (deps.fileExists(path)) {
|
|
342
|
+
const backupPath = `${path}${backupSuffix}`;
|
|
343
|
+
try {
|
|
344
|
+
deps.moveFile(path, backupPath);
|
|
345
|
+
backedUpPaths.push({ original: path, backup: backupPath });
|
|
346
|
+
}
|
|
347
|
+
catch (err) {
|
|
348
|
+
errors.push(`Failed to backup ${path}: ${err.message}`);
|
|
349
|
+
backupFailed = true;
|
|
350
|
+
break;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
if (backupFailed) {
|
|
355
|
+
// Restore any backups already made
|
|
356
|
+
for (const { original, backup } of backedUpPaths) {
|
|
357
|
+
try {
|
|
358
|
+
deps.moveFile(backup, original);
|
|
359
|
+
}
|
|
360
|
+
catch {
|
|
361
|
+
// Best-effort restore — swallow errors
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
// Cleanup temp files
|
|
365
|
+
const allTmps = pendingWrites.map((w) => `${w.path}${tmpSuffix}`);
|
|
366
|
+
cleanupTempFiles(allTmps, deps);
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
// Now rename temp files to final paths
|
|
370
|
+
let renameFailed = false;
|
|
371
|
+
const renamedPaths = [];
|
|
372
|
+
for (let i = 0; i < pendingWrites.length; i++) {
|
|
373
|
+
const { path } = pendingWrites[i];
|
|
374
|
+
const tmpPath = `${path}${tmpSuffix}`;
|
|
375
|
+
try {
|
|
376
|
+
deps.moveFile(tmpPath, path);
|
|
377
|
+
renamedPaths.push(path);
|
|
378
|
+
}
|
|
379
|
+
catch (err) {
|
|
380
|
+
errors.push(`Failed to rename ${tmpPath} -> ${path}: ${err.message}`);
|
|
381
|
+
renameFailed = true;
|
|
382
|
+
break;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
if (renameFailed) {
|
|
386
|
+
// Remove successfully renamed temp->final files and restore from backup
|
|
387
|
+
for (const renamedPath of renamedPaths) {
|
|
388
|
+
try {
|
|
389
|
+
if (deps.deleteFile) {
|
|
390
|
+
deps.deleteFile(renamedPath);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
catch {
|
|
394
|
+
// Best-effort — swallow errors
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
// Restore all backups
|
|
398
|
+
for (const { original, backup } of backedUpPaths) {
|
|
399
|
+
try {
|
|
400
|
+
deps.moveFile(backup, original);
|
|
401
|
+
}
|
|
402
|
+
catch {
|
|
403
|
+
// Best-effort restore — swallow errors
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
// Cleanup remaining temp files (the ones not yet renamed)
|
|
407
|
+
const remainingTmps = pendingWrites
|
|
408
|
+
.filter((w) => !renamedPaths.includes(w.path))
|
|
409
|
+
.map((w) => `${w.path}${tmpSuffix}`);
|
|
410
|
+
cleanupTempFiles(remainingTmps, deps);
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
// All writes succeeded — delete backups
|
|
414
|
+
for (const { backup } of backedUpPaths) {
|
|
415
|
+
try {
|
|
416
|
+
if (deps.deleteFile) {
|
|
417
|
+
deps.deleteFile(backup);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
catch {
|
|
421
|
+
// Best-effort cleanup — swallow errors
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
for (const { path } of pendingWrites) {
|
|
425
|
+
if (path !== resolvedChangePath) {
|
|
426
|
+
modifiedFiles.push(path);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
statusTransitioned = !skipTransition;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
finally {
|
|
435
|
+
releaseLock(options.vaultRoot, deps);
|
|
203
436
|
}
|
|
204
437
|
}
|
|
205
438
|
return {
|
|
206
439
|
changeId: options.changeId,
|
|
207
440
|
changeName: changeRecord.title,
|
|
208
|
-
success:
|
|
441
|
+
success: errors.length === 0,
|
|
209
442
|
staleReport,
|
|
210
443
|
featureResults,
|
|
211
444
|
sectionResults,
|
|
@@ -213,6 +446,7 @@ export function applyChange(options, index, deps) {
|
|
|
213
446
|
pendingAgentOps,
|
|
214
447
|
preEditSnapshots,
|
|
215
448
|
statusTransitioned,
|
|
449
|
+
modifiedFiles,
|
|
216
450
|
warnings,
|
|
217
451
|
errors,
|
|
218
452
|
};
|
|
@@ -235,9 +469,11 @@ export function archiveChange(options, index, deps) {
|
|
|
235
469
|
};
|
|
236
470
|
}
|
|
237
471
|
const resolvedFromPath = resolve(options.vaultRoot, changeRecord.path);
|
|
472
|
+
assertInsideVault(resolvedFromPath, options.vaultRoot);
|
|
238
473
|
const filename = basename(changeRecord.path);
|
|
239
474
|
const archiveDir = join(options.vaultRoot, 'wiki', '99-archive');
|
|
240
475
|
const toPath = join(archiveDir, filename);
|
|
476
|
+
assertInsideVault(toPath, options.vaultRoot);
|
|
241
477
|
if (deps.fileExists(toPath)) {
|
|
242
478
|
return {
|
|
243
479
|
success: false,
|
|
@@ -282,6 +518,19 @@ function preValidateEntry(entry, requirements) {
|
|
|
282
518
|
}
|
|
283
519
|
}
|
|
284
520
|
}
|
|
521
|
+
/** Best-effort cleanup of temp files. Errors are swallowed. */
|
|
522
|
+
function cleanupTempFiles(tmpPaths, deps) {
|
|
523
|
+
for (const tmpPath of tmpPaths) {
|
|
524
|
+
try {
|
|
525
|
+
if (deps.deleteFile) {
|
|
526
|
+
deps.deleteFile(tmpPath);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
catch {
|
|
530
|
+
// Best-effort cleanup — swallow errors
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
285
534
|
function makeResult(options, changeRecord, overrides) {
|
|
286
535
|
return {
|
|
287
536
|
changeId: options.changeId,
|
|
@@ -294,6 +543,7 @@ function makeResult(options, changeRecord, overrides) {
|
|
|
294
543
|
pendingAgentOps: [],
|
|
295
544
|
preEditSnapshots: new Map(),
|
|
296
545
|
statusTransitioned: false,
|
|
546
|
+
modifiedFiles: [],
|
|
297
547
|
warnings: [],
|
|
298
548
|
errors: [],
|
|
299
549
|
...overrides,
|