akm-cli 0.9.1 → 0.9.2-alpha.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/CHANGELOG.md +103 -28
- package/README.md +3 -1
- package/SECURITY.md +1 -1
- package/STABILITY.md +1 -1
- package/dist/akm +2 -2
- package/dist/akm-migrate +2 -2
- package/dist/assets/hints/cli-hints-full.md +14 -9
- package/dist/assets/improve-strategies/proactive-maintenance.json +1 -1
- package/dist/assets/improve-strategies/reflect-distill.json +1 -1
- package/dist/assets/models.json +35 -0
- package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +3 -4
- package/dist/assets/stash-skeleton/facts/conventions/organization.md +1 -3
- package/dist/assets/tasks/core/extract.yml +6 -5
- package/dist/assets/tasks/core/improve.yml +6 -5
- package/dist/assets/tasks/core/index-refresh.yml +6 -5
- package/dist/assets/tasks/core/sync.yml +6 -5
- package/dist/assets/tasks/core/version-check.yml +6 -5
- package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-catchup.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-consolidate.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-frequent.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-nightly.yml +6 -5
- package/dist/cli/confirm.js +2 -2
- package/dist/cli/parse-args.js +3 -24
- package/dist/cli/retired-commands.js +1 -1
- package/dist/cli/shared.js +2 -2
- package/dist/cli.js +11 -9
- package/dist/commands/agent/agent-dispatch.js +55 -89
- package/dist/commands/agent/contribute-cli.js +12 -45
- package/dist/commands/command/builtin-action.js +32 -0
- package/dist/commands/command/command-cli.js +99 -0
- package/dist/commands/command/command-execution.js +308 -0
- package/dist/commands/command/execution-source-loader.js +176 -0
- package/dist/commands/command/portable-template.js +60 -0
- package/dist/commands/config-cli.js +10 -4
- package/dist/commands/env/env.js +4 -2
- package/dist/commands/feedback-cli.js +1 -1
- package/dist/commands/health/checks.js +241 -29
- package/dist/commands/health/html-report.js +0 -14
- package/dist/commands/health/report-view-model.js +0 -1
- package/dist/commands/health/surfaces.js +6 -7
- package/dist/commands/health/types.js +0 -2
- package/dist/commands/health.js +63 -18
- package/dist/commands/improve/collapse-detector.js +5 -6
- package/dist/commands/improve/consolidate.js +251 -214
- package/dist/commands/improve/distill/promote-memory.js +71 -34
- package/dist/commands/improve/distill/quality-gate.js +17 -5
- package/dist/commands/improve/distill.js +232 -155
- package/dist/commands/improve/eligibility.js +112 -79
- package/dist/commands/improve/execution.js +57 -0
- package/dist/commands/improve/extract-cli.js +5 -5
- package/dist/commands/improve/extract-prompt.js +64 -22
- package/dist/commands/improve/extract.js +608 -360
- package/dist/commands/improve/improve-strategies.js +43 -14
- package/dist/commands/improve/improve.js +249 -29
- package/dist/commands/improve/loop-stages.js +11 -17
- package/dist/commands/improve/memory/memory-contradiction-detect.js +90 -66
- package/dist/commands/improve/outcome-loop.js +22 -38
- package/dist/commands/improve/planner.js +134 -0
- package/dist/commands/improve/preparation.js +730 -409
- package/dist/commands/improve/reflect.js +386 -223
- package/dist/commands/improve/run-context.js +3 -4
- package/dist/commands/improve/salience.js +6 -58
- package/dist/commands/improve/session-asset.js +12 -12
- package/dist/commands/lint/index.js +101 -29
- package/dist/commands/migrate-cli.js +11 -69
- package/dist/commands/migration-tool.js +6 -9
- package/dist/commands/models-cli.js +27 -0
- package/dist/commands/proposal/drain.js +258 -186
- package/dist/commands/proposal/proposal-cli.js +32 -10
- package/dist/commands/proposal/proposal.js +2 -5
- package/dist/commands/proposal/propose.js +192 -172
- package/dist/commands/proposal/repository.js +54 -91
- package/dist/commands/proposal/validators/proposal-validators.js +9 -7
- package/dist/commands/read/curate.js +53 -22
- package/dist/commands/read/registry-search.js +25 -9
- package/dist/commands/read/remember-cli.js +14 -2
- package/dist/commands/read/search.js +10 -4
- package/dist/commands/read/show.js +139 -153
- package/dist/commands/registry-cli.js +16 -7
- package/dist/commands/remember.js +33 -18
- package/dist/commands/sources/add-cli.js +19 -178
- package/dist/commands/sources/bundle-cli.js +15 -3
- package/dist/commands/sources/dangerous-env-audit.js +135 -0
- package/dist/commands/sources/info.js +2 -1
- package/dist/commands/sources/installed-stashes.js +901 -177
- package/dist/commands/sources/schema-repair.js +174 -95
- package/dist/commands/sources/self-update.js +30 -74
- package/dist/commands/sources/source-add.js +3 -5
- package/dist/commands/sources/sources-cli.js +2 -15
- package/dist/commands/sources/update-transaction.js +220 -0
- package/dist/commands/tasks/tasks-cli.js +3 -3
- package/dist/commands/tasks/tasks.js +736 -317
- package/dist/commands/workflow-cli.js +2 -2
- package/dist/core/adapter/adapters/agent-skills-adapter.js +3 -0
- package/dist/core/adapter/adapters/akm-adapter.js +85 -35
- package/dist/core/adapter/adapters/akm-lint.js +54 -39
- package/dist/core/adapter/adapters/akm-metadata.js +45 -45
- package/dist/core/adapter/adapters/akm-task-adapter.js +32 -49
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +38 -23
- package/dist/core/adapter/adapters/dotenv-adapter.js +30 -1
- package/dist/core/adapter/adapters/generic-files-adapter.js +11 -0
- package/dist/core/adapter/adapters/index.js +0 -9
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +4 -0
- package/dist/core/adapter/adapters/okf-adapter.js +4 -0
- package/dist/core/adapter/adapters/opencode-adapter.js +5 -8
- package/dist/core/adapter/adapters/tool-dir-shared.js +63 -6
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +4 -0
- package/dist/core/adapter/execution-source.js +308 -0
- package/dist/core/adapter/recognize-match.js +36 -13
- package/dist/core/adapter/registry.js +0 -9
- package/dist/core/asset/stash-meta.js +94 -4
- package/dist/core/common.js +6 -11
- package/dist/core/config/config-io.js +3 -3
- package/dist/core/config/config-schema.js +18 -40
- package/dist/core/config/config-sources.js +11 -21
- package/dist/core/config/config-walker.js +31 -13
- package/dist/core/config/config.js +23 -26
- package/dist/core/config/schema/engines.js +8 -7
- package/dist/core/config/schema/improve-processes.js +29 -5
- package/dist/core/config/schema/index-config.js +0 -27
- package/dist/core/config/schema/primitives.js +1 -23
- package/dist/core/config/schema/sources-bundles.js +13 -16
- package/dist/core/errors.js +2 -0
- package/dist/core/events.js +68 -32
- package/dist/core/extra-params.js +1 -0
- package/dist/core/improve-result.js +315 -0
- package/dist/core/lesson-lint.js +0 -6
- package/dist/core/maintenance-barrier.js +4 -4
- package/dist/core/network-policy.js +152 -0
- package/dist/core/paths.js +1 -1
- package/dist/core/recognition-util.js +4 -4
- package/dist/core/registry-url.js +456 -0
- package/dist/core/state/migrations.js +161 -47
- package/dist/core/state-db.js +453 -80
- package/dist/core/system-error.js +32 -0
- package/dist/core/time.js +2 -12
- package/dist/core/write-source.js +0 -18
- package/dist/execution/directory-identity.js +52 -0
- package/dist/execution/executable-identity.js +107 -0
- package/dist/execution/guarded-source.js +398 -0
- package/dist/execution/json.js +95 -0
- package/dist/{commands/health/types-session-log.js → execution/limits.js} +2 -1
- package/dist/execution/record.js +55 -0
- package/dist/execution/resolved-request.js +730 -0
- package/dist/execution/source.js +320 -0
- package/dist/indexer/bundle-identity-guard.js +5 -4
- package/dist/indexer/db/graph-db.js +33 -0
- package/dist/indexer/graph/graph-boost.js +3 -4
- package/dist/indexer/graph/graph-extraction.js +562 -373
- package/dist/indexer/index-written-assets.js +78 -39
- package/dist/indexer/indexer.js +471 -432
- package/dist/indexer/installations.js +6 -0
- package/dist/indexer/lookup/adapter-concept-owner.js +283 -0
- package/dist/indexer/materialize-embeddings.js +155 -0
- package/dist/indexer/passes/memory-inference.js +227 -174
- package/dist/indexer/passes/metadata.js +263 -118
- package/dist/indexer/scan/doc-to-entry.js +7 -10
- package/dist/indexer/scan/drain-dir.js +51 -23
- package/dist/indexer/search/db-search.js +156 -50
- package/dist/indexer/search/fts-query.js +40 -40
- package/dist/indexer/search/ranking.js +36 -1
- package/dist/indexer/search/search-attribution.js +3 -1
- package/dist/indexer/search/search-fields.js +23 -14
- package/dist/indexer/search/search-hit-enrichers.js +1 -1
- package/dist/indexer/search/search-source.js +7 -16
- package/dist/indexer/search/semantic-status.js +10 -1
- package/dist/indexer/usage/show-usage.js +105 -0
- package/dist/indexer/usage/usage-events.js +7 -2
- package/dist/indexer/walk/matchers.js +40 -10
- package/dist/indexer/walk/path-resolver.js +5 -2
- package/dist/indexer/walk/walker.js +20 -2
- package/dist/integrations/agent/builder-shared.js +3 -6
- package/dist/integrations/agent/conversation-fallback.js +16 -0
- package/dist/integrations/agent/engine-resolution.js +87 -87
- package/dist/integrations/agent/execution-cascade.js +566 -0
- package/dist/integrations/agent/execution-definitions.js +211 -0
- package/dist/integrations/agent/execution-lowering.js +811 -0
- package/dist/integrations/agent/execution-preparation.js +67 -0
- package/dist/integrations/agent/index.js +0 -2
- package/dist/integrations/agent/inline-execution.js +74 -0
- package/dist/integrations/agent/model-map.js +515 -0
- package/dist/integrations/agent/persona-fallback.js +30 -0
- package/dist/integrations/agent/request-lowering.js +186 -0
- package/dist/integrations/agent/runner-dispatch.js +230 -37
- package/dist/integrations/agent/runner.js +12 -83
- package/dist/integrations/harnesses/aider/agent-builder.js +8 -0
- package/dist/integrations/harnesses/aider/index.js +0 -1
- package/dist/integrations/harnesses/amazonq/agent-builder.js +8 -0
- package/dist/integrations/harnesses/amazonq/index.js +0 -1
- package/dist/integrations/harnesses/claude/agent-builder.js +14 -1
- package/dist/integrations/harnesses/claude/index.js +1 -5
- package/dist/integrations/harnesses/claude/session-log.js +3 -33
- package/dist/integrations/harnesses/codex/agent-builder.js +8 -0
- package/dist/integrations/harnesses/codex/index.js +0 -1
- package/dist/integrations/harnesses/copilot/agent-builder.js +8 -0
- package/dist/integrations/harnesses/copilot/index.js +0 -1
- package/dist/integrations/harnesses/gemini/agent-builder.js +8 -0
- package/dist/integrations/harnesses/gemini/index.js +0 -1
- package/dist/integrations/harnesses/index.js +4 -44
- package/dist/integrations/harnesses/opencode/agent-builder.js +16 -9
- package/dist/integrations/harnesses/opencode/index.js +0 -2
- package/dist/integrations/harnesses/opencode/session-log.js +14 -204
- package/dist/integrations/harnesses/opencode-sdk/harness.js +12 -1
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +40 -42
- package/dist/integrations/harnesses/openhands/agent-builder.js +8 -0
- package/dist/integrations/harnesses/openhands/index.js +0 -1
- package/dist/integrations/harnesses/pi/agent-builder.js +8 -0
- package/dist/integrations/harnesses/pi/index.js +0 -1
- package/dist/integrations/harnesses/shared.js +0 -1
- package/dist/integrations/harnesses/types.js +1 -3
- package/dist/integrations/lockfile.js +82 -79
- package/dist/integrations/session-logs/index.js +6 -17
- package/dist/integrations/session-logs/provider-base.js +1 -29
- package/dist/llm/client.js +10 -5
- package/dist/llm/embedder.js +6 -7
- package/dist/llm/embedders/local.js +37 -88
- package/dist/llm/embedders/types.js +1 -1
- package/dist/llm/graph-extract.js +75 -50
- package/dist/llm/index-passes.js +43 -5
- package/dist/llm/memory-infer.js +8 -6
- package/dist/llm/metadata-enhance.js +5 -3
- package/dist/llm/structured-call.js +122 -25
- package/dist/output/format-exempt.js +1 -1
- package/dist/output/render-registry.js +0 -16
- package/dist/output/renderers.js +12 -7
- package/dist/output/shapes/curate.js +1 -0
- package/dist/output/shapes/helpers.js +10 -2
- package/dist/output/shapes/passthrough.js +2 -0
- package/dist/output/text/command-format.js +31 -33
- package/dist/output/text/health-format.js +1 -29
- package/dist/output/text/migrate.js +6 -56
- package/dist/output/text/proposal-format.js +16 -1
- package/dist/output/text/workflow-format.js +16 -0
- package/dist/registry/network.js +279 -0
- package/dist/registry/pinned-request-helper.js +247 -0
- package/dist/registry/pinned-transport.js +717 -0
- package/dist/registry/providers/skills-sh.js +18 -6
- package/dist/registry/providers/static-index.js +20 -7
- package/dist/registry/resolve.js +53 -28
- package/dist/scripts/akm-migrate-node.js +19334 -52269
- package/dist/scripts/akm-migrate.js +19270 -51612
- package/dist/setup/registry-stash-loader.js +64 -20
- package/dist/setup/semantic-assets.js +9 -34
- package/dist/setup/setup.js +12 -30
- package/dist/setup/source-identity.js +17 -0
- package/dist/setup/steps/sources.js +36 -15
- package/dist/setup/steps/tasks.js +39 -11
- package/dist/sources/providers/git-provider.js +3 -3
- package/dist/sources/providers/npm.js +2 -2
- package/dist/sources/providers/provider-utils.js +4 -3
- package/dist/sources/providers/website.js +11 -7
- package/dist/sources/snapshot-fetchers/host-guard.js +9 -136
- package/dist/sources/snapshot-fetchers/website-ingest.js +25 -109
- package/dist/sources/website-url.js +73 -0
- package/dist/storage/engines/sqlite-migrations.js +81 -26
- package/dist/storage/managed-db.js +27 -24
- package/dist/storage/repositories/events-repository.js +3 -0
- package/dist/storage/repositories/index-connection.js +42 -10
- package/dist/storage/repositories/index-entries-repository.js +203 -229
- package/dist/storage/repositories/index-entry-mapper.js +8 -12
- package/dist/storage/repositories/index-entry-schema.js +255 -0
- package/dist/storage/repositories/index-fts-repository.js +64 -71
- package/dist/storage/repositories/index-llm-cache-repository.js +8 -13
- package/dist/storage/repositories/index-meta-repository.js +0 -11
- package/dist/storage/repositories/index-schema.js +74 -350
- package/dist/storage/repositories/index-utility-repository.js +12 -17
- package/dist/storage/repositories/index-vec-repository.js +56 -7
- package/dist/storage/repositories/proposals-repository.js +4 -127
- package/dist/storage/repositories/registry-cache.js +2 -1
- package/dist/storage/repositories/task-history-repository.js +20 -40
- package/dist/storage/repositories/workflow-runs-repository.js +228 -129
- package/dist/storage/sqlite-read-snapshot.js +148 -0
- package/dist/tasks/backends/cron.js +170 -42
- package/dist/tasks/backends/index.js +1 -1
- package/dist/tasks/backends/launchd.js +787 -202
- package/dist/tasks/backends/schtasks.js +282 -83
- package/dist/tasks/embedded.js +7 -7
- package/dist/tasks/frozen-script.js +50 -0
- package/dist/tasks/resolve-akm-bin.js +5 -1
- package/dist/tasks/runner.js +239 -251
- package/dist/tasks/runtime-v3.js +281 -0
- package/dist/tasks/scheduler-binding.js +272 -0
- package/dist/tasks/scheduler-invocation.js +57 -43
- package/dist/tasks/scheduler-sync.js +654 -0
- package/dist/tasks/source-v3.js +752 -0
- package/dist/tasks/standalone-script-entry.js +5 -0
- package/dist/tasks/task-id.js +29 -0
- package/dist/workflows/authoring/authoring.js +15 -32
- package/dist/workflows/exec/dispatch-redaction.js +14 -8
- package/dist/workflows/exec/exec-unit.js +7 -28
- package/dist/workflows/exec/frozen-judge.js +57 -89
- package/dist/workflows/exec/lowering-notices.js +23 -0
- package/dist/workflows/exec/native-executor.js +301 -458
- package/dist/workflows/exec/param-secrets.js +4 -3
- package/dist/workflows/exec/run-workflow.js +26 -32
- package/dist/workflows/exec/step-work.js +105 -109
- package/dist/workflows/exec/unit-dispatch.js +103 -27
- package/dist/workflows/exec/unit-writer.js +3 -3
- package/dist/workflows/exec/worktree.js +2 -2
- package/dist/workflows/ir/compile.js +86 -72
- package/dist/workflows/ir/environment-v4.js +328 -0
- package/dist/workflows/ir/freeze-v4.js +122 -0
- package/dist/workflows/ir/plan-hash.js +13 -7
- package/dist/workflows/ir/schema-v4.js +525 -0
- package/dist/workflows/ir/schema.js +25 -284
- package/dist/workflows/ir/source-freeze-v4.js +506 -0
- package/dist/workflows/parser.js +27 -24
- package/dist/workflows/program/schema.js +1 -2
- package/dist/workflows/renderer.js +42 -29
- package/dist/workflows/resource-limits.js +4 -5
- package/dist/workflows/runtime/agent-identity.js +11 -13
- package/dist/workflows/runtime/plan-classifier.js +8 -8
- package/dist/workflows/runtime/runs.js +27 -43
- package/dist/workflows/runtime/workflow-asset-loader.js +45 -205
- package/dist/workflows/source-files.js +373 -0
- package/dist/workflows/source-ir/compile.js +196 -0
- package/dist/workflows/source-ir/github-yaml.js +577 -0
- package/dist/workflows/source-ir/ordering.js +38 -0
- package/dist/workflows/source-ir/program.js +50 -0
- package/dist/workflows/source-ir/result.js +26 -0
- package/dist/workflows/source-ir/schema.js +772 -0
- package/dist/workflows/source-ir/semantics.js +242 -0
- package/dist/workflows/source-ir/uses.js +14 -0
- package/docs/README.md +2 -0
- package/docs/migration/README.md +3 -1
- package/docs/migration/release-notes/0.9.2.md +55 -0
- package/docs/migration/release-notes/README.md +5 -0
- package/docs/migration/v0.8-to-v0.9.md +76 -1077
- package/docs/migration/v0.9.0-troubleshooting.md +104 -516
- package/docs/migration/v0.9.1-to-v0.9.2.md +150 -0
- package/docs/reference/README.md +1 -0
- package/docs/reference/cli.md +230 -98
- package/docs/reference/configuration.md +159 -36
- package/docs/reference/data-and-telemetry.md +19 -1
- package/docs/reference/supported-formats.md +23 -3
- package/docs/reference/tasks.md +182 -0
- package/docs/reference/workflow-schema.md +91 -40
- package/docs/reference/workflows.md +33 -6
- package/package.json +10 -6
- package/schemas/akm-config.json +372 -224
- package/schemas/akm-task.json +324 -80
- package/schemas/akm-workflow.json +6 -9
- package/dist/core/migration-operation.js +0 -75
- package/dist/integrations/agent/model-aliases.js +0 -74
- package/dist/tasks/parser.js +0 -380
- package/dist/tasks/schema.js +0 -123
- package/dist/tasks/validator.js +0 -80
- package/dist/workflows/ir/freeze.js +0 -320
- package/dist/workflows/runtime/document-cache.js +0 -13
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
import { bundleRefToString, isBundleSlug, parseBundleRef } from "../core/asset/asset-ref.js";
|
|
5
|
+
import { cloneExecutionJson, cloneExecutionJsonObject, } from "./json.js";
|
|
6
|
+
import { assertSnapshotKeys, snapshotStrictRecord } from "./record.js";
|
|
7
|
+
export const EXECUTION_SOURCE_SCHEMA_VERSION = 1;
|
|
8
|
+
/** Current internal adapter identifiers are lowercase kebab-case registry keys. */
|
|
9
|
+
export const EXECUTION_ADAPTER_ID_PATTERN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
10
|
+
const CONTROL_OR_LINE_SEPARATOR_PATTERN = /[\p{Cc}\p{Zl}\p{Zp}]/u;
|
|
11
|
+
const FORMAT_CHARACTER_PATTERN = /\p{Cf}/u;
|
|
12
|
+
const WINDOWS_DRIVE_PREFIX_PATTERN = /^[A-Za-z]:/;
|
|
13
|
+
const RESERVED_EXTENSION_OWNERS = new Set(["__proto__", "constructor", "prototype", "tostring"]);
|
|
14
|
+
const renderedSourceBrand = Symbol("akm.adapter-rendered-execution-source");
|
|
15
|
+
const renderedSourceInstances = new WeakSet();
|
|
16
|
+
function requireRecord(value, path) {
|
|
17
|
+
return snapshotStrictRecord(value, path);
|
|
18
|
+
}
|
|
19
|
+
function assertOnlyKeys(value, allowed, path) {
|
|
20
|
+
assertSnapshotKeys(value, allowed, path);
|
|
21
|
+
}
|
|
22
|
+
function validateExtensionOwner(owner) {
|
|
23
|
+
const normalized = owner.toLowerCase();
|
|
24
|
+
if (!EXECUTION_ADAPTER_ID_PATTERN.test(owner) || RESERVED_EXTENSION_OWNERS.has(normalized)) {
|
|
25
|
+
throw new TypeError(`extension owner must be a canonical, non-reserved adapter identifier: ${owner}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function frozenNullPrototypeMap(entries) {
|
|
29
|
+
const out = Object.create(null);
|
|
30
|
+
for (const [key, value] of entries) {
|
|
31
|
+
Object.defineProperty(out, key, { value, enumerable: true, configurable: false, writable: false });
|
|
32
|
+
}
|
|
33
|
+
return Object.freeze(out);
|
|
34
|
+
}
|
|
35
|
+
function cloneExtensionEntry(value, index) {
|
|
36
|
+
const path = `extension entry ${index}`;
|
|
37
|
+
const cloned = cloneExecutionJson(value, path);
|
|
38
|
+
if (!Array.isArray(cloned) || cloned.length !== 2) {
|
|
39
|
+
throw new TypeError(`${path} must be a two-element [owner, values] array`);
|
|
40
|
+
}
|
|
41
|
+
const [owner, values] = cloned;
|
|
42
|
+
if (typeof owner !== "string")
|
|
43
|
+
throw new TypeError(`${path} owner must be a string`);
|
|
44
|
+
if (values === null || Array.isArray(values) || typeof values !== "object") {
|
|
45
|
+
throw new TypeError(`${path} values must be a JSON object`);
|
|
46
|
+
}
|
|
47
|
+
return [owner, values];
|
|
48
|
+
}
|
|
49
|
+
export function createAdapterExtensions(first, second, ...rest) {
|
|
50
|
+
const rawEntries = typeof first === "string"
|
|
51
|
+
? [[first, second]]
|
|
52
|
+
: [first, ...(second === undefined ? [] : [second]), ...rest];
|
|
53
|
+
const seen = new Set();
|
|
54
|
+
const cloned = [];
|
|
55
|
+
for (const [index, rawEntry] of rawEntries.entries()) {
|
|
56
|
+
const [owner, values] = cloneExtensionEntry(rawEntry, index);
|
|
57
|
+
validateExtensionOwner(owner);
|
|
58
|
+
if (seen.has(owner))
|
|
59
|
+
throw new TypeError(`duplicate extension owner: ${owner}`);
|
|
60
|
+
seen.add(owner);
|
|
61
|
+
cloned.push([owner, cloneExecutionJsonObject(values, `extensions.${owner}`)]);
|
|
62
|
+
}
|
|
63
|
+
return frozenNullPrototypeMap(cloned);
|
|
64
|
+
}
|
|
65
|
+
export function cloneAdapterExtensions(value, path) {
|
|
66
|
+
const record = requireRecord(value, path);
|
|
67
|
+
const entries = Object.entries(record).map(([owner, fields]) => [owner, cloneExecutionJsonObject(fields, `${path}.${owner}`)]);
|
|
68
|
+
const [first, ...rest] = entries;
|
|
69
|
+
return first ? createAdapterExtensions(first, ...rest) : frozenNullPrototypeMap([]);
|
|
70
|
+
}
|
|
71
|
+
function requireCanonicalString(value, path) {
|
|
72
|
+
if (typeof value !== "string" ||
|
|
73
|
+
value.length === 0 ||
|
|
74
|
+
!isWellFormedUnicode(value) ||
|
|
75
|
+
value.normalize("NFC") !== value) {
|
|
76
|
+
throw new TypeError(`${path} must be a non-empty NFC string`);
|
|
77
|
+
}
|
|
78
|
+
if (hasUnsafeIdentityCharacter(value)) {
|
|
79
|
+
throw new TypeError(`${path} must not contain Unicode control or dangerous format characters`);
|
|
80
|
+
}
|
|
81
|
+
return value;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Validate a selector/layer identifier that may cross the durable execution
|
|
85
|
+
* boundary. Keep this shared with the cascade planner so resume cannot admit a
|
|
86
|
+
* selector the live planner would reject.
|
|
87
|
+
*/
|
|
88
|
+
export function requireStableExecutionSelector(value, path) {
|
|
89
|
+
let selector;
|
|
90
|
+
try {
|
|
91
|
+
selector = requireCanonicalString(value, path);
|
|
92
|
+
}
|
|
93
|
+
catch (cause) {
|
|
94
|
+
throw new TypeError(`${path} must be a non-empty stable NFC identifier`, { cause });
|
|
95
|
+
}
|
|
96
|
+
if (selector.length > 512 || selector.trim() !== selector) {
|
|
97
|
+
throw new TypeError(`${path} must be a non-empty stable NFC identifier`);
|
|
98
|
+
}
|
|
99
|
+
return selector;
|
|
100
|
+
}
|
|
101
|
+
export function isPortableExecutionAgentSelector(value) {
|
|
102
|
+
return /^(?:[^/]+\/\/)?agents\/[^/]/.test(value);
|
|
103
|
+
}
|
|
104
|
+
export function executionPersonaMatchesSelector(selector, personaRef) {
|
|
105
|
+
return selector.includes("//") ? selector === personaRef : personaRef.endsWith(`//${selector}`);
|
|
106
|
+
}
|
|
107
|
+
function hasUnsafeIdentityCharacter(value) {
|
|
108
|
+
for (const character of value) {
|
|
109
|
+
if (CONTROL_OR_LINE_SEPARATOR_PATTERN.test(character))
|
|
110
|
+
return true;
|
|
111
|
+
// Join controls are meaningful in emoji and several writing systems. All
|
|
112
|
+
// other format controls are rejected because they can conceal identity.
|
|
113
|
+
if (FORMAT_CHARACTER_PATTERN.test(character) && character !== "\u200C" && character !== "\u200D")
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
function isWellFormedUnicode(value) {
|
|
119
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
120
|
+
const code = value.charCodeAt(index);
|
|
121
|
+
if (code >= 0xd800 && code <= 0xdbff) {
|
|
122
|
+
const next = value.charCodeAt(index + 1);
|
|
123
|
+
if (!(next >= 0xdc00 && next <= 0xdfff))
|
|
124
|
+
return false;
|
|
125
|
+
index += 1;
|
|
126
|
+
}
|
|
127
|
+
else if (code >= 0xdc00 && code <= 0xdfff) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
function validateCanonicalIdentity(input, path) {
|
|
134
|
+
assertOnlyKeys(input, ["ref", "bundle", "adapter", "file", "hash"], path);
|
|
135
|
+
const ref = requireCanonicalString(input.ref, `${path}.ref`);
|
|
136
|
+
const bundle = requireCanonicalString(input.bundle, `${path}.bundle`);
|
|
137
|
+
const adapter = requireCanonicalString(input.adapter, `${path}.adapter`);
|
|
138
|
+
const file = requireCanonicalString(input.file, `${path}.file`);
|
|
139
|
+
const hash = requireCanonicalString(input.hash, `${path}.hash`);
|
|
140
|
+
let parsed;
|
|
141
|
+
try {
|
|
142
|
+
parsed = parseBundleRef(ref);
|
|
143
|
+
}
|
|
144
|
+
catch (cause) {
|
|
145
|
+
throw new TypeError(`${path}.ref is not a canonical bundle ref`, { cause });
|
|
146
|
+
}
|
|
147
|
+
if (parsed.bundle === undefined ||
|
|
148
|
+
parsed.bundle !== bundle ||
|
|
149
|
+
parsed.fragment !== undefined ||
|
|
150
|
+
!isBundleSlug(bundle) ||
|
|
151
|
+
bundleRefToString(parsed) !== ref) {
|
|
152
|
+
throw new TypeError(`${path}.ref must round-trip as the same fully-qualified bundle ref without a fragment`);
|
|
153
|
+
}
|
|
154
|
+
if (!EXECUTION_ADAPTER_ID_PATTERN.test(adapter)) {
|
|
155
|
+
throw new TypeError(`${path}.adapter must use the current lowercase kebab-case adapter identifier grammar`);
|
|
156
|
+
}
|
|
157
|
+
const segments = file.split("/");
|
|
158
|
+
if (file.startsWith("/") ||
|
|
159
|
+
WINDOWS_DRIVE_PREFIX_PATTERN.test(file) ||
|
|
160
|
+
file.includes("\\") ||
|
|
161
|
+
segments.some((segment) => !segment || segment === "." || segment === "..")) {
|
|
162
|
+
throw new TypeError(`${path}.file must be a normalized relative POSIX path`);
|
|
163
|
+
}
|
|
164
|
+
if (!/^[a-f0-9]{64}$/.test(hash))
|
|
165
|
+
throw new TypeError(`${path}.hash must be a SHA-256 hex digest`);
|
|
166
|
+
return { ref, bundle, adapter, file, hash };
|
|
167
|
+
}
|
|
168
|
+
/** Validate, clone, and freeze an identity produced by an adapter renderer. */
|
|
169
|
+
export function createExecutionSourceIdentity(input) {
|
|
170
|
+
return Object.freeze(validateCanonicalIdentity(requireRecord(input, "execution source identity"), "execution source identity"));
|
|
171
|
+
}
|
|
172
|
+
/** Validate and freeze a source identity read back from a frozen request. */
|
|
173
|
+
export function decodeExecutionSourceIdentity(value, path = "execution source identity") {
|
|
174
|
+
return Object.freeze(validateCanonicalIdentity(requireRecord(value, path), path));
|
|
175
|
+
}
|
|
176
|
+
export function cloneUnresolvedExecutionDefaults(input, path = "execution source defaults") {
|
|
177
|
+
const record = requireRecord(input, path);
|
|
178
|
+
assertOnlyKeys(record, [
|
|
179
|
+
"agent",
|
|
180
|
+
"engine",
|
|
181
|
+
"model",
|
|
182
|
+
"inference",
|
|
183
|
+
"outputSchema",
|
|
184
|
+
"tools",
|
|
185
|
+
"timeout",
|
|
186
|
+
"workspace",
|
|
187
|
+
"environment",
|
|
188
|
+
"runtime",
|
|
189
|
+
], path);
|
|
190
|
+
const json = { ...cloneExecutionJsonObject(record, path) };
|
|
191
|
+
for (const key of ["agent", "engine", "model", "workspace"]) {
|
|
192
|
+
const value = json[key];
|
|
193
|
+
if (value !== undefined && value !== null && typeof value !== "string") {
|
|
194
|
+
throw new TypeError(`${path}.${key} must be a string or null`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
const timeout = json.timeout;
|
|
198
|
+
if (timeout !== undefined && timeout !== null && typeof timeout !== "string" && typeof timeout !== "number") {
|
|
199
|
+
throw new TypeError(`${path}.timeout must be a string, number, or null`);
|
|
200
|
+
}
|
|
201
|
+
for (const key of ["inference", "outputSchema", "runtime"]) {
|
|
202
|
+
const value = json[key];
|
|
203
|
+
if (value !== undefined && value !== null && (Array.isArray(value) || typeof value !== "object")) {
|
|
204
|
+
throw new TypeError(`${path}.${key} must be an object or null`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
const environment = json.environment;
|
|
208
|
+
if (environment !== undefined && environment !== null) {
|
|
209
|
+
if (Array.isArray(environment) || typeof environment !== "object") {
|
|
210
|
+
throw new TypeError(`${path}.environment must be an object or null`);
|
|
211
|
+
}
|
|
212
|
+
if (Object.values(environment).some((value) => typeof value !== "string")) {
|
|
213
|
+
throw new TypeError(`${path}.environment values must be strings`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (Object.hasOwn(json, "tools"))
|
|
217
|
+
json.tools = cloneToolSelection(json.tools, `${path}.tools`);
|
|
218
|
+
return Object.freeze(json);
|
|
219
|
+
}
|
|
220
|
+
export function cloneToolSelection(value, path = "tools") {
|
|
221
|
+
if (value === null || typeof value === "string")
|
|
222
|
+
return value;
|
|
223
|
+
const cloned = cloneExecutionJson(value, path);
|
|
224
|
+
if (Array.isArray(cloned)) {
|
|
225
|
+
if (cloned.some((tool) => typeof tool !== "string"))
|
|
226
|
+
throw new TypeError(`${path} array values must be strings`);
|
|
227
|
+
return cloned;
|
|
228
|
+
}
|
|
229
|
+
return cloneExecutionJsonObject(cloned, path);
|
|
230
|
+
}
|
|
231
|
+
export function createAdapterRenderedExecutionSource(input) {
|
|
232
|
+
const record = requireRecord(input, "adapter-rendered execution source");
|
|
233
|
+
assertOnlyKeys(record, ["kind", "content", "identity", "defaults", "extensions"], "adapter-rendered execution source");
|
|
234
|
+
const kind = record.kind;
|
|
235
|
+
const content = record.content;
|
|
236
|
+
if (kind !== "command" && kind !== "persona")
|
|
237
|
+
throw new TypeError("execution source kind is invalid");
|
|
238
|
+
if (typeof content !== "string")
|
|
239
|
+
throw new TypeError("execution source content must be a string");
|
|
240
|
+
const defaults = Object.hasOwn(record, "defaults") ? record.defaults : {};
|
|
241
|
+
if (defaults === undefined) {
|
|
242
|
+
throw new TypeError("execution source defaults must be omitted or be an object");
|
|
243
|
+
}
|
|
244
|
+
const source = {
|
|
245
|
+
schemaVersion: EXECUTION_SOURCE_SCHEMA_VERSION,
|
|
246
|
+
kind,
|
|
247
|
+
content,
|
|
248
|
+
defaults: cloneUnresolvedExecutionDefaults(defaults),
|
|
249
|
+
identity: createExecutionSourceIdentity(record.identity),
|
|
250
|
+
};
|
|
251
|
+
if (Object.hasOwn(record, "extensions")) {
|
|
252
|
+
source.extensions = cloneAdapterExtensions(record.extensions, "execution source extensions");
|
|
253
|
+
}
|
|
254
|
+
Object.defineProperty(source, renderedSourceBrand, { value: true, enumerable: false });
|
|
255
|
+
const frozen = Object.freeze(source);
|
|
256
|
+
renderedSourceInstances.add(frozen);
|
|
257
|
+
return frozen;
|
|
258
|
+
}
|
|
259
|
+
function isAdapterRenderedSource(value, kind) {
|
|
260
|
+
if (typeof value !== "object" || value === null)
|
|
261
|
+
return false;
|
|
262
|
+
if (!renderedSourceInstances.has(value))
|
|
263
|
+
return false;
|
|
264
|
+
if (Object.getPrototypeOf(value) !== Object.prototype || !Object.isFrozen(value))
|
|
265
|
+
return false;
|
|
266
|
+
if (!Object.hasOwn(value, renderedSourceBrand))
|
|
267
|
+
return false;
|
|
268
|
+
const required = new Set(["schemaVersion", "kind", "content", "defaults", "identity"]);
|
|
269
|
+
const optional = new Set(["extensions"]);
|
|
270
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
271
|
+
if (key === renderedSourceBrand)
|
|
272
|
+
continue;
|
|
273
|
+
if (typeof key !== "string" || (!required.delete(key) && !optional.has(key)))
|
|
274
|
+
return false;
|
|
275
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
276
|
+
if (!descriptor || !("value" in descriptor) || !descriptor.enumerable)
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
if (required.size > 0)
|
|
280
|
+
return false;
|
|
281
|
+
const brand = Object.getOwnPropertyDescriptor(value, renderedSourceBrand);
|
|
282
|
+
const source = value;
|
|
283
|
+
if (brand?.value !== true ||
|
|
284
|
+
brand.enumerable !== false ||
|
|
285
|
+
brand.configurable !== false ||
|
|
286
|
+
brand.writable !== false ||
|
|
287
|
+
source.schemaVersion !== EXECUTION_SOURCE_SCHEMA_VERSION ||
|
|
288
|
+
source.kind !== kind ||
|
|
289
|
+
typeof source.content !== "string" ||
|
|
290
|
+
typeof source.defaults !== "object" ||
|
|
291
|
+
source.defaults === null ||
|
|
292
|
+
!Object.isFrozen(source.defaults) ||
|
|
293
|
+
typeof source.identity !== "object" ||
|
|
294
|
+
source.identity === null ||
|
|
295
|
+
Object.getPrototypeOf(source.identity) !== Object.prototype ||
|
|
296
|
+
!Object.isFrozen(source.identity)) {
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
if (Object.hasOwn(source, "extensions")) {
|
|
300
|
+
if (typeof source.extensions !== "object" ||
|
|
301
|
+
source.extensions === null ||
|
|
302
|
+
Object.getPrototypeOf(source.extensions) !== null ||
|
|
303
|
+
!Object.isFrozen(source.extensions)) {
|
|
304
|
+
return false;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
try {
|
|
308
|
+
decodeExecutionSourceIdentity(source.identity);
|
|
309
|
+
}
|
|
310
|
+
catch {
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
return true;
|
|
314
|
+
}
|
|
315
|
+
export function isAdapterRenderedCommandSource(value) {
|
|
316
|
+
return isAdapterRenderedSource(value, "command");
|
|
317
|
+
}
|
|
318
|
+
export function isAdapterRenderedPersonaSource(value) {
|
|
319
|
+
return isAdapterRenderedSource(value, "persona");
|
|
320
|
+
}
|
|
@@ -31,7 +31,7 @@ import fs from "node:fs";
|
|
|
31
31
|
import { loadConfig } from "../core/config/config.js";
|
|
32
32
|
import { getDbPath } from "../core/paths.js";
|
|
33
33
|
import { warn } from "../core/warn.js";
|
|
34
|
-
import {
|
|
34
|
+
import { closeDatabase, openReadonlyExistingDatabase } from "../storage/repositories/index-connection.js";
|
|
35
35
|
let guardSettled = false;
|
|
36
36
|
/** TEST-ONLY: re-arm the once-per-process guard between cases. */
|
|
37
37
|
export function resetBundleIdentityGuardForTests() {
|
|
@@ -43,8 +43,8 @@ function indexBundlePrefixes(dbPath) {
|
|
|
43
43
|
return undefined;
|
|
44
44
|
let db;
|
|
45
45
|
try {
|
|
46
|
-
db =
|
|
47
|
-
if (!db
|
|
46
|
+
db = openReadonlyExistingDatabase(dbPath);
|
|
47
|
+
if (!db)
|
|
48
48
|
return undefined;
|
|
49
49
|
return db
|
|
50
50
|
.prepare("SELECT DISTINCT bundle_id AS b FROM entries WHERE bundle_id IS NOT NULL AND bundle_id != ''")
|
|
@@ -54,7 +54,8 @@ function indexBundlePrefixes(dbPath) {
|
|
|
54
54
|
return undefined;
|
|
55
55
|
}
|
|
56
56
|
finally {
|
|
57
|
-
db
|
|
57
|
+
if (db)
|
|
58
|
+
closeDatabase(db);
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
61
|
/**
|
|
@@ -219,6 +219,39 @@ export function drainExtractionQueue(db, stashRoot, limit) {
|
|
|
219
219
|
return [];
|
|
220
220
|
}
|
|
221
221
|
}
|
|
222
|
+
/** Read queued graph work without claiming or deleting it. */
|
|
223
|
+
export function peekExtractionQueue(db, stashRoot, limit) {
|
|
224
|
+
try {
|
|
225
|
+
const rows = db
|
|
226
|
+
.prepare(`SELECT file_path, body_hash, priority
|
|
227
|
+
FROM graph_extraction_queue
|
|
228
|
+
WHERE stash_root = ?
|
|
229
|
+
ORDER BY priority DESC, queued_at ASC
|
|
230
|
+
LIMIT ?`)
|
|
231
|
+
.all(stashRoot, limit);
|
|
232
|
+
return rows.map((row) => ({ filePath: row.file_path, bodyHash: row.body_hash, priority: row.priority }));
|
|
233
|
+
}
|
|
234
|
+
catch (err) {
|
|
235
|
+
rethrowIfTestIsolationError(err);
|
|
236
|
+
return [];
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Acknowledge the exact queued revision that was classified and handled.
|
|
241
|
+
* A concurrent re-enqueue with a new body hash therefore survives.
|
|
242
|
+
*/
|
|
243
|
+
export function acknowledgeExtractionQueueEntry(db, stashRoot, filePath, bodyHash) {
|
|
244
|
+
try {
|
|
245
|
+
const result = db
|
|
246
|
+
.prepare("DELETE FROM graph_extraction_queue WHERE stash_root = ? AND file_path = ? AND body_hash = ?")
|
|
247
|
+
.run(stashRoot, filePath, bodyHash);
|
|
248
|
+
return result.changes > 0;
|
|
249
|
+
}
|
|
250
|
+
catch (err) {
|
|
251
|
+
rethrowIfTestIsolationError(err);
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
222
255
|
/**
|
|
223
256
|
* Scoped loader — graph_files rows without entities/relations. Used for
|
|
224
257
|
* orphan detection and entity overview commands.
|
|
@@ -250,7 +250,7 @@ export function collectGraphRelatedHit(context, filePath) {
|
|
|
250
250
|
* idx_graph_files_path guarantees one graph_files row per path).
|
|
251
251
|
*
|
|
252
252
|
* The returned `ref` field carries the canonical indexed `concept_id`, never a
|
|
253
|
-
* value re-derived from presentation fields
|
|
253
|
+
* value re-derived from presentation fields. It is undefined
|
|
254
254
|
* when the graph row has no matching entry with current indexed provenance.
|
|
255
255
|
*/
|
|
256
256
|
export function listRelatedPathsForFile(stashRoot, filePath, limit = 5, db) {
|
|
@@ -348,9 +348,8 @@ export function listRelatedPathsForFile(stashRoot, filePath, limit = 5, db) {
|
|
|
348
348
|
try {
|
|
349
349
|
const entryRows = db
|
|
350
350
|
.prepare(`SELECT file_path, concept_id FROM entries
|
|
351
|
-
WHERE file_path IN (${placeholders})
|
|
352
|
-
|
|
353
|
-
.all(...candidatePaths, stashRoot);
|
|
351
|
+
WHERE file_path IN (${placeholders})`)
|
|
352
|
+
.all(...candidatePaths);
|
|
354
353
|
for (const row of entryRows) {
|
|
355
354
|
refByPath.set(row.file_path, row.concept_id);
|
|
356
355
|
}
|