@lsctech/polaris 0.1.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/README.md +87 -0
- package/dist/__mocks__/tool-server-linear.js +34 -0
- package/dist/cli/adopt-approve.js +60 -0
- package/dist/cli/adopt-cognition.js +199 -0
- package/dist/cli/adopt-instructions.js +143 -0
- package/dist/cli/adopt-rules.js +169 -0
- package/dist/cli/adopt-scan.js +25 -0
- package/dist/cli/adopt-smartdocs.js +192 -0
- package/dist/cli/adoption-inventory.js +350 -0
- package/dist/cli/adoption-plan.js +222 -0
- package/dist/cli/args.js +28 -0
- package/dist/cli/args.test.js +30 -0
- package/dist/cli/branding.js +41 -0
- package/dist/cli/graph.js +358 -0
- package/dist/cli/index.js +127 -0
- package/dist/cli/index.test.js +162 -0
- package/dist/cli/init-detect.js +61 -0
- package/dist/cli/init.js +492 -0
- package/dist/cli/init.test.js +259 -0
- package/dist/cli/librarian.js +32 -0
- package/dist/cli/medic.js +96 -0
- package/dist/cli/startup.test.js +23 -0
- package/dist/cli/tracker.js +130 -0
- package/dist/cli/tracker.test.js +126 -0
- package/dist/cli/version.js +10 -0
- package/dist/cli/version.test.js +11 -0
- package/dist/cli/worker.js +287 -0
- package/dist/cluster-state/fixtures/test-clusters.json +19 -0
- package/dist/cluster-state/store.js +302 -0
- package/dist/cluster-state/store.test.js +145 -0
- package/dist/cluster-state/types.js +2 -0
- package/dist/cognition/archive.js +158 -0
- package/dist/cognition/closeout-librarian-types.js +161 -0
- package/dist/cognition/cognition.test.js +623 -0
- package/dist/cognition/index.js +41 -0
- package/dist/cognition/librarian-dispatch.js +391 -0
- package/dist/cognition/librarian-dispatch.test.js +247 -0
- package/dist/cognition/librarian-packet.js +313 -0
- package/dist/cognition/librarian-types.js +57 -0
- package/dist/cognition/route-cognition-delta.js +350 -0
- package/dist/cognition/summary-delta.js +279 -0
- package/dist/cognition/validate.js +162 -0
- package/dist/config/defaults.js +98 -0
- package/dist/config/doctor.js +273 -0
- package/dist/config/index.js +14 -0
- package/dist/config/loader.js +58 -0
- package/dist/config/provider-detect.js +60 -0
- package/dist/config/provider-detect.test.js +119 -0
- package/dist/config/schema.js +2 -0
- package/dist/config/show.js +44 -0
- package/dist/config/show.test.js +42 -0
- package/dist/config/validator.js +675 -0
- package/dist/config/validator.test.js +77 -0
- package/dist/docs/canon-check.js +334 -0
- package/dist/docs/canon-check.test.js +207 -0
- package/dist/docs/doctrine.js +133 -0
- package/dist/docs/doctrine.test.js +139 -0
- package/dist/docs/index.js +168 -0
- package/dist/docs/index.test.js +83 -0
- package/dist/docs/ingest.js +295 -0
- package/dist/docs/ingest.test.js +71 -0
- package/dist/docs/migrate.js +165 -0
- package/dist/docs/migrate.test.js +136 -0
- package/dist/docs/seed-instructions.js +147 -0
- package/dist/docs/seed-instructions.test.js +137 -0
- package/dist/docs/validate-instructions.js +267 -0
- package/dist/docs/validate-instructions.test.js +238 -0
- package/dist/finalize/artifact-policy.js +214 -0
- package/dist/finalize/artifact-policy.test.js +84 -0
- package/dist/finalize/delivery-integrity.js +141 -0
- package/dist/finalize/finalize.test.js +210 -0
- package/dist/finalize/github.js +41 -0
- package/dist/finalize/index.js +474 -0
- package/dist/finalize/linear.js +213 -0
- package/dist/finalize/run-report.js +47 -0
- package/dist/finalize/steps/01-map-update.js +11 -0
- package/dist/finalize/steps/02-map-validate.js +11 -0
- package/dist/finalize/steps/03-schema-validate.js +11 -0
- package/dist/finalize/steps/04-run-checks.js +118 -0
- package/dist/finalize/steps/05-generate-report.js +14 -0
- package/dist/finalize/steps/06-commit.js +39 -0
- package/dist/finalize/steps/07-push.js +10 -0
- package/dist/finalize/steps/08-create-pr.js +9 -0
- package/dist/finalize/steps/09-update-state.js +9 -0
- package/dist/finalize/steps/10-append-jsonl.js +23 -0
- package/dist/finalize/steps/11-update-linear.js +22 -0
- package/dist/finalize/steps/12-archive.js +21 -0
- package/dist/graph/adapter/c/adapter.js +45 -0
- package/dist/graph/adapter/c/extract.js +135 -0
- package/dist/graph/adapter/c/index.js +10 -0
- package/dist/graph/adapter/c/runtime.js +67 -0
- package/dist/graph/adapter/cpp/adapter.js +45 -0
- package/dist/graph/adapter/cpp/extract.js +159 -0
- package/dist/graph/adapter/cpp/index.js +10 -0
- package/dist/graph/adapter/cpp/runtime.js +61 -0
- package/dist/graph/adapter/csharp/adapter.js +45 -0
- package/dist/graph/adapter/csharp/extract.js +127 -0
- package/dist/graph/adapter/csharp/index.js +10 -0
- package/dist/graph/adapter/csharp/runtime.js +61 -0
- package/dist/graph/adapter/dart/adapter.js +56 -0
- package/dist/graph/adapter/dart/extract.js +130 -0
- package/dist/graph/adapter/dart/index.js +10 -0
- package/dist/graph/adapter/dart/runtime.js +61 -0
- package/dist/graph/adapter/go/adapter.js +45 -0
- package/dist/graph/adapter/go/extract.js +112 -0
- package/dist/graph/adapter/go/index.js +10 -0
- package/dist/graph/adapter/go/runtime.js +58 -0
- package/dist/graph/adapter/kotlin-java/extract-common.js +83 -0
- package/dist/graph/adapter/kotlin-java/index.js +15 -0
- package/dist/graph/adapter/kotlin-java/java-adapter.js +45 -0
- package/dist/graph/adapter/kotlin-java/java-extract.js +42 -0
- package/dist/graph/adapter/kotlin-java/kotlin-adapter.js +48 -0
- package/dist/graph/adapter/kotlin-java/kotlin-extract.js +58 -0
- package/dist/graph/adapter/kotlin-java/runtime.js +75 -0
- package/dist/graph/adapter/python/adapter.js +45 -0
- package/dist/graph/adapter/python/extract.js +121 -0
- package/dist/graph/adapter/python/index.js +10 -0
- package/dist/graph/adapter/python/runtime.js +70 -0
- package/dist/graph/adapter/registry.js +82 -0
- package/dist/graph/adapter/rust/adapter.js +45 -0
- package/dist/graph/adapter/rust/extract.js +110 -0
- package/dist/graph/adapter/rust/index.js +10 -0
- package/dist/graph/adapter/rust/runtime.js +74 -0
- package/dist/graph/adapter/shell/adapter.js +34 -0
- package/dist/graph/adapter/shell/extract.js +98 -0
- package/dist/graph/adapter/shell/index.js +8 -0
- package/dist/graph/adapter/svelte/adapter.js +91 -0
- package/dist/graph/adapter/svelte/extract.js +41 -0
- package/dist/graph/adapter/svelte/index.js +8 -0
- package/dist/graph/adapter/swift/adapter.js +45 -0
- package/dist/graph/adapter/swift/extract.js +120 -0
- package/dist/graph/adapter/swift/index.js +10 -0
- package/dist/graph/adapter/swift/runtime.js +70 -0
- package/dist/graph/adapter/types.js +2 -0
- package/dist/graph/adapter/typescript-javascript/adapter.js +72 -0
- package/dist/graph/adapter/typescript-javascript/extract.js +115 -0
- package/dist/graph/adapter/typescript-javascript/index.js +10 -0
- package/dist/graph/adapter/typescript-javascript/runtime.js +97 -0
- package/dist/graph/capability/index.js +105 -0
- package/dist/graph/governance.js +104 -0
- package/dist/graph/parser/extract.js +5 -0
- package/dist/graph/parser/loader.js +2 -0
- package/dist/graph/parser/pipeline.js +194 -0
- package/dist/graph/query/index.js +277 -0
- package/dist/graph/query/types.js +5 -0
- package/dist/graph/resolver/build-edges.js +211 -0
- package/dist/graph/resolver/index.js +23 -0
- package/dist/graph/resolver/resolve-imports.js +168 -0
- package/dist/graph/store/adapter.js +132 -0
- package/dist/graph/store/queries.js +124 -0
- package/dist/graph/store/types.js +4 -0
- package/dist/ignore/defaults.js +41 -0
- package/dist/ignore/parser.js +39 -0
- package/dist/lint/map-reference-validator.js +72 -0
- package/dist/loop/abort.js +188 -0
- package/dist/loop/abort.test.js +151 -0
- package/dist/loop/adapters/__tests__/terminal-cli.test.js +92 -0
- package/dist/loop/adapters/agent-subtask.js +137 -0
- package/dist/loop/adapters/agent-subtask.test.js +151 -0
- package/dist/loop/adapters/cli-subtask-bridge.js +108 -0
- package/dist/loop/adapters/index.js +9 -0
- package/dist/loop/adapters/registry.js +17 -0
- package/dist/loop/adapters/terminal-cli.js +403 -0
- package/dist/loop/adapters/types.js +2 -0
- package/dist/loop/adapters/worker-instructions.js +85 -0
- package/dist/loop/body-parser.js +226 -0
- package/dist/loop/bootstrap-packet.js +97 -0
- package/dist/loop/bootstrap-packet.test.js +171 -0
- package/dist/loop/branch-governance.js +54 -0
- package/dist/loop/budget.js +63 -0
- package/dist/loop/budget.test.js +163 -0
- package/dist/loop/checkpoint.js +325 -0
- package/dist/loop/compact-return.js +59 -0
- package/dist/loop/continue.js +645 -0
- package/dist/loop/continue.test.js +337 -0
- package/dist/loop/dispatch-boundary.js +335 -0
- package/dist/loop/dispatch-state.js +223 -0
- package/dist/loop/dispatch-state.test.js +186 -0
- package/dist/loop/dispatch.js +1236 -0
- package/dist/loop/dispatch.test.js +499 -0
- package/dist/loop/ephemeral-smoke.test.js +160 -0
- package/dist/loop/evidence-backfill.js +216 -0
- package/dist/loop/execution-adapter.js +141 -0
- package/dist/loop/execution-adapter.test.js +66 -0
- package/dist/loop/finalize-evidence.js +169 -0
- package/dist/loop/git-custody.js +250 -0
- package/dist/loop/impl-packet-input.js +38 -0
- package/dist/loop/index.js +270 -0
- package/dist/loop/ledger.js +49 -0
- package/dist/loop/ledger.test.js +127 -0
- package/dist/loop/lifecycle-dispatch.js +348 -0
- package/dist/loop/lifecycle-dispatch.test.js +318 -0
- package/dist/loop/lifecycle.js +93 -0
- package/dist/loop/lifecycle.test.js +150 -0
- package/dist/loop/orphan-recovery.js +276 -0
- package/dist/loop/orphan-recovery.test.js +236 -0
- package/dist/loop/parent.js +1566 -0
- package/dist/loop/parent.test.js +738 -0
- package/dist/loop/provider-sealed-packet.test.js +164 -0
- package/dist/loop/resume.js +295 -0
- package/dist/loop/resume.test.js +172 -0
- package/dist/loop/run-bootstrap.js +234 -0
- package/dist/loop/run-preflight.js +203 -0
- package/dist/loop/status.js +665 -0
- package/dist/loop/status.test.js +235 -0
- package/dist/loop/wait.js +86 -0
- package/dist/loop/worker-packet.js +406 -0
- package/dist/loop/worker-packet.test.js +243 -0
- package/dist/loop/worker-prompt.js +260 -0
- package/dist/loop/worker-prompt.test.js +247 -0
- package/dist/loop/worker.js +498 -0
- package/dist/loop/worker.test.js +372 -0
- package/dist/map/atlas.js +77 -0
- package/dist/map/backfill.js +171 -0
- package/dist/map/backfill.test.js +120 -0
- package/dist/map/index.js +255 -0
- package/dist/map/inference.js +73 -0
- package/dist/map/inference.test.js +35 -0
- package/dist/map/query.js +157 -0
- package/dist/map/query.test.js +174 -0
- package/dist/map/update.js +355 -0
- package/dist/map/update.test.js +67 -0
- package/dist/map/validate.js +153 -0
- package/dist/map/validate.test.js +90 -0
- package/dist/map/welfare.js +86 -0
- package/dist/mcp/lib/invoke.js +35 -0
- package/dist/mcp/lib/redact.js +24 -0
- package/dist/mcp/lib/redact.test.js +112 -0
- package/dist/mcp/lib/root.js +41 -0
- package/dist/mcp/lib/root.test.js +114 -0
- package/dist/mcp/server.js +15 -0
- package/dist/mcp/tools/claim-child.js +119 -0
- package/dist/mcp/tools/claim-child.test.js +69 -0
- package/dist/mcp/tools/current-state.js +73 -0
- package/dist/mcp/tools/current-state.test.js +114 -0
- package/dist/mcp/tools/dispatch-result.js +186 -0
- package/dist/mcp/tools/dispatch-result.test.js +109 -0
- package/dist/mcp/tools/index.js +222 -0
- package/dist/mcp/tools/index.test.js +172 -0
- package/dist/mcp/tools/linear.js +74 -0
- package/dist/mcp/tools/loop-continue.js +159 -0
- package/dist/mcp/tools/loop-continue.test.js +186 -0
- package/dist/mcp/tools/loop-dry-run.js +15 -0
- package/dist/mcp/tools/status.js +65 -0
- package/dist/medic/chart-id.js +75 -0
- package/dist/medic/chart-schema.js +139 -0
- package/dist/runs/index.js +119 -0
- package/dist/runs/index.test.js +184 -0
- package/dist/runs/ledger-tail.js +15 -0
- package/dist/runs/list.js +29 -0
- package/dist/runs/reconcile.js +74 -0
- package/dist/runs/show.js +10 -0
- package/dist/runtime/audit/logger.js +15 -0
- package/dist/runtime/audit/reader.js +42 -0
- package/dist/runtime/checkpoint.js +89 -0
- package/dist/runtime/continuation/confirmed.js +225 -0
- package/dist/runtime/continuation/confirmed.test.js +421 -0
- package/dist/runtime/continuation/dry-run.js +74 -0
- package/dist/runtime/execution-window.js +106 -0
- package/dist/runtime/scheduling/child-selector.js +16 -0
- package/dist/runtime/state.js +43 -0
- package/dist/runtime/status.js +46 -0
- package/dist/runtime/verification/envelope.js +80 -0
- package/dist/runtime/verification/fingerprint.js +26 -0
- package/dist/skill-packet/cli.test.js +105 -0
- package/dist/skill-packet/generator.js +225 -0
- package/dist/skill-packet/generator.test.js +159 -0
- package/dist/skill-packet/index.js +49 -0
- package/dist/skill-packet/types.js +2 -0
- package/dist/smartdocs-engine/audit.js +194 -0
- package/dist/smartdocs-engine/audit.test.js +122 -0
- package/dist/smartdocs-engine/canon-check.js +340 -0
- package/dist/smartdocs-engine/canon-check.test.js +234 -0
- package/dist/smartdocs-engine/doctrine.js +633 -0
- package/dist/smartdocs-engine/doctrine.test.js +374 -0
- package/dist/smartdocs-engine/index.js +456 -0
- package/dist/smartdocs-engine/index.test.js +82 -0
- package/dist/smartdocs-engine/ingest.js +495 -0
- package/dist/smartdocs-engine/ingest.test.js +163 -0
- package/dist/smartdocs-engine/migrate.js +217 -0
- package/dist/smartdocs-engine/migrate.test.js +200 -0
- package/dist/smartdocs-engine/seed-instructions.js +335 -0
- package/dist/smartdocs-engine/seed-instructions.test.js +275 -0
- package/dist/smartdocs-engine/smartdoc-ignore.js +258 -0
- package/dist/smartdocs-engine/smartdoc-ignore.test.js +146 -0
- package/dist/smartdocs-engine/validate-instructions.js +366 -0
- package/dist/smartdocs-engine/validate-instructions.test.js +283 -0
- package/dist/tracker/adapters/github/index.js +305 -0
- package/dist/tracker/adapters/jira/index.js +293 -0
- package/dist/tracker/adapters/linear/http-errors.test.js +51 -0
- package/dist/tracker/adapters/linear/index.js +621 -0
- package/dist/tracker/adapters/linear/index.test.js +238 -0
- package/dist/tracker/adapters/linear.js +50 -0
- package/dist/tracker/adapters/local/index.js +10 -0
- package/dist/tracker/adapters/local-file/index.js +159 -0
- package/dist/tracker/adapters/mcp-bridge.js +158 -0
- package/dist/tracker/adapters/mcp-bridge.test.js +12 -0
- package/dist/tracker/adapters/spec/index.js +146 -0
- package/dist/tracker/capabilities.js +2 -0
- package/dist/tracker/index.js +49 -0
- package/dist/tracker/lifecycle-policy.js +139 -0
- package/dist/tracker/lifecycle-transition.js +164 -0
- package/dist/tracker/local-graph.js +98 -0
- package/dist/tracker/migration.js +56 -0
- package/dist/tracker/schema.js +86 -0
- package/dist/tracker/sync/index.js +404 -0
- package/dist/tracker/sync/queue-store.js +95 -0
- package/dist/tracker/sync/queue-store.test.js +104 -0
- package/dist/tracker/types.js +11 -0
- package/dist/types/linear.js +3 -0
- package/dist/types/result-packet.js +12 -0
- package/dist/types/runtime-state.js +2 -0
- package/dist/types/work-contract.js +2 -0
- package/dist/utils/monotonic-timestamp.js +13 -0
- package/dist/utils/monotonic-timestamp.test.js +19 -0
- package/package.json +64 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SUPPORTED_SKILLS = exports.SKILL_ROLE_MAP = void 0;
|
|
4
|
+
exports.generateSkillPacket = generateSkillPacket;
|
|
5
|
+
const node_crypto_1 = require("node:crypto");
|
|
6
|
+
exports.SKILL_ROLE_MAP = {
|
|
7
|
+
analyze: "Analyst",
|
|
8
|
+
run: "Foreman",
|
|
9
|
+
ingest: "Librarian",
|
|
10
|
+
promote: "Librarian",
|
|
11
|
+
};
|
|
12
|
+
const ROLE_SUMMARIES = {
|
|
13
|
+
Analyst: "The Analyst gathers evidence, assesses feasibility, and produces implementation-ready plans. The Analyst shapes work but never executes it.",
|
|
14
|
+
Foreman: "The Foreman coordinates implementation by dispatching Workers. The Foreman never writes code directly — all implementation is delegated.",
|
|
15
|
+
Librarian: "The Librarian ingests, classifies, indexes, and promotes knowledge artifacts. The Librarian preserves provenance and maintains canonical structure.",
|
|
16
|
+
Worker: "The Worker implements a focused, bounded task as directed by the Foreman. The Worker owns implementation for its assigned child.",
|
|
17
|
+
};
|
|
18
|
+
function buildAnalyzePacket(config) {
|
|
19
|
+
const onBelowThreshold = config.auto_deep_analysis ? "auto_proceed" : "ask_user";
|
|
20
|
+
return {
|
|
21
|
+
authority_boundaries: [
|
|
22
|
+
"Inspect repository files and architecture",
|
|
23
|
+
"Query repo-analysis providers for code intelligence",
|
|
24
|
+
"Summarize findings and assess feasibility",
|
|
25
|
+
"Create implementation plans and specs in docs/",
|
|
26
|
+
"Create or update tracker child issues",
|
|
27
|
+
"Generate local cluster artifacts (.polaris/clusters/)",
|
|
28
|
+
"Update tracker comments and status",
|
|
29
|
+
"Close the analysis issue when complete",
|
|
30
|
+
],
|
|
31
|
+
prohibited_actions: [
|
|
32
|
+
"Implement production or runtime code",
|
|
33
|
+
"Mutate source files (src/, tests, config)",
|
|
34
|
+
"Execute implementation loops",
|
|
35
|
+
"Open implementation PRs",
|
|
36
|
+
"Continue automatically into polaris-run execution",
|
|
37
|
+
"Call polaris loop continue or polaris finalize",
|
|
38
|
+
],
|
|
39
|
+
allowed_outputs: [
|
|
40
|
+
"Linear issue descriptions and child issues",
|
|
41
|
+
"Cluster artifact files (.polaris/clusters/)",
|
|
42
|
+
"Spec documents in docs/",
|
|
43
|
+
"Tracker comments and status updates",
|
|
44
|
+
],
|
|
45
|
+
deliverables: [
|
|
46
|
+
"Implementation-ready Linear issues, or",
|
|
47
|
+
"Explanation of why user approval is needed for deeper analysis",
|
|
48
|
+
],
|
|
49
|
+
stop_conditions: [
|
|
50
|
+
"All cluster children created and linked",
|
|
51
|
+
"Confidence below threshold and user approval required but not yet obtained",
|
|
52
|
+
"Blocking dependency discovered that prevents planning",
|
|
53
|
+
],
|
|
54
|
+
confidence_policy: {
|
|
55
|
+
threshold: config.analysis_confidence_threshold,
|
|
56
|
+
auto_deep_analysis: config.auto_deep_analysis,
|
|
57
|
+
on_below_threshold: onBelowThreshold,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function buildRunPacket(config) {
|
|
62
|
+
const delegationNote = config.allow_cross_provider_delegation
|
|
63
|
+
? "Cross-provider delegation is permitted per configuration."
|
|
64
|
+
: "Cross-provider delegation is NOT permitted. Native subagent spawning is prohibited. Use terminal-cli adapter with configured providers (e.g. copilot, codex), or interactive-agent/agent-subtask adapters when running in interactive mode.";
|
|
65
|
+
return {
|
|
66
|
+
authority_boundaries: [
|
|
67
|
+
"Read cluster artifacts and current run state",
|
|
68
|
+
"Call polaris loop dispatch to assign work to a Worker",
|
|
69
|
+
"Call polaris loop continue after a Worker has returned results",
|
|
70
|
+
"Call polaris loop status to check run state",
|
|
71
|
+
"Pass worker packets to the internal child/subagent as the full prompt",
|
|
72
|
+
`Delegation policy: ${delegationNote}`,
|
|
73
|
+
],
|
|
74
|
+
prohibited_actions: [
|
|
75
|
+
"Implement code directly (inline implementation is forbidden)",
|
|
76
|
+
"Modify source files without dispatching a Worker",
|
|
77
|
+
"Mark a child complete without Worker result evidence",
|
|
78
|
+
"Attempt cross-provider delegation unless explicitly configured",
|
|
79
|
+
"Call polaris finalize before all children are complete",
|
|
80
|
+
],
|
|
81
|
+
allowed_outputs: [
|
|
82
|
+
"polaris loop dispatch invocations",
|
|
83
|
+
"polaris loop continue invocations (post-worker only)",
|
|
84
|
+
"polaris loop status output",
|
|
85
|
+
"Worker packet contents passed to internal child/subagent",
|
|
86
|
+
],
|
|
87
|
+
deliverables: [
|
|
88
|
+
"All assigned children dispatched and completed via Worker",
|
|
89
|
+
"Run checkpointed after each child",
|
|
90
|
+
],
|
|
91
|
+
stop_conditions: [
|
|
92
|
+
"All cluster children complete",
|
|
93
|
+
"A child returns status failed and stop_on_fail is enabled",
|
|
94
|
+
"Budget cap reached",
|
|
95
|
+
"Worker result evidence is absent — do not mark complete without it",
|
|
96
|
+
],
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Builds the ingest skill packet body that defines authority boundaries, prohibited actions, allowed outputs, required deliverables, and stop conditions for processing smartdocs.
|
|
101
|
+
*
|
|
102
|
+
* The packet enforces reading from smartdocs/raw/, classification and routing into smartdocs/, provenance recording, Polaris map updates, doctrine candidate routing, and telemetry emission while forbidding source mutation, silent promotions, writing to root docs/, loop/finalize calls, and conflict suppression.
|
|
103
|
+
*
|
|
104
|
+
* @returns An object with `authority_boundaries`, `prohibited_actions`, `allowed_outputs`, `deliverables`, and `stop_conditions` describing the ingest skill's policies and required outcomes.
|
|
105
|
+
*/
|
|
106
|
+
function buildIngestPacket() {
|
|
107
|
+
return {
|
|
108
|
+
authority_boundaries: [
|
|
109
|
+
"Read documents from smartdocs/raw/",
|
|
110
|
+
"Classify documents by content analysis and front-matter",
|
|
111
|
+
"Route documents to correct authority directories within smartdocs/",
|
|
112
|
+
"Write provenance records alongside placed files",
|
|
113
|
+
"Update Polaris map entries to link docs to code areas",
|
|
114
|
+
"Propose doctrine candidates (route to doctrine/candidate/ only)",
|
|
115
|
+
"Emit telemetry events",
|
|
116
|
+
],
|
|
117
|
+
prohibited_actions: [
|
|
118
|
+
"Write new Smart Docs to root docs/ — smartdocs/ is the canonical target",
|
|
119
|
+
"Silently promote documents to doctrine/active/, specs/active/, architecture/, or decisions/",
|
|
120
|
+
"Mutate source files (src/, tests, config)",
|
|
121
|
+
"Call polaris loop continue or polaris finalize",
|
|
122
|
+
"Suppress detected conflicts",
|
|
123
|
+
],
|
|
124
|
+
allowed_outputs: [
|
|
125
|
+
"Classified and routed documents in smartdocs/",
|
|
126
|
+
"Provenance sidecar records",
|
|
127
|
+
"Polaris map entry updates",
|
|
128
|
+
"Doctrine candidate proposals in doctrine/candidate/",
|
|
129
|
+
"Telemetry events",
|
|
130
|
+
],
|
|
131
|
+
deliverables: [
|
|
132
|
+
"All pending raw documents classified and routed",
|
|
133
|
+
"Provenance records written",
|
|
134
|
+
"Map entries updated",
|
|
135
|
+
],
|
|
136
|
+
stop_conditions: [
|
|
137
|
+
"All documents in raw/ processed",
|
|
138
|
+
"Conflict detected that requires user resolution",
|
|
139
|
+
"Document cannot be classified — report and wait for instruction",
|
|
140
|
+
],
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Construct the promotion/governance packet body that governs doctrine/spec promotion and deprecation.
|
|
145
|
+
*
|
|
146
|
+
* @returns The body of a `SkillPacket` for the `promote` skill containing:
|
|
147
|
+
* - `authority_boundaries`: allowed read/verify/promote/deprecate actions and telemetry emission;
|
|
148
|
+
* - `prohibited_actions`: actions that must not be performed (auto-approve, source mutation, suppressing conflicts, etc.);
|
|
149
|
+
* - `allowed_outputs`: permitted resulting artifacts (promoted/ deprecated docs, conflict reports, telemetry);
|
|
150
|
+
* - `deliverables`: required outcomes (reviewed promotions/deprecations and surfaced conflict reports);
|
|
151
|
+
* - `stop_conditions`: conditions that halt the promotion process (all reviewed, unresolved conflicts, missing user approval).
|
|
152
|
+
*/
|
|
153
|
+
function buildPromotePacket() {
|
|
154
|
+
return {
|
|
155
|
+
authority_boundaries: [
|
|
156
|
+
"Read smartdocs/raw/ and smartdocs/doctrine/candidate/ to identify promotion candidates",
|
|
157
|
+
"Read linked source files (from linkedMapArea in provenance sidecar) to verify relevance",
|
|
158
|
+
"Read smartdocs/doctrine/active/ and smartdocs/specs/active/ to check for conflicts",
|
|
159
|
+
"Call polaris doctrine spec-promote <path> to surface the conflict report (without --approve)",
|
|
160
|
+
"Call polaris doctrine spec-promote <path> --approve only after surfacing report and receiving explicit user confirmation",
|
|
161
|
+
"Call polaris doctrine promote <path> for doctrine candidates that pass governance checks",
|
|
162
|
+
"Call polaris doctrine deprecate <path> for active docs that are superseded or stale",
|
|
163
|
+
"Emit telemetry events",
|
|
164
|
+
],
|
|
165
|
+
prohibited_actions: [
|
|
166
|
+
"Auto-promote without surfacing the conflict report first",
|
|
167
|
+
"Call --approve without explicit user confirmation in the session",
|
|
168
|
+
"Mutate source files (src/, tests, config)",
|
|
169
|
+
"Call polaris loop continue or polaris finalize",
|
|
170
|
+
"Promote to architecture/ or decisions/ — those require explicit ADR process",
|
|
171
|
+
"Suppress or ignore detected conflicts",
|
|
172
|
+
],
|
|
173
|
+
allowed_outputs: [
|
|
174
|
+
"Promoted documents in doctrine/active/ or specs/active/",
|
|
175
|
+
"Deprecated documents with deprecation markers",
|
|
176
|
+
"Conflict reports surfaced to user",
|
|
177
|
+
"Telemetry events",
|
|
178
|
+
],
|
|
179
|
+
deliverables: [
|
|
180
|
+
"Reviewed candidates promoted, deprecated, or deferred with explanation",
|
|
181
|
+
"All conflict reports surfaced before any promotion",
|
|
182
|
+
],
|
|
183
|
+
stop_conditions: [
|
|
184
|
+
"All candidates reviewed",
|
|
185
|
+
"Unresolved conflict requiring user decision",
|
|
186
|
+
"User confirmation not obtained before --approve step",
|
|
187
|
+
],
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function generateSkillPacket(skillName, config) {
|
|
191
|
+
const active_role = exports.SKILL_ROLE_MAP[skillName];
|
|
192
|
+
const role_summary = ROLE_SUMMARIES[active_role];
|
|
193
|
+
const generated_at = new Date().toISOString();
|
|
194
|
+
const packet_id = (0, node_crypto_1.randomUUID)();
|
|
195
|
+
const source_config_snapshot = {
|
|
196
|
+
analysis_confidence_threshold: config.analysis_confidence_threshold,
|
|
197
|
+
auto_deep_analysis: config.auto_deep_analysis,
|
|
198
|
+
allow_cross_provider_delegation: config.allow_cross_provider_delegation,
|
|
199
|
+
};
|
|
200
|
+
let body;
|
|
201
|
+
switch (skillName) {
|
|
202
|
+
case "analyze":
|
|
203
|
+
body = buildAnalyzePacket(config);
|
|
204
|
+
break;
|
|
205
|
+
case "run":
|
|
206
|
+
body = buildRunPacket(config);
|
|
207
|
+
break;
|
|
208
|
+
case "ingest":
|
|
209
|
+
body = buildIngestPacket();
|
|
210
|
+
break;
|
|
211
|
+
case "promote":
|
|
212
|
+
body = buildPromotePacket();
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
return {
|
|
216
|
+
packet_id,
|
|
217
|
+
skill_name: skillName,
|
|
218
|
+
active_role,
|
|
219
|
+
role_summary,
|
|
220
|
+
...body,
|
|
221
|
+
source_config_snapshot,
|
|
222
|
+
generated_at,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
exports.SUPPORTED_SKILLS = ["analyze", "run", "ingest", "promote"];
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const generator_js_1 = require("./generator.js");
|
|
5
|
+
const DEFAULT_CONFIG = {
|
|
6
|
+
analysis_confidence_threshold: 85,
|
|
7
|
+
auto_deep_analysis: false,
|
|
8
|
+
allow_cross_provider_delegation: false,
|
|
9
|
+
};
|
|
10
|
+
(0, vitest_1.describe)("SKILL_ROLE_MAP", () => {
|
|
11
|
+
(0, vitest_1.it)("maps analyze to Analyst", () => {
|
|
12
|
+
(0, vitest_1.expect)(generator_js_1.SKILL_ROLE_MAP.analyze).toBe("Analyst");
|
|
13
|
+
});
|
|
14
|
+
(0, vitest_1.it)("maps run to Foreman", () => {
|
|
15
|
+
(0, vitest_1.expect)(generator_js_1.SKILL_ROLE_MAP.run).toBe("Foreman");
|
|
16
|
+
});
|
|
17
|
+
(0, vitest_1.it)("maps ingest to Librarian", () => {
|
|
18
|
+
(0, vitest_1.expect)(generator_js_1.SKILL_ROLE_MAP.ingest).toBe("Librarian");
|
|
19
|
+
});
|
|
20
|
+
(0, vitest_1.it)("maps promote to Librarian", () => {
|
|
21
|
+
(0, vitest_1.expect)(generator_js_1.SKILL_ROLE_MAP.promote).toBe("Librarian");
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
(0, vitest_1.describe)("SUPPORTED_SKILLS", () => {
|
|
25
|
+
(0, vitest_1.it)("includes all four supported skills", () => {
|
|
26
|
+
(0, vitest_1.expect)(generator_js_1.SUPPORTED_SKILLS).toEqual(["analyze", "run", "ingest", "promote"]);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
(0, vitest_1.describe)("generateSkillPacket", () => {
|
|
30
|
+
vitest_1.it.each(generator_js_1.SUPPORTED_SKILLS)("generates a packet for %s with required fields", (skill) => {
|
|
31
|
+
const packet = (0, generator_js_1.generateSkillPacket)(skill, DEFAULT_CONFIG);
|
|
32
|
+
(0, vitest_1.expect)(packet.packet_id).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/);
|
|
33
|
+
(0, vitest_1.expect)(packet.skill_name).toBe(skill);
|
|
34
|
+
(0, vitest_1.expect)(packet.active_role).toBe(generator_js_1.SKILL_ROLE_MAP[skill]);
|
|
35
|
+
(0, vitest_1.expect)(typeof packet.role_summary).toBe("string");
|
|
36
|
+
(0, vitest_1.expect)(packet.role_summary.length).toBeGreaterThan(0);
|
|
37
|
+
(0, vitest_1.expect)(Array.isArray(packet.authority_boundaries)).toBe(true);
|
|
38
|
+
(0, vitest_1.expect)(packet.authority_boundaries.length).toBeGreaterThan(0);
|
|
39
|
+
(0, vitest_1.expect)(Array.isArray(packet.prohibited_actions)).toBe(true);
|
|
40
|
+
(0, vitest_1.expect)(packet.prohibited_actions.length).toBeGreaterThan(0);
|
|
41
|
+
(0, vitest_1.expect)(Array.isArray(packet.allowed_outputs)).toBe(true);
|
|
42
|
+
(0, vitest_1.expect)(packet.allowed_outputs.length).toBeGreaterThan(0);
|
|
43
|
+
(0, vitest_1.expect)(Array.isArray(packet.deliverables)).toBe(true);
|
|
44
|
+
(0, vitest_1.expect)(packet.deliverables.length).toBeGreaterThan(0);
|
|
45
|
+
(0, vitest_1.expect)(Array.isArray(packet.stop_conditions)).toBe(true);
|
|
46
|
+
(0, vitest_1.expect)(packet.stop_conditions.length).toBeGreaterThan(0);
|
|
47
|
+
(0, vitest_1.expect)(typeof packet.generated_at).toBe("string");
|
|
48
|
+
(0, vitest_1.expect)(new Date(packet.generated_at).toISOString()).toBe(packet.generated_at);
|
|
49
|
+
(0, vitest_1.expect)(packet.source_config_snapshot).toEqual(DEFAULT_CONFIG);
|
|
50
|
+
});
|
|
51
|
+
(0, vitest_1.describe)("analyze packet", () => {
|
|
52
|
+
(0, vitest_1.it)("assigns Analyst role", () => {
|
|
53
|
+
const packet = (0, generator_js_1.generateSkillPacket)("analyze", DEFAULT_CONFIG);
|
|
54
|
+
(0, vitest_1.expect)(packet.active_role).toBe("Analyst");
|
|
55
|
+
});
|
|
56
|
+
(0, vitest_1.it)("includes a confidence_policy", () => {
|
|
57
|
+
const packet = (0, generator_js_1.generateSkillPacket)("analyze", DEFAULT_CONFIG);
|
|
58
|
+
(0, vitest_1.expect)(packet.confidence_policy).toBeDefined();
|
|
59
|
+
(0, vitest_1.expect)(packet.confidence_policy?.threshold).toBe(85);
|
|
60
|
+
(0, vitest_1.expect)(packet.confidence_policy?.auto_deep_analysis).toBe(false);
|
|
61
|
+
(0, vitest_1.expect)(packet.confidence_policy?.on_below_threshold).toBe("ask_user");
|
|
62
|
+
});
|
|
63
|
+
(0, vitest_1.it)("sets on_below_threshold to auto_proceed when auto_deep_analysis is true", () => {
|
|
64
|
+
const packet = (0, generator_js_1.generateSkillPacket)("analyze", {
|
|
65
|
+
...DEFAULT_CONFIG,
|
|
66
|
+
auto_deep_analysis: true,
|
|
67
|
+
});
|
|
68
|
+
(0, vitest_1.expect)(packet.confidence_policy?.on_below_threshold).toBe("auto_proceed");
|
|
69
|
+
(0, vitest_1.expect)(packet.confidence_policy?.auto_deep_analysis).toBe(true);
|
|
70
|
+
});
|
|
71
|
+
(0, vitest_1.it)("reflects custom confidence threshold in policy and snapshot", () => {
|
|
72
|
+
const packet = (0, generator_js_1.generateSkillPacket)("analyze", {
|
|
73
|
+
...DEFAULT_CONFIG,
|
|
74
|
+
analysis_confidence_threshold: 70,
|
|
75
|
+
});
|
|
76
|
+
(0, vitest_1.expect)(packet.confidence_policy?.threshold).toBe(70);
|
|
77
|
+
(0, vitest_1.expect)(packet.source_config_snapshot.analysis_confidence_threshold).toBe(70);
|
|
78
|
+
});
|
|
79
|
+
(0, vitest_1.it)("prohibits implementation actions", () => {
|
|
80
|
+
const packet = (0, generator_js_1.generateSkillPacket)("analyze", DEFAULT_CONFIG);
|
|
81
|
+
const prohibited = packet.prohibited_actions.join(" ");
|
|
82
|
+
(0, vitest_1.expect)(prohibited).toContain("production or runtime code");
|
|
83
|
+
(0, vitest_1.expect)(prohibited).toContain("polaris loop continue");
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
(0, vitest_1.describe)("run packet", () => {
|
|
87
|
+
(0, vitest_1.it)("assigns Foreman role", () => {
|
|
88
|
+
const packet = (0, generator_js_1.generateSkillPacket)("run", DEFAULT_CONFIG);
|
|
89
|
+
(0, vitest_1.expect)(packet.active_role).toBe("Foreman");
|
|
90
|
+
});
|
|
91
|
+
(0, vitest_1.it)("does not include a confidence_policy", () => {
|
|
92
|
+
const packet = (0, generator_js_1.generateSkillPacket)("run", DEFAULT_CONFIG);
|
|
93
|
+
(0, vitest_1.expect)(packet.confidence_policy).toBeUndefined();
|
|
94
|
+
});
|
|
95
|
+
(0, vitest_1.it)("prohibits inline implementation", () => {
|
|
96
|
+
const packet = (0, generator_js_1.generateSkillPacket)("run", DEFAULT_CONFIG);
|
|
97
|
+
const prohibited = packet.prohibited_actions.join(" ");
|
|
98
|
+
(0, vitest_1.expect)(prohibited).toContain("inline implementation");
|
|
99
|
+
});
|
|
100
|
+
(0, vitest_1.it)("notes cross-provider delegation is NOT permitted by default", () => {
|
|
101
|
+
const packet = (0, generator_js_1.generateSkillPacket)("run", DEFAULT_CONFIG);
|
|
102
|
+
const boundaries = packet.authority_boundaries.join(" ");
|
|
103
|
+
(0, vitest_1.expect)(boundaries).toContain("NOT permitted");
|
|
104
|
+
});
|
|
105
|
+
(0, vitest_1.it)("notes cross-provider delegation is permitted when configured", () => {
|
|
106
|
+
const packet = (0, generator_js_1.generateSkillPacket)("run", {
|
|
107
|
+
...DEFAULT_CONFIG,
|
|
108
|
+
allow_cross_provider_delegation: true,
|
|
109
|
+
});
|
|
110
|
+
const boundaries = packet.authority_boundaries.join(" ");
|
|
111
|
+
(0, vitest_1.expect)(boundaries).toContain("permitted per configuration");
|
|
112
|
+
});
|
|
113
|
+
(0, vitest_1.it)("requires Worker result evidence before marking complete", () => {
|
|
114
|
+
const packet = (0, generator_js_1.generateSkillPacket)("run", DEFAULT_CONFIG);
|
|
115
|
+
const stops = packet.stop_conditions.join(" ");
|
|
116
|
+
(0, vitest_1.expect)(stops).toContain("Worker result evidence");
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
(0, vitest_1.describe)("ingest packet", () => {
|
|
120
|
+
(0, vitest_1.it)("assigns Librarian role", () => {
|
|
121
|
+
const packet = (0, generator_js_1.generateSkillPacket)("ingest", DEFAULT_CONFIG);
|
|
122
|
+
(0, vitest_1.expect)(packet.active_role).toBe("Librarian");
|
|
123
|
+
});
|
|
124
|
+
(0, vitest_1.it)("does not include a confidence_policy", () => {
|
|
125
|
+
const packet = (0, generator_js_1.generateSkillPacket)("ingest", DEFAULT_CONFIG);
|
|
126
|
+
(0, vitest_1.expect)(packet.confidence_policy).toBeUndefined();
|
|
127
|
+
});
|
|
128
|
+
(0, vitest_1.it)("prohibits promoting to active without approval", () => {
|
|
129
|
+
const packet = (0, generator_js_1.generateSkillPacket)("ingest", DEFAULT_CONFIG);
|
|
130
|
+
const prohibited = packet.prohibited_actions.join(" ");
|
|
131
|
+
(0, vitest_1.expect)(prohibited).toContain("doctrine/active/");
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
(0, vitest_1.describe)("promote packet", () => {
|
|
135
|
+
(0, vitest_1.it)("assigns Librarian role", () => {
|
|
136
|
+
const packet = (0, generator_js_1.generateSkillPacket)("promote", DEFAULT_CONFIG);
|
|
137
|
+
(0, vitest_1.expect)(packet.active_role).toBe("Librarian");
|
|
138
|
+
});
|
|
139
|
+
(0, vitest_1.it)("does not include a confidence_policy", () => {
|
|
140
|
+
const packet = (0, generator_js_1.generateSkillPacket)("promote", DEFAULT_CONFIG);
|
|
141
|
+
(0, vitest_1.expect)(packet.confidence_policy).toBeUndefined();
|
|
142
|
+
});
|
|
143
|
+
(0, vitest_1.it)("prohibits auto-promote without surfacing conflict report", () => {
|
|
144
|
+
const packet = (0, generator_js_1.generateSkillPacket)("promote", DEFAULT_CONFIG);
|
|
145
|
+
const prohibited = packet.prohibited_actions.join(" ");
|
|
146
|
+
(0, vitest_1.expect)(prohibited).toContain("Auto-promote");
|
|
147
|
+
});
|
|
148
|
+
(0, vitest_1.it)("prohibits calling --approve without user confirmation", () => {
|
|
149
|
+
const packet = (0, generator_js_1.generateSkillPacket)("promote", DEFAULT_CONFIG);
|
|
150
|
+
const prohibited = packet.prohibited_actions.join(" ");
|
|
151
|
+
(0, vitest_1.expect)(prohibited).toContain("--approve");
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
(0, vitest_1.it)("each packet has a unique packet_id", () => {
|
|
155
|
+
const p1 = (0, generator_js_1.generateSkillPacket)("analyze", DEFAULT_CONFIG);
|
|
156
|
+
const p2 = (0, generator_js_1.generateSkillPacket)("analyze", DEFAULT_CONFIG);
|
|
157
|
+
(0, vitest_1.expect)(p1.packet_id).not.toBe(p2.packet_id);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createSkillCommand = createSkillCommand;
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const loader_js_1 = require("../config/loader.js");
|
|
6
|
+
const generator_js_1 = require("./generator.js");
|
|
7
|
+
/**
|
|
8
|
+
* Create a top-level "skill" CLI command configured for safe, read-only skill packet operations.
|
|
9
|
+
*
|
|
10
|
+
* The returned command includes a "packet" subcommand that validates the requested skill, loads
|
|
11
|
+
* repository configuration (falling back to sensible defaults for `skill_packet`), generates a
|
|
12
|
+
* skill packet, and prints the resulting JSON to stdout. If an unknown skill is requested, the
|
|
13
|
+
* subcommand writes an error to stderr and exits with code 1.
|
|
14
|
+
*
|
|
15
|
+
* @param options - Options containing `repoRoot`, the repository root used to locate and load configuration
|
|
16
|
+
* @returns A configured Commander `Command` instance with the `packet` subcommand registered
|
|
17
|
+
*/
|
|
18
|
+
function createSkillCommand(options) {
|
|
19
|
+
const command = new commander_1.Command("skill")
|
|
20
|
+
.description("safe/read-only: skill packet operations")
|
|
21
|
+
.showHelpAfterError()
|
|
22
|
+
.action(() => {
|
|
23
|
+
command.outputHelp();
|
|
24
|
+
});
|
|
25
|
+
const packetCommand = new commander_1.Command("packet")
|
|
26
|
+
.description("safe/read-only: generate a Polaris skill packet for the given skill. " +
|
|
27
|
+
"Any documents produced during the session must be placed in smartdocs/raw/ first — never written directly to active tiers.")
|
|
28
|
+
.argument("<skill-name>", `skill to generate a packet for (${generator_js_1.SUPPORTED_SKILLS.join(", ")})`)
|
|
29
|
+
.action((skillName) => {
|
|
30
|
+
if (!generator_js_1.SUPPORTED_SKILLS.includes(skillName)) {
|
|
31
|
+
process.stderr.write(`Unknown skill: ${skillName}\nSupported skills: ${generator_js_1.SUPPORTED_SKILLS.join(", ")}\n`);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
const config = (0, loader_js_1.loadConfig)(options.repoRoot);
|
|
35
|
+
const skillPacketConfig = config.skill_packet ?? {
|
|
36
|
+
analysis_confidence_threshold: 85,
|
|
37
|
+
auto_deep_analysis: false,
|
|
38
|
+
allow_cross_provider_delegation: false,
|
|
39
|
+
};
|
|
40
|
+
const packet = (0, generator_js_1.generateSkillPacket)(skillName, {
|
|
41
|
+
analysis_confidence_threshold: skillPacketConfig.analysis_confidence_threshold ?? 85,
|
|
42
|
+
auto_deep_analysis: skillPacketConfig.auto_deep_analysis ?? false,
|
|
43
|
+
allow_cross_provider_delegation: skillPacketConfig.allow_cross_provider_delegation ?? false,
|
|
44
|
+
});
|
|
45
|
+
process.stdout.write(`${JSON.stringify(packet, null, 2)}\n`);
|
|
46
|
+
});
|
|
47
|
+
command.addCommand(packetCommand);
|
|
48
|
+
return command;
|
|
49
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.auditIngestRiskSurface = auditIngestRiskSurface;
|
|
4
|
+
exports.formatAuditMarkdown = formatAuditMarkdown;
|
|
5
|
+
exports.formatAuditSummaryTable = formatAuditSummaryTable;
|
|
6
|
+
const node_fs_1 = require("node:fs");
|
|
7
|
+
const node_child_process_1 = require("node:child_process");
|
|
8
|
+
const node_path_1 = require("node:path");
|
|
9
|
+
const smartdoc_ignore_js_1 = require("./smartdoc-ignore.js");
|
|
10
|
+
const ingest_js_1 = require("./ingest.js");
|
|
11
|
+
const GENERATED_BASENAME_RE = /(?:summary|index|moc|overview)(?:[._-]|$)/i;
|
|
12
|
+
const GENERATED_SUFFIX_RE = /(?:-summary|-index)\.md$/i;
|
|
13
|
+
function isGeneratedBasename(filePath) {
|
|
14
|
+
const base = (0, node_path_1.basename)(filePath);
|
|
15
|
+
return GENERATED_BASENAME_RE.test(base) || GENERATED_SUFFIX_RE.test(base);
|
|
16
|
+
}
|
|
17
|
+
function auditIngestRiskSurface(repoRoot) {
|
|
18
|
+
const absRoot = (0, node_path_1.resolve)(repoRoot);
|
|
19
|
+
let rawOutput;
|
|
20
|
+
try {
|
|
21
|
+
rawOutput = (0, node_child_process_1.execFileSync)("git", ["ls-files", "--", "*.md"], {
|
|
22
|
+
cwd: absRoot,
|
|
23
|
+
encoding: "utf-8",
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
28
|
+
throw new Error(`Failed to list tracked markdown files via git: ${message}`);
|
|
29
|
+
}
|
|
30
|
+
const trackedFiles = rawOutput
|
|
31
|
+
.split("\n")
|
|
32
|
+
.map((l) => l.trim())
|
|
33
|
+
.filter((l) => l.length > 0);
|
|
34
|
+
const findings = [];
|
|
35
|
+
for (const relPath of trackedFiles) {
|
|
36
|
+
const absPath = (0, node_path_1.resolve)(absRoot, relPath);
|
|
37
|
+
const eligibility = (0, smartdoc_ignore_js_1.isIngestIneligible)(relPath, absRoot);
|
|
38
|
+
// MEDIUM: file is in smartdocs/ canonical output dirs
|
|
39
|
+
// Check this BEFORE the ineligible branch so these findings are always emitted
|
|
40
|
+
if (relPath.startsWith("smartdocs/")) {
|
|
41
|
+
const protection = eligibility.ineligible
|
|
42
|
+
? "isIngestIneligible"
|
|
43
|
+
: null;
|
|
44
|
+
findings.push({
|
|
45
|
+
filePath: relPath,
|
|
46
|
+
risk: "MEDIUM",
|
|
47
|
+
reason: "File in smartdocs/ canonical output — migrateDocs() would attempt to move it back",
|
|
48
|
+
pipelineStage: "migrate",
|
|
49
|
+
currentProtection: protection,
|
|
50
|
+
proposedEnforcementPoint: "endpoint artifact protection in migrateDocs()",
|
|
51
|
+
});
|
|
52
|
+
// Don't continue yet - still need to check ineligible for HIGH findings
|
|
53
|
+
}
|
|
54
|
+
if (eligibility.ineligible) {
|
|
55
|
+
// HIGH: endpoint artifact that could be ingested
|
|
56
|
+
findings.push({
|
|
57
|
+
filePath: relPath,
|
|
58
|
+
risk: "HIGH",
|
|
59
|
+
reason: "Endpoint artifact matched by .smartdocignore default patterns — ingest would be blocked but file is tracked",
|
|
60
|
+
pipelineStage: "ingest",
|
|
61
|
+
currentProtection: "isIngestIneligible",
|
|
62
|
+
proposedEnforcementPoint: "smartdoc-ignore check in ingestDocs()",
|
|
63
|
+
});
|
|
64
|
+
// HIGH (second case): endpoint artifact that would classify as doctrine-candidate
|
|
65
|
+
if ((0, node_fs_1.existsSync)(absPath)) {
|
|
66
|
+
let content;
|
|
67
|
+
try {
|
|
68
|
+
content = (0, node_fs_1.readFileSync)(absPath, "utf-8");
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
content = "";
|
|
72
|
+
}
|
|
73
|
+
const classification = (0, ingest_js_1.classifyDoc)(content, relPath);
|
|
74
|
+
if (classification === "doctrine-candidate") {
|
|
75
|
+
findings.push({
|
|
76
|
+
filePath: relPath,
|
|
77
|
+
risk: "HIGH",
|
|
78
|
+
reason: "Endpoint artifact would be classified as doctrine-candidate — if bypass were used, it would enter doctrine pipeline",
|
|
79
|
+
pipelineStage: "classify",
|
|
80
|
+
currentProtection: "isIngestIneligible",
|
|
81
|
+
proposedEnforcementPoint: "endpoint artifact check before classifyDoc()",
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
// MEDIUM: generated summary/index/MOC/overview basename
|
|
88
|
+
if (isGeneratedBasename(relPath)) {
|
|
89
|
+
const protection = (0, smartdoc_ignore_js_1.isIngestIneligible)(relPath, absRoot).ineligible
|
|
90
|
+
? "isIngestIneligible"
|
|
91
|
+
: null;
|
|
92
|
+
findings.push({
|
|
93
|
+
filePath: relPath,
|
|
94
|
+
risk: "MEDIUM",
|
|
95
|
+
reason: "Generated summary or index file — ingest risk if not protected",
|
|
96
|
+
pipelineStage: "ingest",
|
|
97
|
+
currentProtection: protection,
|
|
98
|
+
proposedEnforcementPoint: "smartdoc-ignore pattern or explicit check",
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const high = findings.filter((f) => f.risk === "HIGH").length;
|
|
103
|
+
const medium = findings.filter((f) => f.risk === "MEDIUM").length;
|
|
104
|
+
const low = findings.filter((f) => f.risk === "LOW").length;
|
|
105
|
+
const protectedBySmartdocIgnore = findings.filter((f) => f.currentProtection === "isIngestIneligible").length;
|
|
106
|
+
return {
|
|
107
|
+
scanDate: new Date().toISOString(),
|
|
108
|
+
repoRoot: absRoot,
|
|
109
|
+
findings,
|
|
110
|
+
summary: {
|
|
111
|
+
high,
|
|
112
|
+
medium,
|
|
113
|
+
low,
|
|
114
|
+
protectedBySmartdocIgnore,
|
|
115
|
+
alreadyProtected: protectedBySmartdocIgnore,
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function formatAuditMarkdown(result) {
|
|
120
|
+
const lines = [
|
|
121
|
+
"# Polaris Smart Docs — Ingest Risk Audit",
|
|
122
|
+
"",
|
|
123
|
+
`**Scanned:** ${result.repoRoot}`,
|
|
124
|
+
`**Date:** ${result.scanDate}`,
|
|
125
|
+
"",
|
|
126
|
+
`## Summary`,
|
|
127
|
+
"",
|
|
128
|
+
`| Risk | Count |`,
|
|
129
|
+
`|------|-------|`,
|
|
130
|
+
`| HIGH | ${result.summary.high} |`,
|
|
131
|
+
`| MEDIUM | ${result.summary.medium} |`,
|
|
132
|
+
`| LOW | ${result.summary.low} |`,
|
|
133
|
+
`| Protected by .smartdocignore | ${result.summary.protectedBySmartdocIgnore} |`,
|
|
134
|
+
"",
|
|
135
|
+
];
|
|
136
|
+
const highFindings = result.findings.filter((f) => f.risk === "HIGH");
|
|
137
|
+
const mediumFindings = result.findings.filter((f) => f.risk === "MEDIUM");
|
|
138
|
+
const lowFindings = result.findings.filter((f) => f.risk === "LOW");
|
|
139
|
+
if (highFindings.length > 0) {
|
|
140
|
+
lines.push("## HIGH Risk Findings", "");
|
|
141
|
+
for (const f of highFindings) {
|
|
142
|
+
lines.push(`### \`${f.filePath}\``, "", `- **Reason:** ${f.reason}`, `- **Pipeline stage:** ${f.pipelineStage}`, `- **Current protection:** ${f.currentProtection ?? "none"}`, `- **Proposed enforcement:** ${f.proposedEnforcementPoint}`, "");
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (mediumFindings.length > 0) {
|
|
146
|
+
lines.push("## MEDIUM Risk Findings", "");
|
|
147
|
+
for (const f of mediumFindings) {
|
|
148
|
+
lines.push(`### \`${f.filePath}\``, "", `- **Reason:** ${f.reason}`, `- **Pipeline stage:** ${f.pipelineStage}`, `- **Current protection:** ${f.currentProtection ?? "none"}`, `- **Proposed enforcement:** ${f.proposedEnforcementPoint}`, "");
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (lowFindings.length > 0) {
|
|
152
|
+
lines.push("## LOW Risk Findings", "");
|
|
153
|
+
for (const f of lowFindings) {
|
|
154
|
+
lines.push(`### \`${f.filePath}\``, "", `- **Reason:** ${f.reason}`, `- **Pipeline stage:** ${f.pipelineStage}`, `- **Current protection:** ${f.currentProtection ?? "none"}`, `- **Proposed enforcement:** ${f.proposedEnforcementPoint}`, "");
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (result.findings.length === 0) {
|
|
158
|
+
lines.push("_No findings — no files at risk of recursive ingestion detected._", "");
|
|
159
|
+
}
|
|
160
|
+
return lines.join("\n");
|
|
161
|
+
}
|
|
162
|
+
function formatAuditSummaryTable(result) {
|
|
163
|
+
const lines = [
|
|
164
|
+
"Polaris Smart Docs — Ingest Risk Audit",
|
|
165
|
+
`Scanned: ${result.repoRoot} Date: ${result.scanDate}`,
|
|
166
|
+
"",
|
|
167
|
+
];
|
|
168
|
+
const highFindings = result.findings.filter((f) => f.risk === "HIGH");
|
|
169
|
+
const mediumFindings = result.findings.filter((f) => f.risk === "MEDIUM");
|
|
170
|
+
const lowFindings = result.findings.filter((f) => f.risk === "LOW");
|
|
171
|
+
if (highFindings.length > 0) {
|
|
172
|
+
lines.push(`HIGH (${highFindings.length}):`);
|
|
173
|
+
for (const f of highFindings) {
|
|
174
|
+
lines.push(` ${f.filePath} — ${f.reason} [stage: ${f.pipelineStage}]`);
|
|
175
|
+
}
|
|
176
|
+
lines.push("");
|
|
177
|
+
}
|
|
178
|
+
if (mediumFindings.length > 0) {
|
|
179
|
+
lines.push(`MEDIUM (${mediumFindings.length}):`);
|
|
180
|
+
for (const f of mediumFindings) {
|
|
181
|
+
lines.push(` ${f.filePath} — ${f.reason} [stage: ${f.pipelineStage}]`);
|
|
182
|
+
}
|
|
183
|
+
lines.push("");
|
|
184
|
+
}
|
|
185
|
+
if (lowFindings.length > 0) {
|
|
186
|
+
lines.push(`LOW (${lowFindings.length}):`);
|
|
187
|
+
for (const f of lowFindings) {
|
|
188
|
+
lines.push(` ${f.filePath} — ${f.reason} [stage: ${f.pipelineStage}]`);
|
|
189
|
+
}
|
|
190
|
+
lines.push("");
|
|
191
|
+
}
|
|
192
|
+
lines.push("Summary:", ` High: ${result.summary.high} Medium: ${result.summary.medium} Low: ${result.summary.low}`, ` Protected by .smartdocignore: ${result.summary.protectedBySmartdocIgnore}`);
|
|
193
|
+
return lines.join("\n");
|
|
194
|
+
}
|