phewsh 0.15.54 → 0.15.55
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/lib/selfheal.js +14 -2
- package/lib/sequencer/index.js +10 -0
- package/lib/sequencer/parsers/intent.js +16 -2
- package/package.json +1 -1
package/lib/selfheal.js
CHANGED
|
@@ -108,7 +108,9 @@ function upsertBlock(filePath, core, footer, fileLabel, headerText) {
|
|
|
108
108
|
const expectedSource = footerSource(footer);
|
|
109
109
|
if (m && coreOf(m[1]) === coreOf(core) &&
|
|
110
110
|
(!expectedSource || footerSource(m[1]) === expectedSource)) return false;
|
|
111
|
-
|
|
111
|
+
// A replacement function keeps canonical text such as "$10" from being
|
|
112
|
+
// interpreted as a regex capture reference and duplicating old content.
|
|
113
|
+
const next = existing.replace(re, () => wrapped);
|
|
112
114
|
fs.writeFileSync(filePath, next);
|
|
113
115
|
} else if (existing) {
|
|
114
116
|
fs.writeFileSync(filePath, existing.replace(/\s*$/, '') + '\n\n' + wrapped + '\n');
|
|
@@ -153,7 +155,17 @@ function buildContextCore(cwd = process.cwd()) {
|
|
|
153
155
|
let output;
|
|
154
156
|
try {
|
|
155
157
|
if (cwd !== prev) process.chdir(cwd);
|
|
156
|
-
output = sequence({
|
|
158
|
+
output = sequence({
|
|
159
|
+
target: 'claude-md',
|
|
160
|
+
sources: ['intent'],
|
|
161
|
+
sourceNames: ['vision.md', 'project.json', 'status.md', 'next.md', 'next.json'],
|
|
162
|
+
excludeChunkSources: [
|
|
163
|
+
'.intent/project.json:actions',
|
|
164
|
+
'.intent/project.json:responsibilities',
|
|
165
|
+
'.intent/project.json:success',
|
|
166
|
+
],
|
|
167
|
+
write: false,
|
|
168
|
+
}).output;
|
|
157
169
|
} finally {
|
|
158
170
|
if (cwd !== prev) { try { process.chdir(prev); } catch { /* best-effort */ } }
|
|
159
171
|
}
|
package/lib/sequencer/index.js
CHANGED
|
@@ -33,6 +33,8 @@ const emitters = {
|
|
|
33
33
|
* @param {string} options.target - Output format: 'claude-md' | 'stdout' | 'json'
|
|
34
34
|
* @param {string} options.budget - Token budget: 'minimal' | 'standard' | 'full' | 'unlimited'
|
|
35
35
|
* @param {string[]} options.sources - Limit to specific source types (null = all)
|
|
36
|
+
* @param {string[]} options.sourceNames - Limit to specific discovered filenames (null = all)
|
|
37
|
+
* @param {string[]} options.excludeChunkSources - Omit exact parsed chunk sources
|
|
36
38
|
* @param {boolean} options.explain - Show full ranking breakdown
|
|
37
39
|
* @param {boolean} options.write - Write to file (for claude-md target)
|
|
38
40
|
* @param {string} options.cwd - Working directory
|
|
@@ -43,6 +45,8 @@ function sequence(options = {}) {
|
|
|
43
45
|
target = 'claude-md',
|
|
44
46
|
budget = 'standard',
|
|
45
47
|
sources: sourceFilter = null,
|
|
48
|
+
sourceNames = null,
|
|
49
|
+
excludeChunkSources = null,
|
|
46
50
|
explain = false,
|
|
47
51
|
write = false,
|
|
48
52
|
includeGlobal = false,
|
|
@@ -73,6 +77,9 @@ function sequence(options = {}) {
|
|
|
73
77
|
sourceFilter.some(f => s.type === f || s.type.startsWith(f))
|
|
74
78
|
);
|
|
75
79
|
}
|
|
80
|
+
if (sourceNames && sourceNames.length > 0) {
|
|
81
|
+
sources = sources.filter(source => sourceNames.includes(source.name));
|
|
82
|
+
}
|
|
76
83
|
|
|
77
84
|
// 2. Parse all sources into chunks
|
|
78
85
|
let chunks = [];
|
|
@@ -83,6 +90,9 @@ function sequence(options = {}) {
|
|
|
83
90
|
const parsed = parser.parse(source);
|
|
84
91
|
chunks.push(...parsed);
|
|
85
92
|
}
|
|
93
|
+
if (excludeChunkSources && excludeChunkSources.length > 0) {
|
|
94
|
+
chunks = chunks.filter(chunk => !excludeChunkSources.includes(chunk.source));
|
|
95
|
+
}
|
|
86
96
|
|
|
87
97
|
// 3. Rank all chunks
|
|
88
98
|
chunks = rank(chunks);
|
|
@@ -75,12 +75,19 @@ function parseStatus(filePath) {
|
|
|
75
75
|
const { meta, body } = parseFrontmatter(content);
|
|
76
76
|
const mtime = fs.statSync(filePath).mtime.toISOString();
|
|
77
77
|
const timestamp = meta.updated || meta.created || mtime;
|
|
78
|
+
// Harness projections need the curated current state, not the full journal.
|
|
79
|
+
// Truncate before ranking/compression so a long history cannot crowd the
|
|
80
|
+
// structured Next item and its accepted success criteria out of the budget.
|
|
81
|
+
const lines = body.split('\n');
|
|
82
|
+
let cut = lines.findIndex(line => /^---+\s*$/.test(line));
|
|
83
|
+
if (cut < 0 || cut > 24) cut = 24;
|
|
84
|
+
const current = lines.slice(0, cut).join('\n').trim();
|
|
78
85
|
|
|
79
86
|
return [{
|
|
80
87
|
source: '.intent/status.md',
|
|
81
88
|
sourceType: 'intent',
|
|
82
89
|
kind: 'state',
|
|
83
|
-
content:
|
|
90
|
+
content: current,
|
|
84
91
|
timestamp,
|
|
85
92
|
metadata: { frontmatter: meta },
|
|
86
93
|
}];
|
|
@@ -91,12 +98,19 @@ function parseNext(filePath) {
|
|
|
91
98
|
const { meta, body } = parseFrontmatter(content);
|
|
92
99
|
const mtime = fs.statSync(filePath).mtime.toISOString();
|
|
93
100
|
const timestamp = meta.updated || meta.created || mtime;
|
|
101
|
+
const lines = body.split('\n');
|
|
102
|
+
const sectionIndexes = lines
|
|
103
|
+
.map((line, index) => (/^##\s+/.test(line) ? index : -1))
|
|
104
|
+
.filter(index => index >= 0);
|
|
105
|
+
const cut = sectionIndexes.length > 1
|
|
106
|
+
? sectionIndexes[1]
|
|
107
|
+
: Math.min(lines.length, 24);
|
|
94
108
|
|
|
95
109
|
return [{
|
|
96
110
|
source: '.intent/next.md',
|
|
97
111
|
sourceType: 'intent',
|
|
98
112
|
kind: 'state',
|
|
99
|
-
content:
|
|
113
|
+
content: lines.slice(0, cut).join('\n').trim(),
|
|
100
114
|
timestamp,
|
|
101
115
|
metadata: { frontmatter: meta },
|
|
102
116
|
}];
|