akm-cli 0.9.0-beta.6 → 0.9.0-rc.0
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 +663 -0
- package/README.md +12 -4
- package/dist/akm +38 -0
- package/dist/akm-migrate-storage +38 -0
- package/dist/assets/help/help-improve.md +9 -6
- package/dist/assets/hints/cli-hints-full.md +6 -5
- package/dist/assets/profiles/default.json +9 -4
- package/dist/assets/profiles/frequent.json +1 -1
- package/dist/assets/profiles/memory-focus.json +1 -1
- package/dist/assets/profiles/proactive-maintenance.json +25 -0
- package/dist/assets/profiles/quick.json +1 -1
- package/dist/assets/profiles/recombine-only.json +21 -0
- package/dist/assets/profiles/reflect-distill.json +30 -0
- package/dist/assets/profiles/synthesize.json +15 -0
- package/dist/assets/profiles/thorough.json +1 -1
- package/dist/assets/prompts/consolidate-system.md +23 -0
- package/dist/assets/prompts/contradiction-judge.md +33 -0
- package/dist/assets/prompts/distill-knowledge-system.md +22 -0
- package/dist/assets/prompts/distill-lesson-system.md +36 -0
- package/dist/assets/prompts/extract-session.md +11 -3
- package/dist/assets/prompts/graph-extract-system.md +1 -0
- package/dist/assets/prompts/graph-extract-user-prompt.md +1 -1
- package/dist/assets/prompts/memory-infer-system.md +1 -0
- package/dist/assets/prompts/memory-infer-user.md +5 -0
- package/dist/assets/prompts/metadata-enhance-system.md +1 -0
- package/dist/assets/prompts/procedural-system.md +44 -0
- package/dist/assets/prompts/recombine-system.md +40 -0
- package/dist/assets/prompts/staleness-detect-system.md +6 -0
- package/dist/assets/prompts/validate-summary-judge.md +1 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +38 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +38 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +39 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +40 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +43 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +38 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +43 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +40 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +43 -0
- package/dist/assets/templates/html/health.html +281 -111
- package/dist/assets/wiki/ingest-workflow-template.md +45 -16
- package/dist/assets/wiki/schema-template.md +4 -4
- package/dist/cli/clack.js +56 -0
- package/dist/cli/config-migrate.js +7 -1
- package/dist/cli/confirm.js +1 -1
- package/dist/cli/parse-args.js +46 -1
- package/dist/cli/shared.js +28 -0
- package/dist/cli.js +25 -14
- package/dist/commands/agent/agent-dispatch.js +3 -2
- package/dist/commands/agent/agent-support.js +0 -7
- package/dist/commands/agent/contribute-cli.js +26 -7
- package/dist/commands/config-cli.js +26 -13
- package/dist/commands/env/child-env.js +47 -0
- package/dist/commands/env/env-cli.js +220 -227
- package/dist/commands/env/env.js +14 -67
- package/dist/commands/env/secret-cli.js +140 -138
- package/dist/commands/feedback-cli.js +153 -147
- package/dist/commands/graph/graph-cli.js +5 -13
- package/dist/commands/graph/graph.js +76 -72
- package/dist/commands/health/advisories.js +151 -0
- package/dist/commands/health/checks.js +103 -16
- package/dist/commands/health/html-report.js +447 -81
- package/dist/commands/health/improve-metrics.js +771 -0
- package/dist/commands/health/llm-usage.js +65 -0
- package/dist/commands/health/md-report.js +103 -0
- package/dist/commands/health/metrics.js +278 -0
- package/dist/commands/health/stash-exposure.js +46 -0
- package/dist/commands/health/surfaces.js +216 -0
- package/dist/commands/health/task-runs.js +135 -0
- package/dist/commands/health/types.js +26 -0
- package/dist/commands/health/windows.js +195 -0
- package/dist/commands/health.js +91 -1083
- package/dist/commands/improve/anti-collapse.js +170 -0
- package/dist/commands/improve/calibration.js +161 -0
- package/dist/commands/improve/collapse-detector.js +421 -0
- package/dist/commands/improve/consolidate/chunking.js +141 -0
- package/dist/commands/improve/consolidate/eligibility.js +64 -0
- package/dist/commands/improve/consolidate/merge.js +145 -0
- package/dist/commands/improve/consolidate/sanitize.js +231 -0
- package/dist/commands/{lint.js → improve/consolidate/types.js} +1 -1
- package/dist/commands/improve/consolidate.js +1313 -1278
- package/dist/commands/improve/dedup.js +482 -0
- package/dist/commands/improve/distill/content-repair.js +202 -0
- package/dist/commands/improve/distill/promote-memory.js +229 -0
- package/dist/commands/improve/distill/quality-gate.js +236 -0
- package/dist/commands/improve/distill-guards.js +127 -0
- package/dist/commands/improve/distill-promotion-policy.js +826 -167
- package/dist/commands/improve/distill.js +243 -599
- package/dist/commands/improve/eligibility.js +434 -0
- package/dist/commands/improve/encoding-salience.js +205 -0
- package/dist/commands/improve/extract-cli.js +179 -59
- package/dist/commands/improve/extract-prompt.js +55 -4
- package/dist/commands/improve/extract-watch.js +140 -0
- package/dist/commands/improve/extract.js +409 -43
- package/dist/commands/improve/feedback-valence.js +54 -0
- package/dist/commands/improve/hot-probation.js +45 -0
- package/dist/commands/improve/improve-auto-accept.js +160 -7
- package/dist/commands/improve/improve-cli.js +115 -73
- package/dist/commands/improve/improve-profiles.js +32 -8
- package/dist/commands/improve/improve-result-file.js +15 -25
- package/dist/commands/improve/improve-session.js +58 -0
- package/dist/commands/improve/improve.js +510 -2537
- package/dist/commands/improve/locks.js +154 -0
- package/dist/commands/improve/loop-stages.js +1100 -0
- package/dist/commands/improve/memory/memory-belief.js +14 -15
- package/dist/commands/improve/memory/memory-contradiction-detect.js +83 -60
- package/dist/commands/improve/memory/memory-improve.js +27 -27
- package/dist/commands/improve/outcome-loop.js +270 -0
- package/dist/commands/improve/preparation.js +2002 -0
- package/dist/commands/improve/proactive-maintenance.js +115 -0
- package/dist/commands/improve/procedural.js +398 -0
- package/dist/commands/improve/recombine.js +818 -0
- package/dist/commands/improve/reflect-noise.js +0 -0
- package/dist/commands/improve/reflect.js +212 -45
- package/dist/commands/improve/salience.js +455 -0
- package/dist/commands/improve/schema-similarity-gate.js +168 -0
- package/dist/commands/improve/shared.js +51 -0
- package/dist/commands/improve/triage.js +93 -0
- package/dist/commands/lint/agent-linter.js +19 -24
- package/dist/commands/lint/base-linter.js +173 -60
- package/dist/commands/lint/command-linter.js +19 -24
- package/dist/commands/lint/env-key-rules.js +38 -1
- package/dist/commands/lint/fact-linter.js +39 -0
- package/dist/commands/lint/index.js +31 -13
- package/dist/commands/lint/memory-linter.js +1 -1
- package/dist/commands/lint/registry.js +7 -2
- package/dist/commands/lint/task-linter.js +3 -3
- package/dist/commands/lint/workflow-linter.js +26 -1
- package/dist/commands/observability-cli.js +4 -4
- package/dist/commands/proposal/drain-policies.js +13 -4
- package/dist/commands/proposal/drain.js +45 -51
- package/dist/commands/proposal/legacy-import.js +115 -0
- package/dist/commands/proposal/proposal-cli.js +24 -34
- package/dist/commands/proposal/proposal.js +7 -1
- package/dist/commands/proposal/propose.js +8 -3
- package/dist/commands/proposal/repository.js +829 -0
- package/dist/commands/proposal/validators/proposal-quality-validators.js +9 -8
- package/dist/commands/proposal/validators/proposals.js +93 -882
- package/dist/commands/read/curate.js +419 -103
- package/dist/commands/read/knowledge.js +10 -3
- package/dist/commands/read/remember-cli.js +133 -138
- package/dist/commands/read/search-cli.js +15 -8
- package/dist/commands/read/search.js +22 -11
- package/dist/commands/read/show.js +106 -14
- package/dist/commands/registry-cli.js +76 -87
- package/dist/commands/remember.js +11 -12
- package/dist/commands/sources/add-cli.js +91 -95
- package/dist/commands/sources/history.js +1 -1
- package/dist/commands/sources/init.js +66 -18
- package/dist/commands/sources/installed-stashes.js +11 -3
- package/dist/commands/sources/schema-repair.js +44 -46
- package/dist/commands/sources/self-update.js +2 -2
- package/dist/commands/sources/source-add.js +7 -3
- package/dist/commands/sources/sources-cli.js +3 -3
- package/dist/commands/sources/stash-cli.js +29 -41
- package/dist/commands/sources/stash-skeleton.js +57 -8
- package/dist/commands/tasks/default-tasks.js +15 -2
- package/dist/commands/tasks/tasks-cli.js +20 -29
- package/dist/commands/tasks/tasks.js +39 -11
- package/dist/commands/wiki-cli.js +23 -38
- package/dist/commands/workflow-cli.js +15 -1
- package/dist/core/asset/asset-registry.js +3 -1
- package/dist/core/asset/asset-spec.js +21 -4
- package/dist/core/asset/frontmatter.js +188 -167
- package/dist/core/asset/markdown.js +8 -0
- package/dist/core/authoring-rules.js +92 -0
- package/dist/core/common.js +4 -23
- package/dist/core/concurrent.js +10 -1
- package/dist/core/config/config-io.js +10 -1
- package/dist/core/config/config-migration.js +18 -40
- package/dist/core/config/config-schema.js +389 -58
- package/dist/core/config/config-types.js +3 -3
- package/dist/core/config/config.js +67 -22
- package/dist/core/deep-merge.js +38 -0
- package/dist/core/errors.js +1 -0
- package/dist/core/eval/rank-metrics.js +113 -0
- package/dist/core/events.js +4 -7
- package/dist/core/improve-types.js +47 -8
- package/dist/core/logs-db.js +14 -75
- package/dist/core/parse.js +36 -16
- package/dist/core/paths.js +21 -18
- package/dist/core/standards/resolve-standards-context.js +87 -0
- package/dist/core/standards/resolve-stash-standards.js +99 -0
- package/dist/core/standards/resolve-type-conventions.js +66 -0
- package/dist/core/state/migrations.js +770 -0
- package/dist/core/state-db.js +142 -1091
- package/dist/core/structured.js +69 -0
- package/dist/core/time.js +53 -0
- package/dist/core/warn.js +21 -0
- package/dist/core/write-source.js +37 -0
- package/dist/indexer/db/db.js +356 -780
- package/dist/indexer/db/entry-mapper.js +41 -0
- package/dist/indexer/db/graph-db.js +129 -86
- package/dist/indexer/db/llm-cache.js +2 -2
- package/dist/indexer/db/schema.js +516 -0
- package/dist/indexer/ensure-index.js +103 -24
- package/dist/indexer/feedback/utility-policy.js +75 -0
- package/dist/indexer/graph/graph-boost.js +51 -41
- package/dist/indexer/graph/graph-extraction.js +207 -4
- package/dist/indexer/index-writer-lock.js +106 -0
- package/dist/indexer/index-written-assets.js +105 -0
- package/dist/indexer/indexer.js +291 -310
- package/dist/indexer/passes/dir-staleness.js +114 -0
- package/dist/indexer/passes/memory-inference.js +13 -5
- package/dist/indexer/passes/metadata.js +20 -0
- package/dist/indexer/read-preflight.js +23 -0
- package/dist/indexer/search/db-search.js +89 -13
- package/dist/indexer/search/fts-query.js +51 -0
- package/dist/indexer/search/ranking-contributors.js +95 -9
- package/dist/indexer/search/ranking.js +79 -3
- package/dist/indexer/search/search-fields.js +6 -0
- package/dist/indexer/search/search-source.js +32 -21
- package/dist/indexer/search/semantic-status.js +4 -0
- package/dist/indexer/walk/matchers.js +9 -0
- package/dist/indexer/walk/walker.js +21 -13
- package/dist/integrations/agent/builders.js +39 -13
- package/dist/integrations/agent/config.js +20 -59
- package/dist/integrations/agent/detect.js +9 -0
- package/dist/integrations/agent/index.js +3 -19
- package/dist/integrations/agent/model-aliases.js +7 -2
- package/dist/integrations/agent/profiles.js +7 -1
- package/dist/integrations/agent/prompts.js +75 -9
- package/dist/integrations/agent/runner-dispatch.js +59 -0
- package/dist/integrations/agent/runner.js +13 -9
- package/dist/integrations/agent/spawn.js +69 -67
- package/dist/integrations/harnesses/claude/agent-builder.js +1 -1
- package/dist/integrations/harnesses/claude/index.js +2 -0
- package/dist/integrations/harnesses/claude/session-log.js +11 -1
- package/dist/integrations/harnesses/index.js +2 -3
- package/dist/integrations/harnesses/opencode/agent-builder.js +1 -1
- package/dist/integrations/harnesses/opencode/index.js +2 -0
- package/dist/integrations/harnesses/opencode/session-log.js +173 -3
- package/dist/integrations/harnesses/opencode-sdk/index.js +2 -2
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +98 -17
- package/dist/integrations/harnesses/types.js +1 -0
- package/dist/integrations/session-logs/index.js +16 -0
- package/dist/llm/call-ai.js +2 -2
- package/dist/llm/client.js +57 -15
- package/dist/llm/embedder.js +67 -4
- package/dist/llm/embedders/cache.js +3 -1
- package/dist/llm/embedders/deterministic.js +66 -0
- package/dist/llm/embedders/local.js +73 -3
- package/dist/llm/feature-gate.js +16 -15
- package/dist/llm/graph-extract.js +67 -44
- package/dist/llm/memory-infer-impl.js +138 -0
- package/dist/llm/memory-infer.js +1 -127
- package/dist/llm/metadata-enhance.js +44 -31
- package/dist/llm/structured-call.js +49 -0
- package/dist/migrate-storage-node.mjs +8 -0
- package/dist/output/context.js +5 -5
- package/dist/output/renderers.js +85 -14
- package/dist/output/shapes/curate.js +14 -2
- package/dist/output/shapes/helpers.js +0 -3
- package/dist/output/shapes/passthrough.js +2 -1
- package/dist/output/text/helpers.js +29 -1
- package/dist/output/text/workflow.js +1 -0
- package/dist/registry/providers/skills-sh.js +21 -147
- package/dist/registry/providers/static-index.js +15 -157
- package/dist/registry/resolve.js +27 -9
- package/dist/runtime.js +25 -1
- package/dist/scripts/migrate-storage.js +2718 -2354
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +891 -597
- package/dist/setup/detect.js +9 -0
- package/dist/setup/legacy-config.js +106 -0
- package/dist/setup/prompt.js +57 -0
- package/dist/setup/providers.js +14 -0
- package/dist/setup/registry-stash-loader.js +12 -0
- package/dist/setup/semantic-assets.js +124 -0
- package/dist/setup/setup.js +52 -1614
- package/dist/setup/steps/connection.js +734 -0
- package/dist/setup/steps/output.js +31 -0
- package/dist/setup/steps/platforms.js +124 -0
- package/dist/setup/steps/semantic.js +27 -0
- package/dist/setup/steps/sources.js +222 -0
- package/dist/setup/steps/stashdir.js +42 -0
- package/dist/setup/steps/tasks.js +152 -0
- package/dist/sources/include.js +6 -2
- package/dist/sources/providers/filesystem.js +0 -1
- package/dist/sources/providers/git-install.js +210 -0
- package/dist/sources/providers/git-provider.js +234 -0
- package/dist/sources/providers/git-stash.js +248 -0
- package/dist/sources/providers/git.js +10 -661
- package/dist/sources/providers/npm.js +2 -6
- package/dist/sources/providers/provider-utils.js +13 -7
- package/dist/sources/providers/sync-from-ref.js +9 -1
- package/dist/sources/providers/tar-utils.js +16 -8
- package/dist/sources/providers/website.js +9 -5
- package/dist/sources/website-ingest.js +187 -29
- package/dist/sources/wiki-fetchers/registry.js +53 -0
- package/dist/sources/wiki-fetchers/youtube.js +239 -0
- package/dist/storage/database.js +45 -10
- package/dist/storage/managed-db.js +82 -0
- package/dist/storage/repositories/canaries-repository.js +107 -0
- package/dist/storage/repositories/consolidation-repository.js +38 -0
- package/dist/storage/repositories/embeddings-repository.js +72 -0
- package/dist/storage/repositories/events-repository.js +187 -0
- package/dist/storage/repositories/extract-sessions-repository.js +96 -0
- package/dist/storage/repositories/improve-runs-repository.js +146 -0
- package/dist/storage/repositories/index-db.js +14 -8
- package/dist/storage/repositories/proposals-repository.js +220 -0
- package/dist/storage/repositories/recombine-repository.js +213 -0
- package/dist/storage/repositories/registry-cache.js +93 -0
- package/dist/storage/repositories/registry-index-cache-repository.js +46 -0
- package/dist/storage/repositories/task-history-repository.js +93 -0
- package/dist/storage/sqlite-pragmas.js +146 -0
- package/dist/tasks/backends/cron.js +1 -1
- package/dist/tasks/backends/index.js +9 -0
- package/dist/tasks/backends/launchd.js +1 -1
- package/dist/tasks/backends/schtasks.js +1 -1
- package/dist/tasks/{resolveAkmBin.js → resolve-akm-bin.js} +2 -2
- package/dist/tasks/runner.js +15 -13
- package/dist/text-import-hook.mjs +0 -0
- package/dist/wiki/wiki.js +52 -11
- package/dist/workflows/cli.js +1 -0
- package/dist/workflows/db.js +3 -4
- package/dist/workflows/runtime/runs.js +43 -118
- package/dist/workflows/runtime/workflow-asset-loader.js +125 -0
- package/dist/workflows/validate-summary.js +2 -7
- package/docs/README.md +69 -18
- package/docs/data-and-telemetry.md +5 -4
- package/docs/migration/release-notes/0.7.0.md +1 -1
- package/docs/migration/release-notes/0.9.0.md +39 -0
- package/package.json +10 -10
- package/dist/assets/tasks/core/update-stashes.yml +0 -4
- package/dist/commands/db-cli.js +0 -23
- package/dist/indexer/db/db-backup.js +0 -376
- package/dist/indexer/passes/staleness-detect.js +0 -488
|
@@ -0,0 +1,69 @@
|
|
|
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
|
+
* `runStructured<T>()` — transport-free structured-output core (P0.5 seam).
|
|
6
|
+
*
|
|
7
|
+
* akm has two structured-output paths that share no code: the LLM HTTP path
|
|
8
|
+
* (`llm/structured-call.ts` + `responseSchema`) and the agent JSON path
|
|
9
|
+
* (`agent/spawn.ts` `parseOutput: "json"` — embedded-JSON scan, no schema,
|
|
10
|
+
* no retry). This module is the ONE validation-driven retry loop both are
|
|
11
|
+
* meant to converge on: the workflow engine's schema units compose it with a
|
|
12
|
+
* dispatch adapter per runner (llm = `chatCompletion` + `responseSchema`;
|
|
13
|
+
* agent/sdk = `runAgent`/`runOpencodeSdk` + prompt-injected schema;
|
|
14
|
+
* native-schema CLIs pass the schema through and still validate).
|
|
15
|
+
*
|
|
16
|
+
* Layering: this file lives in `core/` — NOT `llm/` — because the agent path
|
|
17
|
+
* must be able to reach it and `agent/ ⇏ llm/` is an enforced invariant
|
|
18
|
+
* (`tests/architecture/agent-no-llm-sdk-guard.test.ts`). The transport is
|
|
19
|
+
* always injected; this module never performs IO of its own.
|
|
20
|
+
*
|
|
21
|
+
* Retry semantics: only parse/validation misses are retried (with corrective
|
|
22
|
+
* feedback appended to the re-dispatch). Transport errors PROPAGATE — the
|
|
23
|
+
* transports own their own retry discipline (`chatCompletion` has a bounded
|
|
24
|
+
* jittered retry; `runAgent` has timeout/abort semantics).
|
|
25
|
+
*/
|
|
26
|
+
import { parseEmbeddedJsonResponse } from "./parse.js";
|
|
27
|
+
function defaultFeedback(failure) {
|
|
28
|
+
if (failure.reason === "parse_error") {
|
|
29
|
+
return "Your previous response contained no parseable JSON. Respond with ONLY a JSON value that matches the requested schema — no prose, no code fences.";
|
|
30
|
+
}
|
|
31
|
+
return `Your previous JSON response failed validation:\n- ${failure.errors.join("\n- ")}\nRespond again with ONLY a corrected JSON value.`;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Run the dispatch→parse→validate loop, re-dispatching with corrective
|
|
35
|
+
* feedback on parse/validation misses, up to `maxAttempts` total attempts.
|
|
36
|
+
* Never throws for structure problems (returns a typed failure); transport
|
|
37
|
+
* throws propagate untouched.
|
|
38
|
+
*/
|
|
39
|
+
export async function runStructured(options) {
|
|
40
|
+
const parse = options.parse ?? ((raw) => parseEmbeddedJsonResponse(raw));
|
|
41
|
+
const buildFeedback = options.buildFeedback ?? defaultFeedback;
|
|
42
|
+
const maxAttempts = Math.max(1, options.maxAttempts ?? 2);
|
|
43
|
+
let feedback;
|
|
44
|
+
let lastFailure;
|
|
45
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
46
|
+
const raw = await options.dispatch(feedback);
|
|
47
|
+
const candidate = parse(raw);
|
|
48
|
+
if (candidate === undefined) {
|
|
49
|
+
lastFailure = {
|
|
50
|
+
ok: false,
|
|
51
|
+
reason: "parse_error",
|
|
52
|
+
errors: ["no JSON structure found in response"],
|
|
53
|
+
attempts: attempt,
|
|
54
|
+
raw,
|
|
55
|
+
};
|
|
56
|
+
feedback = buildFeedback({ reason: "parse_error", errors: lastFailure.errors, raw });
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
const verdict = options.validate(candidate);
|
|
60
|
+
if (verdict.ok) {
|
|
61
|
+
return { ok: true, value: verdict.value, attempts: attempt };
|
|
62
|
+
}
|
|
63
|
+
lastFailure = { ok: false, reason: "validation_error", errors: verdict.errors, attempts: attempt, raw };
|
|
64
|
+
feedback = buildFeedback({ reason: "validation_error", errors: verdict.errors, raw });
|
|
65
|
+
}
|
|
66
|
+
// maxAttempts >= 1 guarantees at least one loop iteration set lastFailure
|
|
67
|
+
// (a success would have returned), so the non-null assertion is safe.
|
|
68
|
+
return lastFailure;
|
|
69
|
+
}
|
package/dist/core/time.js
CHANGED
|
@@ -9,6 +9,59 @@
|
|
|
9
9
|
* consistently without private re-implementations drifting apart.
|
|
10
10
|
*/
|
|
11
11
|
import { UsageError } from "./errors.js";
|
|
12
|
+
// ── Duration-shorthand parsing ───────────────────────────────────────────────
|
|
13
|
+
const MINUTE_MS = 60 * 1000;
|
|
14
|
+
const HOUR_MS = 60 * 60 * 1000;
|
|
15
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
16
|
+
/** A month is approximated as 30 days — this shorthand is not calendar-exact. */
|
|
17
|
+
const MONTH_MS = 30 * DAY_MS;
|
|
18
|
+
/**
|
|
19
|
+
* Canonical duration-shorthand unit map shared by every `--since` / `--expires`
|
|
20
|
+
* / `--window-compare` consumer.
|
|
21
|
+
*
|
|
22
|
+
* The grammar is intentionally uniform across the whole CLI:
|
|
23
|
+
* - `m` = MINUTES, `M` = MONTHS (30-day approximation)
|
|
24
|
+
* - `h`/`H` = hours, `d`/`D` = days
|
|
25
|
+
*
|
|
26
|
+
* Matching is CASE-SENSITIVE (see {@link parseDuration}), which is what lets
|
|
27
|
+
* `m` and `M` mean different things. Historically `akm health --since` and
|
|
28
|
+
* `remember --expires` read a case-insensitive `m` as MONTHS while
|
|
29
|
+
* `consolidate` / `--window-compare` read it as MINUTES; that split is now
|
|
30
|
+
* resolved in favour of the conventional `m`=minutes, with `M` reserved for
|
|
31
|
+
* months. Upper-case `H`/`D` aliases are retained so specs that previously
|
|
32
|
+
* relied on the old case-insensitive parsers (e.g. `"7D"`) keep working.
|
|
33
|
+
*/
|
|
34
|
+
export const DURATION_UNITS = {
|
|
35
|
+
m: MINUTE_MS,
|
|
36
|
+
M: MONTH_MS,
|
|
37
|
+
h: HOUR_MS,
|
|
38
|
+
H: HOUR_MS,
|
|
39
|
+
d: DAY_MS,
|
|
40
|
+
D: DAY_MS,
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Parse a compact duration shorthand (e.g. `"30d"`, `"12h"`, `"5m"`, `"3M"`)
|
|
44
|
+
* into a number of milliseconds using an explicit `units` map (default
|
|
45
|
+
* {@link DURATION_UNITS}), or return `null` when the input does not match
|
|
46
|
+
* `<digits><letter>` or the unit is not in the map.
|
|
47
|
+
*
|
|
48
|
+
* Matching is CASE-SENSITIVE against the map keys, so `m` (minutes) and `M`
|
|
49
|
+
* (months) are distinct — do NOT lower-case the spec before calling, or the
|
|
50
|
+
* two collapse. Amount is parsed with base-10 `parseInt`; `null` is returned
|
|
51
|
+
* rather than throwing so each caller keeps its own error/fallback policy.
|
|
52
|
+
*/
|
|
53
|
+
export function parseDuration(spec, units = DURATION_UNITS) {
|
|
54
|
+
const match = spec.trim().match(/^(\d+)([a-zA-Z])$/);
|
|
55
|
+
if (!match)
|
|
56
|
+
return null;
|
|
57
|
+
const amount = Number.parseInt(match[1] ?? "", 10);
|
|
58
|
+
if (!Number.isFinite(amount))
|
|
59
|
+
return null;
|
|
60
|
+
const multiplier = units[match[2] ?? ""];
|
|
61
|
+
if (multiplier === undefined)
|
|
62
|
+
return null;
|
|
63
|
+
return amount * multiplier;
|
|
64
|
+
}
|
|
12
65
|
// ── Since-flag parsing ───────────────────────────────────────────────────────
|
|
13
66
|
/**
|
|
14
67
|
* Parse a user-supplied `--since` value and return an ISO-8601 timestamp
|
package/dist/core/warn.js
CHANGED
|
@@ -17,6 +17,11 @@ import path from "node:path";
|
|
|
17
17
|
let quiet = false;
|
|
18
18
|
let verbose = false;
|
|
19
19
|
let logFilePath;
|
|
20
|
+
let sinkOverride;
|
|
21
|
+
/** TEST-ONLY. Swap the output sink; pass undefined to restore real output. */
|
|
22
|
+
export function _setWarnSinkForTests(fake) {
|
|
23
|
+
sinkOverride = fake;
|
|
24
|
+
}
|
|
20
25
|
export function setQuiet(value) {
|
|
21
26
|
quiet = value;
|
|
22
27
|
}
|
|
@@ -96,6 +101,10 @@ function appendToLogFile(level, args) {
|
|
|
96
101
|
* Use for progress counters and status lines (replaces console.error used for progress).
|
|
97
102
|
*/
|
|
98
103
|
export function info(...args) {
|
|
104
|
+
if (sinkOverride) {
|
|
105
|
+
sinkOverride("info", args);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
99
108
|
appendToLogFile("INFO", args);
|
|
100
109
|
if (!quiet) {
|
|
101
110
|
console.warn(...args);
|
|
@@ -107,6 +116,10 @@ export function info(...args) {
|
|
|
107
116
|
* Drop-in replacement for console.warn() across the codebase.
|
|
108
117
|
*/
|
|
109
118
|
export function warn(...args) {
|
|
119
|
+
if (sinkOverride) {
|
|
120
|
+
sinkOverride("warn", args);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
110
123
|
appendToLogFile("WARN", args);
|
|
111
124
|
if (!quiet) {
|
|
112
125
|
console.warn(...args);
|
|
@@ -118,6 +131,10 @@ export function warn(...args) {
|
|
|
118
131
|
* Drop-in replacement for console.error() used for diagnostic failures.
|
|
119
132
|
*/
|
|
120
133
|
export function error(...args) {
|
|
134
|
+
if (sinkOverride) {
|
|
135
|
+
sinkOverride("error", args);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
121
138
|
appendToLogFile("ERROR", args);
|
|
122
139
|
if (!quiet) {
|
|
123
140
|
console.error(...args);
|
|
@@ -129,6 +146,10 @@ export function error(...args) {
|
|
|
129
146
|
* default verbosity (e.g. registry-content workflow validation errors).
|
|
130
147
|
*/
|
|
131
148
|
export function warnVerbose(...args) {
|
|
149
|
+
if (sinkOverride) {
|
|
150
|
+
sinkOverride("warnVerbose", args);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
132
153
|
if (isVerbose()) {
|
|
133
154
|
warn(...args);
|
|
134
155
|
}
|
|
@@ -30,6 +30,7 @@ import { resolveAssetPathFromName, TYPE_DIRS } from "./asset/asset-spec.js";
|
|
|
30
30
|
import { isWithin, resolveStashDir } from "./common.js";
|
|
31
31
|
import { resolveConfiguredSources } from "./config/config.js";
|
|
32
32
|
import { ConfigError, UsageError } from "./errors.js";
|
|
33
|
+
import { warn } from "./warn.js";
|
|
33
34
|
/**
|
|
34
35
|
* Source kinds that the loader is allowed to mark `writable: true`. Anything
|
|
35
36
|
* else is rejected at config load (per locked decision 4) — see
|
|
@@ -80,6 +81,34 @@ export function sanitizeCommitMessage(input) {
|
|
|
80
81
|
}
|
|
81
82
|
return out;
|
|
82
83
|
}
|
|
84
|
+
// ── Portability advisory (review 13, D1) ────────────────────────────────────
|
|
85
|
+
/**
|
|
86
|
+
* Matches an absolute host **home** path — `/home/<user>` or `/Users/<user>` —
|
|
87
|
+
* requiring at least one user segment after the prefix. A bare `/home/` or
|
|
88
|
+
* `/Users/` (no user segment) does NOT match. The user segment stops at the
|
|
89
|
+
* first path separator, whitespace, or common delimiter so we capture just the
|
|
90
|
+
* `/home/<user>` prefix rather than the whole path.
|
|
91
|
+
*
|
|
92
|
+
* Deliberately conservative: it does not exempt fenced code blocks, so content
|
|
93
|
+
* that legitimately *documents* a system path (e.g. a tutorial) can produce a
|
|
94
|
+
* false positive. That is accepted — the advisory is non-fatal and correctness
|
|
95
|
+
* (never missing a real leak) is preferred over cleverness here.
|
|
96
|
+
*/
|
|
97
|
+
const ABSOLUTE_HOME_PATH_RE = /\/(?:home|Users)\/[^\s/"'`)\]}<>|:;,]+/g;
|
|
98
|
+
/**
|
|
99
|
+
* Return the distinct `/home/<user>` / `/Users/<user>` prefixes embedded in
|
|
100
|
+
* `content`, in first-seen order. Empty when the content is portable.
|
|
101
|
+
*
|
|
102
|
+
* Used by {@link writeAssetToSource} to emit a write-time advisory: absolute
|
|
103
|
+
* host home paths make the stash non-portable and leak the local username.
|
|
104
|
+
*/
|
|
105
|
+
export function findAbsoluteHomePaths(content) {
|
|
106
|
+
const seen = new Set();
|
|
107
|
+
for (const match of content.matchAll(ABSOLUTE_HOME_PATH_RE)) {
|
|
108
|
+
seen.add(match[0]);
|
|
109
|
+
}
|
|
110
|
+
return [...seen];
|
|
111
|
+
}
|
|
83
112
|
// ── Public helpers ──────────────────────────────────────────────────────────
|
|
84
113
|
/**
|
|
85
114
|
* Resolve the effective `writable` flag for a source config entry, applying
|
|
@@ -132,6 +161,14 @@ export async function writeAssetToSource(source, config, ref, content) {
|
|
|
132
161
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
133
162
|
const normalized = content.endsWith("\n") ? content : `${content}\n`;
|
|
134
163
|
fs.writeFileSync(filePath, normalized, "utf8");
|
|
164
|
+
// Non-fatal portability advisory (review 13, D1): flag absolute host home
|
|
165
|
+
// paths in the written content. These make the stash non-portable and leak
|
|
166
|
+
// the local username. We warn AFTER the write so the advisory never blocks it.
|
|
167
|
+
const hostPaths = findAbsoluteHomePaths(normalized);
|
|
168
|
+
if (hostPaths.length > 0) {
|
|
169
|
+
warn(`warning: asset "${formatRefForMessage(ref)}" embeds absolute host path(s): ${hostPaths.join(", ")}. ` +
|
|
170
|
+
"These make the stash non-portable and leak the local username — prefer $HOME or ~ relative references.");
|
|
171
|
+
}
|
|
135
172
|
return { path: filePath, ref: makeAssetRef(ref.type, ref.name, ref.origin) };
|
|
136
173
|
}
|
|
137
174
|
/**
|