poe-code 4.0.49 → 4.0.50
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/dist/cli/commands/plan.js +52 -15
- package/dist/cli/commands/plan.js.map +1 -1
- package/dist/index.js +165 -68
- package/dist/index.js.map +2 -2
- package/dist/metafile.json +1 -1
- package/package.json +1 -1
- package/packages/plan-browser/dist/actions.d.ts +3 -0
- package/packages/plan-browser/dist/actions.js +20 -0
- package/packages/plan-browser/dist/browser.d.ts +1 -0
- package/packages/plan-browser/dist/browser.js +2 -0
- package/packages/plan-browser/dist/discovery.d.ts +1 -0
- package/packages/plan-browser/dist/discovery.js +48 -13
- package/packages/plan-browser/dist/explorer-config.d.ts +1 -0
- package/packages/plan-browser/dist/explorer-config.js +46 -38
- package/packages/plan-browser/dist/index.d.ts +1 -1
- package/packages/plan-browser/dist/index.js +1 -1
package/package.json
CHANGED
|
@@ -21,6 +21,9 @@ export declare function editPlan(absolutePath: string, options: {
|
|
|
21
21
|
declare function archiveSelectedPlan(entry: Pick<{
|
|
22
22
|
absolutePath: string;
|
|
23
23
|
}, "absolutePath">, fs: ActionFs): Promise<string>;
|
|
24
|
+
export declare function unarchivePlan(entry: Pick<{
|
|
25
|
+
absolutePath: string;
|
|
26
|
+
}, "absolutePath">, fs: ActionFs): Promise<string>;
|
|
24
27
|
export declare function savePlanForLater(entry: Pick<{
|
|
25
28
|
absolutePath: string;
|
|
26
29
|
format: PlanFormat;
|
|
@@ -102,6 +102,26 @@ async function archiveSelectedPlan(entry, fs) {
|
|
|
102
102
|
}
|
|
103
103
|
return archivedPath;
|
|
104
104
|
}
|
|
105
|
+
export async function unarchivePlan(entry, fs) {
|
|
106
|
+
rejectPlanMetaDocument(entry.absolutePath, "unarchive");
|
|
107
|
+
const archiveDir = path.dirname(entry.absolutePath);
|
|
108
|
+
if (path.basename(archiveDir) !== "archive") {
|
|
109
|
+
throw new Error(`Plan is not archived: ${entry.absolutePath}`);
|
|
110
|
+
}
|
|
111
|
+
await rejectSymbolicLink(archiveDir, fs, "unarchive plan through");
|
|
112
|
+
const destinationPath = path.join(path.dirname(archiveDir), path.basename(entry.absolutePath));
|
|
113
|
+
try {
|
|
114
|
+
await fs.readFile(destinationPath, "utf8");
|
|
115
|
+
throw new Error(`Unarchive destination already exists: ${destinationPath}`);
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
if (!hasErrorCode(error, "ENOENT")) {
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
await fs.rename(entry.absolutePath, destinationPath);
|
|
123
|
+
return destinationPath;
|
|
124
|
+
}
|
|
105
125
|
export async function savePlanForLater(entry, fs, options = {}) {
|
|
106
126
|
const reason = entry.savedForLater?.reason?.trim() || options.reason?.trim();
|
|
107
127
|
if (!reason) {
|
|
@@ -8,6 +8,7 @@ export declare function runPlanBrowser(options: {
|
|
|
8
8
|
projectConfigPath: string;
|
|
9
9
|
fs: DiscoveryFs & Partial<ActionFs>;
|
|
10
10
|
kind?: PlanKind;
|
|
11
|
+
archived?: boolean;
|
|
11
12
|
variables?: Record<string, string | undefined>;
|
|
12
13
|
runExplorerImpl?: RunExplorerImpl;
|
|
13
14
|
}): Promise<void>;
|
|
@@ -9,6 +9,7 @@ export async function runPlanBrowser(options) {
|
|
|
9
9
|
projectConfigPath: options.projectConfigPath,
|
|
10
10
|
fs: options.fs,
|
|
11
11
|
kind: options.kind,
|
|
12
|
+
archived: options.archived,
|
|
12
13
|
variables: options.variables
|
|
13
14
|
});
|
|
14
15
|
const plans = await discover();
|
|
@@ -26,6 +27,7 @@ export async function runPlanBrowser(options) {
|
|
|
26
27
|
}
|
|
27
28
|
const config = buildPlanExplorerConfig({
|
|
28
29
|
plans,
|
|
30
|
+
archived: options.archived,
|
|
29
31
|
fs: options.fs,
|
|
30
32
|
variables: options.variables ?? process.env,
|
|
31
33
|
homeDir: options.homeDir,
|
|
@@ -108,7 +108,7 @@ function toPlanKind(value, filePath) {
|
|
|
108
108
|
}
|
|
109
109
|
throw new Error(`${filePath}: unsupported frontmatter kind ${JSON.stringify(value)}`);
|
|
110
110
|
}
|
|
111
|
-
function classifyPlanKind(content, filePath) {
|
|
111
|
+
function classifyPlanKind(content, filePath, archived = false) {
|
|
112
112
|
if (isYamlPlanFile(filePath)) {
|
|
113
113
|
parsePlan(content);
|
|
114
114
|
return "pipeline";
|
|
@@ -117,7 +117,19 @@ function classifyPlanKind(content, filePath) {
|
|
|
117
117
|
if (data === undefined) {
|
|
118
118
|
return "plan";
|
|
119
119
|
}
|
|
120
|
-
|
|
120
|
+
if (data.kind === undefined)
|
|
121
|
+
return "plan";
|
|
122
|
+
if (archived && data.kind === "archived-pipeline-plan")
|
|
123
|
+
return "plan";
|
|
124
|
+
if (archived) {
|
|
125
|
+
try {
|
|
126
|
+
return toPlanKind(data.kind, filePath);
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return "plan";
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return toPlanKind(data.kind, filePath);
|
|
121
133
|
}
|
|
122
134
|
function readPlanReadiness(content, filePath) {
|
|
123
135
|
const value = splitFrontmatter(content, filePath).data?.readiness;
|
|
@@ -142,6 +154,14 @@ async function discoverSharedPlans(options) {
|
|
|
142
154
|
if (canonicalDir !== path.resolve(absoluteDir)) {
|
|
143
155
|
throw new Error(`Plan directory must not be a symbolic link: ${displayDir}`);
|
|
144
156
|
}
|
|
157
|
+
if (options.archived === true) {
|
|
158
|
+
return discoverPlanDirectoryEntries({
|
|
159
|
+
...options,
|
|
160
|
+
absoluteDir: path.join(absoluteDir, "archive"),
|
|
161
|
+
displayDir: path.join(displayDir, "archive"),
|
|
162
|
+
savedForLaterDirectory: false
|
|
163
|
+
});
|
|
164
|
+
}
|
|
145
165
|
const activePlans = await discoverPlanDirectoryEntries({
|
|
146
166
|
...options,
|
|
147
167
|
absoluteDir,
|
|
@@ -199,20 +219,35 @@ async function discoverPlanDirectoryEntries(options) {
|
|
|
199
219
|
}
|
|
200
220
|
const displayPath = path.join(options.displayDir, name);
|
|
201
221
|
const content = await options.fs.readFile(absolutePath, "utf8");
|
|
202
|
-
|
|
222
|
+
let kind = classifyPlanKind(content, displayPath, options.archived);
|
|
223
|
+
const savedForLater = options.savedForLaterDirectory
|
|
224
|
+
? (readSavedForLaterMetadata(content, displayPath) ?? {})
|
|
225
|
+
: readSavedForLaterMetadata(content, displayPath);
|
|
226
|
+
let metadata;
|
|
227
|
+
try {
|
|
228
|
+
metadata = await readPlanMetadata({
|
|
229
|
+
kind,
|
|
230
|
+
absolutePath,
|
|
231
|
+
path: displayPath,
|
|
232
|
+
fs: options.fs,
|
|
233
|
+
content
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
catch (error) {
|
|
237
|
+
if (!options.archived || kind === "plan")
|
|
238
|
+
throw error;
|
|
239
|
+
kind = "plan";
|
|
240
|
+
metadata = await readPlanMetadata({
|
|
241
|
+
kind,
|
|
242
|
+
absolutePath,
|
|
243
|
+
path: displayPath,
|
|
244
|
+
fs: options.fs,
|
|
245
|
+
content
|
|
246
|
+
});
|
|
247
|
+
}
|
|
203
248
|
if (options.kind && kind !== options.kind) {
|
|
204
249
|
continue;
|
|
205
250
|
}
|
|
206
|
-
const savedForLater = options.savedForLaterDirectory
|
|
207
|
-
? readSavedForLaterMetadata(content, displayPath) ?? {}
|
|
208
|
-
: readSavedForLaterMetadata(content, displayPath);
|
|
209
|
-
const metadata = await readPlanMetadata({
|
|
210
|
-
kind,
|
|
211
|
-
absolutePath,
|
|
212
|
-
path: displayPath,
|
|
213
|
-
fs: options.fs,
|
|
214
|
-
content
|
|
215
|
-
});
|
|
216
251
|
plans.push({
|
|
217
252
|
path: displayPath,
|
|
218
253
|
absolutePath,
|
|
@@ -2,6 +2,7 @@ import type { ExplorerConfig } from "../../toolcraft-design/dist/index.js";
|
|
|
2
2
|
import type { ActionFs, DiscoveryFs, PlanEntry } from "./types.js";
|
|
3
3
|
export interface BuildPlanExplorerConfigOptions {
|
|
4
4
|
plans: PlanEntry[];
|
|
5
|
+
archived?: boolean;
|
|
5
6
|
fs: ActionFs & DiscoveryFs;
|
|
6
7
|
variables: Record<string, string | undefined>;
|
|
7
8
|
homeDir?: string;
|
|
@@ -7,14 +7,14 @@ export function buildPlanExplorerConfig(options) {
|
|
|
7
7
|
const loadDetailMarkdown = options.loadDetailMarkdown ?? loadPlanPreviewMarkdown;
|
|
8
8
|
const promptSaveReason = options.promptSaveReason;
|
|
9
9
|
let plans = options.plans;
|
|
10
|
-
let rows = toRows(plans);
|
|
10
|
+
let rows = toRows(plans, options.archived);
|
|
11
11
|
let entryByRowId = toEntryMap(plans);
|
|
12
12
|
let preserveOrderOnNextRefresh = false;
|
|
13
13
|
async function refresh() {
|
|
14
14
|
const refreshedPlans = await options.onRefresh();
|
|
15
15
|
plans = preserveOrderOnNextRefresh ? preservePlanOrder(plans, refreshedPlans) : refreshedPlans;
|
|
16
16
|
preserveOrderOnNextRefresh = false;
|
|
17
|
-
rows = toRows(plans);
|
|
17
|
+
rows = toRows(plans, options.archived);
|
|
18
18
|
entryByRowId = toEntryMap(plans);
|
|
19
19
|
}
|
|
20
20
|
const actions = [
|
|
@@ -154,41 +154,49 @@ export function buildPlanExplorerConfig(options) {
|
|
|
154
154
|
}
|
|
155
155
|
],
|
|
156
156
|
refresh,
|
|
157
|
-
actions
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
157
|
+
actions: options.archived
|
|
158
|
+
? actions.filter((action) => action.id === "edit" || action.id === "delete")
|
|
159
|
+
: actions,
|
|
160
|
+
...(options.archived
|
|
161
|
+
? {}
|
|
162
|
+
: {
|
|
163
|
+
reorder: {
|
|
164
|
+
onReorder: async (orderedIds, ctx) => {
|
|
165
|
+
if (ctx === undefined) {
|
|
166
|
+
throw new Error("Plan reorder context is required");
|
|
167
|
+
}
|
|
168
|
+
const orderedEntries = orderedIds.map((id) => getEntry(entryByRowId, id));
|
|
169
|
+
const movedIndex = orderedIds.indexOf(ctx.movedId);
|
|
170
|
+
const originalIndex = createRowIds(plans).indexOf(ctx.movedId);
|
|
171
|
+
if (movedIndex < 0 || originalIndex < 0) {
|
|
172
|
+
throw new Error(`Plan row is no longer available: ${ctx.movedId}`);
|
|
173
|
+
}
|
|
174
|
+
const moved = orderedEntries[movedIndex];
|
|
175
|
+
const swapTarget = orderedEntries[originalIndex];
|
|
176
|
+
if (swapTarget === undefined || swapTarget.readiness !== moved.readiness) {
|
|
177
|
+
throw new Error("Plans can only be reordered within the same readiness group");
|
|
178
|
+
}
|
|
179
|
+
if (isSavedForLaterEntry(swapTarget) !== isSavedForLaterEntry(moved)) {
|
|
180
|
+
throw new Error("Active and saved-for-later plans cannot be reordered together");
|
|
181
|
+
}
|
|
182
|
+
const previousCandidate = orderedEntries[movedIndex - 1];
|
|
183
|
+
const nextCandidate = orderedEntries[movedIndex + 1];
|
|
184
|
+
const previous = sameOrderingGroup(previousCandidate, moved)
|
|
185
|
+
? previousCandidate
|
|
186
|
+
: undefined;
|
|
187
|
+
const next = sameOrderingGroup(nextCandidate, moved) ? nextCandidate : undefined;
|
|
188
|
+
const [movedStat, previousStat, nextStat] = await Promise.all([
|
|
189
|
+
options.fs.stat(moved.absolutePath),
|
|
190
|
+
previous === undefined ? undefined : options.fs.stat(previous.absolutePath),
|
|
191
|
+
next === undefined ? undefined : options.fs.stat(next.absolutePath)
|
|
192
|
+
]);
|
|
193
|
+
const updatedAt = resolveMovedTimestamp(previousStat?.mtimeMs, nextStat?.mtimeMs);
|
|
194
|
+
await options.fs.utimes(moved.absolutePath, new Date(movedStat.atimeMs ?? movedStat.mtimeMs), new Date(updatedAt));
|
|
195
|
+
await ctx.refresh();
|
|
196
|
+
ctx.toast(`Reordered ${path.basename(moved.path)}`, "info");
|
|
197
|
+
}
|
|
176
198
|
}
|
|
177
|
-
|
|
178
|
-
const nextCandidate = orderedEntries[movedIndex + 1];
|
|
179
|
-
const previous = sameOrderingGroup(previousCandidate, moved) ? previousCandidate : undefined;
|
|
180
|
-
const next = sameOrderingGroup(nextCandidate, moved) ? nextCandidate : undefined;
|
|
181
|
-
const [movedStat, previousStat, nextStat] = await Promise.all([
|
|
182
|
-
options.fs.stat(moved.absolutePath),
|
|
183
|
-
previous === undefined ? undefined : options.fs.stat(previous.absolutePath),
|
|
184
|
-
next === undefined ? undefined : options.fs.stat(next.absolutePath)
|
|
185
|
-
]);
|
|
186
|
-
const updatedAt = resolveMovedTimestamp(previousStat?.mtimeMs, nextStat?.mtimeMs);
|
|
187
|
-
await options.fs.utimes(moved.absolutePath, new Date(movedStat.atimeMs ?? movedStat.mtimeMs), new Date(updatedAt));
|
|
188
|
-
await ctx.refresh();
|
|
189
|
-
ctx.toast(`Reordered ${path.basename(moved.path)}`, "info");
|
|
190
|
-
}
|
|
191
|
-
},
|
|
199
|
+
}),
|
|
192
200
|
multiSelect: false,
|
|
193
201
|
emptyHint: "No plans found"
|
|
194
202
|
});
|
|
@@ -239,14 +247,14 @@ function abbreviateHome(filePath, homeDir) {
|
|
|
239
247
|
}
|
|
240
248
|
return `~${path.sep}${relative}`;
|
|
241
249
|
}
|
|
242
|
-
function toRows(plans) {
|
|
250
|
+
function toRows(plans, archived = false) {
|
|
243
251
|
const rowIds = createRowIds(plans);
|
|
244
252
|
return plans.map((entry, index) => ({
|
|
245
253
|
id: rowIds[index],
|
|
246
254
|
title: formatPlanReadinessLabel(path.basename(entry.path), entry.readiness),
|
|
247
255
|
subtitle: formatSubtitle(entry),
|
|
248
256
|
badge: { text: entry.typeLabel },
|
|
249
|
-
group: isSavedForLaterEntry(entry) ? "Saved for later" : "Active"
|
|
257
|
+
group: archived ? "Archived" : isSavedForLaterEntry(entry) ? "Saved for later" : "Active"
|
|
250
258
|
}));
|
|
251
259
|
}
|
|
252
260
|
function formatSubtitle(entry) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { discoverAllPlans } from "./discovery.js";
|
|
2
|
-
export { archivePlan, deletePlan, editFile, editPlan, resolveEditor, restorePlanFromLater, savePlanForLater, setPlanReadiness } from "./actions.js";
|
|
2
|
+
export { archivePlan, deletePlan, editFile, editPlan, resolveEditor, restorePlanFromLater, savePlanForLater, setPlanReadiness, unarchivePlan } from "./actions.js";
|
|
3
3
|
export { buildPlanExplorerConfig } from "./explorer-config.js";
|
|
4
4
|
export { deriveMarkdownTitle, formatExperimentDetail, formatPipelinePlanMarkdown, formatPipelineProgress, formatRalphDetail, formatSuperintendentDetail, getLastExperimentState, loadPlanPreviewMarkdown, readExperimentState, readPlanMetadata, readSavedForLaterMetadata, writeSavedForLaterReason } from "./format.js";
|
|
5
5
|
export { runPlanBrowser } from "./browser.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { discoverAllPlans } from "./discovery.js";
|
|
2
|
-
export { archivePlan, deletePlan, editFile, editPlan, resolveEditor, restorePlanFromLater, savePlanForLater, setPlanReadiness } from "./actions.js";
|
|
2
|
+
export { archivePlan, deletePlan, editFile, editPlan, resolveEditor, restorePlanFromLater, savePlanForLater, setPlanReadiness, unarchivePlan } from "./actions.js";
|
|
3
3
|
export { buildPlanExplorerConfig } from "./explorer-config.js";
|
|
4
4
|
export { deriveMarkdownTitle, formatExperimentDetail, formatPipelinePlanMarkdown, formatPipelineProgress, formatRalphDetail, formatSuperintendentDetail, getLastExperimentState, loadPlanPreviewMarkdown, readExperimentState, readPlanMetadata, readSavedForLaterMetadata, writeSavedForLaterReason } from "./format.js";
|
|
5
5
|
export { runPlanBrowser } from "./browser.js";
|