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
package/dist/core/paths.js
CHANGED
|
@@ -111,12 +111,12 @@ export function getConfigDir(env = process.env, platform = process.platform) {
|
|
|
111
111
|
}
|
|
112
112
|
return path.join(home, ".config", "akm");
|
|
113
113
|
}
|
|
114
|
-
export function getConfigPath() {
|
|
115
|
-
return path.join(getConfigDir(), "config.json");
|
|
114
|
+
export function getConfigPath(env = process.env) {
|
|
115
|
+
return path.join(getConfigDir(env), "config.json");
|
|
116
116
|
}
|
|
117
117
|
// ── Cache directory ──────────────────────────────────────────────────────────
|
|
118
|
-
export function getCacheDir() {
|
|
119
|
-
const override =
|
|
118
|
+
export function getCacheDir(env = process.env) {
|
|
119
|
+
const override = env.AKM_CACHE_DIR?.trim();
|
|
120
120
|
if (override)
|
|
121
121
|
return override;
|
|
122
122
|
// Explicit XDG/platform overrides win before the transient-stash isolation
|
|
@@ -125,13 +125,13 @@ export function getCacheDir() {
|
|
|
125
125
|
// as set, so the AKM_STASH_DIR transient rule does not silently move cache
|
|
126
126
|
// writes away from where they pointed them.
|
|
127
127
|
if (IS_WINDOWS) {
|
|
128
|
-
const localAppData =
|
|
128
|
+
const localAppData = env.LOCALAPPDATA?.trim();
|
|
129
129
|
if (localAppData)
|
|
130
130
|
return path.join(localAppData, "akm");
|
|
131
|
-
const userProfile =
|
|
131
|
+
const userProfile = env.USERPROFILE?.trim();
|
|
132
132
|
if (userProfile)
|
|
133
133
|
return path.join(userProfile, "AppData", "Local", "akm");
|
|
134
|
-
const appData =
|
|
134
|
+
const appData = env.APPDATA?.trim();
|
|
135
135
|
if (appData) {
|
|
136
136
|
// Heuristic fallback: APPDATA points to %APPDATA% (Roaming), so
|
|
137
137
|
// navigate to the sibling "Local" directory. This is typically
|
|
@@ -141,7 +141,7 @@ export function getCacheDir() {
|
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
143
|
else {
|
|
144
|
-
const xdgCacheHome =
|
|
144
|
+
const xdgCacheHome = env.XDG_CACHE_HOME?.trim();
|
|
145
145
|
if (xdgCacheHome)
|
|
146
146
|
return path.join(xdgCacheHome, "akm");
|
|
147
147
|
}
|
|
@@ -150,7 +150,7 @@ export function getCacheDir() {
|
|
|
150
150
|
// into `${AKM_STASH_DIR}/.akm/cache` so that config backups, registry-index
|
|
151
151
|
// cache, and other regenerable artifacts do not pollute the user's host
|
|
152
152
|
// ~/.cache/akm directory.
|
|
153
|
-
const stashOverride =
|
|
153
|
+
const stashOverride = env.AKM_STASH_DIR?.trim();
|
|
154
154
|
if (stashOverride && isTransientStashPath(stashOverride)) {
|
|
155
155
|
return path.join(stashOverride, ".akm", "cache");
|
|
156
156
|
}
|
|
@@ -158,7 +158,7 @@ export function getCacheDir() {
|
|
|
158
158
|
// None of LOCALAPPDATA / USERPROFILE / APPDATA were set above.
|
|
159
159
|
throw new ConfigError("Unable to determine cache directory. Set LOCALAPPDATA, USERPROFILE, or APPDATA.", "CONFIG_DIR_UNRESOLVABLE");
|
|
160
160
|
}
|
|
161
|
-
const home =
|
|
161
|
+
const home = env.HOME?.trim();
|
|
162
162
|
if (!home)
|
|
163
163
|
return path.join("/tmp", "akm-cache");
|
|
164
164
|
return path.join(home, ".cache", "akm");
|
|
@@ -212,8 +212,11 @@ export function getDataDir(env = process.env, platform = process.platform) {
|
|
|
212
212
|
return path.join("/tmp", "akm-data");
|
|
213
213
|
return path.join(home, ".local", "share", "akm");
|
|
214
214
|
}
|
|
215
|
-
export function getDbPath() {
|
|
216
|
-
return path.join(getDataDir(), "index.db");
|
|
215
|
+
export function getDbPath(env = process.env) {
|
|
216
|
+
return path.join(getDataDir(env), "index.db");
|
|
217
|
+
}
|
|
218
|
+
export function getIndexWriterLockPath() {
|
|
219
|
+
return path.join(getDataDir(), "index.db.write.lock");
|
|
217
220
|
}
|
|
218
221
|
export function getWorkflowDbPath() {
|
|
219
222
|
return path.join(getDataDir(), "workflow.db");
|
|
@@ -254,17 +257,17 @@ export function getTaskHistoryDir() {
|
|
|
254
257
|
return path.join(getCacheDir(), "tasks", "history");
|
|
255
258
|
}
|
|
256
259
|
// ── Default stash directory ──────────────────────────────────────────────────
|
|
257
|
-
export function getDefaultStashDir() {
|
|
258
|
-
const override =
|
|
260
|
+
export function getDefaultStashDir(env = process.env) {
|
|
261
|
+
const override = env.AKM_STASH_DIR?.trim();
|
|
259
262
|
if (override)
|
|
260
263
|
return override;
|
|
261
264
|
if (IS_WINDOWS) {
|
|
262
|
-
const userProfile =
|
|
265
|
+
const userProfile = env.USERPROFILE?.trim();
|
|
263
266
|
if (userProfile)
|
|
264
267
|
return path.join(userProfile, "Documents", "akm");
|
|
265
268
|
return path.join("C:\\", "akm");
|
|
266
269
|
}
|
|
267
|
-
const home =
|
|
270
|
+
const home = env.HOME?.trim();
|
|
268
271
|
if (!home) {
|
|
269
272
|
throw new ConfigError("Unable to determine default stash directory. Set HOME.", "STASH_DIR_NOT_FOUND");
|
|
270
273
|
}
|
|
@@ -291,7 +294,7 @@ export function getDefaultStashDir() {
|
|
|
291
294
|
* is fine even though `~/.local` is refused). This catches fat-finger
|
|
292
295
|
* `--dir /` or `--dir ~` without preventing legitimate nested use.
|
|
293
296
|
*/
|
|
294
|
-
export function assertSafeStashDir(stashDir) {
|
|
297
|
+
export function assertSafeStashDir(stashDir, env = process.env) {
|
|
295
298
|
const resolved = path.resolve(stashDir);
|
|
296
299
|
// Filesystem root — POSIX and Windows drive roots.
|
|
297
300
|
if (resolved === "/" || /^[A-Za-z]:[\\/]?$/.test(resolved)) {
|
|
@@ -331,7 +334,7 @@ export function assertSafeStashDir(stashDir) {
|
|
|
331
334
|
// under bun test (which isolates HOME to a tempdir while os.homedir()
|
|
332
335
|
// still returns the real user's home).
|
|
333
336
|
const candidateHomes = new Set();
|
|
334
|
-
const envHome = (
|
|
337
|
+
const envHome = (env.HOME ?? env.USERPROFILE)?.trim();
|
|
335
338
|
if (envHome)
|
|
336
339
|
candidateHomes.add(path.resolve(envHome));
|
|
337
340
|
try {
|
|
@@ -0,0 +1,87 @@
|
|
|
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
|
+
* Dispatch resolver for the standards prompt seam — selects which of the two
|
|
6
|
+
* standards features fires for a given write target, mutually exclusively:
|
|
7
|
+
*
|
|
8
|
+
* - **Feature A — wiki schema**: the target is a wiki page (a ref/path under
|
|
9
|
+
* `wikis/<name>/`, NOT a `raw/` file and NOT a wiki infra file
|
|
10
|
+
* `schema.md`/`index.md`/`log.md`). Returns that wiki's `schema.md` body.
|
|
11
|
+
* - **Feature B — stash standards**: the target is any non-wiki asset.
|
|
12
|
+
* Returns the concatenated `category: convention`/`meta` fact bodies.
|
|
13
|
+
* - **Neither fires**: a wiki `raw/` file or a wiki infra file. Returns `""`.
|
|
14
|
+
*
|
|
15
|
+
* The two NEVER both fire. Both underlying readers degrade to `""` on
|
|
16
|
+
* missing/malformed input and never throw, so this resolver never throws.
|
|
17
|
+
*/
|
|
18
|
+
import { extractWikiNameFromRef, INDEX_MD, LOG_MD, loadWikiSchema, SCHEMA_MD } from "../../wiki/wiki.js";
|
|
19
|
+
import { resolveStashStandards } from "./resolve-stash-standards.js";
|
|
20
|
+
import { resolveTypeConventions, typeConventionRef } from "./resolve-type-conventions.js";
|
|
21
|
+
/** Wiki infra files that are not authored pages (relative to the wiki root). */
|
|
22
|
+
const WIKI_INFRA_BASENAMES = new Set([SCHEMA_MD, INDEX_MD, LOG_MD]);
|
|
23
|
+
/**
|
|
24
|
+
* Extract the asset type from a canonical ref (`[origin//]type:name`) without
|
|
25
|
+
* throwing. Returns `undefined` for refs that have no `type:` prefix. Kept local
|
|
26
|
+
* and lenient — the per-type resolver validates the result against
|
|
27
|
+
* `getAssetTypes()`, so a bogus prefix here simply yields no convention.
|
|
28
|
+
*/
|
|
29
|
+
function refType(ref) {
|
|
30
|
+
if (!ref)
|
|
31
|
+
return undefined;
|
|
32
|
+
const body = ref.includes("//") ? ref.slice(ref.indexOf("//") + 2) : ref;
|
|
33
|
+
const colon = body.indexOf(":");
|
|
34
|
+
if (colon <= 0)
|
|
35
|
+
return undefined;
|
|
36
|
+
return body.slice(0, colon).trim() || undefined;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Resolve the standards context for a write target identified by its asset ref.
|
|
40
|
+
*
|
|
41
|
+
* @param ref Canonical asset ref of the write target (e.g. `skill:foo`,
|
|
42
|
+
* `wiki:research/topics/x`). When undefined, the target is a
|
|
43
|
+
* non-wiki authoring flow → stash standards.
|
|
44
|
+
* @param stashRoot Stash root directory.
|
|
45
|
+
*/
|
|
46
|
+
export function resolveStandardsContext(ref, stashRoot) {
|
|
47
|
+
const wikiName = ref ? extractWikiNameFromRef(ref) : undefined;
|
|
48
|
+
if (!wikiName) {
|
|
49
|
+
// Non-wiki asset target → Feature B (general stash standards) plus the
|
|
50
|
+
// per-type SOFT conventions layer (#646), type-scoped to the write target.
|
|
51
|
+
const general = resolveStashStandards(stashRoot);
|
|
52
|
+
const type = refType(ref);
|
|
53
|
+
// A non-empty body here guarantees `type` is a `getAssetTypes()`-validated
|
|
54
|
+
// string (the resolver returns "" otherwise).
|
|
55
|
+
const typeConventions = type ? resolveTypeConventions(stashRoot, type) : "";
|
|
56
|
+
if (!typeConventions || !type)
|
|
57
|
+
return general;
|
|
58
|
+
// Soft, type-scoped guidance — clearly labeled and kept separate from the
|
|
59
|
+
// HARD (validator-enforced) rules that `authoringRulesForType` injects
|
|
60
|
+
// downstream. These facts are advice only; they never weaken the gate.
|
|
61
|
+
const softSection = [
|
|
62
|
+
`# ${typeConventionRef(type)} (soft per-type conventions — guidance, not enforced)`,
|
|
63
|
+
typeConventions,
|
|
64
|
+
].join("\n");
|
|
65
|
+
return general ? `${general}\n\n${softSection}` : softSection;
|
|
66
|
+
}
|
|
67
|
+
// Wiki target. Extract the page path after `wiki:<name>/`.
|
|
68
|
+
const prefix = `wiki:${wikiName}/`;
|
|
69
|
+
const pagePath = ref?.startsWith(prefix) ? ref.slice(prefix.length) : "";
|
|
70
|
+
// `wiki:<name>` with no page, a `raw/` file, or a wiki infra file → neither
|
|
71
|
+
// feature fires.
|
|
72
|
+
if (!pagePath)
|
|
73
|
+
return "";
|
|
74
|
+
if (pagePath === "raw" || pagePath.startsWith("raw/"))
|
|
75
|
+
return "";
|
|
76
|
+
// Infra files (`schema`/`index`/`log`) are only special at the WIKI ROOT.
|
|
77
|
+
// A nested page like `wiki:research/analysis/schema` is a genuine page and
|
|
78
|
+
// must NOT be suppressed, so only check when the page is at root depth.
|
|
79
|
+
if (!pagePath.includes("/")) {
|
|
80
|
+
// Refs drop the `.md` extension; compare against both forms defensively.
|
|
81
|
+
if (WIKI_INFRA_BASENAMES.has(pagePath) || WIKI_INFRA_BASENAMES.has(`${pagePath}.md`)) {
|
|
82
|
+
return "";
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// A genuine wiki page → Feature A (that wiki's schema body).
|
|
86
|
+
return loadWikiSchema(stashRoot, wikiName).body;
|
|
87
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
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
|
+
* Resolve the stash-authoring "standards" context (Feature B of the standards
|
|
6
|
+
* plan): gather the bodies of `fact` assets whose `category` frontmatter is
|
|
7
|
+
* `convention` or `meta` so naming / tag / frontmatter conventions are surfaced
|
|
8
|
+
* to the agent when it creates or edits a non-wiki asset.
|
|
9
|
+
*
|
|
10
|
+
* Selection is by **frontmatter `category`**, never by path — flat
|
|
11
|
+
* (`facts/x.md`) and nested (`facts/conventions/x.md`) layouts resolve
|
|
12
|
+
* identically. The MVP does no parsing of fenced blocks, no rule objects, and
|
|
13
|
+
* no warnings: it concatenates the selected facts' bodies in stable enumeration
|
|
14
|
+
* order, each preceded by a one-line `# <ref>` provenance header. Returns `""`
|
|
15
|
+
* when no matching facts exist.
|
|
16
|
+
*/
|
|
17
|
+
import fs from "node:fs";
|
|
18
|
+
import path from "node:path";
|
|
19
|
+
import { parseFrontmatter } from "../asset/frontmatter.js";
|
|
20
|
+
/** `category` values that mark a fact as an authoring standard. */
|
|
21
|
+
const STANDARD_CATEGORIES = new Set(["convention", "meta"]);
|
|
22
|
+
/** Directory (under the stash root) where `fact` assets live. */
|
|
23
|
+
const FACTS_SUBDIR = "facts";
|
|
24
|
+
/**
|
|
25
|
+
* Per-type SOFT convention facts (`facts/conventions/assets/<type>.md`, #646)
|
|
26
|
+
* are surfaced **type-scoped** through `resolveTypeConventions`, so they must
|
|
27
|
+
* NOT leak into this un-type-scoped general layer (authoring a `command` must
|
|
28
|
+
* not pull the `skill` convention). Excluded by relative path (POSIX form).
|
|
29
|
+
*/
|
|
30
|
+
const TYPE_CONVENTIONS_REL = "conventions/assets/";
|
|
31
|
+
/**
|
|
32
|
+
* Recursively collect `.md` files under `dir` in stable (sorted) enumeration
|
|
33
|
+
* order. Returns absolute paths. Missing dir → `[]`.
|
|
34
|
+
*/
|
|
35
|
+
function collectMarkdownFiles(dir) {
|
|
36
|
+
let entries;
|
|
37
|
+
try {
|
|
38
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
const results = [];
|
|
44
|
+
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
45
|
+
const full = path.join(dir, entry.name);
|
|
46
|
+
if (entry.isDirectory()) {
|
|
47
|
+
results.push(...collectMarkdownFiles(full));
|
|
48
|
+
}
|
|
49
|
+
else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
50
|
+
results.push(full);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return results;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Derive a fact ref (`fact:conventions/naming`) from an absolute markdown path
|
|
57
|
+
* relative to the facts root. Mirrors the canonical-name derivation in
|
|
58
|
+
* `asset-spec.ts` (POSIX separators, `.md` stripped).
|
|
59
|
+
*/
|
|
60
|
+
function toFactRef(factsRoot, absPath) {
|
|
61
|
+
const rel = path.relative(factsRoot, absPath).split(path.sep).join("/");
|
|
62
|
+
const name = rel.endsWith(".md") ? rel.slice(0, -3) : rel;
|
|
63
|
+
return `fact:${name}`;
|
|
64
|
+
}
|
|
65
|
+
export function resolveStashStandards(stashRoot) {
|
|
66
|
+
const factsRoot = path.join(stashRoot, FACTS_SUBDIR);
|
|
67
|
+
const sections = [];
|
|
68
|
+
for (const absPath of collectMarkdownFiles(factsRoot)) {
|
|
69
|
+
// Per-type SOFT conventions are delivered type-scoped (#646); skip them
|
|
70
|
+
// here so they never leak un-type-scoped into every authoring flow.
|
|
71
|
+
const relPosix = path.relative(factsRoot, absPath).split(path.sep).join("/");
|
|
72
|
+
if (relPosix.startsWith(TYPE_CONVENTIONS_REL))
|
|
73
|
+
continue;
|
|
74
|
+
let raw;
|
|
75
|
+
try {
|
|
76
|
+
raw = fs.readFileSync(absPath, "utf8");
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
let category = "";
|
|
82
|
+
let body = "";
|
|
83
|
+
try {
|
|
84
|
+
const parsed = parseFrontmatter(raw);
|
|
85
|
+
category = typeof parsed.data.category === "string" ? parsed.data.category.trim() : "";
|
|
86
|
+
body = parsed.content;
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (!STANDARD_CATEGORIES.has(category))
|
|
92
|
+
continue;
|
|
93
|
+
const trimmed = body.trim();
|
|
94
|
+
if (!trimmed)
|
|
95
|
+
continue; // skip stub facts with frontmatter but no body
|
|
96
|
+
sections.push(`# ${toFactRef(factsRoot, absPath)}\n${trimmed}`);
|
|
97
|
+
}
|
|
98
|
+
return sections.join("\n\n");
|
|
99
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
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
|
+
* Resolve **per-type SOFT authoring conventions** (#646) — the third and final
|
|
6
|
+
* authoring-guidance layer:
|
|
7
|
+
*
|
|
8
|
+
* 1. HARD rules (validator-rejecting, code-sourced) → `authoringRulesForType()`
|
|
9
|
+
* (`src/core/authoring-rules.ts`, #645). Never editable; the gate enforces them.
|
|
10
|
+
* 2. General stash standards (cross-type naming/tag conventions) →
|
|
11
|
+
* `resolveStashStandards()` `category: convention|meta` facts (#642).
|
|
12
|
+
* 3. **Per-type SOFT conventions** (voice, structure, length *preference* for
|
|
13
|
+
* *this* asset type) → user-editable `facts/conventions/assets/<type>.md`
|
|
14
|
+
* (THIS module). Augments the built-in `TYPE_HINTS` fallback for display.
|
|
15
|
+
*
|
|
16
|
+
* These facts are **soft only** — advice, not contract. They MUST NOT carry
|
|
17
|
+
* hard, validator-rejecting rules: a user editing or deleting one must never be
|
|
18
|
+
* able to weaken the authoring contract the gate enforces (#645 boundary).
|
|
19
|
+
*
|
|
20
|
+
* Selection is by a `getAssetTypes()`-validated basename: only
|
|
21
|
+
* `facts/conventions/assets/<known-type>.md` resolves. Read directly from disk
|
|
22
|
+
* (no index rebuild); any missing dir/file, unknown type, or read error degrades
|
|
23
|
+
* to `""` and never throws.
|
|
24
|
+
*/
|
|
25
|
+
import fs from "node:fs";
|
|
26
|
+
import path from "node:path";
|
|
27
|
+
import { getAssetTypes } from "../asset/asset-spec.js";
|
|
28
|
+
import { parseFrontmatter } from "../asset/frontmatter.js";
|
|
29
|
+
/** Sub-path (under the stash root) for per-type SOFT convention facts. */
|
|
30
|
+
export const TYPE_CONVENTIONS_SUBDIR = path.join("facts", "conventions", "assets");
|
|
31
|
+
/** The `fact:` ref prefix for a per-type convention, e.g. `fact:conventions/assets/skill`. */
|
|
32
|
+
export function typeConventionRef(type) {
|
|
33
|
+
return `fact:conventions/assets/${type}`;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Read the SOFT authoring-convention body for asset type `type`, if a stash
|
|
37
|
+
* owner has authored `facts/conventions/assets/<type>.md`.
|
|
38
|
+
*
|
|
39
|
+
* @returns the trimmed markdown body (frontmatter stripped), or `""` when the
|
|
40
|
+
* type is unknown, the file is absent, or anything goes wrong.
|
|
41
|
+
*/
|
|
42
|
+
export function resolveTypeConventions(stashRoot, type) {
|
|
43
|
+
if (!stashRoot || !type)
|
|
44
|
+
return "";
|
|
45
|
+
// Basename MUST be a known asset type — never resolve an arbitrary file.
|
|
46
|
+
if (!getAssetTypes().includes(type))
|
|
47
|
+
return "";
|
|
48
|
+
const abs = path.join(stashRoot, TYPE_CONVENTIONS_SUBDIR, `${type}.md`);
|
|
49
|
+
let raw;
|
|
50
|
+
try {
|
|
51
|
+
raw = fs.readFileSync(abs, "utf8");
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return ""; // missing dir/file or read error → degrade to empty
|
|
55
|
+
}
|
|
56
|
+
let body = "";
|
|
57
|
+
try {
|
|
58
|
+
body = parseFrontmatter(raw).content;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Malformed frontmatter: fall back to the whole file (parseFrontmatter
|
|
62
|
+
// normally returns whole content as body, but guard defensively).
|
|
63
|
+
body = raw;
|
|
64
|
+
}
|
|
65
|
+
return body.trim();
|
|
66
|
+
}
|