@really-knows-ai/foundry 2.3.2 → 3.0.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/README.md +180 -369
- package/dist/.opencode/plugins/foundry-tools/appraiser-tools.js +28 -0
- package/dist/.opencode/plugins/foundry-tools/artefact-tools.js +58 -0
- package/dist/.opencode/plugins/foundry-tools/assay-tools.js +92 -0
- package/dist/.opencode/plugins/foundry-tools/attestation-tools.js +191 -0
- package/dist/.opencode/plugins/foundry-tools/config-create-tools.js +128 -0
- package/dist/.opencode/plugins/foundry-tools/config-law-tools.js +380 -0
- package/dist/.opencode/plugins/foundry-tools/config-tools.js +43 -0
- package/dist/.opencode/plugins/foundry-tools/feedback-tools.js +234 -0
- package/dist/.opencode/plugins/foundry-tools/git-helpers.js +354 -0
- package/dist/.opencode/plugins/foundry-tools/git-tools.js +181 -0
- package/dist/.opencode/plugins/foundry-tools/helpers.js +340 -0
- package/dist/.opencode/plugins/foundry-tools/history-tools.js +20 -0
- package/dist/.opencode/plugins/foundry-tools/memory-admin-tools.js +296 -0
- package/dist/.opencode/plugins/foundry-tools/memory-helpers.js +104 -0
- package/dist/.opencode/plugins/foundry-tools/memory-tools.js +286 -0
- package/dist/.opencode/plugins/foundry-tools/orchestrate-tool.js +159 -0
- package/dist/.opencode/plugins/foundry-tools/snapshot-tools.js +104 -0
- package/dist/.opencode/plugins/foundry-tools/stage-tools.js +186 -0
- package/dist/.opencode/plugins/foundry-tools/validate-tools.js +263 -0
- package/dist/.opencode/plugins/foundry-tools/workfile-tools.js +102 -0
- package/dist/.opencode/plugins/foundry.js +105 -0
- package/dist/CHANGELOG.md +490 -0
- package/dist/LICENSE +21 -0
- package/dist/README.md +278 -0
- package/dist/docs/README.md +59 -0
- package/dist/docs/architecture.md +434 -0
- package/dist/docs/concepts.md +396 -0
- package/dist/docs/getting-started.md +345 -0
- package/dist/docs/memory-maintenance.md +176 -0
- package/dist/docs/tools.md +1411 -0
- package/dist/docs/work-spec.md +283 -0
- package/dist/scripts/lib/artefacts.js +151 -0
- package/dist/scripts/lib/assay/loader.js +151 -0
- package/dist/scripts/lib/assay/parse-jsonl.js +102 -0
- package/dist/scripts/lib/assay/permissions.js +52 -0
- package/dist/scripts/lib/assay/run.js +219 -0
- package/dist/scripts/lib/assay/spawn-with-timeout.js +138 -0
- package/dist/scripts/lib/attestation/attest.js +111 -0
- package/dist/scripts/lib/attestation/canonical-json.js +109 -0
- package/dist/scripts/lib/attestation/hash.js +17 -0
- package/dist/scripts/lib/attestation/parse.js +14 -0
- package/dist/scripts/lib/attestation/payload.js +106 -0
- package/dist/scripts/lib/attestation/render.js +16 -0
- package/dist/scripts/lib/attestation/verify.js +15 -0
- package/dist/scripts/lib/branch-guard.js +72 -0
- package/dist/scripts/lib/config-creators/appraiser.js +9 -0
- package/dist/scripts/lib/config-creators/artefact-type.js +9 -0
- package/dist/scripts/lib/config-creators/cycle.js +11 -0
- package/dist/scripts/lib/config-creators/factory.js +49 -0
- package/dist/scripts/lib/config-creators/flow.js +11 -0
- package/dist/scripts/lib/config-validators/appraiser.js +49 -0
- package/dist/scripts/lib/config-validators/artefact-type.js +38 -0
- package/dist/scripts/lib/config-validators/cycle.js +131 -0
- package/dist/scripts/lib/config-validators/flow.js +57 -0
- package/dist/scripts/lib/config-validators/helpers.js +96 -0
- package/dist/scripts/lib/config-validators/law.js +96 -0
- package/dist/scripts/lib/config.js +393 -0
- package/dist/scripts/lib/failed-flow.js +131 -0
- package/dist/scripts/lib/feedback-store.js +249 -0
- package/dist/scripts/lib/feedback-transitions.js +105 -0
- package/dist/scripts/lib/finalize.js +70 -0
- package/dist/scripts/lib/foundational-guards.js +13 -0
- package/dist/scripts/lib/git-bridge.js +77 -0
- package/dist/scripts/lib/git-finish/work-finish.js +233 -0
- package/dist/scripts/lib/git-policy.js +101 -0
- package/dist/scripts/lib/guards.js +125 -0
- package/dist/scripts/lib/history.js +132 -0
- package/dist/scripts/lib/memory/admin/create-edge-type.js +91 -0
- package/dist/scripts/lib/memory/admin/create-entity-type.js +43 -0
- package/dist/scripts/lib/memory/admin/create-extractor.js +67 -0
- package/dist/scripts/lib/memory/admin/drop-edge-type.js +40 -0
- package/dist/scripts/lib/memory/admin/drop-entity-type.js +172 -0
- package/dist/scripts/lib/memory/admin/dump.js +47 -0
- package/dist/scripts/lib/memory/admin/helpers.js +31 -0
- package/dist/scripts/lib/memory/admin/init.js +170 -0
- package/dist/scripts/lib/memory/admin/live-store.js +76 -0
- package/dist/scripts/lib/memory/admin/reembed.js +285 -0
- package/dist/scripts/lib/memory/admin/rename-edge-type.js +54 -0
- package/dist/scripts/lib/memory/admin/rename-entity-type.js +151 -0
- package/dist/scripts/lib/memory/admin/reset.js +24 -0
- package/dist/scripts/lib/memory/admin/vacuum.js +9 -0
- package/dist/scripts/lib/memory/admin/validate.js +19 -0
- package/dist/scripts/lib/memory/config.js +149 -0
- package/dist/scripts/lib/memory/cozo.js +136 -0
- package/dist/scripts/lib/memory/drift.js +71 -0
- package/dist/scripts/lib/memory/embeddings.js +128 -0
- package/dist/scripts/lib/memory/frontmatter.js +75 -0
- package/dist/scripts/lib/memory/ndjson.js +84 -0
- package/dist/scripts/lib/memory/paths.js +25 -0
- package/dist/scripts/lib/memory/permissions.js +41 -0
- package/dist/scripts/lib/memory/prompt.js +109 -0
- package/dist/scripts/lib/memory/query.js +56 -0
- package/dist/scripts/lib/memory/reads.js +109 -0
- package/dist/scripts/lib/memory/schema.js +64 -0
- package/dist/scripts/lib/memory/search.js +73 -0
- package/dist/scripts/lib/memory/singleton.js +49 -0
- package/dist/scripts/lib/memory/store.js +162 -0
- package/dist/scripts/lib/memory/types.js +93 -0
- package/dist/scripts/lib/memory/validate.js +58 -0
- package/dist/scripts/lib/memory/writes.js +40 -0
- package/{scripts → dist/scripts}/lib/pending.js +7 -2
- package/dist/scripts/lib/secret.js +59 -0
- package/{scripts → dist/scripts}/lib/slug.js +3 -2
- package/dist/scripts/lib/snapshot/finish.js +103 -0
- package/dist/scripts/lib/snapshot/inspect.js +253 -0
- package/dist/scripts/lib/snapshot/render.js +55 -0
- package/dist/scripts/lib/sort-fs-check.js +121 -0
- package/dist/scripts/lib/sort-routing.js +101 -0
- package/{scripts → dist/scripts}/lib/stage-guard.js +12 -6
- package/{scripts → dist/scripts}/lib/state.js +4 -0
- package/dist/scripts/lib/token.js +57 -0
- package/dist/scripts/lib/tracing.js +59 -0
- package/dist/scripts/lib/ulid.js +100 -0
- package/dist/scripts/lib/validator-jsonl.js +162 -0
- package/{scripts → dist/scripts}/lib/workfile.js +38 -20
- package/dist/scripts/orchestrate-cycle.js +215 -0
- package/dist/scripts/orchestrate-phases.js +314 -0
- package/dist/scripts/orchestrate.js +163 -0
- package/dist/scripts/sort.js +278 -0
- package/{skills → dist/skills}/add-appraiser/SKILL.md +39 -9
- package/{skills → dist/skills}/add-artefact-type/SKILL.md +46 -24
- package/{skills → dist/skills}/add-cycle/SKILL.md +57 -17
- package/dist/skills/add-extractor/SKILL.md +133 -0
- package/{skills → dist/skills}/add-flow/SKILL.md +36 -10
- package/dist/skills/add-law/SKILL.md +191 -0
- package/dist/skills/add-memory-edge-type/SKILL.md +52 -0
- package/dist/skills/add-memory-entity-type/SKILL.md +74 -0
- package/{skills → dist/skills}/appraise/SKILL.md +62 -13
- package/dist/skills/assay/SKILL.md +72 -0
- package/dist/skills/change-embedding-model/SKILL.md +58 -0
- package/dist/skills/drop-memory-edge-type/SKILL.md +54 -0
- package/dist/skills/drop-memory-entity-type/SKILL.md +57 -0
- package/dist/skills/dry-run/SKILL.md +116 -0
- package/{skills → dist/skills}/flow/SKILL.md +15 -2
- package/dist/skills/forge/SKILL.md +121 -0
- package/dist/skills/human-appraise/SKILL.md +153 -0
- package/{skills → dist/skills}/init-foundry/SKILL.md +23 -4
- package/dist/skills/init-memory/SKILL.md +92 -0
- package/{skills → dist/skills}/orchestrate/SKILL.md +30 -4
- package/dist/skills/quench/SKILL.md +99 -0
- package/{skills → dist/skills}/refresh-agents/SKILL.md +1 -1
- package/dist/skills/rename-memory-edge-type/SKILL.md +50 -0
- package/dist/skills/rename-memory-entity-type/SKILL.md +51 -0
- package/dist/skills/reset-memory/SKILL.md +54 -0
- package/dist/skills/upgrade-foundry/SKILL.md +192 -0
- package/package.json +34 -17
- package/.opencode/plugins/foundry.js +0 -761
- package/CHANGELOG.md +0 -100
- package/docs/concepts.md +0 -122
- package/docs/getting-started.md +0 -187
- package/docs/work-spec.md +0 -207
- package/scripts/lib/artefacts.js +0 -124
- package/scripts/lib/config.js +0 -175
- package/scripts/lib/feedback-transitions.js +0 -25
- package/scripts/lib/feedback.js +0 -440
- package/scripts/lib/finalize.js +0 -41
- package/scripts/lib/history.js +0 -59
- package/scripts/lib/secret.js +0 -23
- package/scripts/lib/tags.js +0 -108
- package/scripts/lib/token.js +0 -26
- package/scripts/orchestrate.js +0 -418
- package/scripts/sort.js +0 -370
- package/scripts/validate-tags.js +0 -54
- package/skills/add-law/SKILL.md +0 -111
- package/skills/forge/SKILL.md +0 -88
- package/skills/human-appraise/SKILL.md +0 -82
- package/skills/quench/SKILL.md +0 -62
- package/skills/upgrade-foundry/SKILL.md +0 -216
- /package/{skills → dist/skills}/list-agents/SKILL.md +0 -0
package/scripts/lib/artefacts.js
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Artefacts table utilities for WORK.md.
|
|
3
|
-
*
|
|
4
|
-
* Parses, adds rows to, and updates status in the markdown artefacts table.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Parse the artefacts markdown table from text.
|
|
9
|
-
* @param {string} text
|
|
10
|
-
* @returns {Array<{file: string, type: string, cycle: string, status: string}>}
|
|
11
|
-
*/
|
|
12
|
-
export function parseArtefactsTable(text) {
|
|
13
|
-
const artefacts = [];
|
|
14
|
-
let inTable = false;
|
|
15
|
-
|
|
16
|
-
for (const line of text.split('\n')) {
|
|
17
|
-
const stripped = line.trim();
|
|
18
|
-
|
|
19
|
-
if (stripped.startsWith('| File')) {
|
|
20
|
-
inTable = true;
|
|
21
|
-
continue;
|
|
22
|
-
}
|
|
23
|
-
if (inTable && stripped.startsWith('|---')) {
|
|
24
|
-
continue;
|
|
25
|
-
}
|
|
26
|
-
if (inTable && stripped.startsWith('|')) {
|
|
27
|
-
const cols = stripped.split('|').slice(1, -1).map(c => c.trim());
|
|
28
|
-
if (cols.length >= 4) {
|
|
29
|
-
artefacts.push({
|
|
30
|
-
file: cols[0],
|
|
31
|
-
type: cols[1],
|
|
32
|
-
cycle: cols[2],
|
|
33
|
-
status: cols[3],
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
} else if (inTable) {
|
|
37
|
-
inTable = false;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return artefacts;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Add a row to the artefacts table.
|
|
46
|
-
* @param {string} text - Full WORK.md text
|
|
47
|
-
* @param {{file: string, type: string, cycle: string, status: string}} row
|
|
48
|
-
* @returns {string} Updated text
|
|
49
|
-
*/
|
|
50
|
-
export function addArtefactRow(text, { file, type, cycle, status }) {
|
|
51
|
-
const lines = text.split('\n');
|
|
52
|
-
let lastTableRow = -1;
|
|
53
|
-
let inTable = false;
|
|
54
|
-
|
|
55
|
-
for (let i = 0; i < lines.length; i++) {
|
|
56
|
-
const stripped = lines[i].trim();
|
|
57
|
-
if (stripped.startsWith('| File')) {
|
|
58
|
-
inTable = true;
|
|
59
|
-
continue;
|
|
60
|
-
}
|
|
61
|
-
if (inTable && stripped.startsWith('|---')) {
|
|
62
|
-
if (lastTableRow < 0) lastTableRow = i; // insert after separator if no data rows
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
if (inTable && stripped.startsWith('|')) {
|
|
66
|
-
lastTableRow = i;
|
|
67
|
-
} else if (inTable) {
|
|
68
|
-
break;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (lastTableRow === -1) {
|
|
73
|
-
throw new Error('Artefacts table not found');
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const newRow = `| ${file} | ${type} | ${cycle} | ${status} |`;
|
|
77
|
-
lines.splice(lastTableRow + 1, 0, newRow);
|
|
78
|
-
return lines.join('\n');
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Update the status column for a specific file in the artefacts table.
|
|
83
|
-
* @param {string} text - Full WORK.md text
|
|
84
|
-
* @param {string} file - File name to match
|
|
85
|
-
* @param {string} newStatus - New status value
|
|
86
|
-
* @returns {string} Updated text
|
|
87
|
-
*/
|
|
88
|
-
export function setArtefactStatus(text, file, newStatus) {
|
|
89
|
-
if (newStatus === 'draft') {
|
|
90
|
-
throw new Error('status draft not permitted; use stage_finalize for registration');
|
|
91
|
-
}
|
|
92
|
-
if (!['done', 'blocked'].includes(newStatus)) {
|
|
93
|
-
throw new Error(`invalid status: ${newStatus}`);
|
|
94
|
-
}
|
|
95
|
-
const lines = text.split('\n');
|
|
96
|
-
let inTable = false;
|
|
97
|
-
let found = false;
|
|
98
|
-
|
|
99
|
-
for (let i = 0; i < lines.length; i++) {
|
|
100
|
-
const stripped = lines[i].trim();
|
|
101
|
-
if (stripped.startsWith('| File')) {
|
|
102
|
-
inTable = true;
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
if (inTable && stripped.startsWith('|---')) continue;
|
|
106
|
-
if (inTable && stripped.startsWith('|')) {
|
|
107
|
-
const cols = stripped.split('|').slice(1, -1).map(c => c.trim());
|
|
108
|
-
if (cols.length >= 4 && cols[0] === file) {
|
|
109
|
-
cols[3] = newStatus;
|
|
110
|
-
lines[i] = '| ' + cols.join(' | ') + ' |';
|
|
111
|
-
found = true;
|
|
112
|
-
break;
|
|
113
|
-
}
|
|
114
|
-
} else if (inTable) {
|
|
115
|
-
break;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (!found) {
|
|
120
|
-
throw new Error(`File not found in artefacts table: ${file}`);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return lines.join('\n');
|
|
124
|
-
}
|
package/scripts/lib/config.js
DELETED
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Structured reads of foundry/ directory contents.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { join } from 'path';
|
|
6
|
-
import { parseFrontmatter } from './workfile.js';
|
|
7
|
-
|
|
8
|
-
function parseDoc(text) {
|
|
9
|
-
const frontmatter = parseFrontmatter(text);
|
|
10
|
-
const body = text.replace(/^---\n.+?\n---\n?/s, '').trim();
|
|
11
|
-
return { frontmatter, body };
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export async function getCycleDefinition(foundryDir, cycleId, io) {
|
|
15
|
-
const path = join(foundryDir, 'cycles', `${cycleId}.md`);
|
|
16
|
-
if (!(await io.exists(path))) {
|
|
17
|
-
throw new Error(`Cycle not found: ${cycleId}`);
|
|
18
|
-
}
|
|
19
|
-
const text = await io.readFile(path);
|
|
20
|
-
return parseDoc(text);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export async function getArtefactType(foundryDir, typeId, io) {
|
|
24
|
-
const path = join(foundryDir, 'artefacts', typeId, 'definition.md');
|
|
25
|
-
if (!(await io.exists(path))) {
|
|
26
|
-
throw new Error(`Artefact type not found: ${typeId}`);
|
|
27
|
-
}
|
|
28
|
-
const text = await io.readFile(path);
|
|
29
|
-
return parseDoc(text);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export async function getLaws(foundryDir, typeId, io) {
|
|
33
|
-
// Handle optional typeId: if typeId is the io object, shift args
|
|
34
|
-
if (typeId && typeof typeId === 'object' && typeof typeId.exists === 'function') {
|
|
35
|
-
io = typeId;
|
|
36
|
-
typeId = null;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const laws = [];
|
|
40
|
-
|
|
41
|
-
function parseLaws(text, source) {
|
|
42
|
-
const lines = text.split('\n');
|
|
43
|
-
let currentId = null;
|
|
44
|
-
let currentLines = [];
|
|
45
|
-
|
|
46
|
-
for (const line of lines) {
|
|
47
|
-
const heading = line.match(/^## (.+)/);
|
|
48
|
-
if (heading) {
|
|
49
|
-
if (currentId) {
|
|
50
|
-
laws.push({ id: currentId, text: currentLines.join('\n').trim(), source });
|
|
51
|
-
}
|
|
52
|
-
currentId = heading[1];
|
|
53
|
-
currentLines = [];
|
|
54
|
-
} else if (currentId) {
|
|
55
|
-
currentLines.push(line);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
if (currentId) {
|
|
59
|
-
laws.push({ id: currentId, text: currentLines.join('\n').trim(), source });
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Global laws
|
|
64
|
-
const globalDir = join(foundryDir, 'laws');
|
|
65
|
-
if (await io.exists(globalDir)) {
|
|
66
|
-
const files = await io.readDir(globalDir);
|
|
67
|
-
const mdFiles = files.filter(f => f.endsWith('.md')).sort();
|
|
68
|
-
for (const file of mdFiles) {
|
|
69
|
-
const text = await io.readFile(join(globalDir, file));
|
|
70
|
-
parseLaws(text, `laws/${file}`);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Type-specific laws
|
|
75
|
-
if (typeId) {
|
|
76
|
-
const typeLawsPath = join(foundryDir, 'artefacts', typeId, 'laws.md');
|
|
77
|
-
if (await io.exists(typeLawsPath)) {
|
|
78
|
-
const text = await io.readFile(typeLawsPath);
|
|
79
|
-
parseLaws(text, `artefacts/${typeId}/laws.md`);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return laws;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export async function getValidation(foundryDir, typeId, io) {
|
|
87
|
-
const path = join(foundryDir, 'artefacts', typeId, 'validation.md');
|
|
88
|
-
if (!(await io.exists(path))) {
|
|
89
|
-
return null;
|
|
90
|
-
}
|
|
91
|
-
const text = await io.readFile(path);
|
|
92
|
-
const entries = [];
|
|
93
|
-
const lines = text.split('\n');
|
|
94
|
-
let currentId = null;
|
|
95
|
-
let currentCommand = null;
|
|
96
|
-
let currentFailure = null;
|
|
97
|
-
|
|
98
|
-
function flush() {
|
|
99
|
-
if (currentId && currentCommand) {
|
|
100
|
-
const entry = { id: currentId, command: currentCommand };
|
|
101
|
-
if (currentFailure) entry.failureMeans = currentFailure;
|
|
102
|
-
entries.push(entry);
|
|
103
|
-
}
|
|
104
|
-
currentId = null;
|
|
105
|
-
currentCommand = null;
|
|
106
|
-
currentFailure = null;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
for (const line of lines) {
|
|
110
|
-
const heading = line.match(/^## (.+)/);
|
|
111
|
-
if (heading) {
|
|
112
|
-
flush();
|
|
113
|
-
currentId = heading[1].trim();
|
|
114
|
-
} else if (currentId) {
|
|
115
|
-
const cmdMatch = line.match(/^Command:\s*(.+)/);
|
|
116
|
-
const failMatch = line.match(/^Failure means:\s*(.+)/);
|
|
117
|
-
if (cmdMatch) currentCommand = cmdMatch[1].trim().replace(/^`|`$/g, '');
|
|
118
|
-
if (failMatch) currentFailure = failMatch[1].trim();
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
flush();
|
|
122
|
-
return entries;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
export async function getAppraisers(foundryDir, io) {
|
|
126
|
-
const dir = join(foundryDir, 'appraisers');
|
|
127
|
-
if (!(await io.exists(dir))) return [];
|
|
128
|
-
const files = await io.readDir(dir);
|
|
129
|
-
const mdFiles = files.filter(f => f.endsWith('.md')).sort();
|
|
130
|
-
const result = [];
|
|
131
|
-
for (const file of mdFiles) {
|
|
132
|
-
const text = await io.readFile(join(dir, file));
|
|
133
|
-
const { frontmatter, body } = parseDoc(text);
|
|
134
|
-
const entry = { id: frontmatter.id, personality: body };
|
|
135
|
-
if (frontmatter.model) entry.model = frontmatter.model;
|
|
136
|
-
result.push(entry);
|
|
137
|
-
}
|
|
138
|
-
return result;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
export async function getFlow(foundryDir, flowId, io) {
|
|
142
|
-
const path = join(foundryDir, 'flows', `${flowId}.md`);
|
|
143
|
-
if (!(await io.exists(path))) {
|
|
144
|
-
throw new Error(`Flow not found: ${flowId}`);
|
|
145
|
-
}
|
|
146
|
-
const text = await io.readFile(path);
|
|
147
|
-
return parseDoc(text);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
export async function selectAppraisers(foundryDir, typeId, countOverride, io) {
|
|
151
|
-
// Handle optional countOverride
|
|
152
|
-
if (countOverride && typeof countOverride === 'object' && typeof countOverride.exists === 'function') {
|
|
153
|
-
io = countOverride;
|
|
154
|
-
countOverride = null;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const { frontmatter } = await getArtefactType(foundryDir, typeId, io);
|
|
158
|
-
const appraiserConfig = frontmatter.appraisers || {};
|
|
159
|
-
const count = countOverride || appraiserConfig.count || 3;
|
|
160
|
-
const allowed = appraiserConfig.allowed || null;
|
|
161
|
-
|
|
162
|
-
const allAppraisers = await getAppraisers(foundryDir, io);
|
|
163
|
-
let pool = allowed
|
|
164
|
-
? allAppraisers.filter(a => allowed.includes(a.id))
|
|
165
|
-
: allAppraisers;
|
|
166
|
-
|
|
167
|
-
if (pool.length === 0) return [];
|
|
168
|
-
|
|
169
|
-
// Round-robin distribute
|
|
170
|
-
const result = [];
|
|
171
|
-
for (let i = 0; i < count; i++) {
|
|
172
|
-
result.push(pool[i % pool.length]);
|
|
173
|
-
}
|
|
174
|
-
return result;
|
|
175
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto';
|
|
2
|
-
|
|
3
|
-
// Matrix: [current][target] => set of allowed stageBases
|
|
4
|
-
const MATRIX = {
|
|
5
|
-
open: { actioned: ['forge'], 'wont-fix': ['forge'] },
|
|
6
|
-
actioned: { approved: ['quench', 'appraise', 'human-appraise'], rejected: ['quench', 'appraise', 'human-appraise'] },
|
|
7
|
-
'wont-fix': { approved: ['appraise', 'human-appraise'], rejected: ['appraise', 'human-appraise'] },
|
|
8
|
-
rejected: { actioned: ['forge'], 'wont-fix': ['forge'] },
|
|
9
|
-
approved: {}, // terminal
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export function validateTransition(current, target, stageBase) {
|
|
13
|
-
const row = MATRIX[current];
|
|
14
|
-
if (!row) return { ok: false, reason: `unknown state: ${current}` };
|
|
15
|
-
const allowedStages = row[target];
|
|
16
|
-
if (!allowedStages) return { ok: false, reason: `invalid transition ${current} → ${target}` };
|
|
17
|
-
if (!allowedStages.includes(stageBase)) {
|
|
18
|
-
return { ok: false, reason: `stage ${stageBase} cannot transition ${current} → ${target}` };
|
|
19
|
-
}
|
|
20
|
-
return { ok: true };
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function hashText(text) {
|
|
24
|
-
return createHash('sha256').update(text).digest('hex').slice(0, 16);
|
|
25
|
-
}
|