@soleri/core 9.14.4 → 9.16.7
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/data/flows/deliver.flow.yaml +11 -0
- package/data/flows/design.flow.yaml +4 -14
- package/data/flows/enhance.flow.yaml +10 -0
- package/data/flows/explore.flow.yaml +16 -0
- package/data/flows/fix.flow.yaml +1 -1
- package/data/flows/review.flow.yaml +13 -4
- package/dist/brain/brain.d.ts +9 -0
- package/dist/brain/brain.d.ts.map +1 -1
- package/dist/brain/brain.js +11 -1
- package/dist/brain/brain.js.map +1 -1
- package/dist/brain/intelligence.d.ts.map +1 -1
- package/dist/brain/intelligence.js +24 -0
- package/dist/brain/intelligence.js.map +1 -1
- package/dist/brain/types.d.ts +1 -0
- package/dist/brain/types.d.ts.map +1 -1
- package/dist/capabilities/chain-mapping.d.ts.map +1 -1
- package/dist/capabilities/chain-mapping.js +5 -4
- package/dist/capabilities/chain-mapping.js.map +1 -1
- package/dist/capabilities/registry.d.ts +6 -0
- package/dist/capabilities/registry.d.ts.map +1 -1
- package/dist/capabilities/registry.js +3 -2
- package/dist/capabilities/registry.js.map +1 -1
- package/dist/chat/chat-session.d.ts +6 -0
- package/dist/chat/chat-session.d.ts.map +1 -1
- package/dist/chat/chat-session.js +68 -17
- package/dist/chat/chat-session.js.map +1 -1
- package/dist/context/context-engine.js +1 -1
- package/dist/context/context-engine.js.map +1 -1
- package/dist/curator/curator.d.ts +6 -0
- package/dist/curator/curator.d.ts.map +1 -1
- package/dist/curator/curator.js +138 -0
- package/dist/curator/curator.js.map +1 -1
- package/dist/curator/types.d.ts +10 -0
- package/dist/curator/types.d.ts.map +1 -1
- package/dist/engine/bin/soleri-engine.js +0 -0
- package/dist/engine/core-ops.d.ts.map +1 -1
- package/dist/engine/core-ops.js +38 -1
- package/dist/engine/core-ops.js.map +1 -1
- package/dist/flows/epilogue.d.ts +5 -1
- package/dist/flows/epilogue.d.ts.map +1 -1
- package/dist/flows/epilogue.js +11 -3
- package/dist/flows/epilogue.js.map +1 -1
- package/dist/flows/executor.d.ts.map +1 -1
- package/dist/flows/executor.js +13 -5
- package/dist/flows/executor.js.map +1 -1
- package/dist/flows/index.d.ts +1 -2
- package/dist/flows/index.d.ts.map +1 -1
- package/dist/flows/index.js +1 -0
- package/dist/flows/index.js.map +1 -1
- package/dist/flows/plan-builder.d.ts +17 -1
- package/dist/flows/plan-builder.d.ts.map +1 -1
- package/dist/flows/plan-builder.js +67 -6
- package/dist/flows/plan-builder.js.map +1 -1
- package/dist/flows/probes.d.ts +1 -1
- package/dist/flows/probes.d.ts.map +1 -1
- package/dist/flows/probes.js +15 -3
- package/dist/flows/probes.js.map +1 -1
- package/dist/flows/types.d.ts +47 -20
- package/dist/flows/types.d.ts.map +1 -1
- package/dist/flows/types.js +6 -1
- package/dist/flows/types.js.map +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/intake/content-classifier.d.ts +10 -4
- package/dist/intake/content-classifier.d.ts.map +1 -1
- package/dist/intake/content-classifier.js +19 -5
- package/dist/intake/content-classifier.js.map +1 -1
- package/dist/intake/text-ingester.d.ts +18 -0
- package/dist/intake/text-ingester.d.ts.map +1 -1
- package/dist/intake/text-ingester.js +37 -13
- package/dist/intake/text-ingester.js.map +1 -1
- package/dist/packs/pack-installer.d.ts.map +1 -1
- package/dist/packs/pack-installer.js +28 -2
- package/dist/packs/pack-installer.js.map +1 -1
- package/dist/planning/planner-types.d.ts +2 -0
- package/dist/planning/planner-types.d.ts.map +1 -1
- package/dist/planning/planner.d.ts +4 -0
- package/dist/planning/planner.d.ts.map +1 -1
- package/dist/planning/planner.js +50 -4
- package/dist/planning/planner.js.map +1 -1
- package/dist/playbooks/playbook-executor.d.ts +10 -1
- package/dist/playbooks/playbook-executor.d.ts.map +1 -1
- package/dist/playbooks/playbook-executor.js +8 -2
- package/dist/playbooks/playbook-executor.js.map +1 -1
- package/dist/playbooks/playbook-types.d.ts +8 -0
- package/dist/playbooks/playbook-types.d.ts.map +1 -1
- package/dist/plugins/types.d.ts +2 -2
- package/dist/runtime/admin-extra-ops.d.ts.map +1 -1
- package/dist/runtime/admin-extra-ops.js +30 -0
- package/dist/runtime/admin-extra-ops.js.map +1 -1
- package/dist/runtime/admin-ops.d.ts.map +1 -1
- package/dist/runtime/admin-ops.js +60 -21
- package/dist/runtime/admin-ops.js.map +1 -1
- package/dist/runtime/admin-setup-ops.d.ts +11 -0
- package/dist/runtime/admin-setup-ops.d.ts.map +1 -1
- package/dist/runtime/admin-setup-ops.js +146 -37
- package/dist/runtime/admin-setup-ops.js.map +1 -1
- package/dist/runtime/capture-ops.d.ts.map +1 -1
- package/dist/runtime/capture-ops.js +38 -12
- package/dist/runtime/capture-ops.js.map +1 -1
- package/dist/runtime/facades/brain-facade.d.ts.map +1 -1
- package/dist/runtime/facades/brain-facade.js +16 -4
- package/dist/runtime/facades/brain-facade.js.map +1 -1
- package/dist/runtime/facades/context-facade.d.ts.map +1 -1
- package/dist/runtime/facades/context-facade.js +9 -3
- package/dist/runtime/facades/context-facade.js.map +1 -1
- package/dist/runtime/facades/memory-facade.d.ts.map +1 -1
- package/dist/runtime/facades/memory-facade.js +20 -7
- package/dist/runtime/facades/memory-facade.js.map +1 -1
- package/dist/runtime/facades/orchestrate-facade.d.ts.map +1 -1
- package/dist/runtime/facades/orchestrate-facade.js +40 -1
- package/dist/runtime/facades/orchestrate-facade.js.map +1 -1
- package/dist/runtime/facades/plan-facade.d.ts.map +1 -1
- package/dist/runtime/facades/plan-facade.js +113 -4
- package/dist/runtime/facades/plan-facade.js.map +1 -1
- package/dist/runtime/facades/vault-facade.d.ts.map +1 -1
- package/dist/runtime/facades/vault-facade.js +24 -3
- package/dist/runtime/facades/vault-facade.js.map +1 -1
- package/dist/runtime/orchestrate-ops.d.ts +21 -0
- package/dist/runtime/orchestrate-ops.d.ts.map +1 -1
- package/dist/runtime/orchestrate-ops.js +132 -38
- package/dist/runtime/orchestrate-ops.js.map +1 -1
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +16 -0
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/runtime/schema-helpers.d.ts.map +1 -1
- package/dist/runtime/schema-helpers.js +4 -0
- package/dist/runtime/schema-helpers.js.map +1 -1
- package/dist/runtime/types.d.ts +19 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/vault-linking-ops.d.ts.map +1 -1
- package/dist/runtime/vault-linking-ops.js +16 -3
- package/dist/runtime/vault-linking-ops.js.map +1 -1
- package/dist/scheduler/cron-validator.d.ts +15 -0
- package/dist/scheduler/cron-validator.d.ts.map +1 -0
- package/dist/scheduler/cron-validator.js +93 -0
- package/dist/scheduler/cron-validator.js.map +1 -0
- package/dist/scheduler/platform-linux.d.ts +14 -0
- package/dist/scheduler/platform-linux.d.ts.map +1 -0
- package/dist/scheduler/platform-linux.js +107 -0
- package/dist/scheduler/platform-linux.js.map +1 -0
- package/dist/scheduler/platform-macos.d.ts +15 -0
- package/dist/scheduler/platform-macos.d.ts.map +1 -0
- package/dist/scheduler/platform-macos.js +131 -0
- package/dist/scheduler/platform-macos.js.map +1 -0
- package/dist/scheduler/scheduler-ops.d.ts +14 -0
- package/dist/scheduler/scheduler-ops.d.ts.map +1 -0
- package/dist/scheduler/scheduler-ops.js +77 -0
- package/dist/scheduler/scheduler-ops.js.map +1 -0
- package/dist/scheduler/scheduler.d.ts +55 -0
- package/dist/scheduler/scheduler.d.ts.map +1 -0
- package/dist/scheduler/scheduler.js +144 -0
- package/dist/scheduler/scheduler.js.map +1 -0
- package/dist/scheduler/types.d.ts +48 -0
- package/dist/scheduler/types.d.ts.map +1 -0
- package/dist/scheduler/types.js +6 -0
- package/dist/scheduler/types.js.map +1 -0
- package/dist/skills/sync-skills.d.ts +11 -0
- package/dist/skills/sync-skills.d.ts.map +1 -1
- package/dist/skills/sync-skills.js +132 -38
- package/dist/skills/sync-skills.js.map +1 -1
- package/dist/skills/validate-skills.d.ts +32 -0
- package/dist/skills/validate-skills.d.ts.map +1 -0
- package/dist/skills/validate-skills.js +396 -0
- package/dist/skills/validate-skills.js.map +1 -0
- package/dist/utils/worktree-reaper.d.ts +38 -0
- package/dist/utils/worktree-reaper.d.ts.map +1 -0
- package/dist/utils/worktree-reaper.js +85 -0
- package/dist/utils/worktree-reaper.js.map +1 -0
- package/dist/vault/default-canonical-tags.d.ts +15 -0
- package/dist/vault/default-canonical-tags.d.ts.map +1 -0
- package/dist/vault/default-canonical-tags.js +65 -0
- package/dist/vault/default-canonical-tags.js.map +1 -0
- package/dist/vault/scope-detector.d.ts.map +1 -1
- package/dist/vault/scope-detector.js +37 -4
- package/dist/vault/scope-detector.js.map +1 -1
- package/dist/vault/tag-normalizer.d.ts +42 -0
- package/dist/vault/tag-normalizer.d.ts.map +1 -0
- package/dist/vault/tag-normalizer.js +157 -0
- package/dist/vault/tag-normalizer.js.map +1 -0
- package/dist/vault/vault-entries.d.ts.map +1 -1
- package/dist/vault/vault-entries.js +3 -1
- package/dist/vault/vault-entries.js.map +1 -1
- package/package.json +5 -1
- package/src/__tests__/embeddings.test.ts +3 -3
- package/src/agency/agency-manager.test.ts +4 -4
- package/src/agency/default-rules.test.ts +0 -13
- package/src/brain/brain-intelligence.test.ts +0 -5
- package/src/brain/brain.ts +25 -1
- package/src/brain/intelligence.ts +25 -0
- package/src/brain/second-brain-features.test.ts +2 -14
- package/src/brain/types.ts +1 -0
- package/src/capabilities/chain-mapping.test.ts +1 -6
- package/src/capabilities/chain-mapping.ts +6 -4
- package/src/capabilities/registry.test.ts +1 -1
- package/src/capabilities/registry.ts +9 -2
- package/src/chat/agent-loop.test.ts +1 -1
- package/src/chat/chat-enhanced.test.ts +0 -8
- package/src/chat/chat-session.ts +75 -17
- package/src/chat/chat-transport.test.ts +31 -1
- package/src/claudemd/compose.test.ts +0 -5
- package/src/context/context-engine.test.ts +0 -1
- package/src/context/context-engine.ts +1 -1
- package/src/control/intent-router.test.ts +2 -2
- package/src/curator/curator.ts +180 -0
- package/src/curator/tag-manager.test.ts +0 -4
- package/src/curator/types.ts +10 -0
- package/src/domain-packs/types.test.ts +0 -5
- package/src/dream/dream.test.ts +0 -7
- package/src/enforcement/registry.test.ts +2 -2
- package/src/engine/core-ops.test.ts +4 -22
- package/src/engine/core-ops.ts +36 -1
- package/src/engine/module-manifest.test.ts +1 -31
- package/src/engine/register-engine.test.ts +3 -33
- package/src/errors/retry.test.ts +3 -1
- package/src/flows/chain-runner.test.ts +0 -6
- package/src/flows/context-router.test.ts +3 -3
- package/src/flows/epilogue.test.ts +40 -2
- package/src/flows/epilogue.ts +11 -2
- package/src/flows/executor.test.ts +48 -2
- package/src/flows/executor.ts +15 -5
- package/src/flows/index.ts +1 -3
- package/src/flows/plan-builder.test.ts +201 -0
- package/src/flows/plan-builder.ts +81 -5
- package/src/flows/probes.ts +17 -3
- package/src/flows/types.ts +31 -2
- package/src/health/health-registry.test.ts +3 -1
- package/src/index.ts +24 -0
- package/src/intake/content-classifier.ts +22 -4
- package/src/intake/dedup-gate.test.ts +2 -6
- package/src/intake/text-ingester.test.ts +3 -4
- package/src/intake/text-ingester.ts +61 -12
- package/src/llm/llm-client.test.ts +1 -1
- package/src/llm/utils.test.ts +1 -1
- package/src/migrations/migration-runner.test.ts +0 -1
- package/src/operator/operator-context-store.test.ts +0 -13
- package/src/operator/operator-profile.test.ts +2 -20
- package/src/packs/pack-installer.ts +28 -2
- package/src/packs/pack-system.test.ts +2 -2
- package/src/persona/defaults.test.ts +19 -19
- package/src/planning/gap-passes.test.ts +0 -46
- package/src/planning/gap-patterns.test.ts +0 -42
- package/src/planning/goal-ancestry.test.ts +3 -1
- package/src/planning/plan-lifecycle.test.ts +15 -7
- package/src/planning/planner-types.ts +2 -0
- package/src/planning/planner.test.ts +86 -90
- package/src/planning/planner.ts +56 -4
- package/src/planning/reconciliation-engine.test.ts +3 -10
- package/src/planning/task-complexity-assessor.test.ts +0 -5
- package/src/planning/task-verifier.test.ts +3 -1
- package/src/playbooks/generic/generic-playbooks.test.ts +0 -28
- package/src/playbooks/index.test.ts +0 -55
- package/src/playbooks/playbook-executor.test.ts +76 -0
- package/src/playbooks/playbook-executor.ts +24 -3
- package/src/playbooks/playbook-types.ts +8 -0
- package/src/plugins/plugin-registry.test.ts +6 -2
- package/src/project/project-registry.test.ts +2 -0
- package/src/queue/async-infrastructure.test.ts +6 -4
- package/src/queue/job-queue.test.ts +13 -7
- package/src/runtime/admin-extra-ops.test.ts +35 -30
- package/src/runtime/admin-extra-ops.ts +30 -0
- package/src/runtime/admin-ops.test.ts +0 -4
- package/src/runtime/admin-ops.ts +63 -21
- package/src/runtime/admin-setup-ops.test.ts +229 -13
- package/src/runtime/admin-setup-ops.ts +145 -36
- package/src/runtime/archive-ops.test.ts +0 -28
- package/src/runtime/branching-ops.test.ts +0 -17
- package/src/runtime/capture-ops.test.ts +41 -16
- package/src/runtime/capture-ops.ts +78 -46
- package/src/runtime/chain-ops.test.ts +0 -21
- package/src/runtime/facades/admin-facade.test.ts +0 -34
- package/src/runtime/facades/agency-facade.test.ts +0 -39
- package/src/runtime/facades/archive-facade.test.ts +0 -43
- package/src/runtime/facades/brain-facade.test.ts +8 -99
- package/src/runtime/facades/brain-facade.ts +29 -12
- package/src/runtime/facades/branching-facade.test.ts +30 -17
- package/src/runtime/facades/chat-facade.test.ts +0 -91
- package/src/runtime/facades/chat-service-ops.test.ts +0 -24
- package/src/runtime/facades/chat-session-ops.test.ts +0 -12
- package/src/runtime/facades/chat-transport-ops.test.ts +0 -23
- package/src/runtime/facades/context-facade.test.ts +0 -17
- package/src/runtime/facades/context-facade.ts +11 -4
- package/src/runtime/facades/control-facade.test.ts +0 -30
- package/src/runtime/facades/curator-facade.test.ts +0 -33
- package/src/runtime/facades/intake-facade.test.ts +0 -33
- package/src/runtime/facades/links-facade.test.ts +0 -37
- package/src/runtime/facades/loop-facade.test.ts +0 -26
- package/src/runtime/facades/memory-facade.test.ts +0 -18
- package/src/runtime/facades/memory-facade.ts +27 -11
- package/src/runtime/facades/operator-facade.test.ts +0 -31
- package/src/runtime/facades/orchestrate-facade.test.ts +0 -21
- package/src/runtime/facades/orchestrate-facade.ts +39 -1
- package/src/runtime/facades/plan-facade.test.ts +7 -32
- package/src/runtime/facades/plan-facade.ts +137 -4
- package/src/runtime/facades/review-facade.test.ts +1 -49
- package/src/runtime/facades/sync-facade.test.ts +24 -41
- package/src/runtime/facades/tier-facade.test.ts +30 -22
- package/src/runtime/facades/vault-facade.test.ts +0 -41
- package/src/runtime/facades/vault-facade.ts +26 -3
- package/src/runtime/grading-ops.test.ts +0 -27
- package/src/runtime/intake-ops.test.ts +0 -19
- package/src/runtime/loop-ops.test.ts +0 -48
- package/src/runtime/memory-cross-project-ops.test.ts +0 -14
- package/src/runtime/memory-extra-ops.test.ts +4 -8
- package/src/runtime/orchestrate-ops.test.ts +238 -19
- package/src/runtime/orchestrate-ops.ts +166 -41
- package/src/runtime/pack-ops.test.ts +0 -26
- package/src/runtime/planning-extra-ops.test.ts +2 -14
- package/src/runtime/playbook-ops-execution.test.ts +9 -20
- package/src/runtime/playbook-ops.test.ts +4 -67
- package/src/runtime/review-ops.test.ts +0 -15
- package/src/runtime/runtime.ts +18 -0
- package/src/runtime/schema-helpers.ts +4 -0
- package/src/runtime/sync-ops.test.ts +0 -18
- package/src/runtime/tier-ops.test.ts +0 -21
- package/src/runtime/types.ts +19 -0
- package/src/runtime/vault-extra-ops.test.ts +0 -12
- package/src/runtime/vault-linking-ops.test.ts +0 -4
- package/src/runtime/vault-linking-ops.ts +26 -8
- package/src/runtime/vault-sharing-ops.test.ts +0 -9
- package/src/scheduler/cron-validator.ts +101 -0
- package/src/scheduler/platform-linux.ts +122 -0
- package/src/scheduler/platform-macos.ts +150 -0
- package/src/scheduler/scheduler-ops.ts +77 -0
- package/src/scheduler/scheduler.test.ts +247 -0
- package/src/scheduler/scheduler.ts +174 -0
- package/src/scheduler/types.ts +52 -0
- package/src/skills/__tests__/sync-skills.test.ts +6 -17
- package/src/skills/global-claude-md.test.ts +113 -0
- package/src/skills/sync-skills.ts +143 -35
- package/src/skills/validate-skills.test.ts +206 -0
- package/src/skills/validate-skills.ts +470 -0
- package/src/telemetry/telemetry.test.ts +1 -0
- package/src/transport/http-server.test.ts +3 -0
- package/src/transport/session-manager.test.ts +3 -1
- package/src/transport/token-auth.test.ts +6 -9
- package/src/transport/ws-server.test.ts +10 -2
- package/src/utils/worktree-reaper.ts +113 -0
- package/src/vault/__tests__/vault-characterization.test.ts +0 -108
- package/src/vault/default-canonical-tags.ts +64 -0
- package/src/vault/linking.test.ts +0 -2
- package/src/vault/playbook.test.ts +4 -1
- package/src/vault/scope-detector.test.ts +3 -1
- package/src/vault/scope-detector.ts +42 -4
- package/src/vault/tag-normalizer.test.ts +214 -0
- package/src/vault/tag-normalizer.ts +188 -0
- package/src/vault/vault-connect.test.ts +1 -1
- package/src/vault/vault-entries.ts +3 -1
- package/src/vault/vault.test.ts +23 -8
- package/dist/embeddings/index.d.ts +0 -5
- package/dist/embeddings/index.d.ts.map +0 -1
- package/dist/embeddings/index.js +0 -3
- package/dist/embeddings/index.js.map +0 -1
package/src/index.ts
CHANGED
|
@@ -18,6 +18,8 @@ export { WorkspaceResolver } from './subagent/workspace-resolver.js';
|
|
|
18
18
|
export { ConcurrencyManager } from './subagent/concurrency-manager.js';
|
|
19
19
|
export { OrphanReaper } from './subagent/orphan-reaper.js';
|
|
20
20
|
export type { ReapResult } from './subagent/orphan-reaper.js';
|
|
21
|
+
export { worktreeReap, worktreeStatus } from './utils/worktree-reaper.js';
|
|
22
|
+
export type { ReapReport, WorktreeStatus } from './utils/worktree-reaper.js';
|
|
21
23
|
export { aggregate as aggregateResults } from './subagent/result-aggregator.js';
|
|
22
24
|
export type {
|
|
23
25
|
SubagentTask,
|
|
@@ -101,6 +103,13 @@ export type {
|
|
|
101
103
|
} from './vault/vault-types.js';
|
|
102
104
|
export { validatePlaybook, parsePlaybookFromEntry } from './vault/playbook.js';
|
|
103
105
|
export type { Playbook, PlaybookStep, PlaybookValidationResult } from './vault/playbook.js';
|
|
106
|
+
export { DEFAULT_CANONICAL_TAGS } from './vault/default-canonical-tags.js';
|
|
107
|
+
export {
|
|
108
|
+
normalizeTag as normalizeTagCanonical,
|
|
109
|
+
normalizeTags as normalizeTagsCanonical,
|
|
110
|
+
isMetadataTag,
|
|
111
|
+
computeEditDistance,
|
|
112
|
+
} from './vault/tag-normalizer.js';
|
|
104
113
|
|
|
105
114
|
// ─── Playbook System (registry, matching, seeding) ─────────────────
|
|
106
115
|
export {
|
|
@@ -949,3 +958,18 @@ export type { WorkflowGate, WorkflowOverride } from './workflows/index.js';
|
|
|
949
958
|
// ─── Update Check ────────────────────────────────────────────────────
|
|
950
959
|
export { checkForUpdate, buildChangelogUrl, detectBreakingChanges } from './update-check.js';
|
|
951
960
|
export type { UpdateInfo } from './update-check.js';
|
|
961
|
+
|
|
962
|
+
// ─── Settings Hooks Sync ─────────────────────────────────────────────
|
|
963
|
+
export { syncHooksToClaudeSettings } from './runtime/admin-setup-ops.js';
|
|
964
|
+
|
|
965
|
+
// ─── Scheduler ───────────────────────────────────────────────────────
|
|
966
|
+
export { Scheduler, InMemorySchedulerStore } from './scheduler/scheduler.js';
|
|
967
|
+
export type { SchedulerStore } from './scheduler/scheduler.js';
|
|
968
|
+
export { createSchedulerOps } from './scheduler/scheduler-ops.js';
|
|
969
|
+
export { validateCron, estimateMinIntervalHours } from './scheduler/cron-validator.js';
|
|
970
|
+
export type {
|
|
971
|
+
ScheduledTask,
|
|
972
|
+
CreateTaskInput,
|
|
973
|
+
TaskListEntry,
|
|
974
|
+
PlatformAdapter,
|
|
975
|
+
} from './scheduler/types.js';
|
|
@@ -45,22 +45,40 @@ Rules:
|
|
|
45
45
|
// CLASSIFIER
|
|
46
46
|
// =============================================================================
|
|
47
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Build the classification system prompt, optionally injecting a canonical tag list.
|
|
50
|
+
* When canonical tags are provided, the LLM is guided to prefer them.
|
|
51
|
+
*/
|
|
52
|
+
export function buildClassificationPrompt(canonicalTags?: string[]): string {
|
|
53
|
+
if (!canonicalTags || canonicalTags.length === 0) {
|
|
54
|
+
return CLASSIFICATION_PROMPT;
|
|
55
|
+
}
|
|
56
|
+
const tagList = canonicalTags.join(', ');
|
|
57
|
+
return (
|
|
58
|
+
CLASSIFICATION_PROMPT +
|
|
59
|
+
`\n\nTag guidance: Use only tags from this approved list where possible: ${tagList}. Create a new tag only when nothing from the list fits the concept.`
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
48
63
|
/**
|
|
49
64
|
* Classify a text chunk into structured knowledge items using an LLM.
|
|
50
65
|
*
|
|
51
|
-
* @param llm
|
|
52
|
-
* @param chunkText
|
|
53
|
-
* @param citation
|
|
66
|
+
* @param llm - LLMClient instance
|
|
67
|
+
* @param chunkText - The text to classify
|
|
68
|
+
* @param citation - Source citation (e.g. "book.pdf, pages 12-15")
|
|
69
|
+
* @param canonicalTags - Optional canonical tag list to inject into the prompt
|
|
54
70
|
* @returns Classified items, or [] on any error
|
|
55
71
|
*/
|
|
56
72
|
export async function classifyChunk(
|
|
57
73
|
llm: LLMClient,
|
|
58
74
|
chunkText: string,
|
|
59
75
|
citation: string,
|
|
76
|
+
canonicalTags?: string[],
|
|
60
77
|
): Promise<ClassifiedItem[]> {
|
|
61
78
|
try {
|
|
79
|
+
const systemPrompt = buildClassificationPrompt(canonicalTags);
|
|
62
80
|
const result = await llm.complete({
|
|
63
|
-
systemPrompt
|
|
81
|
+
systemPrompt,
|
|
64
82
|
userPrompt: chunkText,
|
|
65
83
|
maxTokens: 4096,
|
|
66
84
|
temperature: 0.3,
|
|
@@ -135,13 +135,9 @@ describe('dedupItems — colocated', () => {
|
|
|
135
135
|
const results = dedupItems(items, vault);
|
|
136
136
|
|
|
137
137
|
expect(results).toHaveLength(2);
|
|
138
|
-
// First should be
|
|
139
|
-
expect(results[0].similarity).
|
|
138
|
+
// First should be a high-similarity match (near-exact duplicate)
|
|
139
|
+
expect(results[0].similarity).toBeGreaterThanOrEqual(DEDUP_THRESHOLD);
|
|
140
140
|
// Second should be non-duplicate
|
|
141
141
|
expect(results[1].isDuplicate).toBe(false);
|
|
142
142
|
});
|
|
143
|
-
|
|
144
|
-
it('DEDUP_THRESHOLD is 0.85', () => {
|
|
145
|
-
expect(DEDUP_THRESHOLD).toBe(0.85);
|
|
146
|
-
});
|
|
147
143
|
});
|
|
@@ -86,7 +86,7 @@ describe('TextIngester — ingestText', () => {
|
|
|
86
86
|
expect(result.duplicates).toBe(0);
|
|
87
87
|
expect(result.entries).toHaveLength(1);
|
|
88
88
|
expect(result.entries[0].title).toBe('Pattern A');
|
|
89
|
-
expect(vault._seeded.length).
|
|
89
|
+
expect(vault._seeded.length).toBe(1);
|
|
90
90
|
});
|
|
91
91
|
|
|
92
92
|
it('returns empty result when LLM is null', async () => {
|
|
@@ -120,8 +120,7 @@ describe('TextIngester — ingestText', () => {
|
|
|
120
120
|
const result = await ingester.ingestText('text', { type: 'documentation', title: 'Doc' }, opts);
|
|
121
121
|
|
|
122
122
|
expect(result.ingested).toBe(1);
|
|
123
|
-
|
|
124
|
-
expect(vault._seeded.length).toBeGreaterThan(0);
|
|
123
|
+
expect(vault._seeded.length).toBe(1);
|
|
125
124
|
});
|
|
126
125
|
|
|
127
126
|
it('splits long text into chunks based on chunkSize option', async () => {
|
|
@@ -155,7 +154,7 @@ describe('TextIngester — ingestText', () => {
|
|
|
155
154
|
const longText = 'A'.repeat(100);
|
|
156
155
|
await ingester.ingestText(longText, { type: 'notes', title: 'Test' }, { chunkSize: 30 });
|
|
157
156
|
|
|
158
|
-
expect(callCount.n).
|
|
157
|
+
expect(callCount.n).toBe(4);
|
|
159
158
|
});
|
|
160
159
|
});
|
|
161
160
|
|
|
@@ -11,6 +11,7 @@ import type { IntelligenceEntry } from '../intelligence/types.js';
|
|
|
11
11
|
import type { ClassifiedItem } from './types.js';
|
|
12
12
|
import { classifyChunk } from './content-classifier.js';
|
|
13
13
|
import { dedupItems } from './dedup-gate.js';
|
|
14
|
+
import { normalizeTags as normalizeTagsCanonical } from '../vault/tag-normalizer.js';
|
|
14
15
|
|
|
15
16
|
// ─── Types ───────────────────────────────────────────────────────────
|
|
16
17
|
|
|
@@ -26,6 +27,12 @@ export interface IngestOptions {
|
|
|
26
27
|
tags?: string[];
|
|
27
28
|
/** Max chars per chunk for LLM classification. Default 4000. */
|
|
28
29
|
chunkSize?: number;
|
|
30
|
+
/** Canonical tag list for normalization. If omitted, no canonical normalization. */
|
|
31
|
+
canonicalTags?: string[];
|
|
32
|
+
/** Tag constraint mode. Default: 'suggest'. */
|
|
33
|
+
tagConstraintMode?: 'enforce' | 'suggest' | 'off';
|
|
34
|
+
/** Metadata tag prefixes exempt from canonical normalization. Default: ['source:']. */
|
|
35
|
+
metadataTagPrefixes?: string[];
|
|
29
36
|
}
|
|
30
37
|
|
|
31
38
|
export interface IngestResult {
|
|
@@ -42,15 +49,30 @@ const FETCH_TIMEOUT_MS = 15000;
|
|
|
42
49
|
|
|
43
50
|
// ─── Class ───────────────────────────────────────────────────────────
|
|
44
51
|
|
|
52
|
+
interface CanonicalTagConfig {
|
|
53
|
+
canonicalTags: string[];
|
|
54
|
+
tagConstraintMode: 'enforce' | 'suggest' | 'off';
|
|
55
|
+
metadataTagPrefixes: string[];
|
|
56
|
+
}
|
|
57
|
+
|
|
45
58
|
export class TextIngester {
|
|
46
59
|
private vault: Vault;
|
|
47
60
|
private llm: LLMClient | null;
|
|
61
|
+
private canonicalTagConfig: CanonicalTagConfig | null = null;
|
|
48
62
|
|
|
49
63
|
constructor(vault: Vault, llm: LLMClient | null) {
|
|
50
64
|
this.vault = vault;
|
|
51
65
|
this.llm = llm;
|
|
52
66
|
}
|
|
53
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Wire canonical tag config from runtime — used as defaults for all ingest calls.
|
|
70
|
+
* Caller-provided options in ingestText/ingestUrl/ingestBatch still take precedence.
|
|
71
|
+
*/
|
|
72
|
+
setCanonicalTagConfig(cfg: CanonicalTagConfig): void {
|
|
73
|
+
this.canonicalTagConfig = cfg;
|
|
74
|
+
}
|
|
75
|
+
|
|
54
76
|
/**
|
|
55
77
|
* Ingest a URL — fetch, strip HTML, classify, dedup, store.
|
|
56
78
|
*/
|
|
@@ -101,11 +123,19 @@ export class TextIngester {
|
|
|
101
123
|
const domain = opts?.domain ?? 'general';
|
|
102
124
|
const extraTags = opts?.tags ?? [];
|
|
103
125
|
|
|
126
|
+
// Resolve canonical config — caller opts take precedence over runtime-wired config
|
|
127
|
+
const canonicalTagsForClassify = opts?.canonicalTags ?? this.canonicalTagConfig?.canonicalTags;
|
|
128
|
+
|
|
104
129
|
// Classify all chunks
|
|
105
130
|
const allItems: ClassifiedItem[] = [];
|
|
106
131
|
for (const chunk of chunks) {
|
|
107
132
|
// oxlint-disable-next-line eslint(no-await-in-loop)
|
|
108
|
-
const items = await classifyChunk(
|
|
133
|
+
const items = await classifyChunk(
|
|
134
|
+
this.llm,
|
|
135
|
+
chunk,
|
|
136
|
+
`${source.type}: ${source.title}`,
|
|
137
|
+
canonicalTagsForClassify,
|
|
138
|
+
);
|
|
109
139
|
allItems.push(...items);
|
|
110
140
|
}
|
|
111
141
|
|
|
@@ -121,18 +151,37 @@ export class TextIngester {
|
|
|
121
151
|
// Build source attribution for context field
|
|
122
152
|
const attribution = buildAttribution(source);
|
|
123
153
|
|
|
154
|
+
// Metadata tags use 'source:' prefix so they're exempt from canonical normalization
|
|
155
|
+
const metadataTags = [`source:ingested`, `source:${source.type}`];
|
|
156
|
+
|
|
157
|
+
// Apply canonical tag normalization if configured
|
|
158
|
+
// Caller-provided options take precedence over runtime-wired config
|
|
159
|
+
const canonicalTags = opts?.canonicalTags ?? this.canonicalTagConfig?.canonicalTags;
|
|
160
|
+
const tagMode =
|
|
161
|
+
opts?.tagConstraintMode ?? this.canonicalTagConfig?.tagConstraintMode ?? 'suggest';
|
|
162
|
+
|
|
124
163
|
// Store in vault
|
|
125
|
-
const entries: IntelligenceEntry[] = unique.map((item, i) =>
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
164
|
+
const entries: IntelligenceEntry[] = unique.map((item, i) => {
|
|
165
|
+
const rawTags = [...(item.tags ?? []), ...extraTags];
|
|
166
|
+
// metaPrefixes not passed here — source: tags are added after normalization,
|
|
167
|
+
// so there is nothing to exempt at this point.
|
|
168
|
+
const normalizedTags =
|
|
169
|
+
canonicalTags && tagMode !== 'off'
|
|
170
|
+
? normalizeTagsCanonical(rawTags, canonicalTags, tagMode)
|
|
171
|
+
: rawTags;
|
|
172
|
+
|
|
173
|
+
return {
|
|
174
|
+
id: `ingest-${source.type}-${Date.now()}-${i}-${Math.random().toString(36).slice(2, 6)}`,
|
|
175
|
+
type: mapType(item.type),
|
|
176
|
+
domain,
|
|
177
|
+
title: item.title,
|
|
178
|
+
description: item.description,
|
|
179
|
+
severity: mapSeverity(item.severity),
|
|
180
|
+
tags: [...normalizedTags, ...metadataTags],
|
|
181
|
+
context: attribution,
|
|
182
|
+
origin: 'user' as const,
|
|
183
|
+
};
|
|
184
|
+
});
|
|
136
185
|
|
|
137
186
|
if (entries.length > 0) {
|
|
138
187
|
this.vault.seed(entries);
|
|
@@ -119,7 +119,7 @@ describe('LLMClient — colocated', () => {
|
|
|
119
119
|
expect(result.provider).toBe('openai');
|
|
120
120
|
expect(result.inputTokens).toBe(10);
|
|
121
121
|
expect(result.outputTokens).toBe(5);
|
|
122
|
-
expect(result.durationMs).
|
|
122
|
+
expect(typeof result.durationMs).toBe('number');
|
|
123
123
|
} finally {
|
|
124
124
|
globalThis.fetch = originalFetch;
|
|
125
125
|
}
|
package/src/llm/utils.test.ts
CHANGED
|
@@ -224,7 +224,7 @@ describe('computeDelay', () => {
|
|
|
224
224
|
it('should never return negative delay', () => {
|
|
225
225
|
vi.spyOn(Math, 'random').mockReturnValue(0);
|
|
226
226
|
const config = { maxAttempts: 3, baseDelayMs: 1, maxDelayMs: 30000, jitter: 1 };
|
|
227
|
-
expect(computeDelay({}, 0, config)).
|
|
227
|
+
expect(typeof computeDelay({}, 0, config)).toBe('number');
|
|
228
228
|
vi.restoreAllMocks();
|
|
229
229
|
});
|
|
230
230
|
});
|
|
@@ -51,19 +51,6 @@ describe('OperatorContextStore', () => {
|
|
|
51
51
|
vault.close();
|
|
52
52
|
});
|
|
53
53
|
|
|
54
|
-
// ─── Table Creation ─────────────────────────────────────────────────
|
|
55
|
-
|
|
56
|
-
describe('init', () => {
|
|
57
|
-
it('creates table without error on a fresh database', () => {
|
|
58
|
-
expect(store).toBeDefined();
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('is idempotent — second init does not throw', () => {
|
|
62
|
-
const store2 = new OperatorContextStore(vault.getProvider());
|
|
63
|
-
expect(store2).toBeDefined();
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
|
|
67
54
|
// ─── Empty State ──────────────────────────────────────────────────
|
|
68
55
|
|
|
69
56
|
describe('getContext (empty)', () => {
|
|
@@ -47,15 +47,6 @@ describe('OperatorProfileStore', () => {
|
|
|
47
47
|
vault.close();
|
|
48
48
|
});
|
|
49
49
|
|
|
50
|
-
// ─── Table Creation ─────────────────────────────────────────────
|
|
51
|
-
|
|
52
|
-
it('creates tables without error on new runtime', () => {
|
|
53
|
-
// Constructor ran initTables — no error means tables exist.
|
|
54
|
-
// Creating a second instance also succeeds (IF NOT EXISTS).
|
|
55
|
-
const store2 = new OperatorProfileStore(vault);
|
|
56
|
-
expect(store2).toBeDefined();
|
|
57
|
-
});
|
|
58
|
-
|
|
59
50
|
// ─── getProfile ─────────────────────────────────────────────────
|
|
60
51
|
|
|
61
52
|
it('returns null when no profile exists', () => {
|
|
@@ -186,8 +177,8 @@ describe('OperatorProfileStore', () => {
|
|
|
186
177
|
'SELECT trigger, version FROM operator_profile_history WHERE profile_id = ?',
|
|
187
178
|
[profileBefore!.id],
|
|
188
179
|
);
|
|
189
|
-
expect(history.length).
|
|
190
|
-
expect(history.
|
|
180
|
+
expect(history.length).toBe(1);
|
|
181
|
+
expect(history[0].trigger).toBe('correction');
|
|
191
182
|
});
|
|
192
183
|
|
|
193
184
|
// ─── snapshot ───────────────────────────────────────────────────
|
|
@@ -320,13 +311,4 @@ describe('OperatorProfileStore', () => {
|
|
|
320
311
|
expect(section.signalWords).toContain('please');
|
|
321
312
|
expect(section.adaptationRules).toHaveLength(1);
|
|
322
313
|
});
|
|
323
|
-
|
|
324
|
-
// ─── No `any` types ────────────────────────────────────────────
|
|
325
|
-
|
|
326
|
-
it('type system enforced — file compiles with strict TypeScript', () => {
|
|
327
|
-
// This test is a compile-time assertion:
|
|
328
|
-
// if operator-profile.ts had `any` types, tsc --noEmit would catch it.
|
|
329
|
-
// The fact that this test file compiles is the proof.
|
|
330
|
-
expect(true).toBe(true);
|
|
331
|
-
});
|
|
332
314
|
});
|
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
* 5. Return install summary
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
12
|
+
import { existsSync, readdirSync, readFileSync, rmSync } from 'node:fs';
|
|
13
13
|
import { join, basename } from 'node:path';
|
|
14
|
+
import { homedir } from 'node:os';
|
|
14
15
|
import {
|
|
15
16
|
packManifestSchema,
|
|
16
17
|
type InstalledPack,
|
|
@@ -200,10 +201,19 @@ export class PackInstaller {
|
|
|
200
201
|
facadesRegistered = true;
|
|
201
202
|
}
|
|
202
203
|
|
|
203
|
-
// 3. Discover skills
|
|
204
|
+
// 3. Discover skills and sync to .claude/skills/<packId>:<skill>/
|
|
204
205
|
const skillsDir = join(packDir, manifest.skills?.dir ?? 'skills');
|
|
205
206
|
const skills = existsSync(skillsDir) ? listMarkdownFiles(skillsDir) : [];
|
|
206
207
|
|
|
208
|
+
if (skills.length > 0) {
|
|
209
|
+
try {
|
|
210
|
+
const { syncSkillsToClaudeCode } = await import('../skills/sync-skills.js');
|
|
211
|
+
syncSkillsToClaudeCode([skillsDir], manifest.id, { global: true });
|
|
212
|
+
} catch {
|
|
213
|
+
// Skill sync is best-effort — never blocks install
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
207
217
|
// 4. Discover hooks
|
|
208
218
|
const hooksDir = join(packDir, manifest.hooks?.dir ?? 'hooks');
|
|
209
219
|
const hooks = existsSync(hooksDir) ? listMarkdownFiles(hooksDir) : [];
|
|
@@ -281,6 +291,22 @@ export class PackInstaller {
|
|
|
281
291
|
this.pluginRegistry.deactivate(packId);
|
|
282
292
|
}
|
|
283
293
|
|
|
294
|
+
// Remove pack skills from .claude/skills/
|
|
295
|
+
if (pack.skills.length > 0) {
|
|
296
|
+
try {
|
|
297
|
+
const claudeSkillsDir = join(homedir(), '.claude', 'skills');
|
|
298
|
+
for (const skillPath of pack.skills) {
|
|
299
|
+
const skillName = basename(skillPath, '.md');
|
|
300
|
+
const registeredPath = join(claudeSkillsDir, `${packId}:${skillName}`);
|
|
301
|
+
if (existsSync(registeredPath)) {
|
|
302
|
+
rmSync(registeredPath, { recursive: true, force: true });
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
} catch {
|
|
306
|
+
// Skill cleanup is best-effort
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
284
310
|
// Transition to uninstalled
|
|
285
311
|
try {
|
|
286
312
|
this.lifecycle.transition(packId, 'uninstalled', 'User uninstall');
|
|
@@ -233,7 +233,7 @@ describe('PackInstaller', () => {
|
|
|
233
233
|
|
|
234
234
|
const result = installer.validate(packDir);
|
|
235
235
|
expect(result.valid).toBe(true);
|
|
236
|
-
expect(result.warnings.length).
|
|
236
|
+
expect(result.warnings.length).toBe(2);
|
|
237
237
|
});
|
|
238
238
|
});
|
|
239
239
|
|
|
@@ -271,7 +271,7 @@ describe('PackInstaller', () => {
|
|
|
271
271
|
|
|
272
272
|
// Verify vault was seeded
|
|
273
273
|
const entries = vault.list({ domain: 'test' });
|
|
274
|
-
expect(entries.length).
|
|
274
|
+
expect(entries.length).toBe(1);
|
|
275
275
|
});
|
|
276
276
|
|
|
277
277
|
it('should install a pack with facades', async () => {
|
|
@@ -12,21 +12,21 @@ describe('ITALIAN_CRAFTSPERSON', () => {
|
|
|
12
12
|
});
|
|
13
13
|
|
|
14
14
|
it('has non-empty voice, culture, and inspiration', () => {
|
|
15
|
-
expect(ITALIAN_CRAFTSPERSON.voice
|
|
15
|
+
expect(ITALIAN_CRAFTSPERSON.voice).toContain('Italian mentor');
|
|
16
16
|
expect(ITALIAN_CRAFTSPERSON.culture).toBe('Italian');
|
|
17
|
-
expect(ITALIAN_CRAFTSPERSON.inspiration
|
|
17
|
+
expect(ITALIAN_CRAFTSPERSON.inspiration).toContain('Paolo Soleri');
|
|
18
18
|
});
|
|
19
19
|
|
|
20
20
|
it('provides greetings and signoffs pools', () => {
|
|
21
|
-
expect(ITALIAN_CRAFTSPERSON.greetings
|
|
22
|
-
expect(ITALIAN_CRAFTSPERSON.signoffs
|
|
21
|
+
expect(ITALIAN_CRAFTSPERSON.greetings).toHaveLength(5);
|
|
22
|
+
expect(ITALIAN_CRAFTSPERSON.signoffs).toHaveLength(5);
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
it('includes expected trait and quirk arrays', () => {
|
|
26
|
-
expect(ITALIAN_CRAFTSPERSON.traits
|
|
27
|
-
expect(ITALIAN_CRAFTSPERSON.quirks
|
|
28
|
-
expect(ITALIAN_CRAFTSPERSON.metaphors
|
|
29
|
-
expect(ITALIAN_CRAFTSPERSON.opinions
|
|
26
|
+
expect(ITALIAN_CRAFTSPERSON.traits).toHaveLength(7);
|
|
27
|
+
expect(ITALIAN_CRAFTSPERSON.quirks).toHaveLength(6);
|
|
28
|
+
expect(ITALIAN_CRAFTSPERSON.metaphors).toHaveLength(8);
|
|
29
|
+
expect(ITALIAN_CRAFTSPERSON.opinions).toHaveLength(6);
|
|
30
30
|
});
|
|
31
31
|
});
|
|
32
32
|
|
|
@@ -36,26 +36,26 @@ describe('NEUTRAL_PERSONA', () => {
|
|
|
36
36
|
});
|
|
37
37
|
|
|
38
38
|
it('has non-empty voice and inspiration', () => {
|
|
39
|
-
expect(NEUTRAL_PERSONA.voice
|
|
40
|
-
expect(NEUTRAL_PERSONA.inspiration
|
|
39
|
+
expect(NEUTRAL_PERSONA.voice).toContain('helpful assistant');
|
|
40
|
+
expect(NEUTRAL_PERSONA.inspiration).toContain('reliable professional');
|
|
41
41
|
});
|
|
42
42
|
|
|
43
43
|
it('has no cultural flavor', () => {
|
|
44
44
|
expect(NEUTRAL_PERSONA.culture).toBe('');
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
-
it('has all arrays populated with
|
|
48
|
-
expect(NEUTRAL_PERSONA.traits
|
|
49
|
-
expect(NEUTRAL_PERSONA.quirks
|
|
50
|
-
expect(NEUTRAL_PERSONA.opinions
|
|
51
|
-
expect(NEUTRAL_PERSONA.metaphors
|
|
52
|
-
expect(NEUTRAL_PERSONA.greetings
|
|
53
|
-
expect(NEUTRAL_PERSONA.signoffs
|
|
47
|
+
it('has all arrays populated with exact counts', () => {
|
|
48
|
+
expect(NEUTRAL_PERSONA.traits).toHaveLength(6);
|
|
49
|
+
expect(NEUTRAL_PERSONA.quirks).toHaveLength(4);
|
|
50
|
+
expect(NEUTRAL_PERSONA.opinions).toHaveLength(6);
|
|
51
|
+
expect(NEUTRAL_PERSONA.metaphors).toHaveLength(5);
|
|
52
|
+
expect(NEUTRAL_PERSONA.greetings).toHaveLength(3);
|
|
53
|
+
expect(NEUTRAL_PERSONA.signoffs).toHaveLength(3);
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
it('has non-empty language and name rules', () => {
|
|
57
|
-
expect(NEUTRAL_PERSONA.languageRule
|
|
58
|
-
expect(NEUTRAL_PERSONA.nameRule
|
|
57
|
+
expect(NEUTRAL_PERSONA.languageRule).toContain("user's language");
|
|
58
|
+
expect(NEUTRAL_PERSONA.nameRule).toContain('name changes');
|
|
59
59
|
});
|
|
60
60
|
});
|
|
61
61
|
|
|
@@ -10,12 +10,6 @@ import {
|
|
|
10
10
|
analyzeSemanticQuality,
|
|
11
11
|
analyzeKnowledgeDepth,
|
|
12
12
|
analyzeAlternatives,
|
|
13
|
-
AMBIGUOUS_WORDS,
|
|
14
|
-
GENERIC_OBJECTIVE_PATTERNS,
|
|
15
|
-
RATIONALE_INDICATORS,
|
|
16
|
-
SHALLOW_INDICATORS,
|
|
17
|
-
KNOWLEDGE_INDICATORS,
|
|
18
|
-
NAMED_PATTERN_REGEX,
|
|
19
13
|
} from './gap-passes.js';
|
|
20
14
|
|
|
21
15
|
function makePlan(overrides: Partial<Plan> = {}): Plan {
|
|
@@ -77,46 +71,6 @@ function makeAlternative(overrides: Partial<PlanAlternative> = {}): PlanAlternat
|
|
|
77
71
|
};
|
|
78
72
|
}
|
|
79
73
|
|
|
80
|
-
describe('Pattern constants (passes 5-8)', () => {
|
|
81
|
-
it('AMBIGUOUS_WORDS contains common vague terms', () => {
|
|
82
|
-
expect(AMBIGUOUS_WORDS).toContain('maybe');
|
|
83
|
-
expect(AMBIGUOUS_WORDS).toContain('probably');
|
|
84
|
-
expect(AMBIGUOUS_WORDS).toContain('etc');
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it('GENERIC_OBJECTIVE_PATTERNS matches simple verb-noun objectives', () => {
|
|
88
|
-
expect(GENERIC_OBJECTIVE_PATTERNS.some((p) => p.test('Create something'))).toBe(true);
|
|
89
|
-
expect(GENERIC_OBJECTIVE_PATTERNS.some((p) => p.test('Fix bug'))).toBe(true);
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
it('GENERIC_OBJECTIVE_PATTERNS does not match detailed objectives', () => {
|
|
93
|
-
expect(
|
|
94
|
-
GENERIC_OBJECTIVE_PATTERNS.some((p) => p.test('Create a user auth module with JWT')),
|
|
95
|
-
).toBe(false);
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
it('RATIONALE_INDICATORS contains reasoning words', () => {
|
|
99
|
-
expect(RATIONALE_INDICATORS).toContain('because');
|
|
100
|
-
expect(RATIONALE_INDICATORS).toContain('due to');
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
it('SHALLOW_INDICATORS contains subjective words', () => {
|
|
104
|
-
expect(SHALLOW_INDICATORS).toContain('better');
|
|
105
|
-
expect(SHALLOW_INDICATORS).toContain('good');
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it('KNOWLEDGE_INDICATORS match domain patterns', () => {
|
|
109
|
-
expect(KNOWLEDGE_INDICATORS.some((p) => p.test('vault pattern'))).toBe(true);
|
|
110
|
-
expect(KNOWLEDGE_INDICATORS.some((p) => p.test('WCAG 2.1'))).toBe(true);
|
|
111
|
-
expect(KNOWLEDGE_INDICATORS.some((p) => p.test('aria-label'))).toBe(true);
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
it('NAMED_PATTERN_REGEX matches hyphenated identifiers', () => {
|
|
115
|
-
expect(NAMED_PATTERN_REGEX.test('zod-form-validation')).toBe(true);
|
|
116
|
-
expect(NAMED_PATTERN_REGEX.test('simple')).toBe(false);
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
|
|
120
74
|
describe('Pass 5: Clarity', () => {
|
|
121
75
|
it('flags ambiguous language in objective', () => {
|
|
122
76
|
const plan = makePlan({
|
|
@@ -14,13 +14,6 @@ import {
|
|
|
14
14
|
analyzeCompleteness,
|
|
15
15
|
analyzeFeasibility,
|
|
16
16
|
analyzeRisk,
|
|
17
|
-
METRIC_PATTERNS,
|
|
18
|
-
EXCLUSION_KEYWORDS,
|
|
19
|
-
OVERLY_BROAD_PATTERNS,
|
|
20
|
-
DEPENDENCY_KEYWORDS,
|
|
21
|
-
BREAKING_CHANGE_KEYWORDS,
|
|
22
|
-
MITIGATION_KEYWORDS,
|
|
23
|
-
VERIFICATION_KEYWORDS,
|
|
24
17
|
} from './gap-patterns.js';
|
|
25
18
|
|
|
26
19
|
function makePlan(overrides: Partial<Plan> = {}): Plan {
|
|
@@ -161,41 +154,6 @@ describe('Helper functions', () => {
|
|
|
161
154
|
});
|
|
162
155
|
});
|
|
163
156
|
|
|
164
|
-
describe('Pattern constants', () => {
|
|
165
|
-
it('METRIC_PATTERNS matches numbers', () => {
|
|
166
|
-
expect(METRIC_PATTERNS.some((p) => p.test('reduce latency by 50%'))).toBe(true);
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
it('EXCLUSION_KEYWORDS includes common exclusion words', () => {
|
|
170
|
-
expect(EXCLUSION_KEYWORDS).toContain('exclude');
|
|
171
|
-
expect(EXCLUSION_KEYWORDS).toContain('not');
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
it('OVERLY_BROAD_PATTERNS includes dangerous scope terms', () => {
|
|
175
|
-
expect(OVERLY_BROAD_PATTERNS).toContain('complete rewrite');
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
it('DEPENDENCY_KEYWORDS includes ordering terms', () => {
|
|
179
|
-
expect(DEPENDENCY_KEYWORDS).toContain('depends');
|
|
180
|
-
expect(DEPENDENCY_KEYWORDS).toContain('prerequisite');
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
it('BREAKING_CHANGE_KEYWORDS includes migration terms', () => {
|
|
184
|
-
expect(BREAKING_CHANGE_KEYWORDS).toContain('breaking change');
|
|
185
|
-
expect(BREAKING_CHANGE_KEYWORDS).toContain('database migration');
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
it('MITIGATION_KEYWORDS includes safety terms', () => {
|
|
189
|
-
expect(MITIGATION_KEYWORDS).toContain('rollback');
|
|
190
|
-
expect(MITIGATION_KEYWORDS).toContain('feature flag');
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
it('VERIFICATION_KEYWORDS includes testing terms', () => {
|
|
194
|
-
expect(VERIFICATION_KEYWORDS).toContain('test');
|
|
195
|
-
expect(VERIFICATION_KEYWORDS).toContain('coverage');
|
|
196
|
-
});
|
|
197
|
-
});
|
|
198
|
-
|
|
199
157
|
describe('Pass 1: Structure', () => {
|
|
200
158
|
it('returns no gaps for a well-structured plan', () => {
|
|
201
159
|
const gaps = analyzeStructure(makePlan());
|
|
@@ -287,8 +287,10 @@ describe('JsonGoalRepository', () => {
|
|
|
287
287
|
});
|
|
288
288
|
|
|
289
289
|
it('should create and retrieve a goal', () => {
|
|
290
|
+
const before = Date.now();
|
|
290
291
|
const goal = repo.create({ id: 'g1', title: 'Ship it', level: 'objective', status: 'planned' });
|
|
291
|
-
expect(goal.createdAt).
|
|
292
|
+
expect(goal.createdAt).toBeGreaterThanOrEqual(before);
|
|
293
|
+
expect(goal.createdAt).toBeLessThanOrEqual(Date.now());
|
|
292
294
|
expect(repo.getById('g1')?.title).toBe('Ship it');
|
|
293
295
|
});
|
|
294
296
|
|