@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,161 @@
|
|
|
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 chalk from "chalk";
|
|
7
|
+
import { networkInterfaces } from "os";
|
|
8
|
+
import {
|
|
9
|
+
PortalServer,
|
|
10
|
+
ensureToken,
|
|
11
|
+
readStatus,
|
|
12
|
+
stopRunning
|
|
13
|
+
} from "../../features/portal/index.js";
|
|
14
|
+
import { DEFAULT_PORTAL_CONFIG } from "../../features/portal/types.js";
|
|
15
|
+
function tailscaleIp() {
|
|
16
|
+
const nets = networkInterfaces();
|
|
17
|
+
for (const addrs of Object.values(nets)) {
|
|
18
|
+
for (const a of addrs ?? []) {
|
|
19
|
+
if (a.family === "IPv4" && a.address.startsWith("100.")) {
|
|
20
|
+
return a.address;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return void 0;
|
|
25
|
+
}
|
|
26
|
+
function printAccessUrls(host, port, token) {
|
|
27
|
+
const path = token ? `/?token=${token}` : "/";
|
|
28
|
+
const ts = tailscaleIp();
|
|
29
|
+
console.log(chalk.cyan("\nAccess your agent:"));
|
|
30
|
+
if (ts) {
|
|
31
|
+
console.log(
|
|
32
|
+
chalk.green(` http://${ts}:${port}${path}`) + chalk.gray(" (tailnet)")
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
console.log(chalk.gray(` http://localhost:${port}${path}`));
|
|
36
|
+
if (!ts && host === "0.0.0.0") {
|
|
37
|
+
console.log(
|
|
38
|
+
chalk.gray(
|
|
39
|
+
" Tip: connect this machine to Tailscale, then use its 100.x address."
|
|
40
|
+
)
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function createPortalCommand() {
|
|
45
|
+
const cmd = new Command("portal").description("Browser terminal into a persistent tmux Claude Code session").addHelpText(
|
|
46
|
+
"after",
|
|
47
|
+
`
|
|
48
|
+
Examples:
|
|
49
|
+
stackmemory portal start Start the portal (foreground)
|
|
50
|
+
stackmemory portal start --port 8080 Use a custom port
|
|
51
|
+
stackmemory portal start --command "claude --resume"
|
|
52
|
+
stackmemory portal start --no-auth Disable token (Tailscale-only)
|
|
53
|
+
stackmemory portal status Show running status + access URL
|
|
54
|
+
stackmemory portal stop Stop a backgrounded portal
|
|
55
|
+
stackmemory portal token Print the access token
|
|
56
|
+
|
|
57
|
+
Run it on a VPS behind Tailscale for 24/7 agents. See docs/guides/PORTAL.md.
|
|
58
|
+
`
|
|
59
|
+
);
|
|
60
|
+
cmd.command("start").description("Start the portal server (runs in the foreground)").option(
|
|
61
|
+
"--port <number>",
|
|
62
|
+
"Port to listen on",
|
|
63
|
+
String(DEFAULT_PORTAL_CONFIG.port)
|
|
64
|
+
).option("--host <host>", "Interface to bind", DEFAULT_PORTAL_CONFIG.host).option(
|
|
65
|
+
"--session <name>",
|
|
66
|
+
"tmux session name",
|
|
67
|
+
DEFAULT_PORTAL_CONFIG.session
|
|
68
|
+
).option(
|
|
69
|
+
"--command <cmd>",
|
|
70
|
+
"Command tmux runs in the session",
|
|
71
|
+
DEFAULT_PORTAL_CONFIG.command
|
|
72
|
+
).option("--cwd <dir>", "Working directory for the session").option("--no-auth", "Disable token auth (rely on Tailscale)").action(async (options) => {
|
|
73
|
+
const server = new PortalServer({
|
|
74
|
+
port: parseInt(options.port, 10),
|
|
75
|
+
host: options.host,
|
|
76
|
+
session: options.session,
|
|
77
|
+
command: options.command,
|
|
78
|
+
cwd: options.cwd,
|
|
79
|
+
noAuth: options.auth === false
|
|
80
|
+
});
|
|
81
|
+
try {
|
|
82
|
+
const status = await server.start();
|
|
83
|
+
const cfg = server.getConfig();
|
|
84
|
+
console.log(chalk.green("\u2713 StackMemory Portal started"));
|
|
85
|
+
console.log(
|
|
86
|
+
chalk.gray(
|
|
87
|
+
` Session: ${cfg.session} (tmux new-session -A -s ${cfg.session})`
|
|
88
|
+
)
|
|
89
|
+
);
|
|
90
|
+
console.log(chalk.gray(` Command: ${cfg.command}`));
|
|
91
|
+
console.log(chalk.gray(` Listening: ${cfg.host}:${status.port}`));
|
|
92
|
+
if (cfg.noAuth) {
|
|
93
|
+
console.log(
|
|
94
|
+
chalk.yellow(" Auth: disabled (anyone on the network can connect)")
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
printAccessUrls(cfg.host, cfg.port, cfg.token);
|
|
98
|
+
console.log(
|
|
99
|
+
chalk.gray(
|
|
100
|
+
"\nPress Ctrl+C to stop the portal (your tmux session keeps running)."
|
|
101
|
+
)
|
|
102
|
+
);
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.error(
|
|
105
|
+
chalk.red("Failed to start portal:"),
|
|
106
|
+
error.message
|
|
107
|
+
);
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
const shutdown = async () => {
|
|
111
|
+
console.log(chalk.gray("\nShutting down portal\u2026"));
|
|
112
|
+
await server.stop();
|
|
113
|
+
process.exit(0);
|
|
114
|
+
};
|
|
115
|
+
process.on("SIGINT", shutdown);
|
|
116
|
+
process.on("SIGTERM", shutdown);
|
|
117
|
+
});
|
|
118
|
+
cmd.command("status").description("Show portal status and access URL").action(() => {
|
|
119
|
+
const status = readStatus();
|
|
120
|
+
if (!status.running) {
|
|
121
|
+
console.log(chalk.yellow("Portal is not running"));
|
|
122
|
+
console.log(chalk.gray(" Start with: stackmemory portal start"));
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
console.log(chalk.green("Portal is running"));
|
|
126
|
+
console.log(chalk.gray(` PID: ${status.pid}`));
|
|
127
|
+
console.log(chalk.gray(` Session: ${status.session}`));
|
|
128
|
+
console.log(chalk.gray(` Listening: ${status.host}:${status.port}`));
|
|
129
|
+
if (status.startedAt) {
|
|
130
|
+
const up = Math.floor((Date.now() - status.startedAt) / 1e3);
|
|
131
|
+
console.log(chalk.gray(` Uptime: ${formatUptime(up)}`));
|
|
132
|
+
}
|
|
133
|
+
const token = ensureToken();
|
|
134
|
+
if (status.port)
|
|
135
|
+
printAccessUrls(status.host ?? "0.0.0.0", status.port, token);
|
|
136
|
+
});
|
|
137
|
+
cmd.command("stop").description("Stop a running portal server").action(() => {
|
|
138
|
+
if (stopRunning()) {
|
|
139
|
+
console.log(chalk.green("\u2713 Portal stopped"));
|
|
140
|
+
} else {
|
|
141
|
+
console.log(chalk.yellow("Portal is not running"));
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
cmd.command("token").description("Print the portal access token (auto-generated on first use)").action(() => {
|
|
145
|
+
console.log(ensureToken());
|
|
146
|
+
});
|
|
147
|
+
return cmd;
|
|
148
|
+
}
|
|
149
|
+
function formatUptime(seconds) {
|
|
150
|
+
if (seconds < 60) return `${seconds}s`;
|
|
151
|
+
if (seconds < 3600) return `${Math.floor(seconds / 60)}m ${seconds % 60}s`;
|
|
152
|
+
if (seconds < 86400) {
|
|
153
|
+
const h = Math.floor(seconds / 3600);
|
|
154
|
+
return `${h}h ${Math.floor(seconds % 3600 / 60)}m`;
|
|
155
|
+
}
|
|
156
|
+
const d = Math.floor(seconds / 86400);
|
|
157
|
+
return `${d}d ${Math.floor(seconds % 86400 / 3600)}h`;
|
|
158
|
+
}
|
|
159
|
+
export {
|
|
160
|
+
createPortalCommand
|
|
161
|
+
};
|
|
@@ -0,0 +1,92 @@
|
|
|
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
|
+
const DIRS = ["company", "wiki", "skills", "clients", "raw", ".stackmemory"];
|
|
11
|
+
const TEMPLATES = {
|
|
12
|
+
"company/voice.md": "---\nname: Voice Guide\ndescription: How we write and communicate\n---\n\n# Voice Guide\n\n## Tone\n- [Your tone descriptors here]\n\n## Words we use\n- [Preferred terms]\n\n## Words we avoid\n- [Banned terms]\n",
|
|
13
|
+
"company/team.md": "---\nname: Team Directory\ndescription: Who works here and what they do\n---\n\n# Team\n\n| Name | Role | Contact |\n|------|------|---------||\n",
|
|
14
|
+
"company/design.md": "---\nname: Design System\ndescription: Logos, colors, components\n---\n\n# Design System\n\n## Colors\n- Primary:\n- Secondary:\n\n## Logos\n- [paths or URLs]\n",
|
|
15
|
+
"wiki/README.md": "# Wiki \u2014 SOPs & Playbooks\n\nAdd markdown files here. Files with skill frontmatter become Claude skills.\n\nSOPs should follow the Company OS schema:\n\n- `## Objective`\n- `## Procedure`\n- `## Verification`\n- `## Non-compliance`\n\nEach SOP must reference a PROSE Expectation from `docs/specs/COMPANY-OS-PROSE.md`.\n",
|
|
16
|
+
"wiki/SOP-301-onboarding.md": "# SOP-301 New Hire Onboarding\n\n**Owner:** People Ops \n**Status:** Active \n**Related PROSE Expectation:** [E.1 Onboarding completeness](../docs/specs/COMPANY-OS-PROSE.md#e1-onboarding-completeness)\n\n## Objective\nEnsure every new hire has accounts, hardware, and access documented before their start date.\n\n## Procedure\n\n1. **Pre-start checklist (5 days before)**\n - Hiring manager opens an onboarding ticket.\n - People Ops confirms laptop requirement and shipping address.\n\n2. **Account provisioning (3 days before)**\n - IT creates SSO account and adds the hire to default groups.\n - People Ops sends welcome email with first-week schedule.\n\n3. **Access verification (1 day before)**\n - Hiring manager verifies the hire can log in to primary systems.\n\n## Verification\n\n- Run audit: `stackmemory company-os audit onboarding`\n- Expected result: 100% of hires in last 30 days have completed checklist.\n\n## Non-compliance\n\nOnboarding missing SSO access or hardware assignment on start date is non-compliant.\n",
|
|
17
|
+
"skills/README.md": '# Skills\n\nClaude skill-packs. Each file is a markdown instruction set with frontmatter.\n\n```yaml\n---\nname: skill-name\ndescription: What this skill does\nactivates_on: [keyword1, keyword2]\nversion: "1.0"\n---\n```\n',
|
|
18
|
+
"clients/README.md": "# Clients\n\nEach client gets a subfolder with icp.md, voice.md, campaigns/, context/.\n",
|
|
19
|
+
"raw/README.md": "# Raw\n\nUnstructured data: transcripts, research, scrapes.\n",
|
|
20
|
+
".stackmemory/config.yml": `# StackMemory Company OS Configuration
|
|
21
|
+
|
|
22
|
+
sources:
|
|
23
|
+
- path: ./company
|
|
24
|
+
type: reference
|
|
25
|
+
- path: ./wiki
|
|
26
|
+
type: sop
|
|
27
|
+
- path: ./skills
|
|
28
|
+
type: skill
|
|
29
|
+
- path: ./raw
|
|
30
|
+
type: raw
|
|
31
|
+
|
|
32
|
+
tenants: {}
|
|
33
|
+
|
|
34
|
+
freshness_threshold_hours: 24
|
|
35
|
+
|
|
36
|
+
skill_rot:
|
|
37
|
+
enabled: true
|
|
38
|
+
stale_days: 90
|
|
39
|
+
correction_threshold: 5
|
|
40
|
+
`
|
|
41
|
+
};
|
|
42
|
+
function createScaffoldCommand() {
|
|
43
|
+
const cmd = new Command("scaffold").alias("os-init").description(
|
|
44
|
+
"Scaffold a Company OS folder structure for local context management"
|
|
45
|
+
).option("--force", "Overwrite existing template files").option("--dir <path>", "Target directory (default: current directory)").action(async (options) => {
|
|
46
|
+
const targetDir = path.resolve(options.dir || process.cwd());
|
|
47
|
+
const created = [];
|
|
48
|
+
const skipped = [];
|
|
49
|
+
for (const dir of DIRS) {
|
|
50
|
+
const fullPath = path.join(targetDir, dir);
|
|
51
|
+
if (!fs.existsSync(fullPath)) {
|
|
52
|
+
fs.mkdirSync(fullPath, { recursive: true });
|
|
53
|
+
created.push(dir + "/");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
for (const [relPath, content] of Object.entries(TEMPLATES)) {
|
|
57
|
+
const fullPath = path.join(targetDir, relPath);
|
|
58
|
+
const dir = path.dirname(fullPath);
|
|
59
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
60
|
+
if (fs.existsSync(fullPath) && !options.force) {
|
|
61
|
+
skipped.push(relPath);
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
fs.writeFileSync(fullPath, content, "utf-8");
|
|
65
|
+
created.push(relPath);
|
|
66
|
+
}
|
|
67
|
+
console.log(chalk.cyan("\n Company OS scaffolded\n"));
|
|
68
|
+
if (created.length) {
|
|
69
|
+
console.log(chalk.green(` Created: ${created.length} files/dirs`));
|
|
70
|
+
for (const f of created) {
|
|
71
|
+
console.log(chalk.gray(` + ${f}`));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (skipped.length) {
|
|
75
|
+
console.log(chalk.gray(` Skipped: ${skipped.length} (already exist)`));
|
|
76
|
+
}
|
|
77
|
+
console.log();
|
|
78
|
+
console.log(chalk.gray(" Next steps:"));
|
|
79
|
+
console.log(
|
|
80
|
+
chalk.gray(" 1. Edit company/voice.md with your tone and brand")
|
|
81
|
+
);
|
|
82
|
+
console.log(chalk.gray(" 2. Add skills to skills/ as markdown files"));
|
|
83
|
+
console.log(
|
|
84
|
+
chalk.gray(" 3. Set COMPANY_OS_ROOT=. in .env for MCP auto-indexing")
|
|
85
|
+
);
|
|
86
|
+
console.log();
|
|
87
|
+
});
|
|
88
|
+
return cmd;
|
|
89
|
+
}
|
|
90
|
+
export {
|
|
91
|
+
createScaffoldCommand
|
|
92
|
+
};
|
|
@@ -7,12 +7,16 @@ import Database from "better-sqlite3";
|
|
|
7
7
|
import { join } from "path";
|
|
8
8
|
import { existsSync } from "fs";
|
|
9
9
|
import { z } from "zod";
|
|
10
|
+
import { CrossProjectSearch } from "../../core/cross-search/cross-project-search.js";
|
|
10
11
|
const SearchQuerySchema = z.string().min(1, "Search query is required").max(500, "Search query too long (max 500 characters)").transform((val) => {
|
|
11
12
|
return val.replace(/[%_\\]/g, "\\$&");
|
|
12
13
|
});
|
|
13
14
|
const LimitSchema = z.string().transform((val) => parseInt(val, 10)).pipe(z.number().int().min(1).max(100).default(20));
|
|
14
15
|
function createSearchCommand() {
|
|
15
|
-
const search = new Command("search").alias("find").description("Search across tasks and context").argument("<query>", "Search query").option("-t, --tasks", "Search only tasks").option("-c, --context", "Search only context").option(
|
|
16
|
+
const search = new Command("search").alias("find").description("Search across tasks and context").argument("<query>", "Search query").option("-t, --tasks", "Search only tasks").option("-c, --context", "Search only context").option(
|
|
17
|
+
"-a, --all-projects",
|
|
18
|
+
"Search across all registered project databases"
|
|
19
|
+
).option("-l, --limit <n>", "Limit results", "20").action(async (rawQuery, options) => {
|
|
16
20
|
const projectRoot = process.cwd();
|
|
17
21
|
const dbPath = join(projectRoot, ".stackmemory", "context.db");
|
|
18
22
|
if (!existsSync(dbPath)) {
|
|
@@ -34,6 +38,41 @@ function createSearchCommand() {
|
|
|
34
38
|
}
|
|
35
39
|
return;
|
|
36
40
|
}
|
|
41
|
+
if (options.allProjects) {
|
|
42
|
+
console.log(
|
|
43
|
+
`
|
|
44
|
+
\u{1F50D} Searching across all projects for "${rawQuery}"...
|
|
45
|
+
`
|
|
46
|
+
);
|
|
47
|
+
const crossSearch = new CrossProjectSearch();
|
|
48
|
+
const results = await crossSearch.search({
|
|
49
|
+
query: rawQuery,
|
|
50
|
+
limit
|
|
51
|
+
});
|
|
52
|
+
if (results.length === 0) {
|
|
53
|
+
console.log("No results found across project databases.\n");
|
|
54
|
+
console.log(
|
|
55
|
+
'Tip: Run "stackmemory search --all-projects" after "stackmemory projects scan" to discover databases.'
|
|
56
|
+
);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
console.log(`\u{1F4C1} Cross-Project Results (${results.length})
|
|
60
|
+
`);
|
|
61
|
+
for (const r of results) {
|
|
62
|
+
const date = new Date(r.createdAt).toLocaleDateString();
|
|
63
|
+
console.log(
|
|
64
|
+
` [${r.projectName}] ${r.name} (${r.type}, score: ${r.score.toFixed(3)})`
|
|
65
|
+
);
|
|
66
|
+
if (r.digestText) {
|
|
67
|
+
console.log(` ${r.digestText.slice(0, 100)}`);
|
|
68
|
+
}
|
|
69
|
+
console.log(` ${date} | ${r.projectPath}`);
|
|
70
|
+
}
|
|
71
|
+
console.log(`
|
|
72
|
+
Found ${results.length} results.
|
|
73
|
+
`);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
37
76
|
const db = new Database(dbPath);
|
|
38
77
|
const searchTasks = !options.context || options.tasks;
|
|
39
78
|
const searchContext = !options.tasks || options.context;
|
|
@@ -241,13 +241,7 @@ function createDoctorCommand() {
|
|
|
241
241
|
const toolDefs = new MCPToolDefinitions();
|
|
242
242
|
const allTools = toolDefs.getAllToolDefinitions();
|
|
243
243
|
const toolNames = allTools.map((t) => t.name);
|
|
244
|
-
const expectedTools = [
|
|
245
|
-
"sm_digest",
|
|
246
|
-
"cord_spawn",
|
|
247
|
-
"team_search",
|
|
248
|
-
"get_context",
|
|
249
|
-
"create_task"
|
|
250
|
-
];
|
|
244
|
+
const expectedTools = ["sm_digest", "get_context", "create_task"];
|
|
251
245
|
const missing = expectedTools.filter((t) => !toolNames.includes(t));
|
|
252
246
|
if (missing.length === 0) {
|
|
253
247
|
results.push({
|
|
@@ -684,7 +678,6 @@ function createSetupPluginsCommand() {
|
|
|
684
678
|
}
|
|
685
679
|
console.log(chalk.gray(`Source: ${sourcePluginsDir}
|
|
686
680
|
`));
|
|
687
|
-
const plugins = ["stackmemory", "ralph-wiggum"];
|
|
688
681
|
let installed = 0;
|
|
689
682
|
for (const plugin of plugins) {
|
|
690
683
|
const sourcePath = join(sourcePluginsDir, plugin);
|
|
@@ -741,9 +734,7 @@ function createSetupPluginsCommand() {
|
|
|
741
734
|
console.log(
|
|
742
735
|
chalk.white(" /sm-help ") + chalk.gray("Show all commands")
|
|
743
736
|
);
|
|
744
|
-
console.log(
|
|
745
|
-
chalk.white(" /ralph-loop ") + chalk.gray("Start Ralph iteration loop")
|
|
746
|
-
);
|
|
737
|
+
console.log(chalk.gray("Start Ralph iteration loop"));
|
|
747
738
|
} else {
|
|
748
739
|
console.log(chalk.yellow("No plugins installed"));
|
|
749
740
|
}
|
|
@@ -1011,14 +1002,190 @@ Logs: ${logDir}/remote-mcp.log`));
|
|
|
1011
1002
|
});
|
|
1012
1003
|
return cmd;
|
|
1013
1004
|
}
|
|
1005
|
+
function createSetupCommandsCommand() {
|
|
1006
|
+
const cmd = new Command("setup-commands");
|
|
1007
|
+
cmd.description("Install StackMemory command packs for Claude Code").argument("[pack]", "Pack name to install (default: core)", "core").option("--list", "List available packs and their commands").option("--force", "Overwrite existing command files").option("--uninstall", "Remove installed commands").option("--dry-run", "Show what would be installed without making changes").action(async (pack, options) => {
|
|
1008
|
+
const commandsDir = join(CLAUDE_DIR, "commands");
|
|
1009
|
+
const possiblePaths = [
|
|
1010
|
+
join(process.cwd(), "packs"),
|
|
1011
|
+
join(__dirname, "..", "..", "..", "packs")
|
|
1012
|
+
];
|
|
1013
|
+
try {
|
|
1014
|
+
const globalRoot = execSync("npm root -g", {
|
|
1015
|
+
encoding: "utf-8"
|
|
1016
|
+
}).trim();
|
|
1017
|
+
possiblePaths.push(
|
|
1018
|
+
join(globalRoot, "@stackmemoryai", "stackmemory", "packs")
|
|
1019
|
+
);
|
|
1020
|
+
} catch {
|
|
1021
|
+
}
|
|
1022
|
+
let packsDir;
|
|
1023
|
+
for (const p of possiblePaths) {
|
|
1024
|
+
if (existsSync(p)) {
|
|
1025
|
+
packsDir = p;
|
|
1026
|
+
break;
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
if (!packsDir) {
|
|
1030
|
+
console.log(chalk.red("Could not find packs directory"));
|
|
1031
|
+
process.exit(1);
|
|
1032
|
+
}
|
|
1033
|
+
if (options.list) {
|
|
1034
|
+
console.log(chalk.cyan("\nAvailable command packs:\n"));
|
|
1035
|
+
const packs = readdirSync(packsDir).filter(
|
|
1036
|
+
(d) => existsSync(join(packsDir, d, "manifest.json"))
|
|
1037
|
+
);
|
|
1038
|
+
for (const p of packs) {
|
|
1039
|
+
const manifest2 = JSON.parse(
|
|
1040
|
+
readFileSync(join(packsDir, p, "manifest.json"), "utf8")
|
|
1041
|
+
);
|
|
1042
|
+
console.log(
|
|
1043
|
+
chalk.white(` ${manifest2.name}`) + chalk.gray(` v${manifest2.version} \u2014 ${manifest2.description}`)
|
|
1044
|
+
);
|
|
1045
|
+
if (manifest2.commands?.public) {
|
|
1046
|
+
for (const cmd2 of manifest2.commands.public) {
|
|
1047
|
+
console.log(
|
|
1048
|
+
chalk.green(` /${cmd2.name}`) + chalk.gray(` \u2014 ${cmd2.description}`)
|
|
1049
|
+
);
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
if (manifest2.commands?.internal) {
|
|
1053
|
+
console.log(
|
|
1054
|
+
chalk.gray(
|
|
1055
|
+
` + ${manifest2.commands.internal.length} internal deps`
|
|
1056
|
+
)
|
|
1057
|
+
);
|
|
1058
|
+
}
|
|
1059
|
+
console.log("");
|
|
1060
|
+
}
|
|
1061
|
+
return;
|
|
1062
|
+
}
|
|
1063
|
+
const packDir = join(packsDir, pack);
|
|
1064
|
+
const manifestPath = join(packDir, "manifest.json");
|
|
1065
|
+
if (!existsSync(manifestPath)) {
|
|
1066
|
+
console.log(chalk.red(`Pack "${pack}" not found`));
|
|
1067
|
+
console.log(chalk.gray("Run: stackmemory setup-commands --list"));
|
|
1068
|
+
process.exit(1);
|
|
1069
|
+
}
|
|
1070
|
+
const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
1071
|
+
const allCommands = [
|
|
1072
|
+
...manifest.commands?.public || [],
|
|
1073
|
+
...manifest.commands?.internal || []
|
|
1074
|
+
];
|
|
1075
|
+
if (options.uninstall) {
|
|
1076
|
+
console.log(
|
|
1077
|
+
chalk.cyan(
|
|
1078
|
+
`
|
|
1079
|
+
Uninstalling pack: ${manifest.name} v${manifest.version}
|
|
1080
|
+
`
|
|
1081
|
+
)
|
|
1082
|
+
);
|
|
1083
|
+
let removed = 0;
|
|
1084
|
+
for (const cmd2 of allCommands) {
|
|
1085
|
+
const targetPath = join(commandsDir, `${cmd2.name}.md`);
|
|
1086
|
+
if (existsSync(targetPath)) {
|
|
1087
|
+
if (options.dryRun) {
|
|
1088
|
+
console.log(chalk.gray(` Would remove: /${cmd2.name}`));
|
|
1089
|
+
} else {
|
|
1090
|
+
rmSync(targetPath, { force: true });
|
|
1091
|
+
console.log(chalk.green(` [OK]`) + ` Removed /${cmd2.name}`);
|
|
1092
|
+
removed++;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
console.log(chalk.green(`
|
|
1097
|
+
Removed ${removed} command(s)`));
|
|
1098
|
+
return;
|
|
1099
|
+
}
|
|
1100
|
+
console.log(
|
|
1101
|
+
chalk.cyan(`
|
|
1102
|
+
Installing pack: ${manifest.name} v${manifest.version}
|
|
1103
|
+
`)
|
|
1104
|
+
);
|
|
1105
|
+
console.log(chalk.gray(`${manifest.description}
|
|
1106
|
+
`));
|
|
1107
|
+
if (!existsSync(commandsDir)) {
|
|
1108
|
+
if (options.dryRun) {
|
|
1109
|
+
console.log(chalk.gray(`Would create: ${commandsDir}`));
|
|
1110
|
+
} else {
|
|
1111
|
+
mkdirSync(commandsDir, { recursive: true });
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
let installed = 0;
|
|
1115
|
+
let skipped = 0;
|
|
1116
|
+
for (const cmd2 of allCommands) {
|
|
1117
|
+
const sourcePath = join(packDir, cmd2.file);
|
|
1118
|
+
const targetPath = join(commandsDir, `${cmd2.name}.md`);
|
|
1119
|
+
const isPublic = manifest.commands?.public?.some(
|
|
1120
|
+
(c) => c.name === cmd2.name
|
|
1121
|
+
);
|
|
1122
|
+
if (!existsSync(sourcePath)) {
|
|
1123
|
+
console.log(
|
|
1124
|
+
chalk.red(` [MISS] /${cmd2.name}`) + chalk.gray(` \u2014 source not found: ${cmd2.file}`)
|
|
1125
|
+
);
|
|
1126
|
+
continue;
|
|
1127
|
+
}
|
|
1128
|
+
if (existsSync(targetPath) && !options.force) {
|
|
1129
|
+
console.log(
|
|
1130
|
+
chalk.gray(` [SKIP] /${cmd2.name} \u2014 exists (use --force)`)
|
|
1131
|
+
);
|
|
1132
|
+
skipped++;
|
|
1133
|
+
continue;
|
|
1134
|
+
}
|
|
1135
|
+
if (options.dryRun) {
|
|
1136
|
+
const tag = isPublic ? chalk.green("PUBLIC") : chalk.gray("INTERNAL");
|
|
1137
|
+
console.log(
|
|
1138
|
+
chalk.gray(` Would install: `) + chalk.white(`/${cmd2.name}`) + ` [${tag}]`
|
|
1139
|
+
);
|
|
1140
|
+
installed++;
|
|
1141
|
+
continue;
|
|
1142
|
+
}
|
|
1143
|
+
if (existsSync(targetPath)) {
|
|
1144
|
+
rmSync(targetPath, { force: true });
|
|
1145
|
+
}
|
|
1146
|
+
try {
|
|
1147
|
+
execSync(`ln -s "${sourcePath}" "${targetPath}"`, {
|
|
1148
|
+
encoding: "utf-8"
|
|
1149
|
+
});
|
|
1150
|
+
const tag = isPublic ? chalk.green("PUBLIC") : chalk.gray("INTERNAL");
|
|
1151
|
+
console.log(
|
|
1152
|
+
chalk.green(` [OK]`) + ` /${cmd2.name} [${tag}]` + chalk.gray(` \u2014 ${cmd2.description}`)
|
|
1153
|
+
);
|
|
1154
|
+
installed++;
|
|
1155
|
+
} catch (err) {
|
|
1156
|
+
console.log(
|
|
1157
|
+
chalk.red(` [ERROR] /${cmd2.name}`) + chalk.gray(` \u2014 ${err.message}`)
|
|
1158
|
+
);
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
console.log("");
|
|
1162
|
+
if (installed > 0) {
|
|
1163
|
+
console.log(chalk.green(`Installed ${installed} command(s)`));
|
|
1164
|
+
}
|
|
1165
|
+
if (skipped > 0) {
|
|
1166
|
+
console.log(chalk.gray(`Skipped ${skipped} (already exist)`));
|
|
1167
|
+
}
|
|
1168
|
+
if (!options.dryRun && installed > 0) {
|
|
1169
|
+
console.log(chalk.cyan("\nAvailable commands in Claude Code:"));
|
|
1170
|
+
for (const cmd2 of manifest.commands?.public || []) {
|
|
1171
|
+
console.log(
|
|
1172
|
+
chalk.white(` /${cmd2.name}`) + chalk.gray(` ${cmd2.description}`)
|
|
1173
|
+
);
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
});
|
|
1177
|
+
return cmd;
|
|
1178
|
+
}
|
|
1014
1179
|
function registerSetupCommands(program) {
|
|
1015
1180
|
program.addCommand(createSetupMCPCommand());
|
|
1016
1181
|
program.addCommand(createDoctorCommand());
|
|
1017
1182
|
program.addCommand(createSetupPluginsCommand());
|
|
1018
1183
|
program.addCommand(createSetupRemoteCommand());
|
|
1184
|
+
program.addCommand(createSetupCommandsCommand());
|
|
1019
1185
|
}
|
|
1020
1186
|
export {
|
|
1021
1187
|
createDoctorCommand,
|
|
1188
|
+
createSetupCommandsCommand,
|
|
1022
1189
|
createSetupMCPCommand,
|
|
1023
1190
|
createSetupPluginsCommand,
|
|
1024
1191
|
createSetupRemoteCommand,
|
|
@@ -46,6 +46,9 @@ function getVersion() {
|
|
|
46
46
|
_version = "0.0.0";
|
|
47
47
|
return _version;
|
|
48
48
|
}
|
|
49
|
+
function collectRepeatedOption(value, previous = []) {
|
|
50
|
+
return [...previous, value];
|
|
51
|
+
}
|
|
49
52
|
function _getEnv(key, defaultValue) {
|
|
50
53
|
const value = process.env[key];
|
|
51
54
|
if (value === void 0) {
|
|
@@ -309,7 +312,12 @@ function createSkillsCommand() {
|
|
|
309
312
|
"--execute",
|
|
310
313
|
"Execute implementer (codex-sm) instead of dry-run",
|
|
311
314
|
false
|
|
312
|
-
).option("--audit-dir <path>", "Persist spike results to directory").option(
|
|
315
|
+
).option("--audit-dir <path>", "Persist spike results to directory").option(
|
|
316
|
+
"--verify <cmd>",
|
|
317
|
+
"Verification command to run after each implementation attempt; repeatable",
|
|
318
|
+
collectRepeatedOption,
|
|
319
|
+
[]
|
|
320
|
+
).option("--record-frame", "Record as real frame with anchors", false).option(
|
|
313
321
|
"--record",
|
|
314
322
|
"Record plan & critique into StackMemory context",
|
|
315
323
|
false
|
|
@@ -329,6 +337,7 @@ function createSkillsCommand() {
|
|
|
329
337
|
maxIters: parseInt(options.maxIters),
|
|
330
338
|
dryRun: !options.execute,
|
|
331
339
|
auditDir: options.auditDir,
|
|
340
|
+
verificationCommands: options.verify,
|
|
332
341
|
recordFrame: Boolean(options.recordFrame),
|
|
333
342
|
record: Boolean(options.record)
|
|
334
343
|
}
|