facult 2.8.2 → 2.8.3
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/package.json +1 -1
- package/src/ai-state.ts +28 -0
- package/src/ai.ts +52 -25
package/package.json
CHANGED
package/src/ai-state.ts
CHANGED
|
@@ -196,6 +196,20 @@ export async function ensureAiIndexPath(args: {
|
|
|
196
196
|
)) {
|
|
197
197
|
if (await fileExists(legacyPath)) {
|
|
198
198
|
if (args.repair !== false) {
|
|
199
|
+
if (
|
|
200
|
+
await canonicalAssetsNewerThanIndex({
|
|
201
|
+
homeDir: args.homeDir,
|
|
202
|
+
rootDir: args.rootDir,
|
|
203
|
+
indexPath: legacyPath,
|
|
204
|
+
})
|
|
205
|
+
) {
|
|
206
|
+
const { outputPath } = await buildIndex({
|
|
207
|
+
rootDir: args.rootDir,
|
|
208
|
+
homeDir: args.homeDir,
|
|
209
|
+
force: false,
|
|
210
|
+
});
|
|
211
|
+
return { path: outputPath, repaired: true, source: "rebuilt" };
|
|
212
|
+
}
|
|
199
213
|
await mkdir(dirname(generatedPath), { recursive: true });
|
|
200
214
|
await copyFile(legacyPath, generatedPath);
|
|
201
215
|
}
|
|
@@ -257,6 +271,20 @@ export async function ensureAiGraphPath(args: {
|
|
|
257
271
|
)) {
|
|
258
272
|
if (await fileExists(legacyGeneratedPath)) {
|
|
259
273
|
if (args.repair !== false) {
|
|
274
|
+
if (
|
|
275
|
+
await canonicalAssetsNewerThanIndex({
|
|
276
|
+
homeDir: args.homeDir,
|
|
277
|
+
rootDir: args.rootDir,
|
|
278
|
+
indexPath: legacyGeneratedPath,
|
|
279
|
+
})
|
|
280
|
+
) {
|
|
281
|
+
const { graphPath } = await buildIndex({
|
|
282
|
+
rootDir: args.rootDir,
|
|
283
|
+
homeDir: args.homeDir,
|
|
284
|
+
force: false,
|
|
285
|
+
});
|
|
286
|
+
return { path: graphPath, rebuilt: true };
|
|
287
|
+
}
|
|
260
288
|
await mkdir(dirname(generatedPath), { recursive: true });
|
|
261
289
|
await copyFile(legacyGeneratedPath, generatedPath);
|
|
262
290
|
}
|
package/src/ai.ts
CHANGED
|
@@ -256,6 +256,24 @@ function aiJournalReadPaths(homeDir: string, rootDir: string): string[] {
|
|
|
256
256
|
];
|
|
257
257
|
}
|
|
258
258
|
|
|
259
|
+
function aiProposalReadDirs(homeDir: string, rootDir: string): string[] {
|
|
260
|
+
return uniqueStrings([
|
|
261
|
+
facultAiProposalDir(homeDir, rootDir),
|
|
262
|
+
...legacyAiRuntimeScopeDirs(homeDir, rootDir).map((dir) =>
|
|
263
|
+
join(dir, "evolution", "proposals")
|
|
264
|
+
),
|
|
265
|
+
]);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
async function firstExistingFile(paths: string[]): Promise<string | null> {
|
|
269
|
+
for (const pathValue of paths) {
|
|
270
|
+
if (await fileExists(pathValue)) {
|
|
271
|
+
return pathValue;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
|
|
259
277
|
function supportedDraftTarget(pathValue: string): boolean {
|
|
260
278
|
return pathValue.toLowerCase().endsWith(".md");
|
|
261
279
|
}
|
|
@@ -645,11 +663,15 @@ async function nextProposalId(
|
|
|
645
663
|
homeDir: string,
|
|
646
664
|
rootDir: string
|
|
647
665
|
): Promise<string> {
|
|
648
|
-
const
|
|
649
|
-
const
|
|
650
|
-
|
|
651
|
-
.
|
|
652
|
-
|
|
666
|
+
const ids: string[] = [];
|
|
667
|
+
for (const dir of aiProposalReadDirs(homeDir, rootDir)) {
|
|
668
|
+
const entries = await readdir(dir).catch(() => [] as string[]);
|
|
669
|
+
ids.push(
|
|
670
|
+
...entries
|
|
671
|
+
.filter((entry) => entry.endsWith(".json"))
|
|
672
|
+
.map((entry) => basename(entry, ".json"))
|
|
673
|
+
);
|
|
674
|
+
}
|
|
653
675
|
return nextId("EV", ids);
|
|
654
676
|
}
|
|
655
677
|
|
|
@@ -842,18 +864,19 @@ export async function listProposals(args?: {
|
|
|
842
864
|
throw new Error("listProposals requires a rootDir");
|
|
843
865
|
}
|
|
844
866
|
const homeDir = args?.homeDir ?? process.env.HOME ?? "";
|
|
845
|
-
const
|
|
846
|
-
const
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
867
|
+
const byId = new Map<string, AiProposalRecord>();
|
|
868
|
+
for (const dir of [...aiProposalReadDirs(homeDir, args.rootDir)].reverse()) {
|
|
869
|
+
const entries = await readdir(dir).catch(() => [] as string[]);
|
|
870
|
+
for (const entry of entries.sort()) {
|
|
871
|
+
if (!entry.endsWith(".json")) {
|
|
872
|
+
continue;
|
|
873
|
+
}
|
|
874
|
+
const raw = await readFile(join(dir, entry), "utf8");
|
|
875
|
+
const parsed = JSON.parse(raw) as AiProposalRecord;
|
|
876
|
+
byId.set(parsed.id, parsed);
|
|
851
877
|
}
|
|
852
|
-
const raw = await readFile(join(dir, entry), "utf8");
|
|
853
|
-
const parsed = JSON.parse(raw) as AiProposalRecord;
|
|
854
|
-
out.push(parsed);
|
|
855
878
|
}
|
|
856
|
-
return
|
|
879
|
+
return [...byId.values()].sort((a, b) => a.id.localeCompare(b.id));
|
|
857
880
|
}
|
|
858
881
|
|
|
859
882
|
export async function showProposal(
|
|
@@ -861,15 +884,15 @@ export async function showProposal(
|
|
|
861
884
|
args: { homeDir?: string; rootDir: string }
|
|
862
885
|
): Promise<AiProposalRecord | null> {
|
|
863
886
|
const homeDir = args.homeDir ?? process.env.HOME ?? "";
|
|
864
|
-
const
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
887
|
+
for (const dir of aiProposalReadDirs(homeDir, args.rootDir)) {
|
|
888
|
+
const pathValue = join(dir, `${id}.json`);
|
|
889
|
+
if (!(await fileExists(pathValue))) {
|
|
890
|
+
continue;
|
|
891
|
+
}
|
|
892
|
+
const raw = await readFile(pathValue, "utf8");
|
|
893
|
+
return JSON.parse(raw) as AiProposalRecord;
|
|
870
894
|
}
|
|
871
|
-
|
|
872
|
-
return JSON.parse(raw) as AiProposalRecord;
|
|
895
|
+
return null;
|
|
873
896
|
}
|
|
874
897
|
|
|
875
898
|
function promoteTargetRef(target: string, to: "global"): string {
|
|
@@ -1122,9 +1145,13 @@ export async function draftProposal(
|
|
|
1122
1145
|
const patchPath = patchRefForProposal(homeDir, args.rootDir, id);
|
|
1123
1146
|
await mkdir(dirname(draftPath), { recursive: true });
|
|
1124
1147
|
const generatedBody = renderDraftBody(current, writebacks);
|
|
1148
|
+
const existingDraftPath = await firstExistingFile([
|
|
1149
|
+
draftPath,
|
|
1150
|
+
...current.draftRefs.filter((pathValue) => pathValue.endsWith(".md")),
|
|
1151
|
+
]);
|
|
1125
1152
|
const priorDraft =
|
|
1126
|
-
args.append &&
|
|
1127
|
-
? await readFile(
|
|
1153
|
+
args.append && existingDraftPath
|
|
1154
|
+
? await readFile(existingDraftPath, "utf8")
|
|
1128
1155
|
: null;
|
|
1129
1156
|
const draftBody = args.append
|
|
1130
1157
|
? `${(priorDraft ?? generatedBody).trimEnd()}\n\n## Draft Revision\n${args.append.trim()}\n`
|