poe-code 3.0.184 → 3.0.186
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/configure-payload.d.ts +2 -1
- package/dist/cli/commands/configure-payload.js +4 -2
- package/dist/cli/commands/configure-payload.js.map +1 -1
- package/dist/cli/commands/configure.d.ts +1 -0
- package/dist/cli/commands/configure.js +50 -11
- package/dist/cli/commands/configure.js.map +1 -1
- package/dist/cli/commands/ensure-isolated-config.js +24 -2
- package/dist/cli/commands/ensure-isolated-config.js.map +1 -1
- package/dist/cli/commands/experiment.js +15 -2
- package/dist/cli/commands/experiment.js.map +1 -1
- package/dist/cli/commands/login.js +8 -4
- package/dist/cli/commands/login.js.map +1 -1
- package/dist/cli/commands/memory.js +16 -7
- package/dist/cli/commands/memory.js.map +1 -1
- package/dist/cli/commands/pipeline-init.js +32 -48
- package/dist/cli/commands/pipeline-init.js.map +1 -1
- package/dist/cli/commands/pipeline.js +89 -77
- package/dist/cli/commands/pipeline.js.map +1 -1
- package/dist/cli/commands/provider.d.ts +6 -0
- package/dist/cli/commands/provider.js +100 -0
- package/dist/cli/commands/provider.js.map +1 -0
- package/dist/cli/commands/shared.d.ts +7 -0
- package/dist/cli/commands/shared.js +3 -0
- package/dist/cli/commands/shared.js.map +1 -1
- package/dist/cli/commands/test.js +1 -1
- package/dist/cli/commands/test.js.map +1 -1
- package/dist/cli/commands/unconfigure.js +12 -3
- package/dist/cli/commands/unconfigure.js.map +1 -1
- package/dist/cli/container.d.ts +2 -0
- package/dist/cli/container.js +3 -0
- package/dist/cli/container.js.map +1 -1
- package/dist/cli/isolated-env-runner.js +2 -2
- package/dist/cli/isolated-env-runner.js.map +1 -1
- package/dist/cli/isolated-env.d.ts +3 -2
- package/dist/cli/isolated-env.js +31 -40
- package/dist/cli/isolated-env.js.map +1 -1
- package/dist/cli/poe-code-command-runner.js +9 -2
- package/dist/cli/poe-code-command-runner.js.map +1 -1
- package/dist/cli/program.js +5 -0
- package/dist/cli/program.js.map +1 -1
- package/dist/cli/service-registry.d.ts +7 -7
- package/dist/cli/service-registry.js.map +1 -1
- package/dist/index.js +2496 -1911
- package/dist/index.js.map +4 -4
- package/dist/providers/claude-code.d.ts +2 -1
- package/dist/providers/claude-code.js +5 -5
- package/dist/providers/claude-code.js.map +2 -2
- package/dist/providers/codex.d.ts +5 -1
- package/dist/providers/codex.js +39 -12
- package/dist/providers/codex.js.map +2 -2
- package/dist/providers/goose.d.ts +2 -1
- package/dist/providers/goose.js +24 -8
- package/dist/providers/goose.js.map +3 -3
- package/dist/providers/kimi.js +3 -3
- package/dist/providers/kimi.js.map +3 -3
- package/dist/providers/opencode.js +2 -2
- package/dist/providers/opencode.js.map +3 -3
- package/dist/providers/poe-agent.js +753 -649
- package/dist/providers/poe-agent.js.map +4 -4
- package/dist/sdk/container.js +3 -0
- package/dist/sdk/container.js.map +1 -1
- package/dist/sdk/pipeline.d.ts +1 -2
- package/dist/sdk/pipeline.js +51 -119
- package/dist/sdk/pipeline.js.map +1 -1
- package/dist/services/config.d.ts +1 -0
- package/dist/services/config.js +27 -2
- package/dist/services/config.js.map +1 -1
- package/dist/templates/pipeline/SKILL_plan.md +16 -42
- package/package.json +15 -1
- package/packages/agent-mcp-config/dist/apply.d.ts +6 -0
- package/packages/agent-mcp-config/dist/apply.js +175 -0
- package/packages/agent-mcp-config/dist/configs.d.ts +22 -0
- package/packages/agent-mcp-config/dist/configs.js +74 -0
- package/packages/agent-mcp-config/dist/index.d.ts +3 -0
- package/packages/agent-mcp-config/dist/index.js +2 -0
- package/packages/agent-mcp-config/dist/shapes.d.ts +31 -0
- package/packages/agent-mcp-config/dist/shapes.js +87 -0
- package/packages/agent-mcp-config/dist/types.d.ts +25 -0
- package/packages/agent-mcp-config/dist/types.js +1 -0
- package/packages/agent-skill-config/dist/apply.d.ts +25 -0
- package/packages/agent-skill-config/dist/apply.js +109 -0
- package/packages/agent-skill-config/dist/configs.d.ts +16 -0
- package/packages/agent-skill-config/dist/configs.js +66 -0
- package/packages/agent-skill-config/dist/exports.compile-check.d.ts +1 -0
- package/packages/agent-skill-config/dist/exports.compile-check.js +1 -0
- package/packages/agent-skill-config/dist/index.d.ts +5 -0
- package/packages/agent-skill-config/dist/index.js +2 -0
- package/packages/agent-skill-config/dist/templates/poe-generate.md +47 -0
- package/packages/agent-skill-config/dist/templates/terminal-pilot.md +45 -0
- package/packages/agent-skill-config/dist/templates.d.ts +3 -0
- package/packages/agent-skill-config/dist/templates.js +63 -0
- package/packages/agent-skill-config/dist/types.d.ts +16 -0
- package/packages/agent-skill-config/dist/types.js +1 -0
- package/packages/cmdkit/dist/cli.js +7 -2
- package/packages/cmdkit/dist/cli.js.map +2 -2
- package/packages/cmdkit-openapi/dist/api-command.d.ts +7 -0
- package/packages/cmdkit-openapi/dist/api-command.js +4 -0
- package/packages/cmdkit-openapi/dist/auth/bearer-token-auth.d.ts +8 -0
- package/packages/cmdkit-openapi/dist/auth/bearer-token-auth.js +216 -0
- package/packages/cmdkit-openapi/dist/auth/types.d.ts +9 -0
- package/packages/cmdkit-openapi/dist/auth/types.js +1 -0
- package/packages/cmdkit-openapi/dist/bin/generate.d.ts +40 -0
- package/packages/cmdkit-openapi/dist/bin/generate.js +248 -0
- package/packages/cmdkit-openapi/dist/define-client.d.ts +20 -0
- package/packages/cmdkit-openapi/dist/define-client.js +148 -0
- package/packages/cmdkit-openapi/dist/generate.d.ts +210 -0
- package/packages/cmdkit-openapi/dist/generate.js +1091 -0
- package/packages/cmdkit-openapi/dist/group-by-noun.d.ts +6 -0
- package/packages/cmdkit-openapi/dist/group-by-noun.js +17 -0
- package/packages/cmdkit-openapi/dist/http.d.ts +26 -0
- package/packages/cmdkit-openapi/dist/http.js +123 -0
- package/packages/cmdkit-openapi/dist/index.d.ts +12 -0
- package/packages/cmdkit-openapi/dist/index.js +6 -0
- package/packages/cmdkit-openapi/dist/interpreter.d.ts +6 -0
- package/packages/cmdkit-openapi/dist/interpreter.js +289 -0
- package/packages/cmdkit-openapi/dist/lock.d.ts +14 -0
- package/packages/cmdkit-openapi/dist/lock.js +48 -0
- package/packages/cmdkit-openapi/dist/naming.d.ts +24 -0
- package/packages/cmdkit-openapi/dist/naming.js +218 -0
- package/packages/cmdkit-openapi/dist/request-shape.d.ts +15 -0
- package/packages/cmdkit-openapi/dist/request-shape.js +5 -0
- package/packages/cmdkit-openapi/dist/runtime.d.ts +13 -0
- package/packages/cmdkit-openapi/dist/runtime.js +94 -0
- package/packages/cmdkit-openapi/dist/spec-source.d.ts +11 -0
- package/packages/cmdkit-openapi/dist/spec-source.js +63 -0
- package/packages/config-mutations/dist/execution/apply-mutation.d.ts +5 -0
- package/packages/config-mutations/dist/execution/apply-mutation.js +552 -0
- package/packages/config-mutations/dist/execution/path-utils.d.ts +17 -0
- package/packages/config-mutations/dist/execution/path-utils.js +58 -0
- package/packages/config-mutations/dist/execution/run-mutations.d.ts +7 -0
- package/packages/config-mutations/dist/execution/run-mutations.js +46 -0
- package/packages/config-mutations/dist/formats/index.d.ts +13 -0
- package/packages/config-mutations/dist/formats/index.js +49 -0
- package/packages/config-mutations/dist/formats/json.d.ts +31 -0
- package/packages/config-mutations/dist/formats/json.js +140 -0
- package/packages/config-mutations/dist/formats/toml.d.ts +2 -0
- package/packages/config-mutations/dist/formats/toml.js +72 -0
- package/packages/config-mutations/dist/formats/yaml.d.ts +2 -0
- package/packages/config-mutations/dist/formats/yaml.js +73 -0
- package/packages/config-mutations/dist/fs-utils.d.ts +18 -0
- package/packages/config-mutations/dist/fs-utils.js +45 -0
- package/packages/config-mutations/dist/index.d.ts +8 -0
- package/packages/config-mutations/dist/index.js +8 -0
- package/packages/config-mutations/dist/mutations/config-mutation.d.ts +47 -0
- package/packages/config-mutations/dist/mutations/config-mutation.js +34 -0
- package/packages/config-mutations/dist/mutations/file-mutation.d.ts +52 -0
- package/packages/config-mutations/dist/mutations/file-mutation.js +46 -0
- package/packages/config-mutations/dist/mutations/template-mutation.d.ts +40 -0
- package/packages/config-mutations/dist/mutations/template-mutation.js +32 -0
- package/packages/config-mutations/dist/template/render.d.ts +7 -0
- package/packages/config-mutations/dist/template/render.js +28 -0
- package/packages/config-mutations/dist/testing/format-utils.d.ts +7 -0
- package/packages/config-mutations/dist/testing/format-utils.js +21 -0
- package/packages/config-mutations/dist/testing/index.d.ts +3 -0
- package/packages/config-mutations/dist/testing/index.js +2 -0
- package/packages/config-mutations/dist/testing/mock-fs.d.ts +25 -0
- package/packages/config-mutations/dist/testing/mock-fs.js +170 -0
- package/packages/config-mutations/dist/types.d.ts +156 -0
- package/packages/config-mutations/dist/types.js +6 -0
- package/packages/memory/dist/audit.d.ts +11 -0
- package/packages/memory/dist/audit.js +131 -0
- package/packages/memory/dist/cache.cli.d.ts +9 -0
- package/packages/memory/dist/cache.cli.js +24 -0
- package/packages/memory/dist/cache.d.ts +14 -0
- package/packages/memory/dist/cache.js +149 -0
- package/packages/memory/dist/confidence.d.ts +4 -0
- package/packages/memory/dist/confidence.js +201 -0
- package/packages/memory/dist/corpus/001-archaeoastronomy.md +479 -0
- package/packages/memory/dist/corpus/002-magnetohydrodynamics.md +475 -0
- package/packages/memory/dist/corpus/003-biosemiotics.md +483 -0
- package/packages/memory/dist/corpus/004-cryopedology.md +483 -0
- package/packages/memory/dist/corpus/005-geomicrobiology.md +479 -0
- package/packages/memory/dist/corpus/006-aeronomy.md +487 -0
- package/packages/memory/dist/corpus/007-paleoclimatology.md +479 -0
- package/packages/memory/dist/corpus/008-hydrogeophysics.md +479 -0
- package/packages/memory/dist/corpus/009-magnetostratigraphy.md +475 -0
- package/packages/memory/dist/corpus/010-isotope-hydrology.md +481 -0
- package/packages/memory/dist/corpus/011-speleothem-geochemistry.md +474 -0
- package/packages/memory/dist/corpus/012-astrobiogeochemistry.md +475 -0
- package/packages/memory/dist/corpus/013-neuroethology.md +483 -0
- package/packages/memory/dist/corpus/014-chronophysiology.md +483 -0
- package/packages/memory/dist/corpus/015-limnogeochemistry.md +475 -0
- package/packages/memory/dist/corpus/016-palynology.md +483 -0
- package/packages/memory/dist/corpus/017-volcanotectonics.md +473 -0
- package/packages/memory/dist/corpus/018-seismotectonics.md +473 -0
- package/packages/memory/dist/corpus/019-biogeomorphology.md +475 -0
- package/packages/memory/dist/corpus/020-geobiophysics.md +479 -0
- package/packages/memory/dist/corpus/021-phytolith-analysis.md +481 -0
- package/packages/memory/dist/corpus/022-archaeometallurgy.md +479 -0
- package/packages/memory/dist/corpus/023-paleomagnetism.md +479 -0
- package/packages/memory/dist/corpus/024-biocalorimetry.md +475 -0
- package/packages/memory/dist/corpus/025-atmospheric-chemiluminescence.md +473 -0
- package/packages/memory/dist/corpus/026-cryoseismology.md +479 -0
- package/packages/memory/dist/corpus/027-extremophile-radiobiology.md +475 -0
- package/packages/memory/dist/corpus/028-heliophysics.md +479 -0
- package/packages/memory/dist/corpus/029-astroparticle-geophysics.md +474 -0
- package/packages/memory/dist/corpus/030-glaciohydrology.md +479 -0
- package/packages/memory/dist/corpus/031-permafrost-microbiology.md +477 -0
- package/packages/memory/dist/corpus/032-ecoacoustics.md +479 -0
- package/packages/memory/dist/corpus/033-dendroclimatology.md +473 -0
- package/packages/memory/dist/corpus/034-ionospheric-tomography.md +477 -0
- package/packages/memory/dist/corpus/035-marine-geodesy.md +481 -0
- package/packages/memory/dist/corpus/036-sedimentary-ancient-dna.md +481 -0
- package/packages/memory/dist/corpus/037-myrmecochory-dynamics.md +474 -0
- package/packages/memory/dist/corpus/038-chemosensory-ecology.md +477 -0
- package/packages/memory/dist/corpus/039-spintronics-materials.md +479 -0
- package/packages/memory/dist/corpus/040-nanotoxicology.md +483 -0
- package/packages/memory/dist/corpus/041-cosmochemistry.md +483 -0
- package/packages/memory/dist/corpus/042-quaternary-geochronology.md +471 -0
- package/packages/memory/dist/corpus/043-biophotonics.md +479 -0
- package/packages/memory/dist/corpus/044-evolutionary-morphometrics.md +481 -0
- package/packages/memory/dist/corpus/045-cryovolcanology.md +475 -0
- package/packages/memory/dist/corpus/046-exoplanet-atmospheric-dynamics.md +479 -0
- package/packages/memory/dist/corpus/047-microbial-electrosynthesis.md +477 -0
- package/packages/memory/dist/corpus/048-paleoseismology.md +479 -0
- package/packages/memory/dist/corpus/049-actinide-geochemistry.md +477 -0
- package/packages/memory/dist/corpus/050-quantum-biology.md +489 -0
- package/packages/memory/dist/edit.d.ts +10 -0
- package/packages/memory/dist/edit.js +43 -0
- package/packages/memory/dist/explain.cli.d.ts +8 -0
- package/packages/memory/dist/explain.cli.js +9 -0
- package/packages/memory/dist/explain.d.ts +8 -0
- package/packages/memory/dist/explain.js +77 -0
- package/packages/memory/dist/frontmatter.d.ts +9 -0
- package/packages/memory/dist/frontmatter.js +217 -0
- package/packages/memory/dist/index.d.ts +21 -0
- package/packages/memory/dist/index.js +4807 -0
- package/packages/memory/dist/index.js.map +7 -0
- package/packages/memory/dist/ingest.d.ts +3 -0
- package/packages/memory/dist/ingest.js +118 -0
- package/packages/memory/dist/init.d.ts +2 -0
- package/packages/memory/dist/init.js +24 -0
- package/packages/memory/dist/install.d.ts +18 -0
- package/packages/memory/dist/install.js +50 -0
- package/packages/memory/dist/lock.d.ts +19 -0
- package/packages/memory/dist/lock.js +102 -0
- package/packages/memory/dist/mcp.d.ts +7 -0
- package/packages/memory/dist/mcp.js +58 -0
- package/packages/memory/dist/pages.d.ts +4 -0
- package/packages/memory/dist/pages.js +92 -0
- package/packages/memory/dist/paths.d.ts +12 -0
- package/packages/memory/dist/paths.js +34 -0
- package/packages/memory/dist/query.d.ts +10 -0
- package/packages/memory/dist/query.js +130 -0
- package/packages/memory/dist/reconcile.d.ts +9 -0
- package/packages/memory/dist/reconcile.js +138 -0
- package/packages/memory/dist/resolve-root.d.ts +11 -0
- package/packages/memory/dist/resolve-root.js +22 -0
- package/packages/memory/dist/search.d.ts +2 -0
- package/packages/memory/dist/search.js +29 -0
- package/packages/memory/dist/status.d.ts +7 -0
- package/packages/memory/dist/status.js +46 -0
- package/packages/memory/dist/tokens.d.ts +2 -0
- package/packages/memory/dist/tokens.js +71 -0
- package/packages/memory/dist/types.d.ts +155 -0
- package/packages/memory/dist/types.js +1 -0
- package/packages/memory/dist/write.d.ts +9 -0
- package/packages/memory/dist/write.js +76 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
function write(options) {
|
|
2
|
+
return {
|
|
3
|
+
kind: "templateWrite",
|
|
4
|
+
target: options.target,
|
|
5
|
+
templateId: options.templateId,
|
|
6
|
+
context: options.context,
|
|
7
|
+
label: options.label
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
function mergeToml(options) {
|
|
11
|
+
return {
|
|
12
|
+
kind: "templateMergeToml",
|
|
13
|
+
target: options.target,
|
|
14
|
+
templateId: options.templateId,
|
|
15
|
+
context: options.context,
|
|
16
|
+
label: options.label
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function mergeJson(options) {
|
|
20
|
+
return {
|
|
21
|
+
kind: "templateMergeJson",
|
|
22
|
+
target: options.target,
|
|
23
|
+
templateId: options.templateId,
|
|
24
|
+
context: options.context,
|
|
25
|
+
label: options.label
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export const templateMutation = {
|
|
29
|
+
write,
|
|
30
|
+
mergeToml,
|
|
31
|
+
mergeJson
|
|
32
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type TemplateVariables = Record<string, string | number | boolean | string[]>;
|
|
2
|
+
/**
|
|
3
|
+
* Render a mustache template with the given variables.
|
|
4
|
+
* Arrays are automatically joined with newlines.
|
|
5
|
+
* HTML escaping is disabled.
|
|
6
|
+
*/
|
|
7
|
+
export declare function renderTemplate(template: string, variables: TemplateVariables): string;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import Mustache from "mustache";
|
|
2
|
+
// Disable HTML escaping - we're rendering prompts, not HTML
|
|
3
|
+
const originalEscape = Mustache.escape;
|
|
4
|
+
/**
|
|
5
|
+
* Render a mustache template with the given variables.
|
|
6
|
+
* Arrays are automatically joined with newlines.
|
|
7
|
+
* HTML escaping is disabled.
|
|
8
|
+
*/
|
|
9
|
+
export function renderTemplate(template, variables) {
|
|
10
|
+
// Pre-process variables to handle arrays
|
|
11
|
+
const processed = {};
|
|
12
|
+
for (const [key, value] of Object.entries(variables)) {
|
|
13
|
+
if (Array.isArray(value)) {
|
|
14
|
+
processed[key] = value.join("\n");
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
processed[key] = value;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
// Temporarily disable HTML escaping
|
|
21
|
+
Mustache.escape = (text) => text;
|
|
22
|
+
try {
|
|
23
|
+
return Mustache.render(template, processed);
|
|
24
|
+
}
|
|
25
|
+
finally {
|
|
26
|
+
Mustache.escape = originalEscape;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ConfigObject } from "../types.js";
|
|
2
|
+
export declare function parseToml(content: string): ConfigObject;
|
|
3
|
+
export declare function serializeToml(obj: ConfigObject): string;
|
|
4
|
+
export declare function parseJson(content: string): ConfigObject;
|
|
5
|
+
export declare function serializeJson(obj: ConfigObject): string;
|
|
6
|
+
export declare function parseYaml(content: string): ConfigObject;
|
|
7
|
+
export declare function serializeYaml(obj: ConfigObject): string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsonFormat } from "../formats/json.js";
|
|
2
|
+
import { tomlFormat } from "../formats/toml.js";
|
|
3
|
+
import { yamlFormat } from "../formats/yaml.js";
|
|
4
|
+
export function parseToml(content) {
|
|
5
|
+
return tomlFormat.parse(content);
|
|
6
|
+
}
|
|
7
|
+
export function serializeToml(obj) {
|
|
8
|
+
return tomlFormat.serialize(obj);
|
|
9
|
+
}
|
|
10
|
+
export function parseJson(content) {
|
|
11
|
+
return jsonFormat.parse(content);
|
|
12
|
+
}
|
|
13
|
+
export function serializeJson(obj) {
|
|
14
|
+
return jsonFormat.serialize(obj);
|
|
15
|
+
}
|
|
16
|
+
export function parseYaml(content) {
|
|
17
|
+
return yamlFormat.parse(content);
|
|
18
|
+
}
|
|
19
|
+
export function serializeYaml(obj) {
|
|
20
|
+
return yamlFormat.serialize(obj);
|
|
21
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { FileSystem } from "../types.js";
|
|
2
|
+
export interface MockFileSystem extends FileSystem {
|
|
3
|
+
/** Current file contents, keyed by absolute path */
|
|
4
|
+
files: Record<string, string>;
|
|
5
|
+
/** Created directories */
|
|
6
|
+
directories: Set<string>;
|
|
7
|
+
/** Check if a path exists (file or directory) */
|
|
8
|
+
exists(path: string): boolean;
|
|
9
|
+
/** Get file content or undefined if not found */
|
|
10
|
+
getContent(path: string): string | undefined;
|
|
11
|
+
/** Read file with encoding overloads for compatibility */
|
|
12
|
+
readFile(path: string, encoding: BufferEncoding): Promise<string>;
|
|
13
|
+
readFile(path: string): Promise<Buffer>;
|
|
14
|
+
}
|
|
15
|
+
export interface MockFsOptions {
|
|
16
|
+
/** Initial files - paths can use ~ which will be expanded to homeDir */
|
|
17
|
+
[path: string]: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Create an in-memory mock filesystem for testing mutations.
|
|
21
|
+
*
|
|
22
|
+
* @param initialFiles - Initial files to populate the filesystem with
|
|
23
|
+
* @param homeDir - Home directory for ~ expansion (defaults to /home/test)
|
|
24
|
+
*/
|
|
25
|
+
export declare function createMockFs(initialFiles?: MockFsOptions, homeDir?: string): MockFileSystem;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
const DEFAULT_HOME_DIR = "/home/test";
|
|
3
|
+
/**
|
|
4
|
+
* Create an in-memory mock filesystem for testing mutations.
|
|
5
|
+
*
|
|
6
|
+
* @param initialFiles - Initial files to populate the filesystem with
|
|
7
|
+
* @param homeDir - Home directory for ~ expansion (defaults to /home/test)
|
|
8
|
+
*/
|
|
9
|
+
export function createMockFs(initialFiles, homeDir = DEFAULT_HOME_DIR) {
|
|
10
|
+
const files = {};
|
|
11
|
+
const directories = new Set();
|
|
12
|
+
// Initialize with provided files
|
|
13
|
+
if (initialFiles) {
|
|
14
|
+
for (const [filePath, content] of Object.entries(initialFiles)) {
|
|
15
|
+
const absolutePath = expandPath(filePath, homeDir);
|
|
16
|
+
files[absolutePath] = content;
|
|
17
|
+
// Ensure parent directories exist
|
|
18
|
+
const parentDir = path.dirname(absolutePath);
|
|
19
|
+
addDirectoryTree(parentDir, directories);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
// Ensure home directory exists
|
|
23
|
+
addDirectoryTree(homeDir, directories);
|
|
24
|
+
const mockFs = {
|
|
25
|
+
files,
|
|
26
|
+
directories,
|
|
27
|
+
exists(filePath) {
|
|
28
|
+
const absolutePath = expandPath(filePath, homeDir);
|
|
29
|
+
return absolutePath in files || directories.has(absolutePath);
|
|
30
|
+
},
|
|
31
|
+
getContent(filePath) {
|
|
32
|
+
const absolutePath = expandPath(filePath, homeDir);
|
|
33
|
+
return files[absolutePath];
|
|
34
|
+
},
|
|
35
|
+
async readFile(filePath, encoding) {
|
|
36
|
+
const absolutePath = expandPath(filePath, homeDir);
|
|
37
|
+
if (!(absolutePath in files)) {
|
|
38
|
+
const error = new Error(`ENOENT: no such file or directory, open '${absolutePath}'`);
|
|
39
|
+
error.code = "ENOENT";
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
const content = files[absolutePath];
|
|
43
|
+
if (encoding) {
|
|
44
|
+
return content;
|
|
45
|
+
}
|
|
46
|
+
return Buffer.from(content, "utf8");
|
|
47
|
+
},
|
|
48
|
+
async writeFile(filePath, content, options) {
|
|
49
|
+
void options; // TypeScript satisfaction
|
|
50
|
+
const absolutePath = expandPath(filePath, homeDir);
|
|
51
|
+
// Ensure parent directory exists
|
|
52
|
+
const parentDir = path.dirname(absolutePath);
|
|
53
|
+
if (!directories.has(parentDir)) {
|
|
54
|
+
const error = new Error(`ENOENT: no such file or directory, open '${absolutePath}'`);
|
|
55
|
+
error.code = "ENOENT";
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
if (typeof content === "string") {
|
|
59
|
+
files[absolutePath] = content;
|
|
60
|
+
}
|
|
61
|
+
else if (Buffer.isBuffer(content)) {
|
|
62
|
+
files[absolutePath] = content.toString("utf8");
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
files[absolutePath] = Buffer.from(content.buffer, content.byteOffset, content.byteLength).toString("utf8");
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
async mkdir(dirPath, options) {
|
|
69
|
+
const absolutePath = expandPath(dirPath, homeDir);
|
|
70
|
+
if (options?.recursive) {
|
|
71
|
+
addDirectoryTree(absolutePath, directories);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
// Check parent exists
|
|
75
|
+
const parentDir = path.dirname(absolutePath);
|
|
76
|
+
if (parentDir !== absolutePath && !directories.has(parentDir)) {
|
|
77
|
+
const error = new Error(`ENOENT: no such file or directory, mkdir '${absolutePath}'`);
|
|
78
|
+
error.code = "ENOENT";
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
81
|
+
directories.add(absolutePath);
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
async unlink(filePath) {
|
|
85
|
+
const absolutePath = expandPath(filePath, homeDir);
|
|
86
|
+
if (!(absolutePath in files)) {
|
|
87
|
+
const error = new Error(`ENOENT: no such file or directory, unlink '${absolutePath}'`);
|
|
88
|
+
error.code = "ENOENT";
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
delete files[absolutePath];
|
|
92
|
+
},
|
|
93
|
+
async stat(filePath) {
|
|
94
|
+
const absolutePath = expandPath(filePath, homeDir);
|
|
95
|
+
if (absolutePath in files) {
|
|
96
|
+
return { mode: 0o644 };
|
|
97
|
+
}
|
|
98
|
+
if (directories.has(absolutePath)) {
|
|
99
|
+
return { mode: 0o755 };
|
|
100
|
+
}
|
|
101
|
+
const error = new Error(`ENOENT: no such file or directory, stat '${absolutePath}'`);
|
|
102
|
+
error.code = "ENOENT";
|
|
103
|
+
throw error;
|
|
104
|
+
},
|
|
105
|
+
async readdir(dirPath) {
|
|
106
|
+
const absolutePath = expandPath(dirPath, homeDir);
|
|
107
|
+
if (absolutePath in files) {
|
|
108
|
+
const error = new Error(`ENOTDIR: not a directory, scandir '${absolutePath}'`);
|
|
109
|
+
error.code = "ENOTDIR";
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
if (!directories.has(absolutePath)) {
|
|
113
|
+
const error = new Error(`ENOENT: no such file or directory, scandir '${absolutePath}'`);
|
|
114
|
+
error.code = "ENOENT";
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
const entries = new Set();
|
|
118
|
+
for (const filePath of Object.keys(files)) {
|
|
119
|
+
if (path.dirname(filePath) === absolutePath) {
|
|
120
|
+
entries.add(path.basename(filePath));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
for (const dir of directories) {
|
|
124
|
+
if (dir !== absolutePath && path.dirname(dir) === absolutePath) {
|
|
125
|
+
entries.add(path.basename(dir));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return Array.from(entries);
|
|
129
|
+
},
|
|
130
|
+
async chmod(filePath, mode) {
|
|
131
|
+
void mode; // In mock fs, we don't actually store mode changes
|
|
132
|
+
const absolutePath = expandPath(filePath, homeDir);
|
|
133
|
+
if (!(absolutePath in files) && !directories.has(absolutePath)) {
|
|
134
|
+
const error = new Error(`ENOENT: no such file or directory, chmod '${absolutePath}'`);
|
|
135
|
+
error.code = "ENOENT";
|
|
136
|
+
throw error;
|
|
137
|
+
}
|
|
138
|
+
// Mode change is a no-op in mock fs but we don't throw
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
return mockFs;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Expand ~ to homeDir in a path.
|
|
145
|
+
*/
|
|
146
|
+
function expandPath(inputPath, homeDir) {
|
|
147
|
+
if (inputPath.startsWith("~/")) {
|
|
148
|
+
return path.join(homeDir, inputPath.slice(2));
|
|
149
|
+
}
|
|
150
|
+
if (inputPath === "~") {
|
|
151
|
+
return homeDir;
|
|
152
|
+
}
|
|
153
|
+
if (inputPath.startsWith("~")) {
|
|
154
|
+
// ~something (not ~/) - treat as relative path from home
|
|
155
|
+
return path.join(homeDir, inputPath.slice(1));
|
|
156
|
+
}
|
|
157
|
+
return inputPath;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Add a directory and all its parent directories to the set.
|
|
161
|
+
*/
|
|
162
|
+
function addDirectoryTree(dirPath, directories) {
|
|
163
|
+
const parts = dirPath.split(path.sep).filter(Boolean);
|
|
164
|
+
let current = "/";
|
|
165
|
+
directories.add(current);
|
|
166
|
+
for (const part of parts) {
|
|
167
|
+
current = path.join(current, part);
|
|
168
|
+
directories.add(current);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
export type ConfigPrimitive = string | number | boolean | null;
|
|
2
|
+
export type ConfigValue = ConfigPrimitive | ConfigObject | ConfigArray | Date;
|
|
3
|
+
export interface ConfigObject {
|
|
4
|
+
[key: string]: ConfigValue;
|
|
5
|
+
}
|
|
6
|
+
export type ConfigArray = ConfigValue[];
|
|
7
|
+
export declare function isConfigObject(value: unknown): value is ConfigObject;
|
|
8
|
+
export interface FileSystem {
|
|
9
|
+
readFile(path: string, encoding: "utf8"): Promise<string>;
|
|
10
|
+
writeFile(path: string, content: string, options?: {
|
|
11
|
+
encoding: "utf8";
|
|
12
|
+
}): Promise<void>;
|
|
13
|
+
mkdir(path: string, options?: {
|
|
14
|
+
recursive: boolean;
|
|
15
|
+
}): Promise<void>;
|
|
16
|
+
unlink(path: string): Promise<void>;
|
|
17
|
+
rm?(path: string, options?: {
|
|
18
|
+
recursive?: boolean;
|
|
19
|
+
force?: boolean;
|
|
20
|
+
}): Promise<void>;
|
|
21
|
+
stat(path: string): Promise<{
|
|
22
|
+
mode?: number;
|
|
23
|
+
}>;
|
|
24
|
+
readdir(path: string): Promise<string[]>;
|
|
25
|
+
chmod?(path: string, mode: number): Promise<void>;
|
|
26
|
+
}
|
|
27
|
+
export type TemplateLoader = (templateId: string) => Promise<string>;
|
|
28
|
+
export interface ConfigFormat {
|
|
29
|
+
/** Parse string content into object */
|
|
30
|
+
parse(content: string): ConfigObject;
|
|
31
|
+
/** Serialize object to string (with consistent formatting) */
|
|
32
|
+
serialize(obj: ConfigObject): string;
|
|
33
|
+
/** Deep merge patch into base, returning new object */
|
|
34
|
+
merge(base: ConfigObject, patch: ConfigObject): ConfigObject;
|
|
35
|
+
/** Remove keys matching shape from object, returning new object */
|
|
36
|
+
prune(obj: ConfigObject, shape: ConfigObject): {
|
|
37
|
+
changed: boolean;
|
|
38
|
+
result: ConfigObject;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export interface PathMapper {
|
|
42
|
+
/** Map a target directory to a different location (e.g., for isolated configs) */
|
|
43
|
+
mapTargetDirectory(input: {
|
|
44
|
+
targetDirectory: string;
|
|
45
|
+
}): string;
|
|
46
|
+
}
|
|
47
|
+
export interface MutationContext {
|
|
48
|
+
/** Filesystem interface - required */
|
|
49
|
+
fs: FileSystem;
|
|
50
|
+
/** Home directory for ~ expansion - required */
|
|
51
|
+
homeDir: string;
|
|
52
|
+
/** Optional dry-run mode */
|
|
53
|
+
dryRun?: boolean;
|
|
54
|
+
/** Optional observers for logging */
|
|
55
|
+
observers?: MutationObservers;
|
|
56
|
+
/** Required for template mutations */
|
|
57
|
+
templates?: TemplateLoader;
|
|
58
|
+
/** Optional path mapper for redirecting paths (used for isolated configs) */
|
|
59
|
+
pathMapper?: PathMapper;
|
|
60
|
+
}
|
|
61
|
+
export interface MutationOptions {
|
|
62
|
+
[key: string]: unknown;
|
|
63
|
+
}
|
|
64
|
+
export type ValueResolver<T> = T | ((ctx: MutationOptions) => T);
|
|
65
|
+
interface BaseMutation {
|
|
66
|
+
/** Human-readable label for logging */
|
|
67
|
+
label?: string;
|
|
68
|
+
}
|
|
69
|
+
export interface ConfigMergeMutation extends BaseMutation {
|
|
70
|
+
kind: "configMerge";
|
|
71
|
+
target: ValueResolver<string>;
|
|
72
|
+
value: ValueResolver<ConfigObject>;
|
|
73
|
+
format?: "json" | "toml" | "yaml";
|
|
74
|
+
pruneByPrefix?: Record<string, string>;
|
|
75
|
+
}
|
|
76
|
+
export interface ConfigPruneMutation extends BaseMutation {
|
|
77
|
+
kind: "configPrune";
|
|
78
|
+
target: ValueResolver<string>;
|
|
79
|
+
shape: ValueResolver<ConfigObject>;
|
|
80
|
+
format?: "json" | "toml" | "yaml";
|
|
81
|
+
onlyIf?: (doc: ConfigObject, ctx: MutationOptions) => boolean;
|
|
82
|
+
}
|
|
83
|
+
export interface ConfigTransformMutation extends BaseMutation {
|
|
84
|
+
kind: "configTransform";
|
|
85
|
+
target: ValueResolver<string>;
|
|
86
|
+
format?: "json" | "toml" | "yaml";
|
|
87
|
+
transform: (content: ConfigObject, ctx: MutationOptions) => {
|
|
88
|
+
content: ConfigObject | null;
|
|
89
|
+
changed: boolean;
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
export interface EnsureDirectoryMutation extends BaseMutation {
|
|
93
|
+
kind: "ensureDirectory";
|
|
94
|
+
path: ValueResolver<string>;
|
|
95
|
+
}
|
|
96
|
+
export interface RemoveDirectoryMutation extends BaseMutation {
|
|
97
|
+
kind: "removeDirectory";
|
|
98
|
+
path: ValueResolver<string>;
|
|
99
|
+
force?: boolean;
|
|
100
|
+
}
|
|
101
|
+
export interface RemoveFileMutation extends BaseMutation {
|
|
102
|
+
kind: "removeFile";
|
|
103
|
+
target: ValueResolver<string>;
|
|
104
|
+
whenEmpty?: boolean;
|
|
105
|
+
whenContentMatches?: RegExp;
|
|
106
|
+
}
|
|
107
|
+
export interface ChmodMutation extends BaseMutation {
|
|
108
|
+
kind: "chmod";
|
|
109
|
+
target: ValueResolver<string>;
|
|
110
|
+
mode: number;
|
|
111
|
+
}
|
|
112
|
+
export interface BackupMutation extends BaseMutation {
|
|
113
|
+
kind: "backup";
|
|
114
|
+
target: ValueResolver<string>;
|
|
115
|
+
}
|
|
116
|
+
export interface TemplateWriteMutation extends BaseMutation {
|
|
117
|
+
kind: "templateWrite";
|
|
118
|
+
target: ValueResolver<string>;
|
|
119
|
+
templateId: string;
|
|
120
|
+
context?: ValueResolver<ConfigObject>;
|
|
121
|
+
}
|
|
122
|
+
export interface TemplateMergeTomlMutation extends BaseMutation {
|
|
123
|
+
kind: "templateMergeToml";
|
|
124
|
+
target: ValueResolver<string>;
|
|
125
|
+
templateId: string;
|
|
126
|
+
context?: ValueResolver<ConfigObject>;
|
|
127
|
+
}
|
|
128
|
+
export interface TemplateMergeJsonMutation extends BaseMutation {
|
|
129
|
+
kind: "templateMergeJson";
|
|
130
|
+
target: ValueResolver<string>;
|
|
131
|
+
templateId: string;
|
|
132
|
+
context?: ValueResolver<ConfigObject>;
|
|
133
|
+
}
|
|
134
|
+
export type Mutation = ConfigMergeMutation | ConfigPruneMutation | ConfigTransformMutation | EnsureDirectoryMutation | RemoveDirectoryMutation | RemoveFileMutation | ChmodMutation | BackupMutation | TemplateWriteMutation | TemplateMergeTomlMutation | TemplateMergeJsonMutation;
|
|
135
|
+
export type MutationEffect = "none" | "mkdir" | "write" | "delete" | "chmod" | "copy";
|
|
136
|
+
export type MutationDetail = "create" | "update" | "delete" | "noop" | "backup";
|
|
137
|
+
export interface MutationOutcome {
|
|
138
|
+
changed: boolean;
|
|
139
|
+
effect: MutationEffect;
|
|
140
|
+
detail?: MutationDetail;
|
|
141
|
+
}
|
|
142
|
+
export interface MutationDetails {
|
|
143
|
+
kind: string;
|
|
144
|
+
label: string;
|
|
145
|
+
targetPath?: string;
|
|
146
|
+
}
|
|
147
|
+
export interface MutationObservers {
|
|
148
|
+
onStart?(details: MutationDetails): void;
|
|
149
|
+
onComplete?(details: MutationDetails, outcome: MutationOutcome): void;
|
|
150
|
+
onError?(details: MutationDetails, error: unknown): void;
|
|
151
|
+
}
|
|
152
|
+
export interface MutationResult {
|
|
153
|
+
changed: boolean;
|
|
154
|
+
effects: MutationOutcome[];
|
|
155
|
+
}
|
|
156
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Config Object Types
|
|
3
|
+
// ============================================================================
|
|
4
|
+
export function isConfigObject(value) {
|
|
5
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { MemoryRoot } from "./types.js";
|
|
2
|
+
export type AuditClaimsOptions = {
|
|
3
|
+
minInferredConfidence?: number;
|
|
4
|
+
rejectUntagged?: boolean;
|
|
5
|
+
untaggedBodyThresholdChars?: number;
|
|
6
|
+
};
|
|
7
|
+
export type PageAudit = {
|
|
8
|
+
page: string;
|
|
9
|
+
issues: string[];
|
|
10
|
+
};
|
|
11
|
+
export declare function auditClaims(root: MemoryRoot, repoRoot: string, options?: AuditClaimsOptions): Promise<PageAudit[]>;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { parseClaims } from "./confidence.js";
|
|
4
|
+
import { serializeSourceRef } from "./frontmatter.js";
|
|
5
|
+
import { listPages } from "./pages.js";
|
|
6
|
+
const DEFAULT_MIN_INFERRED_CONFIDENCE = 0.3;
|
|
7
|
+
const DEFAULT_REJECT_UNTAGGED = false;
|
|
8
|
+
const DEFAULT_UNTAGGED_BODY_THRESHOLD_CHARS = 200;
|
|
9
|
+
export async function auditClaims(root, repoRoot, options = {}) {
|
|
10
|
+
const minInferredConfidence = options.minInferredConfidence ?? DEFAULT_MIN_INFERRED_CONFIDENCE;
|
|
11
|
+
const rejectUntagged = options.rejectUntagged ?? DEFAULT_REJECT_UNTAGGED;
|
|
12
|
+
const untaggedBodyThresholdChars = options.untaggedBodyThresholdChars ?? DEFAULT_UNTAGGED_BODY_THRESHOLD_CHARS;
|
|
13
|
+
const sourceCache = new Map();
|
|
14
|
+
const pages = await listPages(root);
|
|
15
|
+
const audits = [];
|
|
16
|
+
for (const page of pages) {
|
|
17
|
+
const issues = [];
|
|
18
|
+
let claims;
|
|
19
|
+
try {
|
|
20
|
+
claims = parseClaims(page.body);
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
issues.push(formatError(error));
|
|
24
|
+
audits.push({ page: page.relPath, issues });
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (rejectUntagged && claims.length === 0 && page.body.trim().length > untaggedBodyThresholdChars) {
|
|
28
|
+
issues.push(`Page has a long untagged body (>${untaggedBodyThresholdChars} chars) with no memory:* tags.`);
|
|
29
|
+
}
|
|
30
|
+
const inlineSources = new Set();
|
|
31
|
+
for (const claim of claims) {
|
|
32
|
+
if (claim.tag.verb === "inferred" && claim.tag.confidence < minInferredConfidence) {
|
|
33
|
+
issues.push(`Claim on line ${claim.lineNumber} uses inferred confidence=${claim.tag.confidence}, below the minimum ${minInferredConfidence}.`);
|
|
34
|
+
}
|
|
35
|
+
const source = "source" in claim.tag ? claim.tag.source : undefined;
|
|
36
|
+
if (source === undefined) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const serializedSource = serializeSourceRef(source);
|
|
40
|
+
inlineSources.add(serializedSource);
|
|
41
|
+
const sourceIssue = await auditSourceRef(source, claim.lineNumber, repoRoot, sourceCache);
|
|
42
|
+
if (sourceIssue !== undefined) {
|
|
43
|
+
issues.push(sourceIssue);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
issues.push(...auditFrontmatterSources(page.frontmatter.sources ?? [], inlineSources));
|
|
47
|
+
if (issues.length > 0) {
|
|
48
|
+
audits.push({ page: page.relPath, issues });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return audits;
|
|
52
|
+
}
|
|
53
|
+
async function auditSourceRef(source, claimLineNumber, repoRoot, sourceCache) {
|
|
54
|
+
if (isUrlLike(source.path)) {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
if (path.isAbsolute(source.path)) {
|
|
58
|
+
return `Claim on line ${claimLineNumber} cites "${serializeSourceRef(source)}", but source paths must be repo-relative or URLs.`;
|
|
59
|
+
}
|
|
60
|
+
const absPath = path.resolve(repoRoot, source.path);
|
|
61
|
+
if (!isWithinRoot(repoRoot, absPath)) {
|
|
62
|
+
return `Claim on line ${claimLineNumber} cites "${serializeSourceRef(source)}", which resolves outside the repo root.`;
|
|
63
|
+
}
|
|
64
|
+
const meta = await readSourceFile(absPath, sourceCache);
|
|
65
|
+
if (!meta.exists) {
|
|
66
|
+
return `Claim on line ${claimLineNumber} cites "${serializeSourceRef(source)}", resolved to "${meta.absPath}", but the file does not exist.`;
|
|
67
|
+
}
|
|
68
|
+
const lastReferencedLine = source.endLine ?? source.startLine;
|
|
69
|
+
if (lastReferencedLine !== undefined && lastReferencedLine > meta.lineCount) {
|
|
70
|
+
return `Claim on line ${claimLineNumber} cites "${serializeSourceRef(source)}", but current EOF ${meta.lineCount} is before the referenced line.`;
|
|
71
|
+
}
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
function auditFrontmatterSources(frontmatterSources, inlineSources) {
|
|
75
|
+
const serializedFrontmatterSources = new Set(frontmatterSources.map((source) => serializeSourceRef(source)));
|
|
76
|
+
const issues = [];
|
|
77
|
+
const missingSources = [...inlineSources].filter((source) => !serializedFrontmatterSources.has(source));
|
|
78
|
+
for (const source of missingSources.sort((left, right) => left.localeCompare(right))) {
|
|
79
|
+
issues.push(`Page frontmatter sources are missing "${source}" from inline tags.`);
|
|
80
|
+
}
|
|
81
|
+
const staleSources = [...serializedFrontmatterSources].filter((source) => !inlineSources.has(source));
|
|
82
|
+
for (const source of staleSources.sort((left, right) => left.localeCompare(right))) {
|
|
83
|
+
issues.push(`Page frontmatter sources contain stale entry "${source}" not found in inline tags.`);
|
|
84
|
+
}
|
|
85
|
+
return issues;
|
|
86
|
+
}
|
|
87
|
+
function readSourceFile(absPath, sourceCache) {
|
|
88
|
+
const cached = sourceCache.get(absPath);
|
|
89
|
+
if (cached !== undefined) {
|
|
90
|
+
return cached;
|
|
91
|
+
}
|
|
92
|
+
const pending = fs
|
|
93
|
+
.readFile(absPath, "utf8")
|
|
94
|
+
.then((content) => ({
|
|
95
|
+
exists: true,
|
|
96
|
+
absPath,
|
|
97
|
+
lineCount: countLines(content)
|
|
98
|
+
}))
|
|
99
|
+
.catch((error) => {
|
|
100
|
+
if (isMissing(error)) {
|
|
101
|
+
return {
|
|
102
|
+
exists: false,
|
|
103
|
+
absPath
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
throw error;
|
|
107
|
+
});
|
|
108
|
+
sourceCache.set(absPath, pending);
|
|
109
|
+
return pending;
|
|
110
|
+
}
|
|
111
|
+
function countLines(content) {
|
|
112
|
+
if (content.length === 0) {
|
|
113
|
+
return 0;
|
|
114
|
+
}
|
|
115
|
+
const normalized = content.replaceAll("\r\n", "\n").replaceAll("\r", "\n");
|
|
116
|
+
const trimmed = normalized.endsWith("\n") ? normalized.slice(0, -1) : normalized;
|
|
117
|
+
return trimmed.length === 0 ? 0 : trimmed.split("\n").length;
|
|
118
|
+
}
|
|
119
|
+
function formatError(error) {
|
|
120
|
+
return error instanceof Error ? error.message : String(error);
|
|
121
|
+
}
|
|
122
|
+
function isMissing(error) {
|
|
123
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
124
|
+
}
|
|
125
|
+
function isUrlLike(value) {
|
|
126
|
+
return /^[a-z][a-z\d+.-]*:\/\//i.test(value);
|
|
127
|
+
}
|
|
128
|
+
function isWithinRoot(root, absPath) {
|
|
129
|
+
const relative = path.relative(root, absPath);
|
|
130
|
+
return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
|
|
131
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { MemoryRoot } from "./types.js";
|
|
2
|
+
export declare function runMemoryCacheStatus(): Promise<void>;
|
|
3
|
+
export declare function runMemoryCacheClear(input: {
|
|
4
|
+
root: MemoryRoot;
|
|
5
|
+
olderThan?: string;
|
|
6
|
+
yes?: boolean;
|
|
7
|
+
}): Promise<{
|
|
8
|
+
removed: number;
|
|
9
|
+
}>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import parseDuration from "parse-duration";
|
|
2
|
+
import { clearCache } from "./cache.js";
|
|
3
|
+
export async function runMemoryCacheStatus() {
|
|
4
|
+
console.log("cache status not implemented yet");
|
|
5
|
+
}
|
|
6
|
+
export async function runMemoryCacheClear(input) {
|
|
7
|
+
if (!input.yes) {
|
|
8
|
+
throw new Error("Refusing to clear cache without --yes.");
|
|
9
|
+
}
|
|
10
|
+
const olderThanMs = parseOlderThan(input.olderThan);
|
|
11
|
+
const result = await clearCache(input.root, olderThanMs === undefined ? {} : { olderThanMs });
|
|
12
|
+
console.log(`removed ${result.removed} cache ${result.removed === 1 ? "entry" : "entries"}`);
|
|
13
|
+
return result;
|
|
14
|
+
}
|
|
15
|
+
function parseOlderThan(value) {
|
|
16
|
+
if (value === undefined) {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
const duration = parseDuration(value);
|
|
20
|
+
if (duration === null || Number.isNaN(duration) || duration < 0) {
|
|
21
|
+
throw new Error(`Invalid duration for --older-than: "${value}".`);
|
|
22
|
+
}
|
|
23
|
+
return duration;
|
|
24
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { IngestCacheEntry, IngestCacheKey, MemoryRoot } from "./types.js";
|
|
2
|
+
export declare function computeIngestKey(input: {
|
|
3
|
+
sourceBytes: Buffer;
|
|
4
|
+
indexMdBytes: Buffer;
|
|
5
|
+
promptTemplateVersion: string;
|
|
6
|
+
agentId: string;
|
|
7
|
+
}): IngestCacheKey;
|
|
8
|
+
export declare function readCacheEntry(root: MemoryRoot, key: IngestCacheKey): Promise<IngestCacheEntry | null>;
|
|
9
|
+
export declare function writeCacheEntry(root: MemoryRoot, entry: IngestCacheEntry): Promise<void>;
|
|
10
|
+
export declare function clearCache(root: MemoryRoot, opts?: {
|
|
11
|
+
olderThanMs?: number;
|
|
12
|
+
}): Promise<{
|
|
13
|
+
removed: number;
|
|
14
|
+
}>;
|