akm-cli 0.8.7 → 0.8.14
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 +428 -0
- package/dist/assets/help/help-proposals.md +1 -2
- package/dist/assets/hints/cli-hints-full.md +34 -19
- package/dist/assets/hints/cli-hints-short.md +1 -1
- package/dist/assets/profiles/catchup.json +13 -0
- package/dist/assets/profiles/consolidate.json +13 -0
- package/dist/assets/profiles/frequent.json +13 -0
- package/dist/assets/tasks/core/backup.yml +4 -0
- package/dist/assets/tasks/core/extract.yml +4 -0
- package/dist/assets/tasks/core/improve.yml +4 -0
- package/dist/assets/tasks/core/index-refresh.yml +4 -0
- package/dist/assets/tasks/core/sync.yml +4 -0
- package/dist/assets/tasks/core/update-stashes.yml +4 -0
- package/dist/assets/tasks/core/version-check.yml +4 -0
- package/dist/assets/templates/html/default.html +78 -0
- package/dist/assets/templates/html/health.html +560 -0
- package/dist/assets/templates/html/vendor/echarts.min.js +45 -0
- package/dist/cli/config-migrate.js +6 -6
- package/dist/cli/config-validate.js +4 -4
- package/dist/cli/confirm.js +3 -3
- package/dist/cli/parse-args.js +1 -1
- package/dist/cli/shared.js +72 -19
- package/dist/cli-node.mjs +26 -0
- package/dist/cli.js +206 -3866
- package/dist/commands/{agent-dispatch.js → agent/agent-dispatch.js} +6 -6
- package/dist/commands/{agent-support.js → agent/agent-support.js} +2 -2
- package/dist/commands/agent/contribute-cli.js +200 -0
- package/dist/commands/completions.js +1 -1
- package/dist/commands/config-cli.js +230 -3
- package/dist/commands/db-cli.js +2 -2
- package/dist/commands/env/env-cli.js +529 -0
- package/dist/commands/env/env.js +410 -0
- package/dist/commands/env/secret-cli.js +259 -0
- package/dist/commands/{secret.js → env/secret.js} +6 -47
- package/dist/commands/events.js +4 -4
- package/dist/commands/feedback-cli.js +18 -34
- package/dist/commands/graph/graph-cli.js +132 -0
- package/dist/commands/{graph.js → graph/graph.js} +22 -16
- package/dist/commands/health/checks.js +279 -0
- package/dist/commands/health/html-report.js +448 -0
- package/dist/commands/health.js +189 -266
- package/dist/commands/{consolidate.js → improve/consolidate.js} +48 -36
- package/dist/commands/{distill-promotion-policy.js → improve/distill-promotion-policy.js} +3 -3
- package/dist/commands/{distill.js → improve/distill.js} +39 -18
- package/dist/commands/{eval-cases.js → improve/eval-cases.js} +1 -1
- package/dist/commands/{extract-cli.js → improve/extract-cli.js} +4 -4
- package/dist/commands/{extract-prompt.js → improve/extract-prompt.js} +2 -2
- package/dist/commands/{extract.js → improve/extract.js} +221 -26
- package/dist/commands/{improve-auto-accept.js → improve/improve-auto-accept.js} +30 -4
- package/dist/commands/{improve-cli.js → improve/improve-cli.js} +44 -22
- package/dist/commands/{improve-profiles.js → improve/improve-profiles.js} +13 -7
- package/dist/commands/{improve-result-file.js → improve/improve-result-file.js} +1 -1
- package/dist/commands/{improve.js → improve/improve.js} +672 -292
- package/dist/{core → commands/improve/memory}/memory-belief.js +2 -2
- package/dist/{core → commands/improve/memory}/memory-contradiction-detect.js +5 -5
- package/dist/{core → commands/improve/memory}/memory-improve.js +4 -4
- package/dist/commands/improve/reflect-noise.js +0 -0
- package/dist/commands/{reflect.js → improve/reflect.js} +58 -28
- package/dist/commands/improve/session-asset.js +248 -0
- package/dist/commands/lint/agent-linter.js +1 -1
- package/dist/commands/lint/base-linter.js +55 -37
- package/dist/commands/lint/command-linter.js +1 -1
- package/dist/commands/lint/default-linter.js +1 -1
- package/dist/commands/lint/env-key-rules.js +1 -1
- package/dist/commands/lint/index.js +19 -25
- package/dist/commands/lint/knowledge-linter.js +1 -1
- package/dist/commands/lint/memory-linter.js +1 -1
- package/dist/commands/lint/registry.js +8 -8
- package/dist/commands/lint/skill-linter.js +1 -1
- package/dist/commands/lint/task-linter.js +1 -1
- package/dist/commands/lint/workflow-linter.js +1 -1
- package/dist/commands/lint.js +1 -1
- package/dist/commands/observability-cli.js +244 -0
- package/dist/commands/proposal/drain-policies.js +3 -3
- package/dist/commands/proposal/drain.js +87 -15
- package/dist/commands/proposal/proposal-cli.js +490 -0
- package/dist/commands/{proposal.js → proposal/proposal.js} +17 -6
- package/dist/commands/{propose.js → proposal/propose.js} +11 -11
- package/dist/{core → commands/proposal/validators}/proposal-quality-validators.js +8 -3
- package/dist/{core → commands/proposal/validators}/proposal-validators.js +5 -5
- package/dist/{core → commands/proposal/validators}/proposals.js +374 -345
- package/dist/commands/{curate.js → read/curate.js} +7 -7
- package/dist/commands/{knowledge.js → read/knowledge.js} +22 -9
- package/dist/commands/{registry-search.js → read/registry-search.js} +5 -5
- package/dist/commands/{remember-cli.js → read/remember-cli.js} +15 -7
- package/dist/commands/read/search-cli.js +207 -0
- package/dist/commands/{search.js → read/search.js} +22 -27
- package/dist/commands/{show.js → read/show.js} +31 -45
- package/dist/commands/registry-cli.js +8 -8
- package/dist/commands/remember.js +14 -10
- package/dist/commands/sources/add-cli.js +293 -0
- package/dist/commands/{history.js → sources/history.js} +27 -25
- package/dist/commands/{info.js → sources/info.js} +6 -6
- package/dist/commands/{init.js → sources/init.js} +6 -6
- package/dist/commands/{installed-stashes.js → sources/installed-stashes.js} +12 -12
- package/dist/commands/{migration-help.js → sources/migration-help.js} +3 -2
- package/dist/commands/{schema-repair.js → sources/schema-repair.js} +8 -8
- package/dist/commands/{self-update.js → sources/self-update.js} +10 -9
- package/dist/commands/{source-add.js → sources/source-add.js} +10 -10
- package/dist/commands/{source-clone.js → sources/source-clone.js} +7 -7
- package/dist/commands/{source-manage.js → sources/source-manage.js} +4 -4
- package/dist/commands/sources/sources-cli.js +305 -0
- package/dist/commands/sources/stash-cli.js +219 -0
- package/dist/commands/{stash-skeleton.js → sources/stash-skeleton.js} +2 -1
- package/dist/commands/tasks/default-tasks.js +173 -0
- package/dist/commands/tasks/tasks-cli.js +210 -0
- package/dist/commands/{tasks.js → tasks/tasks.js} +14 -14
- package/dist/commands/wiki-cli.js +307 -0
- package/dist/commands/workflow-cli.js +329 -0
- package/dist/core/action-contributors.js +1 -1
- package/dist/core/assert.js +40 -0
- package/dist/core/asset/asset-create.js +54 -0
- package/dist/core/{asset-ref.js → asset/asset-ref.js} +21 -4
- package/dist/core/{asset-registry.js → asset/asset-registry.js} +3 -3
- package/dist/core/{asset-spec.js → asset/asset-spec.js} +17 -31
- package/dist/core/{markdown.js → asset/markdown.js} +1 -1
- package/dist/core/{stash-meta.js → asset/stash-meta.js} +1 -1
- package/dist/core/best-effort.js +64 -0
- package/dist/core/common.js +32 -18
- package/dist/core/{config-io.js → config/config-io.js} +29 -19
- package/dist/core/{config-migration.js → config/config-migration.js} +11 -9
- package/dist/core/{config-schema.js → config/config-schema.js} +50 -7
- package/dist/core/config/config-types.js +16 -0
- package/dist/core/{config-walker.js → config/config-walker.js} +2 -2
- package/dist/core/{config.js → config/config.js} +10 -8
- package/dist/core/env-secret-ref.js +90 -0
- package/dist/core/errors.js +13 -3
- package/dist/core/events.js +27 -4
- package/dist/core/file-lock.js +1 -1
- package/dist/core/improve-types.js +48 -0
- package/dist/core/lesson-lint.js +2 -2
- package/dist/core/logs-db.js +304 -0
- package/dist/core/paths.js +2 -2
- package/dist/core/ripgrep/install.js +2 -2
- package/dist/core/ripgrep/resolve.js +2 -2
- package/dist/core/state-db.js +195 -60
- package/dist/core/text-truncation.js +148 -0
- package/dist/core/time.js +1 -1
- package/dist/core/write-source.js +98 -85
- package/dist/indexer/{db-backup.js → db/db-backup.js} +9 -24
- package/dist/indexer/{db.js → db/db.js} +128 -118
- package/dist/indexer/{graph-db.js → db/graph-db.js} +9 -4
- package/dist/indexer/{llm-cache.js → db/llm-cache.js} +15 -12
- package/dist/indexer/ensure-index.js +4 -4
- package/dist/indexer/{graph-boost.js → graph/graph-boost.js} +1 -1
- package/dist/indexer/{graph-extraction.js → graph/graph-extraction.js} +55 -13
- package/dist/indexer/indexer.js +37 -30
- package/dist/indexer/init.js +54 -0
- package/dist/indexer/manifest.js +10 -10
- package/dist/indexer/{memory-inference.js → passes/memory-inference.js} +141 -33
- package/dist/indexer/{metadata-contributors.js → passes/metadata-contributors.js} +10 -8
- package/dist/indexer/{metadata.js → passes/metadata.js} +15 -19
- package/dist/indexer/{staleness-detect.js → passes/staleness-detect.js} +53 -12
- package/dist/indexer/{db-search.js → search/db-search.js} +28 -16
- package/dist/indexer/{ranking-contributors.js → search/ranking-contributors.js} +1 -1
- package/dist/indexer/{ranking.js → search/ranking.js} +2 -2
- package/dist/indexer/{search-hit-enrichers.js → search/search-hit-enrichers.js} +3 -3
- package/dist/indexer/{search-source.js → search/search-source.js} +8 -8
- package/dist/indexer/{semantic-status.js → search/semantic-status.js} +3 -3
- package/dist/indexer/usage/unmigrated-vaults-guard.js +94 -0
- package/dist/indexer/{usage-events.js → usage/usage-events.js} +32 -0
- package/dist/indexer/{file-context.js → walk/file-context.js} +10 -15
- package/dist/indexer/{matchers.js → walk/matchers.js} +13 -9
- package/dist/indexer/{path-resolver.js → walk/path-resolver.js} +6 -6
- package/dist/indexer/{project-context.js → walk/project-context.js} +1 -1
- package/dist/indexer/{walker.js → walk/walker.js} +4 -3
- package/dist/integrations/agent/builder-shared.js +39 -0
- package/dist/integrations/agent/builders.js +14 -81
- package/dist/integrations/agent/config.js +6 -4
- package/dist/integrations/agent/detect.js +1 -1
- package/dist/integrations/agent/index.js +23 -8
- package/dist/integrations/agent/prompts.js +2 -3
- package/dist/integrations/agent/runner.js +22 -3
- package/dist/integrations/agent/spawn.js +9 -10
- package/dist/integrations/harnesses/claude/agent-builder.js +48 -0
- package/dist/integrations/harnesses/claude/config-import.js +70 -0
- package/dist/integrations/harnesses/claude/index.js +64 -0
- package/dist/integrations/{session-logs/providers/claude-code.js → harnesses/claude/session-log.js} +32 -5
- package/dist/integrations/harnesses/index.js +144 -0
- package/dist/integrations/harnesses/opencode/agent-builder.js +43 -0
- package/dist/integrations/harnesses/opencode/config-import.js +82 -0
- package/dist/integrations/harnesses/opencode/index.js +59 -0
- package/dist/integrations/{session-logs/providers/opencode.js → harnesses/opencode/session-log.js} +1 -1
- package/dist/integrations/harnesses/opencode-sdk/index.js +49 -0
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +234 -0
- package/dist/integrations/harnesses/types.js +43 -0
- package/dist/integrations/lockfile.js +7 -16
- package/dist/integrations/session-logs/index.js +82 -9
- package/dist/llm/call-ai.js +4 -4
- package/dist/llm/client.js +146 -6
- package/dist/llm/embedder.js +6 -6
- package/dist/llm/embedders/local.js +9 -22
- package/dist/llm/embedders/remote.js +2 -2
- package/dist/llm/embedders/types.js +1 -1
- package/dist/llm/graph-extract.js +31 -12
- package/dist/llm/index-passes.js +1 -1
- package/dist/llm/memory-infer.js +12 -5
- package/dist/llm/metadata-enhance.js +2 -2
- package/dist/llm/usage-persist.js +77 -0
- package/dist/llm/usage-telemetry.js +103 -0
- package/dist/output/context.js +9 -46
- package/dist/output/html-render.js +73 -0
- package/dist/output/renderers.js +88 -58
- package/dist/output/shapes/curate.js +7 -3
- package/dist/output/shapes/distill.js +7 -3
- package/dist/output/shapes/env-list.js +18 -16
- package/dist/output/shapes/events.js +5 -4
- package/dist/output/shapes/helpers.js +19 -5
- package/dist/output/shapes/history.js +7 -3
- package/dist/output/shapes/passthrough.js +8 -11
- package/dist/output/shapes/{proposal-accept.js → proposal/accept.js} +7 -3
- package/dist/output/shapes/{proposal-diff.js → proposal/diff.js} +7 -3
- package/dist/output/shapes/{proposal-list.js → proposal/list.js} +7 -3
- package/dist/output/shapes/{proposal-producer.js → proposal/producer.js} +5 -4
- package/dist/output/shapes/{proposal-reject.js → proposal/reject.js} +7 -3
- package/dist/output/shapes/{proposal-show.js → proposal/show.js} +7 -3
- package/dist/output/shapes/registry-search.js +7 -3
- package/dist/output/shapes/registry.js +12 -0
- package/dist/output/shapes/search.js +7 -3
- package/dist/output/shapes/secret-list.js +18 -16
- package/dist/output/shapes/show.js +7 -3
- package/dist/output/shapes.js +55 -30
- package/dist/output/text/add.js +2 -3
- package/dist/output/text/clone.js +2 -3
- package/dist/output/text/config.js +2 -3
- package/dist/output/text/curate.js +4 -3
- package/dist/output/text/distill.js +2 -3
- package/dist/output/text/enable-disable.js +5 -4
- package/dist/output/text/env.js +13 -0
- package/dist/output/text/events.js +5 -4
- package/dist/output/text/feedback.js +4 -3
- package/dist/output/text/helpers.js +123 -40
- package/dist/output/text/history.js +2 -3
- package/dist/output/text/import.js +2 -3
- package/dist/output/text/index.js +2 -3
- package/dist/output/text/info.js +2 -3
- package/dist/output/text/init.js +2 -3
- package/dist/output/text/list.js +2 -3
- package/dist/output/text/proposal/producer.js +9 -0
- package/dist/output/text/proposal/proposal.js +13 -0
- package/dist/output/text/registry-commands.js +8 -7
- package/dist/output/text/registry.js +12 -0
- package/dist/output/text/remember.js +4 -3
- package/dist/output/text/remove.js +2 -3
- package/dist/output/text/save.js +2 -3
- package/dist/output/text/search.js +4 -3
- package/dist/output/text/show.js +4 -3
- package/dist/output/text/update.js +2 -3
- package/dist/output/text/upgrade.js +2 -3
- package/dist/output/text/wiki.js +12 -11
- package/dist/output/text/workflow.js +12 -10
- package/dist/output/text.js +66 -32
- package/dist/registry/build-index.js +11 -10
- package/dist/registry/factory.js +1 -1
- package/dist/registry/origin-resolve.js +1 -1
- package/dist/registry/providers/index.js +2 -2
- package/dist/registry/providers/skills-sh.js +91 -72
- package/dist/registry/providers/static-index.js +75 -52
- package/dist/registry/resolve.js +3 -3
- package/dist/runtime.js +242 -0
- package/dist/scripts/migrate-storage.js +1654 -683
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +254 -168
- package/dist/setup/detect.js +311 -9
- package/dist/setup/harness-config-import.js +6 -120
- package/dist/setup/setup.js +454 -43
- package/dist/sources/include.js +1 -1
- package/dist/sources/provider-factory.js +2 -2
- package/dist/sources/providers/filesystem.js +3 -3
- package/dist/sources/providers/git.js +9 -9
- package/dist/sources/providers/index.js +4 -4
- package/dist/sources/providers/npm.js +6 -6
- package/dist/sources/providers/provider-utils.js +13 -20
- package/dist/sources/providers/sync-from-ref.js +5 -5
- package/dist/sources/providers/tar-utils.js +2 -2
- package/dist/sources/providers/website.js +2 -2
- package/dist/sources/resolve.js +5 -5
- package/dist/sources/website-ingest.js +5 -5
- package/dist/storage/database.js +102 -0
- package/dist/storage/engines/sqlite-migrations.js +42 -0
- package/dist/storage/locations.js +25 -0
- package/dist/storage/repositories/index-db.js +43 -0
- package/dist/storage/repositories/workflow-runs-repository.js +141 -0
- package/dist/tasks/backends/cron.js +4 -4
- package/dist/tasks/backends/exec-utils.js +32 -0
- package/dist/tasks/backends/index.js +3 -3
- package/dist/tasks/backends/launchd.js +7 -14
- package/dist/tasks/backends/schtasks.js +7 -16
- package/dist/tasks/embedded.js +71 -0
- package/dist/tasks/parser.js +2 -2
- package/dist/tasks/resolveAkmBin.js +1 -1
- package/dist/tasks/runner.js +127 -31
- package/dist/tasks/schedule.js +1 -1
- package/dist/tasks/validator.js +7 -7
- package/dist/text-import-hook.mjs +51 -0
- package/dist/version.js +2 -1
- package/dist/wiki/wiki.js +7 -7
- package/dist/workflows/{authoring.js → authoring/authoring.js} +6 -6
- package/dist/workflows/{scope-key.js → authoring/scope-key.js} +1 -1
- package/dist/workflows/cli.js +1 -1
- package/dist/workflows/db.js +54 -32
- package/dist/workflows/parser.js +4 -4
- package/dist/workflows/renderer.js +5 -5
- package/dist/workflows/runtime/agent-identity.js +56 -0
- package/dist/workflows/runtime/checkin.js +57 -0
- package/dist/workflows/{runs.js → runtime/runs.js} +197 -101
- package/dist/workflows/validate-summary.js +82 -0
- package/docs/README.md +1 -1
- package/docs/data-and-telemetry.md +6 -6
- package/package.json +17 -8
- package/dist/commands/add-cli.js +0 -279
- package/dist/commands/env.js +0 -213
- package/dist/integrations/agent/sdk-runner.js +0 -126
- package/dist/output/shapes/vault-list.js +0 -19
- package/dist/output/text/proposal-producer.js +0 -8
- package/dist/output/text/proposal.js +0 -12
- package/dist/output/text/vault.js +0 -16
- /package/dist/core/{asset-serialize.js → asset/asset-serialize.js} +0 -0
- /package/dist/core/{frontmatter.js → asset/frontmatter.js} +0 -0
- /package/dist/core/{config-sources.js → config/config-sources.js} +0 -0
- /package/dist/indexer/{graph-dedup.js → graph/graph-dedup.js} +0 -0
- /package/dist/{core/config-types.js → indexer/passes/pass-context.js} +0 -0
- /package/dist/indexer/{search-fields.js → search/search-fields.js} +0 -0
- /package/dist/indexer/{index-context.js → walk/index-context.js} +0 -0
- /package/dist/workflows/{document-cache.js → runtime/document-cache.js} +0 -0
|
@@ -0,0 +1,77 @@
|
|
|
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
|
+
/**
|
|
5
|
+
* Bridge per-call LLM usage telemetry (#576) to the events stream.
|
|
6
|
+
*
|
|
7
|
+
* `usage-telemetry.ts` stays dependency-free of the events/db layer so the
|
|
8
|
+
* low-level `client.ts` never imports persistence. This module is the wiring:
|
|
9
|
+
* it installs a {@link LlmUsageSink} that persists each {@link LlmUsageRecord}
|
|
10
|
+
* as one `llm_usage` event.
|
|
11
|
+
*
|
|
12
|
+
* Why reuse the events table (vs a dedicated table): volume is low (~100
|
|
13
|
+
* calls/day), the records are append-only and time-windowed exactly like every
|
|
14
|
+
* other event, and `akm health` already aggregates per-window event reads — a
|
|
15
|
+
* separate table would duplicate retention (`purgeOldEvents`), reads, and
|
|
16
|
+
* migration surface for no benefit. See the commit message for #576.
|
|
17
|
+
*
|
|
18
|
+
* Every record is written through `appendEvent`, which is itself best-effort
|
|
19
|
+
* (a write failure logs once and never throws). Combined with the sink-error
|
|
20
|
+
* swallowing in `emitLlmUsage`, telemetry can never break a real run.
|
|
21
|
+
*/
|
|
22
|
+
import { appendEvent } from "../core/events.js";
|
|
23
|
+
import { clearLlmUsageSink, hasLlmUsageSink, setLlmUsageSink } from "./usage-telemetry.js";
|
|
24
|
+
/** Event type for persisted per-call LLM usage telemetry. */
|
|
25
|
+
export const LLM_USAGE_EVENT = "llm_usage";
|
|
26
|
+
/**
|
|
27
|
+
* Project a usage record into event metadata, dropping `undefined` token
|
|
28
|
+
* fields so an absent-usage call records only `{stage, model, durationMs}`.
|
|
29
|
+
*/
|
|
30
|
+
function toEventMetadata(record) {
|
|
31
|
+
const metadata = { durationMs: record.durationMs };
|
|
32
|
+
if (record.stage !== undefined)
|
|
33
|
+
metadata.stage = record.stage;
|
|
34
|
+
if (record.model !== undefined)
|
|
35
|
+
metadata.model = record.model;
|
|
36
|
+
if (record.finishReason !== undefined)
|
|
37
|
+
metadata.finishReason = record.finishReason;
|
|
38
|
+
if (record.promptTokens !== undefined)
|
|
39
|
+
metadata.promptTokens = record.promptTokens;
|
|
40
|
+
if (record.completionTokens !== undefined)
|
|
41
|
+
metadata.completionTokens = record.completionTokens;
|
|
42
|
+
if (record.totalTokens !== undefined)
|
|
43
|
+
metadata.totalTokens = record.totalTokens;
|
|
44
|
+
if (record.reasoningTokens !== undefined)
|
|
45
|
+
metadata.reasoningTokens = record.reasoningTokens;
|
|
46
|
+
return metadata;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Install a usage sink that persists each LLM call as an `llm_usage` event via
|
|
50
|
+
* `appendEvent`. Returns a disposer that clears the sink — call it in a
|
|
51
|
+
* `finally` block so per-run wiring does not leak across runs (and so the
|
|
52
|
+
* test-isolation harness sees a clean sink between tests).
|
|
53
|
+
*
|
|
54
|
+
* `ctx` should carry the same long-lived `state.db` handle the caller already
|
|
55
|
+
* opened for its other events; when omitted, `appendEvent` falls back to its
|
|
56
|
+
* default open-insert-close path.
|
|
57
|
+
*/
|
|
58
|
+
export function installLlmUsagePersistence(ctx) {
|
|
59
|
+
setLlmUsageSink((record) => {
|
|
60
|
+
appendEvent({ eventType: LLM_USAGE_EVENT, metadata: toEventMetadata(record) }, ctx);
|
|
61
|
+
});
|
|
62
|
+
return () => {
|
|
63
|
+
clearLlmUsageSink();
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Like {@link installLlmUsagePersistence}, but a no-op when a sink is already
|
|
68
|
+
* installed — used by standalone entry points (`akm consolidate`, `akm drain`)
|
|
69
|
+
* that may also run as a sub-step of `akm improve`. When invoked inside an
|
|
70
|
+
* enclosing run the existing per-run sink keeps ownership; the returned
|
|
71
|
+
* disposer then does nothing, so the enclosing run's `finally` still clears it.
|
|
72
|
+
*/
|
|
73
|
+
export function installLlmUsagePersistenceIfAbsent(ctx) {
|
|
74
|
+
if (hasLlmUsageSink())
|
|
75
|
+
return () => { };
|
|
76
|
+
return installLlmUsagePersistence(ctx);
|
|
77
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
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
|
+
/**
|
|
5
|
+
* Per-call LLM usage telemetry (#576).
|
|
6
|
+
*
|
|
7
|
+
* `chatCompletion` captures usage + model + finish_reason + wall-time for
|
|
8
|
+
* EVERY OpenAI-compatible call and emits one {@link LlmUsageRecord} through a
|
|
9
|
+
* module-level sink. The sink indirection keeps `client.ts` free of any
|
|
10
|
+
* dependency on the events/db layer: the application wires the sink to
|
|
11
|
+
* persistence at startup / per improve run, and tests can inspect records in
|
|
12
|
+
* memory.
|
|
13
|
+
*
|
|
14
|
+
* The pipeline *stage* that made the call is ambient, not threaded through
|
|
15
|
+
* call sites. A param-threading prototype was deliberately discarded in 0.8.5
|
|
16
|
+
* (every call site would have to forward a `stage` argument it does not care
|
|
17
|
+
* about). Instead callers wrap a well-delimited phase once with
|
|
18
|
+
* {@link withLlmStage}; any `chatCompletion` invoked inside that async region —
|
|
19
|
+
* however deeply nested — is attributed to that stage via `AsyncLocalStorage`.
|
|
20
|
+
*
|
|
21
|
+
* EVERYTHING here is best-effort. Telemetry must NEVER break a real LLM call:
|
|
22
|
+
* a sink that throws, an unset stage, or a malformed usage block all degrade
|
|
23
|
+
* silently. `emitLlmUsage` swallows sink errors; `currentLlmStage` returns
|
|
24
|
+
* `undefined` outside any `withLlmStage` scope.
|
|
25
|
+
*/
|
|
26
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
27
|
+
const stageStorage = new AsyncLocalStorage();
|
|
28
|
+
let usageSink;
|
|
29
|
+
/**
|
|
30
|
+
* Run `fn` with `stage` as the ambient LLM stage. Any `chatCompletion` call
|
|
31
|
+
* made synchronously or asynchronously within `fn` (including through awaited
|
|
32
|
+
* helpers and nested `withLlmStage` calls — the innermost wins) is attributed
|
|
33
|
+
* to `stage`. Returns whatever `fn` returns; never alters control flow.
|
|
34
|
+
*/
|
|
35
|
+
export function withLlmStage(stage, fn) {
|
|
36
|
+
return stageStorage.run(stage, fn);
|
|
37
|
+
}
|
|
38
|
+
/** The ambient LLM stage for the current async context, or `undefined` outside any {@link withLlmStage} scope. */
|
|
39
|
+
export function currentLlmStage() {
|
|
40
|
+
return stageStorage.getStore();
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Install the process-wide usage sink. Replaces any previously installed sink.
|
|
44
|
+
* The application wires this to persistence; tests install an in-memory
|
|
45
|
+
* collector. Pair with {@link clearLlmUsageSink} in a `finally` block.
|
|
46
|
+
*/
|
|
47
|
+
export function setLlmUsageSink(sink) {
|
|
48
|
+
usageSink = sink;
|
|
49
|
+
}
|
|
50
|
+
/** Remove the installed sink so subsequent calls emit nowhere. Idempotent. */
|
|
51
|
+
export function clearLlmUsageSink() {
|
|
52
|
+
usageSink = undefined;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Whether a usage sink is currently installed. Standalone entry points use
|
|
56
|
+
* this to avoid clobbering a sink an enclosing run (e.g. `akm improve`) already
|
|
57
|
+
* installed: they install their own only when none is active.
|
|
58
|
+
*/
|
|
59
|
+
export function hasLlmUsageSink() {
|
|
60
|
+
return usageSink !== undefined;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Emit one usage record to the installed sink, stamping the ambient stage.
|
|
64
|
+
* Best-effort: no sink is a no-op, and a sink that throws is swallowed so
|
|
65
|
+
* telemetry can never fail the LLM call that produced it.
|
|
66
|
+
*/
|
|
67
|
+
export function emitLlmUsage(record) {
|
|
68
|
+
const sink = usageSink;
|
|
69
|
+
if (!sink)
|
|
70
|
+
return;
|
|
71
|
+
try {
|
|
72
|
+
sink({ ...record, stage: record.stage ?? currentLlmStage() });
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// Telemetry must never break a real run.
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function asFiniteNonNegative(value) {
|
|
79
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : undefined;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Project a provider `usage` block into the token fields of an
|
|
83
|
+
* {@link LlmUsageRecord}. Missing or garbled values are omitted (not zeroed)
|
|
84
|
+
* so a best-effort record still distinguishes "0 tokens" from "unknown".
|
|
85
|
+
*/
|
|
86
|
+
export function extractUsageTokens(usage) {
|
|
87
|
+
if (!usage || typeof usage !== "object")
|
|
88
|
+
return {};
|
|
89
|
+
const out = {};
|
|
90
|
+
const prompt = asFiniteNonNegative(usage.prompt_tokens);
|
|
91
|
+
const completion = asFiniteNonNegative(usage.completion_tokens);
|
|
92
|
+
const total = asFiniteNonNegative(usage.total_tokens);
|
|
93
|
+
const reasoning = asFiniteNonNegative(usage.completion_tokens_details?.reasoning_tokens);
|
|
94
|
+
if (prompt !== undefined)
|
|
95
|
+
out.promptTokens = prompt;
|
|
96
|
+
if (completion !== undefined)
|
|
97
|
+
out.completionTokens = completion;
|
|
98
|
+
if (total !== undefined)
|
|
99
|
+
out.totalTokens = total;
|
|
100
|
+
if (reasoning !== undefined)
|
|
101
|
+
out.reasoningTokens = reasoning;
|
|
102
|
+
return out;
|
|
103
|
+
}
|
package/dist/output/context.js
CHANGED
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
*
|
|
12
12
|
* Initialized from `cli.ts` before `runMain`.
|
|
13
13
|
*/
|
|
14
|
-
import { UsageError } from "../core/errors";
|
|
15
|
-
export const OUTPUT_FORMATS = ["json", "yaml", "text", "jsonl", "md"];
|
|
14
|
+
import { UsageError } from "../core/errors.js";
|
|
15
|
+
export const OUTPUT_FORMATS = ["json", "yaml", "text", "jsonl", "md", "html"];
|
|
16
16
|
export const DETAIL_LEVELS = ["brief", "normal", "full"];
|
|
17
17
|
export const SHAPE_MODES = ["human", "agent", "summary"];
|
|
18
18
|
export function parseOutputFormat(value) {
|
|
@@ -75,50 +75,13 @@ export function resolveOutputMode(argv, defaults = {}) {
|
|
|
75
75
|
const format = parseOutputFormat(parseFlagValue(argv, "--format")) ?? defaults?.format ?? "json";
|
|
76
76
|
const rawDetail = parseFlagValue(argv, "--detail");
|
|
77
77
|
const rawShape = parseFlagValue(argv, "--shape");
|
|
78
|
-
|
|
79
|
-
//
|
|
80
|
-
// `--
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if (rawDetail === "summary" || rawDetail === "agent") {
|
|
86
|
-
// Only nudge toward `--shape` when the caller did not already pass an
|
|
87
|
-
// explicit `--shape` (which wins below). Otherwise the "use --shape <x>"
|
|
88
|
-
// advice would name a projection the caller did not request.
|
|
89
|
-
if (rawShape === undefined)
|
|
90
|
-
emitDetailShapeDeprecation(rawDetail);
|
|
91
|
-
shapeFromLegacyDetail = rawDetail;
|
|
92
|
-
detailForVerbosity = "normal";
|
|
93
|
-
}
|
|
94
|
-
else if (rawDetail === "per-run") {
|
|
95
|
-
// Legacy `akm health --detail per-run` (→ `--group-by run`). The health
|
|
96
|
-
// command owns the back-compat warning + mapping; the global singleton must
|
|
97
|
-
// not reject the value here, so fall through to the default verbosity.
|
|
98
|
-
detailForVerbosity = undefined;
|
|
99
|
-
}
|
|
100
|
-
if (usedForAgent) {
|
|
101
|
-
emitForAgentDeprecation();
|
|
102
|
-
}
|
|
103
|
-
const detail = parseDetailLevel(detailForVerbosity) ?? defaults?.detail ?? "brief";
|
|
104
|
-
// Precedence: explicit `--shape` wins; then legacy `--detail summary|agent`;
|
|
105
|
-
// then legacy `--for-agent`; default `human`.
|
|
106
|
-
const shape = parseShapeMode(rawShape) ?? shapeFromLegacyDetail ?? (usedForAgent ? "agent" : "human");
|
|
107
|
-
return { format, detail, shape, forAgent: shape === "agent" };
|
|
108
|
-
}
|
|
109
|
-
/** Suppress deprecation warnings under `--quiet` (mirrors the rest of the CLI). */
|
|
110
|
-
function isQuietArgv() {
|
|
111
|
-
return process.argv.includes("--quiet") || process.argv.includes("-q");
|
|
112
|
-
}
|
|
113
|
-
function emitDetailShapeDeprecation(value) {
|
|
114
|
-
if (isQuietArgv())
|
|
115
|
-
return;
|
|
116
|
-
process.stderr.write(`warning: '--detail ${value}' is deprecated; use '--shape ${value}'. Removed in 0.9.0.\n`);
|
|
117
|
-
}
|
|
118
|
-
function emitForAgentDeprecation() {
|
|
119
|
-
if (isQuietArgv())
|
|
120
|
-
return;
|
|
121
|
-
process.stderr.write("warning: '--for-agent' is deprecated; use '--shape agent'. Removed in 0.9.0.\n");
|
|
78
|
+
// `--detail` is verbosity only (brief|normal|full); the projection presets
|
|
79
|
+
// (`summary`/`agent`) and the `--for-agent` boolean were removed in 0.9.0 —
|
|
80
|
+
// use `--shape`. Unknown `--detail` values fall through to the default.
|
|
81
|
+
const detail = parseDetailLevel(rawDetail) ?? defaults?.detail ?? "brief";
|
|
82
|
+
const shape = parseShapeMode(rawShape) ?? "human";
|
|
83
|
+
const outputPath = parseFlagValue(argv, "--output");
|
|
84
|
+
return { format, detail, shape, forAgent: shape === "agent", ...(outputPath ? { outputPath } : {}) };
|
|
122
85
|
}
|
|
123
86
|
let _mode;
|
|
124
87
|
/**
|
|
@@ -0,0 +1,73 @@
|
|
|
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
|
+
/**
|
|
5
|
+
* `--format html` rendering primitives (#582).
|
|
6
|
+
*
|
|
7
|
+
* Templates live in `src/assets/templates/html/` (mirrored to
|
|
8
|
+
* `dist/assets/templates/html/` by `scripts/copy-assets.ts`). A command with a
|
|
9
|
+
* bespoke template ships `<command>.html`; every other command falls back to
|
|
10
|
+
* `default.html`, which renders the command's JSON envelope in a `<pre>`
|
|
11
|
+
* block. Substitution is plain `%%TOKEN%%` string replacement — no template
|
|
12
|
+
* engine, by design.
|
|
13
|
+
*/
|
|
14
|
+
import fs from "node:fs";
|
|
15
|
+
import path from "node:path";
|
|
16
|
+
import { getDirname } from "../runtime.js";
|
|
17
|
+
const TEMPLATES_DIR = path.join(getDirname(import.meta.url), "../assets/templates/html");
|
|
18
|
+
/** Template used by every command without a bespoke `<command>.html`. */
|
|
19
|
+
export const DEFAULT_TEMPLATE = "default";
|
|
20
|
+
/**
|
|
21
|
+
* Resolve the on-disk template path for a command. `<command>.html` when the
|
|
22
|
+
* command ships a bespoke template (today: `health`), otherwise
|
|
23
|
+
* `default.html`. Command names are sanitized to a bare basename so a hostile
|
|
24
|
+
* command string can never escape the templates directory.
|
|
25
|
+
*/
|
|
26
|
+
export function resolveTemplatePath(command) {
|
|
27
|
+
const name = path.basename(command.trim());
|
|
28
|
+
const candidate = path.join(TEMPLATES_DIR, `${name}.html`);
|
|
29
|
+
if (name !== DEFAULT_TEMPLATE && fs.existsSync(candidate))
|
|
30
|
+
return candidate;
|
|
31
|
+
return path.join(TEMPLATES_DIR, `${DEFAULT_TEMPLATE}.html`);
|
|
32
|
+
}
|
|
33
|
+
/** Matches a `%%TOKEN%%` placeholder (uppercase + underscore key). */
|
|
34
|
+
const TOKEN_RE = /%%[A-Z_]+%%/g;
|
|
35
|
+
/**
|
|
36
|
+
* Read a template and substitute every `%%TOKEN%%` in `replacements` in a
|
|
37
|
+
* single pass. Substitution is order-independent: a value that happens to
|
|
38
|
+
* contain another token's literal text is never re-processed (the pass scans
|
|
39
|
+
* the original template, not the growing output). Unknown tokens in the
|
|
40
|
+
* template are left in place (the health template is verified token-complete by
|
|
41
|
+
* tests); replacement keys missing from the template are silently ignored,
|
|
42
|
+
* matching the skill renderer's behaviour.
|
|
43
|
+
*/
|
|
44
|
+
export function renderHtml(templatePath, replacements) {
|
|
45
|
+
const html = fs.readFileSync(templatePath, "utf8");
|
|
46
|
+
return html.replace(TOKEN_RE, (token) => (token in replacements ? replacements[token] : token));
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Minimal HTML entity escaping for text interpolated into templates. Escapes
|
|
50
|
+
* the single quote as well as the double quote so escaped values are safe in
|
|
51
|
+
* both `"…"` and `'…'` attribute contexts, not only the double-quoted
|
|
52
|
+
* attributes the bundled templates use today.
|
|
53
|
+
*/
|
|
54
|
+
export function escapeHtml(value) {
|
|
55
|
+
return value
|
|
56
|
+
.replaceAll("&", "&")
|
|
57
|
+
.replaceAll("<", "<")
|
|
58
|
+
.replaceAll(">", ">")
|
|
59
|
+
.replaceAll('"', """)
|
|
60
|
+
.replaceAll("'", "'");
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Deliver a rendered document: write to `outputPath` when set (`--output`),
|
|
64
|
+
* otherwise print to stdout.
|
|
65
|
+
*/
|
|
66
|
+
export function deliverRendered(content, outputPath) {
|
|
67
|
+
if (outputPath) {
|
|
68
|
+
fs.mkdirSync(path.dirname(path.resolve(outputPath)), { recursive: true });
|
|
69
|
+
fs.writeFileSync(outputPath, content.endsWith("\n") ? content : `${content}\n`);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
console.log(content);
|
|
73
|
+
}
|
package/dist/output/renderers.js
CHANGED
|
@@ -11,14 +11,14 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import fs from "node:fs";
|
|
13
13
|
import path from "node:path";
|
|
14
|
-
import { listKeys as listVaultKeys } from "../commands/env";
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import { buildWorkflowAction, workflowMdRenderer } from "../workflows/renderer";
|
|
14
|
+
import { listKeys as listVaultKeys } from "../commands/env/env.js";
|
|
15
|
+
import { parseFrontmatter } from "../core/asset/frontmatter.js";
|
|
16
|
+
import { extractFrontmatterOnly, extractLineRange, extractSection, formatToc, parseMarkdownToc, } from "../core/asset/markdown.js";
|
|
17
|
+
import { asNonEmptyString, hasErrnoCode } from "../core/common.js";
|
|
18
|
+
import { extractCommentMetadata, extractDescriptionFromComments } from "../indexer/passes/metadata.js";
|
|
19
|
+
import { registerMetadataContributor } from "../indexer/passes/metadata-contributors.js";
|
|
20
|
+
import { registerRenderer } from "../indexer/walk/file-context.js";
|
|
21
|
+
import { buildWorkflowAction, workflowMdRenderer } from "../workflows/renderer.js";
|
|
22
22
|
// ── Interpreter auto-detection map ───────────────────────────────────────────
|
|
23
23
|
const INTERPRETER_MAP = {
|
|
24
24
|
".sh": "bash",
|
|
@@ -362,38 +362,11 @@ const scriptSourceRenderer = {
|
|
|
362
362
|
}
|
|
363
363
|
},
|
|
364
364
|
};
|
|
365
|
-
// ── 8.
|
|
365
|
+
// ── 8. env-file ───────────────────────────────────────────────────────────────
|
|
366
366
|
/**
|
|
367
|
-
*
|
|
368
|
-
* values. Deliberately omits content/template/prompt so
|
|
369
|
-
*
|
|
370
|
-
*/
|
|
371
|
-
const vaultEnvRenderer = {
|
|
372
|
-
name: "vault-env",
|
|
373
|
-
buildShowResponse(ctx) {
|
|
374
|
-
const name = deriveName(ctx);
|
|
375
|
-
const { keys, comments } = listVaultKeys(ctx.absPath);
|
|
376
|
-
return {
|
|
377
|
-
type: "vault",
|
|
378
|
-
name,
|
|
379
|
-
path: ctx.absPath,
|
|
380
|
-
action: 'Vault — keys + comments only. Use `source "$(akm vault path <ref>)"` to load values into the current shell, or `akm vault run <ref[/KEY]> -- <command>` to run with injected env. Values stay on disk and are never written to akm\'s stdout.',
|
|
381
|
-
description: comments.length > 0 ? comments.join("\n") : undefined,
|
|
382
|
-
keys,
|
|
383
|
-
comments,
|
|
384
|
-
};
|
|
385
|
-
},
|
|
386
|
-
enrichSearchHit(hit, _stashDir) {
|
|
387
|
-
const { keys } = listVaultKeys(hit.path);
|
|
388
|
-
if (keys.length > 0)
|
|
389
|
-
hit.keys = keys;
|
|
390
|
-
},
|
|
391
|
-
};
|
|
392
|
-
// ── 8b. env-file ───────────────────────────────────────────────────────────────
|
|
393
|
-
/**
|
|
394
|
-
* Env renderer. Like the (deprecated) vault renderer, returns ONLY key names
|
|
395
|
-
* and start-of-line comments — never values. Deliberately omits
|
|
396
|
-
* content/template/prompt so env values cannot leak through `akm show`.
|
|
367
|
+
* Env renderer. Returns ONLY key names and start-of-line comments — never
|
|
368
|
+
* values. Deliberately omits content/template/prompt so env values cannot leak
|
|
369
|
+
* through `akm show`.
|
|
397
370
|
*/
|
|
398
371
|
const envFileRenderer = {
|
|
399
372
|
name: "env-file",
|
|
@@ -449,6 +422,75 @@ const taskMdRenderer = {
|
|
|
449
422
|
};
|
|
450
423
|
},
|
|
451
424
|
};
|
|
425
|
+
// ── 8. session-md (#561) ─────────────────────────────────────────────────────
|
|
426
|
+
/**
|
|
427
|
+
* Renderer for the `session` asset type (#561). A session asset is generated by
|
|
428
|
+
* the `extract` pass and carries `harness`, `started_at`/`ended_at`, `project`,
|
|
429
|
+
* `log_path`, and `access` frontmatter plus an LLM `## Summary` / `## Key topics`
|
|
430
|
+
* body. The renderer surfaces a human-readable one-liner (harness + date +
|
|
431
|
+
* project) and concrete `access` instructions rather than dumping raw
|
|
432
|
+
* frontmatter, so an agent can decide whether to open the raw log.
|
|
433
|
+
*/
|
|
434
|
+
const sessionMdRenderer = {
|
|
435
|
+
name: "session-md",
|
|
436
|
+
buildShowResponse(ctx) {
|
|
437
|
+
const name = deriveName(ctx);
|
|
438
|
+
const parsed = parseFrontmatter(ctx.content());
|
|
439
|
+
const fm = parsed.data;
|
|
440
|
+
const harness = asNonEmptyString(fm.harness);
|
|
441
|
+
const project = asNonEmptyString(fm.project);
|
|
442
|
+
const startedAt = asNonEmptyString(fm.started_at);
|
|
443
|
+
const endedAt = asNonEmptyString(fm.ended_at);
|
|
444
|
+
const logPath = asNonEmptyString(fm.log_path);
|
|
445
|
+
const access = asNonEmptyString(fm.access);
|
|
446
|
+
const description = asNonEmptyString(fm.description);
|
|
447
|
+
const dateRange = startedAt ? (endedAt ? `${startedAt} – ${endedAt}` : startedAt) : undefined;
|
|
448
|
+
const headerParts = [
|
|
449
|
+
harness ? `harness: ${harness}` : undefined,
|
|
450
|
+
project ? `project: ${project}` : undefined,
|
|
451
|
+
dateRange,
|
|
452
|
+
].filter((p) => !!p);
|
|
453
|
+
const accessLine = [logPath ? `log: ${logPath}` : undefined, access].filter((p) => !!p).join("\n");
|
|
454
|
+
const action = [
|
|
455
|
+
"Prior agent session — read the summary below.",
|
|
456
|
+
headerParts.length > 0 ? headerParts.join(" ") : undefined,
|
|
457
|
+
accessLine ? `Open the raw log:\n${accessLine}` : undefined,
|
|
458
|
+
]
|
|
459
|
+
.filter((p) => !!p)
|
|
460
|
+
.join("\n");
|
|
461
|
+
return {
|
|
462
|
+
type: "session",
|
|
463
|
+
name,
|
|
464
|
+
path: ctx.absPath,
|
|
465
|
+
action,
|
|
466
|
+
description,
|
|
467
|
+
content: parsed.content,
|
|
468
|
+
};
|
|
469
|
+
},
|
|
470
|
+
};
|
|
471
|
+
function applySessionMetadata(entry, ctx) {
|
|
472
|
+
try {
|
|
473
|
+
const fm = applyFrontmatterDescriptionAndTags(entry, ctx);
|
|
474
|
+
entry.tags = Array.from(new Set([...(entry.tags ?? []), "session"]));
|
|
475
|
+
const hints = new Set(entry.searchHints ?? []);
|
|
476
|
+
const harness = asNonEmptyString(fm.harness);
|
|
477
|
+
if (harness)
|
|
478
|
+
hints.add(`harness:${harness}`);
|
|
479
|
+
const project = asNonEmptyString(fm.project);
|
|
480
|
+
if (project)
|
|
481
|
+
hints.add(`project:${project}`);
|
|
482
|
+
// log_path is the durable correlation key — keep it discoverable as a hint
|
|
483
|
+
// so it survives in the index even when the body is re-derived.
|
|
484
|
+
const logPath = asNonEmptyString(fm.log_path);
|
|
485
|
+
if (logPath)
|
|
486
|
+
hints.add(`log_path:${logPath}`);
|
|
487
|
+
if (hints.size > 0)
|
|
488
|
+
entry.searchHints = Array.from(hints).filter(Boolean);
|
|
489
|
+
}
|
|
490
|
+
catch {
|
|
491
|
+
// Non-fatal: skip metadata extraction on parse error
|
|
492
|
+
}
|
|
493
|
+
}
|
|
452
494
|
function applyTocMetadata(entry, ctx) {
|
|
453
495
|
try {
|
|
454
496
|
const toc = parseMarkdownToc(ctx.content());
|
|
@@ -538,18 +580,6 @@ function applyScriptMetadata(entry, ctx) {
|
|
|
538
580
|
entry.confidence = 0.7;
|
|
539
581
|
}
|
|
540
582
|
}
|
|
541
|
-
function applyVaultMetadata(entry, ctx) {
|
|
542
|
-
const { keys, comments } = listVaultKeys(ctx.absPath);
|
|
543
|
-
if (comments.length > 0 && !entry.description) {
|
|
544
|
-
entry.description = comments.join(" ").slice(0, 500);
|
|
545
|
-
entry.source = "comments";
|
|
546
|
-
entry.confidence = 0.7;
|
|
547
|
-
}
|
|
548
|
-
if (keys.length > 0) {
|
|
549
|
-
entry.searchHints = keys;
|
|
550
|
-
}
|
|
551
|
-
entry.tags = Array.from(new Set([...(entry.tags ?? []), "vault", "secrets"]));
|
|
552
|
-
}
|
|
553
583
|
function applyEnvMetadata(entry, ctx) {
|
|
554
584
|
const { keys, comments } = listVaultKeys(ctx.absPath);
|
|
555
585
|
if (comments.length > 0 && !entry.description) {
|
|
@@ -610,11 +640,6 @@ registerMetadataContributor({
|
|
|
610
640
|
appliesTo: ({ rendererName }) => rendererName === "script-source",
|
|
611
641
|
contribute: (entry, ctx) => applyScriptMetadata(entry, ctx.renderContext),
|
|
612
642
|
});
|
|
613
|
-
registerMetadataContributor({
|
|
614
|
-
name: "vault-secret-metadata",
|
|
615
|
-
appliesTo: ({ rendererName }) => rendererName === "vault-env",
|
|
616
|
-
contribute: (entry, ctx) => applyVaultMetadata(entry, ctx.renderContext),
|
|
617
|
-
});
|
|
618
643
|
registerMetadataContributor({
|
|
619
644
|
name: "env-file-metadata",
|
|
620
645
|
appliesTo: ({ rendererName }) => rendererName === "env-file",
|
|
@@ -630,6 +655,11 @@ registerMetadataContributor({
|
|
|
630
655
|
appliesTo: ({ rendererName }) => rendererName === "task-yaml",
|
|
631
656
|
contribute: (entry, ctx) => applyTaskMetadata(entry, ctx.renderContext),
|
|
632
657
|
});
|
|
658
|
+
registerMetadataContributor({
|
|
659
|
+
name: "session-md-metadata",
|
|
660
|
+
appliesTo: ({ rendererName }) => rendererName === "session-md",
|
|
661
|
+
contribute: (entry, ctx) => applySessionMetadata(entry, ctx.renderContext),
|
|
662
|
+
});
|
|
633
663
|
// ── Registration ─────────────────────────────────────────────────────────────
|
|
634
664
|
/** All built-in renderers. */
|
|
635
665
|
const builtinRenderers = [
|
|
@@ -643,9 +673,9 @@ const builtinRenderers = [
|
|
|
643
673
|
workflowMdRenderer,
|
|
644
674
|
scriptSourceRenderer,
|
|
645
675
|
envFileRenderer,
|
|
646
|
-
vaultEnvRenderer,
|
|
647
676
|
secretFileRenderer,
|
|
648
677
|
taskMdRenderer,
|
|
678
|
+
sessionMdRenderer,
|
|
649
679
|
];
|
|
650
680
|
/**
|
|
651
681
|
* Register all built-in renderers with the file-context registry.
|
|
@@ -657,4 +687,4 @@ export function registerBuiltinRenderers() {
|
|
|
657
687
|
}
|
|
658
688
|
}
|
|
659
689
|
// ── Named exports for testing ────────────────────────────────────────────────
|
|
660
|
-
export { agentMdRenderer, commandMdRenderer, envFileRenderer, INTERPRETER_MAP, knowledgeMdRenderer, lessonMdRenderer, memoryMdRenderer, SETUP_SIGNALS, scriptSourceRenderer, secretFileRenderer, skillMdRenderer,
|
|
690
|
+
export { agentMdRenderer, commandMdRenderer, envFileRenderer, INTERPRETER_MAP, knowledgeMdRenderer, lessonMdRenderer, memoryMdRenderer, SETUP_SIGNALS, scriptSourceRenderer, secretFileRenderer, skillMdRenderer, wikiMdRenderer, workflowMdRenderer, };
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
-
import { capDescription, NORMAL_DESCRIPTION_LIMIT, pickFields } from "./helpers";
|
|
5
|
-
import { registerOutputShape } from "./registry";
|
|
4
|
+
import { capDescription, NORMAL_DESCRIPTION_LIMIT, pickFields } from "./helpers.js";
|
|
6
5
|
// Curation is a small, high-signal top-N. Even at `brief` we keep `followUp`
|
|
7
6
|
// (the actionable `akm show <ref>` command) and `reason` (why this asset was
|
|
8
7
|
// selected) — these are the point of curate, unlike a bulk search listing.
|
|
@@ -53,4 +52,9 @@ export function shapeCurateOutput(result, detail, shape) {
|
|
|
53
52
|
};
|
|
54
53
|
return base;
|
|
55
54
|
}
|
|
56
|
-
|
|
55
|
+
export const curateShapes = [
|
|
56
|
+
{
|
|
57
|
+
command: "curate",
|
|
58
|
+
handler: (result, detail, shape) => shapeCurateOutput(result, detail, shape),
|
|
59
|
+
},
|
|
60
|
+
];
|
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
// simple — outcome + ids + optional payload — so `brief` strips the full
|
|
6
6
|
// proposal blob, `normal` keeps the headline fields, and `full` projects
|
|
7
7
|
// everything for downstream automation.
|
|
8
|
-
import { shapeDistillOutput } from "./helpers";
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
import { shapeDistillOutput } from "./helpers.js";
|
|
9
|
+
export const distillShapes = [
|
|
10
|
+
{
|
|
11
|
+
command: "distill",
|
|
12
|
+
handler: (result, detail) => shapeDistillOutput(result, detail),
|
|
13
|
+
},
|
|
14
|
+
];
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
4
|
+
export const envListShapes = [
|
|
5
|
+
{
|
|
6
|
+
command: "env-list",
|
|
7
|
+
handler: (result) => {
|
|
8
|
+
const r = result;
|
|
9
|
+
const envs = Array.isArray(r.envs) ? r.envs : [];
|
|
10
|
+
return {
|
|
11
|
+
...r,
|
|
12
|
+
shape: r.shape ?? "env-list",
|
|
13
|
+
schemaVersion: r.schemaVersion ?? 1,
|
|
14
|
+
envs: envs.map((v) => {
|
|
15
|
+
const { path: _path, ...rest } = v;
|
|
16
|
+
return rest;
|
|
17
|
+
}),
|
|
18
|
+
};
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
];
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
// Output shape registration for `akm events list` and `akm events tail` (#204).
|
|
5
5
|
// Both share the same envelope; the renderer in text.ts uses distinct command
|
|
6
6
|
// names so it can format streaming differently.
|
|
7
|
-
import { shapeEventsOutput } from "./helpers";
|
|
8
|
-
import { registerOutputShape } from "./registry";
|
|
7
|
+
import { shapeEventsOutput } from "./helpers.js";
|
|
9
8
|
const handler = (result, detail) => shapeEventsOutput(result, detail);
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
export const eventsShapes = [
|
|
10
|
+
{ command: "events-list", handler },
|
|
11
|
+
{ command: "events-tail", handler },
|
|
12
|
+
];
|