prompt-profile 0.2.1 → 0.2.2
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 +3 -1
- package/dist/bin.js +93 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -59,7 +59,9 @@ for extraction and macOS setup.
|
|
|
59
59
|
- **PNG share cards**: a 1200 × 630 card per language, without prompt quotes.
|
|
60
60
|
- **`profile.json`**: the data used to render the report again without another analysis.
|
|
61
61
|
- **Local history**: successful analyses are kept in a report library; open the output folder's
|
|
62
|
-
`index.html` to browse them.
|
|
62
|
+
`index.html` to browse them. Generated output includes a `README.md` explaining each file,
|
|
63
|
+
backups, deletion and index repair; an existing user README is preserved. New report folders use readable local timestamps, for example
|
|
64
|
+
`2026-11-01_03-12-04+0800-<id>` (`+0800` is the UTC offset). Older report folders remain readable.
|
|
63
65
|
|
|
64
66
|
Reports support English and Traditional Chinese; quotes stay in their original language.
|
|
65
67
|
The default is English, or both languages on a Chinese system locale. Each extra language
|
package/dist/bin.js
CHANGED
|
@@ -1493,7 +1493,7 @@ const ChunkObservations = Schema.Struct({
|
|
|
1493
1493
|
})).pipe(Schema.withDecodingDefaultKey(Effect.succeed([])))
|
|
1494
1494
|
});
|
|
1495
1495
|
// src/domain/Library.ts
|
|
1496
|
-
const RUN_ID = /^(?:\d{8}T\d{6}Z-[a-f0-9]{32}|legacy-[a-f0-9]{32})$/u;
|
|
1496
|
+
const RUN_ID = /^(?:(?:\d{8}T\d{6}Z|\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}[+-]\d{4})-[a-f0-9]{32}|legacy-[a-f0-9]{32})$/u;
|
|
1497
1497
|
const Count = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0));
|
|
1498
1498
|
const Iso = Schema.String.check(Schema.makeFilter((s) => /^\d{4}-\d\d-\d\dT/u.test(s) && Number.isFinite(Date.parse(s))));
|
|
1499
1499
|
const RunManifest = Schema.Struct({
|
|
@@ -2288,6 +2288,83 @@ const readAsset = (name, locate) => new Uint8Array(readFileSync(locate()));
|
|
|
2288
2288
|
* `$XDG_CACHE_HOME/prompt-profile`, else `~/.cache/prompt-profile` (macOS too).
|
|
2289
2289
|
*/
|
|
2290
2290
|
const resolveCacheDir = (env, home, path) => path.join(env["XDG_CACHE_HOME"] || path.join(home, ".cache"), "prompt-profile");
|
|
2291
|
+
// src/platform/output-guide.ts
|
|
2292
|
+
const MARKER = "<!-- Generated by prompt-profile: output guide -->";
|
|
2293
|
+
const GUIDE = `${MARKER}
|
|
2294
|
+
# Your prompt-profile output
|
|
2295
|
+
|
|
2296
|
+
Open **index.html** to browse completed reports, newest first. Inside a report
|
|
2297
|
+
folder, open **report.html** directly. Both work offline without a server.
|
|
2298
|
+
Only files relevant to the commands you ran will be present.
|
|
2299
|
+
|
|
2300
|
+
## What the files mean
|
|
2301
|
+
|
|
2302
|
+
| File or folder | Purpose |
|
|
2303
|
+
| --- | --- |
|
|
2304
|
+
| index.html | The report library: start here to find the latest report. |
|
|
2305
|
+
| reports/<timestamp>-<id>/ | One completed analysis. Each new analysis gets its own folder. |
|
|
2306
|
+
| reports/legacy-<id>/ | A preserved report from an older output layout. |
|
|
2307
|
+
| report.html | The readable report, with a language switch when available. |
|
|
2308
|
+
| card.png | The summary image in the report's first language. |
|
|
2309
|
+
| card.<language>.png | Additional language images, such as card.en.png. A missing card does not mean the HTML report failed. |
|
|
2310
|
+
| profile.json | The analysis data. Keep this to render supported profiles again without another LLM analysis. Older formats may require the package version that created them. |
|
|
2311
|
+
| run.json | Completion metadata: time, engine, languages, coverage and card status. Keep with the completed report. |
|
|
2312
|
+
| render.json | Rendering choices, version, profile fingerprint and relative source path. |
|
|
2313
|
+
| variants/<name>/ | Alternative renders. Each contains its own report, profile, rendering metadata and available cards. Rendering the same variant again replaces its generated files. |
|
|
2314
|
+
| library.json | Rebuildable catalog of completed reports; it is not the analysis itself. |
|
|
2315
|
+
| executions/<id>/summary.json | Execution status, call accounting and recovery information, including failed or interrupted runs. These are separate from completed reports. |
|
|
2316
|
+
| stats.json | Statistics-only output from the stats command; replaced the next time stats uses this folder. |
|
|
2317
|
+
| plan.json and chunks/ | Dry-run estimate and redacted text prepared for analysis. Use a separate output folder for each dry run; later runs may leave older chunks. |
|
|
2318
|
+
| README.md | This generated guide. Your own existing README is left untouched. |
|
|
2319
|
+
|
|
2320
|
+
## Dates and names
|
|
2321
|
+
|
|
2322
|
+
New analysis folders use the computer's local time, for example
|
|
2323
|
+
2026-11-01_03-12-04+0800-<id>: November 1, 2026 at 03:12:04, UTC+08:00.
|
|
2324
|
+
The final ID prevents collisions. Older names such as 20261031T191204Z-<id>
|
|
2325
|
+
use UTC (Z); they represent the same instant in this example. JSON timestamps
|
|
2326
|
+
remain in machine-readable formats. The library orders reports by completion
|
|
2327
|
+
time, so use index.html rather than sorting mixed old and new folder names.
|
|
2328
|
+
|
|
2329
|
+
## Keep, move or delete
|
|
2330
|
+
|
|
2331
|
+
- Back up or move the whole output folder to preserve relative links. Copy a
|
|
2332
|
+
complete report folder when archiving one analysis; its link back to the library
|
|
2333
|
+
needs the original surrounding layout. Do not rename report folders or edit IDs.
|
|
2334
|
+
- To remove an analysis, delete its whole folder under reports/, including any
|
|
2335
|
+
variants you no longer need. This permanently removes that saved analysis.
|
|
2336
|
+
Never delete profile.json or run.json alone from a report you want to keep.
|
|
2337
|
+
- After deleting reports, rebuild index.html and library.json without an LLM call:
|
|
2338
|
+
|
|
2339
|
+
prompt-profile history --out "<output-folder>"
|
|
2340
|
+
|
|
2341
|
+
- Unwanted variants, stats.json, dry-run plan.json and chunks/ can be deleted
|
|
2342
|
+
independently. Keep profile.json if you want to render a variant again.
|
|
2343
|
+
- Execution folders can be deleted independently when their diagnostics are no
|
|
2344
|
+
longer needed. Deleting them does not remove completed reports or the separate
|
|
2345
|
+
analysis cache; keep them while troubleshooting an interrupted run.
|
|
2346
|
+
- Hidden reports/.pending-* folders are unfinished output. Remove them only after
|
|
2347
|
+
confirming that no prompt-profile process is using this output folder.
|
|
2348
|
+
- Older root-level report files and variants may have been copied to a legacy
|
|
2349
|
+
archive. Remove originals only after verifying that the archived copies match.
|
|
2350
|
+
|
|
2351
|
+
These files contain personal analysis and may include prompt excerpts, local paths
|
|
2352
|
+
or redacted input. Review the files you choose to share. Render and history commands
|
|
2353
|
+
work locally; neither requires another LLM analysis. No saved report history is
|
|
2354
|
+
pruned automatically.
|
|
2355
|
+
`;
|
|
2356
|
+
/** Refresh our generated guide without replacing user notes or following README symlinks. */
|
|
2357
|
+
const writeOutputGuide = (root) => Effect.gen(function* () {
|
|
2358
|
+
const fs = yield* FileSystem.FileSystem;
|
|
2359
|
+
const path = yield* Path.Path;
|
|
2360
|
+
const file = path.join(root, "README.md");
|
|
2361
|
+
const info = yield* fs.lstat(file).pipe(Effect.catchIf(isNotFound$1, () => Effect.succeed(null)));
|
|
2362
|
+
if (info !== null) {
|
|
2363
|
+
if (info.type !== "File" || info.size > 64000n) return;
|
|
2364
|
+
if (!(yield* fs.readFileString(file)).startsWith(`${MARKER}\n`)) return;
|
|
2365
|
+
}
|
|
2366
|
+
yield* writePrivateFile(fs, path, file, GUIDE);
|
|
2367
|
+
}).pipe(Effect.mapError(toFileError(root)));
|
|
2291
2368
|
// src/platform/executions.ts
|
|
2292
2369
|
const ID = /^[0-9a-f-]{36}$/u;
|
|
2293
2370
|
/** `<root>/executions`, never a symlink. */
|
|
@@ -2331,6 +2408,7 @@ const createExecution = (root, startedAtMs) => Effect.gen(function* () {
|
|
|
2331
2408
|
const fs = yield* FileSystem.FileSystem;
|
|
2332
2409
|
const path = yield* Path.Path;
|
|
2333
2410
|
const folder = yield* directory(root, true);
|
|
2411
|
+
yield* writeOutputGuide(root);
|
|
2334
2412
|
const id = randomUUID();
|
|
2335
2413
|
yield* fs.makeDirectory(path.join(folder, id), { mode: 448 });
|
|
2336
2414
|
const initial = {
|
|
@@ -2422,7 +2500,12 @@ const reportsDirectory = (root, create) => Effect.gen(function* () {
|
|
|
2422
2500
|
});
|
|
2423
2501
|
const createStage = (root) => Effect.gen(function* () {
|
|
2424
2502
|
const reports = yield* reportsDirectory(root, true);
|
|
2425
|
-
const
|
|
2503
|
+
const now = /* @__PURE__ */ new Date();
|
|
2504
|
+
const pad = (value) => String(value).padStart(2, "0");
|
|
2505
|
+
const date = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`;
|
|
2506
|
+
const time = `${pad(now.getHours())}-${pad(now.getMinutes())}-${pad(now.getSeconds())}`;
|
|
2507
|
+
const offset = -now.getTimezoneOffset();
|
|
2508
|
+
const id = `${`${date}_${time}${`${offset >= 0 ? "+" : "-"}${pad(Math.floor(Math.abs(offset) / 60))}${pad(Math.abs(offset) % 60)}`}`}-${randomUUID().replaceAll("-", "")}`;
|
|
2426
2509
|
const directory = (yield* Path.Path).join(reports, `.pending-${id}`);
|
|
2427
2510
|
yield* (yield* FileSystem.FileSystem).makeDirectory(directory, { mode: 448 });
|
|
2428
2511
|
return {
|
|
@@ -2461,6 +2544,7 @@ const scan = (root) => Effect.gen(function* () {
|
|
|
2461
2544
|
const repair = (root, render) => Effect.gen(function* () {
|
|
2462
2545
|
const path = yield* Path.Path;
|
|
2463
2546
|
yield* reportsDirectory(root, true);
|
|
2547
|
+
yield* writeOutputGuide(root);
|
|
2464
2548
|
for (let attempt = 0; attempt < 32; attempt++) {
|
|
2465
2549
|
const index = yield* scan(root);
|
|
2466
2550
|
yield* write(path.join(root, "library.json"), json(index));
|
|
@@ -7999,7 +8083,7 @@ const cardFileName = (lang, isDefault) => isDefault ? "card.png" : `card.${lang}
|
|
|
7999
8083
|
const noCjkFonts = Effect.fail(new FontUnavailable({ reason: "no CJK font available" }));
|
|
8000
8084
|
/**
|
|
8001
8085
|
* Write `report.html`, `profile.json` and one card per language into `outDir` (overwriting
|
|
8002
|
-
* only
|
|
8086
|
+
* only generated files, including README.md). A card failure never fails the report. Every render also writes
|
|
8003
8087
|
* `render.json`: its options and the profile it came from (`source`, relative to `outDir`).
|
|
8004
8088
|
*/
|
|
8005
8089
|
const writeReport = (profile, outDir, options = DEFAULT_RENDER_OPTIONS, source = null, cjkFonts = noCjkFonts) => Effect.gen(function* () {
|
|
@@ -8057,6 +8141,7 @@ const writeReport = (profile, outDir, options = DEFAULT_RENDER_OPTIONS, source =
|
|
|
8057
8141
|
error: "reason" in e ? e.reason : e.message
|
|
8058
8142
|
}))));
|
|
8059
8143
|
}
|
|
8144
|
+
yield* writeOutputGuide(outDir).pipe(Effect.mapError((e) => new Error(e.detail)));
|
|
8060
8145
|
const first = cards[0];
|
|
8061
8146
|
return {
|
|
8062
8147
|
html,
|
|
@@ -14337,7 +14422,7 @@ const analyze = (input) => Effect.gen(function* () {
|
|
|
14337
14422
|
* Package version. Injected by tsdown at build time; during development and tests
|
|
14338
14423
|
* (tsx / vitest) it falls back to reading package.json.
|
|
14339
14424
|
*/
|
|
14340
|
-
const VERSION = "0.2.
|
|
14425
|
+
const VERSION = "0.2.2";
|
|
14341
14426
|
// src/cli/render-error.ts
|
|
14342
14427
|
/** How to fix an InvalidArgument, per flag. */
|
|
14343
14428
|
const ARGUMENT_HINTS = {
|
|
@@ -14578,6 +14663,7 @@ const writeDryRun = (p, outDir, context, voice = DEFAULT_VOICE) => Effect.gen(fu
|
|
|
14578
14663
|
}))
|
|
14579
14664
|
};
|
|
14580
14665
|
yield* writeFileOrFail(path.join(outDir, "plan.json"), `${JSON.stringify(summary, null, 2)}\n`);
|
|
14666
|
+
yield* writeOutputGuide(outDir);
|
|
14581
14667
|
});
|
|
14582
14668
|
/**
|
|
14583
14669
|
* The plan a CLI reports wins over the hint from local files; the file's extra detail is kept.
|
|
@@ -14954,8 +15040,10 @@ const runStats = (options) => Effect.gen(function* () {
|
|
|
14954
15040
|
yield* out.line("");
|
|
14955
15041
|
const collected = yield* readSources;
|
|
14956
15042
|
const { stats } = yield* runPipelineStep(collected, options.since);
|
|
14957
|
-
const
|
|
15043
|
+
const root = yield* resolveOut(options.out);
|
|
15044
|
+
const file = path.join(root, "stats.json");
|
|
14958
15045
|
yield* writeFileOrFail(file, `${JSON.stringify(encodeStats(stats), null, 2)}\n`);
|
|
15046
|
+
yield* writeOutputGuide(root);
|
|
14959
15047
|
const peak = peakHour(stats);
|
|
14960
15048
|
const percent = (x) => Math.round(x * 100);
|
|
14961
15049
|
yield* out.line("");
|
package/package.json
CHANGED