@stackmemoryai/stackmemory 1.10.5 → 1.14.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/LICENSE +131 -64
- package/README.md +107 -24
- package/bin/claude-sm +16 -1
- package/bin/claude-smd +16 -1
- package/bin/codex-smd +16 -1
- package/bin/gemini-sm +16 -1
- package/bin/hermes-sm +21 -0
- package/bin/hermes-smd +21 -0
- package/bin/opencode-sm +16 -1
- package/dist/src/cli/claude-sm.js +266 -84
- package/dist/src/cli/codex-sm.js +225 -33
- package/dist/src/cli/commands/bench.js +209 -2
- package/dist/src/cli/commands/brain.js +206 -0
- package/dist/src/cli/commands/cache.js +126 -0
- package/dist/src/cli/commands/company-os.js +184 -0
- package/dist/src/cli/commands/context.js +5 -0
- package/dist/src/cli/commands/daemon.js +41 -0
- package/dist/src/cli/commands/handoff.js +40 -9
- package/dist/src/cli/commands/onboard.js +70 -3
- package/dist/src/cli/commands/operator.js +127 -0
- package/dist/src/cli/commands/optimize.js +117 -0
- package/dist/src/cli/commands/orchestrate.js +232 -5
- package/dist/src/cli/commands/orchestrator.js +315 -26
- package/dist/src/cli/commands/pack.js +322 -0
- package/dist/src/cli/commands/patterns.js +254 -0
- package/dist/src/cli/commands/portal.js +161 -0
- package/dist/src/cli/commands/scaffold.js +92 -0
- package/dist/src/cli/commands/search.js +40 -1
- package/dist/src/cli/commands/setup.js +178 -11
- package/dist/src/cli/commands/skills.js +10 -1
- package/dist/src/cli/commands/state.js +265 -0
- package/dist/src/cli/commands/sync.js +253 -0
- package/dist/src/cli/commands/tasks.js +130 -1
- package/dist/src/cli/commands/vision.js +221 -0
- package/dist/src/cli/gemini-sm.js +19 -29
- package/dist/src/cli/hermes-sm.js +224 -0
- package/dist/src/cli/index.js +105 -39
- package/dist/src/cli/opencode-sm.js +38 -21
- package/dist/src/cli/utils/determinism-watcher.js +66 -0
- package/dist/src/cli/utils/real-cli-bin.js +116 -0
- package/dist/src/core/brain/brain-store.js +187 -0
- package/dist/src/core/brain/brain-sync.js +193 -0
- package/dist/src/core/brain/index.js +78 -0
- package/dist/src/core/brain/types.js +10 -0
- package/dist/src/core/cache/content-cache.js +238 -0
- package/dist/src/{integrations/diffmem → core/cache}/index.js +5 -5
- package/dist/src/core/cache/token-estimator.js +39 -0
- package/dist/src/core/config/feature-flags.js +2 -6
- package/dist/src/core/context/frame-database.js +79 -27
- package/dist/src/core/context/recursive-context-manager.js +1 -1
- package/dist/src/core/context/rehydration.js +2 -1
- package/dist/src/core/cross-search/cross-project-search.js +269 -0
- package/dist/src/core/cross-search/index.js +10 -0
- package/dist/src/core/database/sqlite-adapter.js +14 -84
- package/dist/src/core/extensions/provider-adapter.js +5 -0
- package/dist/src/core/models/model-router.js +54 -2
- package/dist/src/core/models/provider-pricing.js +58 -4
- package/dist/src/core/monitoring/logger.js +2 -1
- package/dist/src/core/optimization/trace-optimizer.js +413 -0
- package/dist/src/core/patterns/index.js +22 -0
- package/dist/src/core/patterns/pattern-applier.js +39 -0
- package/dist/src/core/patterns/pattern-observer.js +157 -0
- package/dist/src/core/patterns/pattern-store.js +259 -0
- package/dist/src/core/patterns/types.js +19 -0
- package/dist/src/core/provenance/confidence-scorer.js +128 -0
- package/dist/src/core/provenance/index.js +40 -0
- package/dist/src/core/provenance/provenance-store.js +194 -0
- package/dist/src/core/provenance/types.js +82 -0
- package/dist/src/core/retrieval/llm-context-retrieval.js +5 -4
- package/dist/src/core/retrieval/unified-context-assembler.js +11 -66
- package/dist/src/core/session/project-handoff.js +64 -0
- package/dist/src/core/session/session-manager.js +28 -0
- package/dist/src/core/shared-state/canonical-store.js +564 -0
- package/dist/src/core/skill-packs/index.js +18 -0
- package/dist/src/core/skill-packs/parser.js +42 -0
- package/dist/src/core/skill-packs/registry.js +224 -0
- package/dist/src/core/skill-packs/types.js +79 -0
- package/dist/src/core/storage/cloud-sync-manager.js +116 -0
- package/dist/src/core/storage/cloud-sync.js +574 -0
- package/dist/src/core/storage/two-tier-storage.js +5 -1
- package/dist/src/core/tasks/master-tasks-template.js +43 -0
- package/dist/src/core/tasks/md-task-parser.js +138 -0
- package/dist/src/core/trace/trace-event-store.js +282 -0
- package/dist/src/core/vision/index.js +27 -0
- package/dist/src/core/vision/signals.js +79 -0
- package/dist/src/core/vision/types.js +22 -0
- package/dist/src/core/vision/vision-file.js +146 -0
- package/dist/src/core/vision/vision-loop.js +220 -0
- package/dist/src/core/wiki/wiki-compiler.js +103 -1
- package/dist/src/daemon/daemon-config.js +52 -0
- package/dist/src/daemon/services/desire-path-service.js +566 -0
- package/dist/src/daemon/services/github-service.js +126 -0
- package/dist/src/daemon/services/research-stream-service.js +320 -0
- package/dist/src/daemon/services/telemetry-service.js +192 -0
- package/dist/src/daemon/unified-daemon.js +58 -1
- package/dist/src/features/browser/cli-browser-agent.js +417 -0
- package/dist/src/features/browser/stagehand-workflows.js +578 -0
- package/dist/src/features/operator/adapter-factory.js +62 -0
- package/dist/src/features/operator/browser-adapter.js +109 -0
- package/dist/src/features/operator/desktop-adapter.js +125 -0
- package/dist/src/features/operator/index.js +39 -0
- package/dist/src/features/operator/llm-decision.js +137 -0
- package/dist/src/features/operator/operator-logger.js +92 -0
- package/dist/src/features/operator/overnight-runner.js +327 -0
- package/dist/src/features/operator/screen-adapter.js +91 -0
- package/dist/src/features/operator/session-manager.js +127 -0
- package/dist/src/features/operator/state-machine.js +227 -0
- package/dist/src/features/operator/task-queue.js +81 -0
- package/dist/src/features/portal/index.js +26 -0
- package/dist/src/features/portal/server.js +240 -0
- package/dist/src/features/portal/types.js +14 -0
- package/dist/src/features/portal/ui.js +195 -0
- package/dist/src/features/sweep/pty-wrapper.js +13 -5
- package/dist/src/features/tasks/task-aware-context.js +2 -1
- package/dist/src/features/tui/simple-monitor.js +0 -23
- package/dist/src/features/tui/swarm-monitor.js +8 -66
- package/dist/src/features/web/client/hooks/use-socket.js +12 -0
- package/dist/src/{core/merge/index.js → features/web/client/lib/utils.js} +8 -4
- package/dist/src/features/web/client/next-env.d.js +4 -0
- package/dist/src/features/web/client/stores/session-store.js +12 -0
- package/dist/src/features/web/server/gcp-billing.js +76 -0
- package/dist/src/features/web/server/index.js +10 -0
- package/dist/src/features/web/server/spend-calculator.js +228 -0
- package/dist/src/hooks/schemas.js +6 -1
- package/dist/src/integrations/anthropic/client.js +3 -2
- package/dist/src/integrations/claude-code/agent-bridge.js +0 -3
- package/dist/src/integrations/claude-code/subagent-client.js +307 -11
- package/dist/src/integrations/claude-code/task-coordinator.js +2 -1
- package/dist/src/integrations/github/pr-state.js +158 -0
- package/dist/src/integrations/linear/client.js +4 -1
- package/dist/src/integrations/linear/webhook-retry.js +196 -0
- package/dist/src/integrations/linear/webhook-server.js +18 -22
- package/dist/src/integrations/mcp/handlers/cloud-sync-handlers.js +101 -0
- package/dist/src/integrations/mcp/handlers/index.js +40 -84
- package/dist/src/integrations/mcp/server.js +542 -641
- package/dist/src/integrations/mcp/tool-alias-registry.js +297 -0
- package/dist/src/integrations/mcp/tool-definitions.js +152 -682
- package/dist/src/mcp/stackmemory-mcp-server.js +571 -231
- package/dist/src/orchestrators/multimodal/determinism.js +244 -0
- package/dist/src/orchestrators/multimodal/harness.js +149 -78
- package/dist/src/orchestrators/multimodal/providers.js +44 -3
- package/dist/src/skills/recursive-agent-orchestrator.js +2 -4
- package/dist/src/utils/hook-installer.js +0 -8
- package/dist/src/utils/process-cleanup.js +1 -7
- package/docs/README.md +42 -0
- package/docs/guides/README_INSTALL.md +208 -0
- package/package.json +27 -9
- package/packs/coding/python-fastapi/instructions.md +60 -0
- package/packs/coding/python-fastapi/pack.yaml +28 -0
- package/packs/coding/typescript-react/instructions.md +47 -0
- package/packs/coding/typescript-react/pack.yaml +28 -0
- package/packs/core/commands/capture.md +32 -0
- package/packs/core/commands/learn.md +73 -0
- package/packs/core/commands/next.md +36 -0
- package/packs/core/commands/restart.md +58 -0
- package/packs/core/commands/restore.md +29 -0
- package/packs/core/commands/start.md +57 -0
- package/packs/core/commands/stop.md +65 -0
- package/packs/core/commands/summary.md +40 -0
- package/packs/core/manifest.json +24 -0
- package/packs/ops/decision-recovery/instructions.md +65 -0
- package/packs/ops/decision-recovery/pack.yaml +89 -0
- package/scripts/claude-code-wrapper.sh +11 -0
- package/scripts/claude-sm-setup.sh +12 -1
- package/scripts/codex-wrapper.sh +11 -0
- package/scripts/git-hooks/branch-context-manager.sh +11 -0
- package/scripts/git-hooks/post-checkout-stackmemory.sh +11 -0
- package/scripts/git-hooks/post-commit-stackmemory.sh +11 -0
- package/scripts/git-hooks/pre-commit-stackmemory.sh +11 -0
- package/scripts/hooks/cleanup-shell.sh +12 -1
- package/scripts/hooks/task-complete.sh +12 -1
- package/scripts/install-code-execution-hooks.sh +12 -1
- package/scripts/install-sweep-hook.sh +12 -0
- package/scripts/install.sh +11 -0
- package/scripts/opencode-wrapper.sh +11 -0
- package/scripts/portal/cloud-init.yaml +69 -0
- package/scripts/portal/setup.sh +69 -0
- package/scripts/portal/stackmemory-portal.service +34 -0
- package/scripts/setup-claude-integration.sh +12 -1
- package/scripts/smoke-init-db.sh +23 -0
- package/scripts/stackmemory-daemon.sh +11 -0
- package/scripts/verify-dist.cjs +11 -4
- package/dist/src/cli/commands/ralph.js +0 -1053
- package/dist/src/cli/commands/team.js +0 -168
- package/dist/src/core/context/shared-context-layer.js +0 -620
- package/dist/src/core/context/stack-merge-resolver.js +0 -748
- package/dist/src/core/merge/conflict-detector.js +0 -430
- package/dist/src/core/merge/resolution-engine.js +0 -557
- package/dist/src/core/merge/stack-diff.js +0 -531
- package/dist/src/core/merge/unified-merge-resolver.js +0 -302
- package/dist/src/hooks/diffmem-hooks.js +0 -376
- package/dist/src/integrations/diffmem/client.js +0 -208
- package/dist/src/integrations/diffmem/config.js +0 -14
- package/dist/src/integrations/greptile/client.js +0 -101
- package/dist/src/integrations/greptile/config.js +0 -14
- package/dist/src/integrations/greptile/index.js +0 -11
- package/dist/src/integrations/mcp/handlers/cord-handlers.js +0 -397
- package/dist/src/integrations/mcp/handlers/diffmem-handlers.js +0 -455
- package/dist/src/integrations/mcp/handlers/greptile-handlers.js +0 -456
- package/dist/src/integrations/mcp/handlers/provider-handlers.js +0 -227
- package/dist/src/integrations/mcp/handlers/team-handlers.js +0 -211
- package/dist/src/integrations/ralph/bridge/ralph-stackmemory-bridge.js +0 -863
- package/dist/src/integrations/ralph/context/context-budget-manager.js +0 -308
- package/dist/src/integrations/ralph/context/stackmemory-context-loader.js +0 -391
- package/dist/src/integrations/ralph/index.js +0 -17
- package/dist/src/integrations/ralph/learning/pattern-learner.js +0 -435
- package/dist/src/integrations/ralph/lifecycle/iteration-lifecycle.js +0 -448
- package/dist/src/integrations/ralph/loopmax.js +0 -488
- package/dist/src/integrations/ralph/monitoring/swarm-dashboard.js +0 -293
- package/dist/src/integrations/ralph/monitoring/swarm-registry.js +0 -107
- package/dist/src/integrations/ralph/orchestration/multi-loop-orchestrator.js +0 -508
- package/dist/src/integrations/ralph/patterns/compounding-engineering-pattern.js +0 -407
- package/dist/src/integrations/ralph/patterns/extended-coherence-sessions.js +0 -495
- package/dist/src/integrations/ralph/patterns/oracle-worker-pattern.js +0 -387
- package/dist/src/integrations/ralph/performance/performance-optimizer.js +0 -357
- package/dist/src/integrations/ralph/recovery/crash-recovery.js +0 -461
- package/dist/src/integrations/ralph/state/state-reconciler.js +0 -420
- package/dist/src/integrations/ralph/swarm/git-workflow-manager.js +0 -444
- package/dist/src/integrations/ralph/swarm/swarm-coordinator.js +0 -1007
- package/dist/src/integrations/ralph/visualization/ralph-debugger.js +0 -635
- package/scripts/ralph-loop-implementation.js +0 -404
- /package/dist/src/core/{merge → cache}/types.js +0 -0
- /package/dist/src/{integrations/diffmem/types.js → core/storage/cloud-sync-types.js} +0 -0
- /package/dist/src/{integrations/greptile/types.js → core/trace/trace-event.js} +0 -0
- /package/dist/src/{integrations/ralph → features/operator}/types.js +0 -0
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { fileURLToPath as __fileURLToPath } from 'url';
|
|
3
|
+
import { dirname as __pathDirname } from 'path';
|
|
4
|
+
const __filename = __fileURLToPath(import.meta.url);
|
|
5
|
+
const __dirname = __pathDirname(__filename);
|
|
6
|
+
import { Command } from "commander";
|
|
7
|
+
import chalk from "chalk";
|
|
8
|
+
import * as fs from "fs";
|
|
9
|
+
import * as path from "path";
|
|
10
|
+
import * as os from "os";
|
|
11
|
+
import { execSync } from "child_process";
|
|
12
|
+
import * as yaml from "js-yaml";
|
|
13
|
+
import {
|
|
14
|
+
getSkillPackRegistry,
|
|
15
|
+
loadPackFromDir
|
|
16
|
+
} from "../../core/skill-packs/index.js";
|
|
17
|
+
function resolvePackSource(source) {
|
|
18
|
+
if (fs.existsSync(source) && fs.statSync(source).isDirectory()) {
|
|
19
|
+
return source;
|
|
20
|
+
}
|
|
21
|
+
if (fs.existsSync(source) && (source.endsWith(".yaml") || source.endsWith(".yml"))) {
|
|
22
|
+
return path.dirname(source);
|
|
23
|
+
}
|
|
24
|
+
if (/^[\w-]+\/[\w-]+$/.test(source)) {
|
|
25
|
+
return cloneFromGitHub(source);
|
|
26
|
+
}
|
|
27
|
+
if (source.startsWith("https://github.com/")) {
|
|
28
|
+
return cloneFromGitHub(source);
|
|
29
|
+
}
|
|
30
|
+
throw new Error(
|
|
31
|
+
`Cannot resolve pack source: ${source}
|
|
32
|
+
Expected: local directory, pack.yaml path, namespace/pack-name, or GitHub URL`
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
function cloneFromGitHub(source) {
|
|
36
|
+
const registryOrg = process.env["STACKMEMORY_PACK_REGISTRY"] || "stackmemoryai";
|
|
37
|
+
let repoUrl;
|
|
38
|
+
let packSubdir;
|
|
39
|
+
if (source.startsWith("https://")) {
|
|
40
|
+
repoUrl = source;
|
|
41
|
+
} else {
|
|
42
|
+
repoUrl = `https://github.com/${registryOrg}/skill-packs.git`;
|
|
43
|
+
packSubdir = source.replace("/", "/");
|
|
44
|
+
}
|
|
45
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "sm-pack-"));
|
|
46
|
+
try {
|
|
47
|
+
execSync(`git clone --depth 1 ${repoUrl} ${tmpDir}`, {
|
|
48
|
+
stdio: "pipe",
|
|
49
|
+
timeout: 3e4
|
|
50
|
+
});
|
|
51
|
+
} catch {
|
|
52
|
+
throw new Error(
|
|
53
|
+
`Failed to clone ${repoUrl}. Check the URL or run: git clone ${repoUrl}`
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
const packDir = packSubdir ? path.join(tmpDir, packSubdir) : tmpDir;
|
|
57
|
+
if (!fs.existsSync(path.join(packDir, "pack.yaml"))) {
|
|
58
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
59
|
+
throw new Error(`No pack.yaml found in ${packSubdir || "repository root"}`);
|
|
60
|
+
}
|
|
61
|
+
return packDir;
|
|
62
|
+
}
|
|
63
|
+
function formatPack(pack) {
|
|
64
|
+
const m = pack.manifest;
|
|
65
|
+
const tools = m.mcp?.tools?.length ?? 0;
|
|
66
|
+
const examples = m.examples?.length ?? 0;
|
|
67
|
+
const runtime = m.runtime?.type ?? "local";
|
|
68
|
+
const installed = pack.metadata?.installedAt ? new Date(pack.metadata.installedAt).toLocaleDateString() : "";
|
|
69
|
+
return [
|
|
70
|
+
` ${chalk.bold(m.name)} ${chalk.dim(`v${m.version}`)}`,
|
|
71
|
+
` ${chalk.dim(m.description)}`,
|
|
72
|
+
` ${chalk.dim(`runtime: ${runtime} | tools: ${tools} | examples: ${examples}`)}`,
|
|
73
|
+
installed ? ` ${chalk.dim(`installed: ${installed}`)}` : ""
|
|
74
|
+
].filter(Boolean).join("\n");
|
|
75
|
+
}
|
|
76
|
+
function createPackCommand() {
|
|
77
|
+
const cmd = new Command("pack").description(
|
|
78
|
+
"Manage skill packs \u2014 versioned, distributable agent bundles (pack.yaml)"
|
|
79
|
+
);
|
|
80
|
+
cmd.command("install <source>").description(
|
|
81
|
+
"Install a skill pack from a local dir, GitHub URL, or namespace/name"
|
|
82
|
+
).option("--force", "Overwrite existing pack").action(async (source, options) => {
|
|
83
|
+
try {
|
|
84
|
+
const dir = resolvePackSource(source);
|
|
85
|
+
const pack = await loadPackFromDir(dir);
|
|
86
|
+
const registry = getSkillPackRegistry();
|
|
87
|
+
const existing = registry.get(pack.manifest.name);
|
|
88
|
+
if (existing && !options.force) {
|
|
89
|
+
console.log(
|
|
90
|
+
chalk.yellow(
|
|
91
|
+
`Pack ${pack.manifest.name}@${existing.manifest.version} already installed. Use --force to overwrite.`
|
|
92
|
+
)
|
|
93
|
+
);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
registry.install(pack);
|
|
97
|
+
console.log(
|
|
98
|
+
chalk.green(
|
|
99
|
+
`\u2713 Installed ${pack.manifest.name}@${pack.manifest.version}`
|
|
100
|
+
)
|
|
101
|
+
);
|
|
102
|
+
if (pack.manifest.mcp?.tools?.length) {
|
|
103
|
+
console.log(
|
|
104
|
+
chalk.dim(
|
|
105
|
+
` ${pack.manifest.mcp.tools.length} MCP tools registered`
|
|
106
|
+
)
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
} catch (err) {
|
|
110
|
+
console.error(
|
|
111
|
+
chalk.red(
|
|
112
|
+
`Failed to install: ${err instanceof Error ? err.message : err}`
|
|
113
|
+
)
|
|
114
|
+
);
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
cmd.command("uninstall <name>").description("Remove an installed skill pack").action((name) => {
|
|
119
|
+
const registry = getSkillPackRegistry();
|
|
120
|
+
if (registry.uninstall(name)) {
|
|
121
|
+
console.log(chalk.green(`\u2713 Uninstalled ${name}`));
|
|
122
|
+
} else {
|
|
123
|
+
console.log(chalk.yellow(`Pack ${name} not found`));
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
cmd.command("list").description("List installed skill packs").option("--namespace <ns>", "Filter by namespace").option("--json", "Output as JSON").action((options) => {
|
|
127
|
+
const registry = getSkillPackRegistry();
|
|
128
|
+
const packs = registry.list(
|
|
129
|
+
options.namespace ? { namespace: options.namespace } : void 0
|
|
130
|
+
);
|
|
131
|
+
if (options.json) {
|
|
132
|
+
console.log(JSON.stringify(packs, null, 2));
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
if (packs.length === 0) {
|
|
136
|
+
console.log(
|
|
137
|
+
chalk.dim(
|
|
138
|
+
"No packs installed. Run: stackmemory pack install <source>"
|
|
139
|
+
)
|
|
140
|
+
);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
console.log(chalk.bold(`${packs.length} pack(s) installed:
|
|
144
|
+
`));
|
|
145
|
+
for (const pack of packs) {
|
|
146
|
+
console.log(formatPack(pack));
|
|
147
|
+
console.log();
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
cmd.command("search <query>").description("Search installed packs by keyword").action((query) => {
|
|
151
|
+
const registry = getSkillPackRegistry();
|
|
152
|
+
const results = registry.search(query);
|
|
153
|
+
if (results.length === 0) {
|
|
154
|
+
console.log(chalk.dim(`No packs matching "${query}"`));
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
console.log(chalk.bold(`${results.length} result(s):
|
|
158
|
+
`));
|
|
159
|
+
for (const pack of results) {
|
|
160
|
+
console.log(formatPack(pack));
|
|
161
|
+
console.log();
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
cmd.command("show <name>").description("Show details of an installed pack").action((name) => {
|
|
165
|
+
const registry = getSkillPackRegistry();
|
|
166
|
+
const pack = registry.get(name);
|
|
167
|
+
if (!pack) {
|
|
168
|
+
console.log(chalk.yellow(`Pack ${name} not found`));
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const m = pack.manifest;
|
|
172
|
+
console.log(chalk.bold(m.name) + " " + chalk.dim(`v${m.version}`));
|
|
173
|
+
console.log(chalk.dim(m.description));
|
|
174
|
+
console.log();
|
|
175
|
+
if (m.author) console.log(` Author: ${m.author}`);
|
|
176
|
+
if (m.license) console.log(` License: ${m.license}`);
|
|
177
|
+
if (m.runtime) console.log(` Runtime: ${m.runtime.type}`);
|
|
178
|
+
if (pack.metadata?.installedAt)
|
|
179
|
+
console.log(` Installed: ${pack.metadata.installedAt}`);
|
|
180
|
+
if (pack.metadata?.source)
|
|
181
|
+
console.log(` Source: ${pack.metadata.source}`);
|
|
182
|
+
if (m.mcp?.tools?.length) {
|
|
183
|
+
console.log(`
|
|
184
|
+
MCP Tools:`);
|
|
185
|
+
for (const tool of m.mcp.tools) {
|
|
186
|
+
console.log(` - ${tool.name}: ${tool.description}`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (m.examples?.length) {
|
|
190
|
+
console.log(`
|
|
191
|
+
Examples: ${m.examples.length}`);
|
|
192
|
+
}
|
|
193
|
+
if (m.ingestion?.sources?.length) {
|
|
194
|
+
console.log(`
|
|
195
|
+
Ingestion sources: ${m.ingestion.sources.join(", ")}`);
|
|
196
|
+
}
|
|
197
|
+
if (pack.instructions) {
|
|
198
|
+
console.log(`
|
|
199
|
+
Instructions: ${pack.instructions.length} chars`);
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
cmd.command("init <name>").description(
|
|
203
|
+
"Initialize a new skill pack in the current directory (creates pack.yaml)"
|
|
204
|
+
).option("--runtime <type>", "Runtime type", "local").action((name, options) => {
|
|
205
|
+
const yamlPath = path.join(process.cwd(), "pack.yaml");
|
|
206
|
+
if (fs.existsSync(yamlPath)) {
|
|
207
|
+
console.log(chalk.yellow("pack.yaml already exists in this directory"));
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
const template = `name: ${name}
|
|
211
|
+
version: 0.1.0
|
|
212
|
+
description: <one-line description>
|
|
213
|
+
author: <your-name>
|
|
214
|
+
license: MIT
|
|
215
|
+
runtime:
|
|
216
|
+
type: ${options.runtime || "local"}
|
|
217
|
+
ingestion:
|
|
218
|
+
sources: []
|
|
219
|
+
ontology:
|
|
220
|
+
entities: []
|
|
221
|
+
relations: []
|
|
222
|
+
mcp:
|
|
223
|
+
tools: []
|
|
224
|
+
examples: []
|
|
225
|
+
instructions: instructions.md
|
|
226
|
+
`;
|
|
227
|
+
fs.writeFileSync(yamlPath, template, "utf-8");
|
|
228
|
+
const instrPath = path.join(process.cwd(), "instructions.md");
|
|
229
|
+
if (!fs.existsSync(instrPath)) {
|
|
230
|
+
fs.writeFileSync(
|
|
231
|
+
instrPath,
|
|
232
|
+
`# ${name}
|
|
233
|
+
|
|
234
|
+
Instructions for this skill pack.
|
|
235
|
+
`,
|
|
236
|
+
"utf-8"
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
console.log(chalk.green(`\u2713 Created pack.yaml for ${name}`));
|
|
240
|
+
console.log(chalk.dim(" Edit pack.yaml and instructions.md, then:"));
|
|
241
|
+
console.log(chalk.dim(" stackmemory pack install ."));
|
|
242
|
+
});
|
|
243
|
+
cmd.command("fork <name> <new-name>").description("Fork an installed pack under a new namespace/name").action((name, newName) => {
|
|
244
|
+
const registry = getSkillPackRegistry();
|
|
245
|
+
const existing = registry.get(name);
|
|
246
|
+
if (!existing) {
|
|
247
|
+
console.log(chalk.yellow(`Pack ${name} not found`));
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
const targetDir = path.join(process.cwd(), newName.replace("/", "-"));
|
|
251
|
+
if (fs.existsSync(targetDir)) {
|
|
252
|
+
console.log(chalk.yellow(`Directory ${targetDir} already exists`));
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
256
|
+
const forked = {
|
|
257
|
+
...existing.manifest,
|
|
258
|
+
name: newName,
|
|
259
|
+
version: "0.1.0"
|
|
260
|
+
};
|
|
261
|
+
fs.writeFileSync(
|
|
262
|
+
path.join(targetDir, "pack.yaml"),
|
|
263
|
+
yaml.dump(forked),
|
|
264
|
+
"utf-8"
|
|
265
|
+
);
|
|
266
|
+
if (existing.instructions) {
|
|
267
|
+
fs.writeFileSync(
|
|
268
|
+
path.join(targetDir, "instructions.md"),
|
|
269
|
+
existing.instructions,
|
|
270
|
+
"utf-8"
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
console.log(chalk.green(`\u2713 Forked ${name} \u2192 ${newName} in ${targetDir}`));
|
|
274
|
+
console.log(
|
|
275
|
+
chalk.dim(" Edit and install: stackmemory pack install " + targetDir)
|
|
276
|
+
);
|
|
277
|
+
});
|
|
278
|
+
cmd.command("publish [dir]").description(
|
|
279
|
+
"Validate and publish a pack to the public registry (creates a GitHub PR)"
|
|
280
|
+
).option("--dry-run", "Validate only, do not publish").action(async (dir, options) => {
|
|
281
|
+
const packDir = dir || process.cwd();
|
|
282
|
+
try {
|
|
283
|
+
const pack = await loadPackFromDir(packDir);
|
|
284
|
+
console.log(
|
|
285
|
+
chalk.green(
|
|
286
|
+
`\u2713 Valid pack: ${pack.manifest.name}@${pack.manifest.version}`
|
|
287
|
+
)
|
|
288
|
+
);
|
|
289
|
+
if (options.dryRun) {
|
|
290
|
+
console.log(chalk.dim("Dry run \u2014 skipping publish"));
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
const registryOrg = process.env["STACKMEMORY_PACK_REGISTRY"] || "stackmemoryai";
|
|
294
|
+
console.log();
|
|
295
|
+
console.log(chalk.bold("To publish to the public registry:"));
|
|
296
|
+
console.log(
|
|
297
|
+
chalk.dim(` 1. Fork https://github.com/${registryOrg}/skill-packs`)
|
|
298
|
+
);
|
|
299
|
+
console.log(
|
|
300
|
+
chalk.dim(
|
|
301
|
+
` 2. Add your pack to ${pack.manifest.name.replace("/", "/")}/`
|
|
302
|
+
)
|
|
303
|
+
);
|
|
304
|
+
console.log(chalk.dim(" 3. Open a pull request"));
|
|
305
|
+
console.log();
|
|
306
|
+
console.log(
|
|
307
|
+
chalk.dim("Automated publish via `gh pr create` coming soon.")
|
|
308
|
+
);
|
|
309
|
+
} catch (err) {
|
|
310
|
+
console.error(
|
|
311
|
+
chalk.red(
|
|
312
|
+
`Validation failed: ${err instanceof Error ? err.message : err}`
|
|
313
|
+
)
|
|
314
|
+
);
|
|
315
|
+
process.exit(1);
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
return cmd;
|
|
319
|
+
}
|
|
320
|
+
export {
|
|
321
|
+
createPackCommand
|
|
322
|
+
};
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { fileURLToPath as __fileURLToPath } from 'url';
|
|
2
|
+
import { dirname as __pathDirname } from 'path';
|
|
3
|
+
const __filename = __fileURLToPath(import.meta.url);
|
|
4
|
+
const __dirname = __pathDirname(__filename);
|
|
5
|
+
import { Command } from "commander";
|
|
6
|
+
import Database from "better-sqlite3";
|
|
7
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
8
|
+
import { join } from "path";
|
|
9
|
+
import { homedir } from "os";
|
|
10
|
+
import { PatternStore } from "../../core/patterns/pattern-store.js";
|
|
11
|
+
function getDb() {
|
|
12
|
+
const dbPath = join(homedir(), ".stackmemory", "stackmemory.db");
|
|
13
|
+
return new Database(dbPath);
|
|
14
|
+
}
|
|
15
|
+
function getStore() {
|
|
16
|
+
return new PatternStore(getDb());
|
|
17
|
+
}
|
|
18
|
+
function createPatternsCommand() {
|
|
19
|
+
const patterns = new Command("patterns").description(
|
|
20
|
+
"Manage learned behavioral patterns"
|
|
21
|
+
);
|
|
22
|
+
patterns.command("list").description("List learned patterns").option("-d, --domain <domain>", "Filter by domain").option("-s, --status <status>", "Filter by status", "active").option("--min-confidence <n>", "Minimum confidence", "0").option("--json", "Output JSON").action((opts) => {
|
|
23
|
+
const store = getStore();
|
|
24
|
+
const list = store.list({
|
|
25
|
+
domain: opts.domain,
|
|
26
|
+
status: opts.status,
|
|
27
|
+
minConfidence: parseFloat(opts.minConfidence)
|
|
28
|
+
});
|
|
29
|
+
if (opts.json) {
|
|
30
|
+
process.stdout.write(JSON.stringify(list, null, 2) + "\n");
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (list.length === 0) {
|
|
34
|
+
process.stdout.write("No patterns found.\n");
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
for (const p of list) {
|
|
38
|
+
const bar = confidenceBar(p.confidence);
|
|
39
|
+
const scope = p.scope === "global" ? "[global]" : "[project]";
|
|
40
|
+
process.stdout.write(
|
|
41
|
+
`${bar} ${p.confidence.toFixed(2)} ${scope} ${p.id}
|
|
42
|
+
trigger: ${p.trigger}
|
|
43
|
+
action: ${p.action}
|
|
44
|
+
domain: ${p.domain} obs: ${p.observationCount} status: ${p.status}
|
|
45
|
+
|
|
46
|
+
`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
patterns.command("learn").description("Manually record a pattern").requiredOption("-t, --trigger <text>", "When this happens").requiredOption("-a, --action <text>", "Do this").option("-d, --domain <domain>", "Pattern domain", "general").option("--scope <scope>", "project or global", "project").option("--id <id>", "Pattern ID (auto-generated if omitted)").action((opts) => {
|
|
51
|
+
const store = getStore();
|
|
52
|
+
const id = opts.id ?? slugify(`${opts.domain}-${opts.trigger.slice(0, 40)}`);
|
|
53
|
+
const input = {
|
|
54
|
+
id,
|
|
55
|
+
domain: opts.domain,
|
|
56
|
+
trigger: opts.trigger,
|
|
57
|
+
action: opts.action,
|
|
58
|
+
scope: opts.scope,
|
|
59
|
+
source: "manual",
|
|
60
|
+
confidence: 0.5
|
|
61
|
+
};
|
|
62
|
+
const pattern = store.create(input);
|
|
63
|
+
process.stdout.write(
|
|
64
|
+
`Pattern created: ${pattern.id} (confidence: ${pattern.confidence})
|
|
65
|
+
`
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
patterns.command("stats").description("Show pattern statistics").option("--json", "Output JSON").action((opts) => {
|
|
69
|
+
const store = getStore();
|
|
70
|
+
const s = store.stats();
|
|
71
|
+
if (opts.json) {
|
|
72
|
+
process.stdout.write(JSON.stringify(s, null, 2) + "\n");
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const lines = [
|
|
76
|
+
`Total patterns: ${s.total}`,
|
|
77
|
+
`Avg confidence: ${s.avgConfidence.toFixed(2)}`,
|
|
78
|
+
"",
|
|
79
|
+
"By domain:",
|
|
80
|
+
...Object.entries(s.byDomain).map(([d, n]) => ` ${d}: ${n}`),
|
|
81
|
+
"",
|
|
82
|
+
"By status:",
|
|
83
|
+
...Object.entries(s.byStatus).map(([d, n]) => ` ${d}: ${n}`)
|
|
84
|
+
];
|
|
85
|
+
if (s.topPatterns.length > 0) {
|
|
86
|
+
lines.push("", "Top patterns:");
|
|
87
|
+
for (const p of s.topPatterns) {
|
|
88
|
+
lines.push(
|
|
89
|
+
` ${confidenceBar(p.confidence)} ${p.confidence.toFixed(2)} ${p.id}`
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
process.stdout.write(lines.join("\n") + "\n");
|
|
94
|
+
});
|
|
95
|
+
patterns.command("prune").description("Remove old pending patterns").option("--days <n>", "Max age in days", "30").action((opts) => {
|
|
96
|
+
const store = getStore();
|
|
97
|
+
const removed = store.prune(parseInt(opts.days, 10));
|
|
98
|
+
process.stdout.write(
|
|
99
|
+
`Pruned ${removed} pending patterns older than ${opts.days} days.
|
|
100
|
+
`
|
|
101
|
+
);
|
|
102
|
+
});
|
|
103
|
+
patterns.command("export").description("Export patterns to JSON file").option("-o, --output <path>", "Output file", "patterns-export.json").option("--min-confidence <n>", "Minimum confidence", "0.3").action((opts) => {
|
|
104
|
+
const store = getStore();
|
|
105
|
+
const list = store.list({
|
|
106
|
+
status: "active",
|
|
107
|
+
minConfidence: parseFloat(opts.minConfidence)
|
|
108
|
+
});
|
|
109
|
+
writeFileSync(opts.output, JSON.stringify(list, null, 2), "utf-8");
|
|
110
|
+
process.stdout.write(
|
|
111
|
+
`Exported ${list.length} patterns to ${opts.output}
|
|
112
|
+
`
|
|
113
|
+
);
|
|
114
|
+
});
|
|
115
|
+
patterns.command("import").description("Import patterns from JSON file").argument("<file>", "JSON file to import").option("--scope <scope>", "Override scope", "project").action((file, opts) => {
|
|
116
|
+
if (!existsSync(file)) {
|
|
117
|
+
process.stderr.write(`File not found: ${file}
|
|
118
|
+
`);
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
121
|
+
const store = getStore();
|
|
122
|
+
const data = JSON.parse(readFileSync(file, "utf-8"));
|
|
123
|
+
const patterns2 = Array.isArray(data) ? data : [data];
|
|
124
|
+
let imported = 0;
|
|
125
|
+
for (const p of patterns2) {
|
|
126
|
+
if (!p.id || !p.trigger || !p.action) continue;
|
|
127
|
+
const existing = store.get(p.id);
|
|
128
|
+
if (existing) {
|
|
129
|
+
store.reinforce(p.id, "imported");
|
|
130
|
+
} else {
|
|
131
|
+
store.create({
|
|
132
|
+
id: p.id,
|
|
133
|
+
domain: p.domain ?? "general",
|
|
134
|
+
trigger: p.trigger,
|
|
135
|
+
action: p.action,
|
|
136
|
+
evidence: p.evidence ?? ["imported"],
|
|
137
|
+
scope: opts.scope ?? p.scope ?? "project",
|
|
138
|
+
source: "imported",
|
|
139
|
+
confidence: p.confidence ?? 0.5
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
imported++;
|
|
143
|
+
}
|
|
144
|
+
process.stdout.write(`Imported ${imported} patterns.
|
|
145
|
+
`);
|
|
146
|
+
});
|
|
147
|
+
patterns.command("promote").description("Promote a project-scoped pattern to global").argument("[id]", "Pattern ID to promote (omit for auto-candidates)").option("--dry-run", "Show candidates without promoting").action((id, opts) => {
|
|
148
|
+
const store = getStore();
|
|
149
|
+
if (id) {
|
|
150
|
+
const pattern = store.get(id);
|
|
151
|
+
if (!pattern) {
|
|
152
|
+
process.stderr.write(`Pattern not found: ${id}
|
|
153
|
+
`);
|
|
154
|
+
process.exit(1);
|
|
155
|
+
}
|
|
156
|
+
if (pattern.scope === "global") {
|
|
157
|
+
process.stdout.write(`Already global: ${id}
|
|
158
|
+
`);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (!opts.dryRun) {
|
|
162
|
+
store.promote(id);
|
|
163
|
+
process.stdout.write(`Promoted to global: ${id}
|
|
164
|
+
`);
|
|
165
|
+
} else {
|
|
166
|
+
process.stdout.write(
|
|
167
|
+
`Would promote: ${id} (confidence: ${pattern.confidence.toFixed(2)})
|
|
168
|
+
`
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const candidates = store.promotionCandidates(0.7);
|
|
174
|
+
if (candidates.length === 0) {
|
|
175
|
+
process.stdout.write(
|
|
176
|
+
"No promotion candidates found (need 0.7+ confidence in 2+ projects).\n"
|
|
177
|
+
);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
for (const c of candidates) {
|
|
181
|
+
const action = opts.dryRun ? "candidate" : "promoted";
|
|
182
|
+
if (!opts.dryRun) store.promote(c.id);
|
|
183
|
+
process.stdout.write(
|
|
184
|
+
`${action}: ${c.id} (${c.confidence.toFixed(2)}, project: ${c.projectId})
|
|
185
|
+
`
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
if (opts.dryRun) {
|
|
189
|
+
process.stdout.write(
|
|
190
|
+
`
|
|
191
|
+
${candidates.length} candidates. Run without --dry-run to promote.
|
|
192
|
+
`
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
patterns.command("projects").description("List projects with pattern counts").option("--json", "Output JSON").action((opts) => {
|
|
197
|
+
const store = getStore();
|
|
198
|
+
const projs = store.projects();
|
|
199
|
+
if (opts.json) {
|
|
200
|
+
process.stdout.write(JSON.stringify(projs, null, 2) + "\n");
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (projs.length === 0) {
|
|
204
|
+
process.stdout.write("No project-scoped patterns found.\n");
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
for (const p of projs) {
|
|
208
|
+
process.stdout.write(
|
|
209
|
+
`${p.projectId} ${p.count} patterns avg confidence: ${p.avgConfidence.toFixed(2)}
|
|
210
|
+
`
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
patterns.command("evolve").description("Analyze pattern clusters and suggest evolved structures").option("--min-cluster <n>", "Minimum cluster size", "2").option("--json", "Output JSON").action((opts) => {
|
|
215
|
+
const store = getStore();
|
|
216
|
+
const clusters = store.findClusters(parseInt(opts.minCluster, 10));
|
|
217
|
+
if (opts.json) {
|
|
218
|
+
process.stdout.write(JSON.stringify(clusters, null, 2) + "\n");
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
if (clusters.length === 0) {
|
|
222
|
+
process.stdout.write(
|
|
223
|
+
"No pattern clusters found. Need 2+ active patterns in a domain.\n"
|
|
224
|
+
);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
for (const cluster of clusters) {
|
|
228
|
+
const avgConf = cluster.patterns.reduce((s, p) => s + p.confidence, 0) / cluster.patterns.length;
|
|
229
|
+
const label = avgConf >= 0.8 ? "SKILL candidate" : avgConf >= 0.6 ? "command candidate" : "cluster";
|
|
230
|
+
process.stdout.write(
|
|
231
|
+
`
|
|
232
|
+
[${cluster.domain}] ${cluster.patterns.length} patterns \u2014 ${label} (avg: ${avgConf.toFixed(2)})
|
|
233
|
+
`
|
|
234
|
+
);
|
|
235
|
+
for (const p of cluster.patterns) {
|
|
236
|
+
process.stdout.write(
|
|
237
|
+
` ${confidenceBar(p.confidence)} ${p.id}: ${p.trigger}
|
|
238
|
+
`
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
return patterns;
|
|
244
|
+
}
|
|
245
|
+
function confidenceBar(confidence) {
|
|
246
|
+
const filled = Math.round(confidence * 10);
|
|
247
|
+
return "\u2588".repeat(filled) + "\u2591".repeat(10 - filled);
|
|
248
|
+
}
|
|
249
|
+
function slugify(s) {
|
|
250
|
+
return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
251
|
+
}
|
|
252
|
+
export {
|
|
253
|
+
createPatternsCommand
|
|
254
|
+
};
|