@pleri/olam-cli 0.1.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/dist/__tests__/auth-status.test.d.ts +2 -0
- package/dist/__tests__/auth-status.test.d.ts.map +1 -0
- package/dist/__tests__/auth-status.test.js +290 -0
- package/dist/__tests__/auth-status.test.js.map +1 -0
- package/dist/__tests__/auth-upgrade.test.d.ts +9 -0
- package/dist/__tests__/auth-upgrade.test.d.ts.map +1 -0
- package/dist/__tests__/auth-upgrade.test.js +161 -0
- package/dist/__tests__/auth-upgrade.test.js.map +1 -0
- package/dist/__tests__/create-app-urls.test.d.ts +2 -0
- package/dist/__tests__/create-app-urls.test.d.ts.map +1 -0
- package/dist/__tests__/create-app-urls.test.js +102 -0
- package/dist/__tests__/create-app-urls.test.js.map +1 -0
- package/dist/__tests__/enter.test.d.ts +2 -0
- package/dist/__tests__/enter.test.d.ts.map +1 -0
- package/dist/__tests__/enter.test.js +90 -0
- package/dist/__tests__/enter.test.js.map +1 -0
- package/dist/__tests__/host-cp-gh-token.test.d.ts +9 -0
- package/dist/__tests__/host-cp-gh-token.test.d.ts.map +1 -0
- package/dist/__tests__/host-cp-gh-token.test.js +119 -0
- package/dist/__tests__/host-cp-gh-token.test.js.map +1 -0
- package/dist/__tests__/host-cp.test.d.ts +9 -0
- package/dist/__tests__/host-cp.test.d.ts.map +1 -0
- package/dist/__tests__/host-cp.test.js +254 -0
- package/dist/__tests__/host-cp.test.js.map +1 -0
- package/dist/__tests__/keys.test.d.ts +9 -0
- package/dist/__tests__/keys.test.d.ts.map +1 -0
- package/dist/__tests__/keys.test.js +145 -0
- package/dist/__tests__/keys.test.js.map +1 -0
- package/dist/__tests__/logs.test.d.ts +9 -0
- package/dist/__tests__/logs.test.d.ts.map +1 -0
- package/dist/__tests__/logs.test.js +124 -0
- package/dist/__tests__/logs.test.js.map +1 -0
- package/dist/__tests__/ps.test.d.ts +2 -0
- package/dist/__tests__/ps.test.d.ts.map +1 -0
- package/dist/__tests__/ps.test.js +172 -0
- package/dist/__tests__/ps.test.js.map +1 -0
- package/dist/__tests__/status-app-urls.test.d.ts +2 -0
- package/dist/__tests__/status-app-urls.test.d.ts.map +1 -0
- package/dist/__tests__/status-app-urls.test.js +125 -0
- package/dist/__tests__/status-app-urls.test.js.map +1 -0
- package/dist/__tests__/upgrade.test.d.ts +9 -0
- package/dist/__tests__/upgrade.test.d.ts.map +1 -0
- package/dist/__tests__/upgrade.test.js +262 -0
- package/dist/__tests__/upgrade.test.js.map +1 -0
- package/dist/commands/__tests__/carry-uncommitted.test.d.ts +14 -0
- package/dist/commands/__tests__/carry-uncommitted.test.d.ts.map +1 -0
- package/dist/commands/__tests__/carry-uncommitted.test.js +83 -0
- package/dist/commands/__tests__/carry-uncommitted.test.js.map +1 -0
- package/dist/commands/__tests__/openHostCpUrl.test.d.ts +2 -0
- package/dist/commands/__tests__/openHostCpUrl.test.d.ts.map +1 -0
- package/dist/commands/__tests__/openHostCpUrl.test.js +63 -0
- package/dist/commands/__tests__/openHostCpUrl.test.js.map +1 -0
- package/dist/commands/__tests__/refresh.test.d.ts +13 -0
- package/dist/commands/__tests__/refresh.test.d.ts.map +1 -0
- package/dist/commands/__tests__/refresh.test.js +170 -0
- package/dist/commands/__tests__/refresh.test.js.map +1 -0
- package/dist/commands/auth-status.d.ts +43 -0
- package/dist/commands/auth-status.d.ts.map +1 -0
- package/dist/commands/auth-status.js +208 -0
- package/dist/commands/auth-status.js.map +1 -0
- package/dist/commands/auth-upgrade.d.ts +47 -0
- package/dist/commands/auth-upgrade.d.ts.map +1 -0
- package/dist/commands/auth-upgrade.js +277 -0
- package/dist/commands/auth-upgrade.js.map +1 -0
- package/dist/commands/auth.d.ts +16 -0
- package/dist/commands/auth.d.ts.map +1 -0
- package/dist/commands/auth.js +283 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/create.d.ts +8 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +512 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/crystallize.d.ts +8 -0
- package/dist/commands/crystallize.d.ts.map +1 -0
- package/dist/commands/crystallize.js +101 -0
- package/dist/commands/crystallize.js.map +1 -0
- package/dist/commands/destroy.d.ts +6 -0
- package/dist/commands/destroy.d.ts.map +1 -0
- package/dist/commands/destroy.js +54 -0
- package/dist/commands/destroy.js.map +1 -0
- package/dist/commands/dispatch.d.ts +9 -0
- package/dist/commands/dispatch.d.ts.map +1 -0
- package/dist/commands/dispatch.js +94 -0
- package/dist/commands/dispatch.js.map +1 -0
- package/dist/commands/enter.d.ts +63 -0
- package/dist/commands/enter.d.ts.map +1 -0
- package/dist/commands/enter.js +206 -0
- package/dist/commands/enter.js.map +1 -0
- package/dist/commands/host-cp.d.ts +191 -0
- package/dist/commands/host-cp.d.ts.map +1 -0
- package/dist/commands/host-cp.js +797 -0
- package/dist/commands/host-cp.js.map +1 -0
- package/dist/commands/init.d.ts +9 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +143 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/install.d.ts +22 -0
- package/dist/commands/install.d.ts.map +1 -0
- package/dist/commands/install.js +203 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/keys.d.ts +26 -0
- package/dist/commands/keys.d.ts.map +1 -0
- package/dist/commands/keys.js +151 -0
- package/dist/commands/keys.js.map +1 -0
- package/dist/commands/lanes.d.ts +18 -0
- package/dist/commands/lanes.d.ts.map +1 -0
- package/dist/commands/lanes.js +122 -0
- package/dist/commands/lanes.js.map +1 -0
- package/dist/commands/list.d.ts +6 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +39 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/logs.d.ts +38 -0
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/commands/logs.js +177 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/observe.d.ts +9 -0
- package/dist/commands/observe.d.ts.map +1 -0
- package/dist/commands/observe.js +34 -0
- package/dist/commands/observe.js.map +1 -0
- package/dist/commands/policy-check.d.ts +14 -0
- package/dist/commands/policy-check.d.ts.map +1 -0
- package/dist/commands/policy-check.js +76 -0
- package/dist/commands/policy-check.js.map +1 -0
- package/dist/commands/pr.d.ts +17 -0
- package/dist/commands/pr.d.ts.map +1 -0
- package/dist/commands/pr.js +148 -0
- package/dist/commands/pr.js.map +1 -0
- package/dist/commands/ps.d.ts +25 -0
- package/dist/commands/ps.d.ts.map +1 -0
- package/dist/commands/ps.js +164 -0
- package/dist/commands/ps.js.map +1 -0
- package/dist/commands/refresh-helpers.d.ts +25 -0
- package/dist/commands/refresh-helpers.d.ts.map +1 -0
- package/dist/commands/refresh-helpers.js +56 -0
- package/dist/commands/refresh-helpers.js.map +1 -0
- package/dist/commands/refresh.d.ts +23 -0
- package/dist/commands/refresh.d.ts.map +1 -0
- package/dist/commands/refresh.js +237 -0
- package/dist/commands/refresh.js.map +1 -0
- package/dist/commands/status.d.ts +6 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +51 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/upgrade.d.ts +67 -0
- package/dist/commands/upgrade.d.ts.map +1 -0
- package/dist/commands/upgrade.js +358 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/commands/workspace.d.ts +23 -0
- package/dist/commands/workspace.d.ts.map +1 -0
- package/dist/commands/workspace.js +198 -0
- package/dist/commands/workspace.js.map +1 -0
- package/dist/commands/world-snapshot.d.ts +18 -0
- package/dist/commands/world-snapshot.d.ts.map +1 -0
- package/dist/commands/world-snapshot.js +327 -0
- package/dist/commands/world-snapshot.js.map +1 -0
- package/dist/context.d.ts +26 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +51 -0
- package/dist/context.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18007 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server.js +32236 -0
- package/dist/output.d.ts +10 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +31 -0
- package/dist/output.js.map +1 -0
- package/host-cp/compose.yaml +126 -0
- package/host-cp/src/auth-secret-hint.mjs +45 -0
- package/host-cp/src/auth.mjs +155 -0
- package/host-cp/src/compose-worlds-sources.mjs +170 -0
- package/host-cp/src/container-secret-fetcher.mjs +163 -0
- package/host-cp/src/docker-events.mjs +184 -0
- package/host-cp/src/local-worlds-source.mjs +83 -0
- package/host-cp/src/plan-orchestrator.mjs +829 -0
- package/host-cp/src/plan-progress.mjs +282 -0
- package/host-cp/src/pr-cache.mjs +201 -0
- package/host-cp/src/pr-merge-poller.mjs +154 -0
- package/host-cp/src/process-poller.mjs +250 -0
- package/host-cp/src/proxy.mjs +245 -0
- package/host-cp/src/pylon-worlds-source.mjs +68 -0
- package/host-cp/src/redact.mjs +67 -0
- package/host-cp/src/secret-cache.mjs +104 -0
- package/host-cp/src/server.mjs +2215 -0
- package/host-cp/src/sse-gate.mjs +117 -0
- package/host-cp/src/version-status.mjs +209 -0
- package/host-cp/src/workspace-catalog.mjs +149 -0
- package/host-cp/src/world-names-store.mjs +176 -0
- package/host-cp/src/world-pr-state.mjs +97 -0
- package/host-cp/src/world-progress.mjs +322 -0
- package/host-cp/src/world-tunnel-manager.mjs +288 -0
- package/host-cp/src/worlds-db-source.mjs +191 -0
- package/host-cp/src/worlds-source.mjs +59 -0
- package/package.json +38 -0
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* olam create — Provision a new isolated development world.
|
|
3
|
+
*
|
|
4
|
+
* Delegates to WorldManager.createWorld, same as the MCP server tool.
|
|
5
|
+
*/
|
|
6
|
+
import { spawnSync } from 'node:child_process';
|
|
7
|
+
import { existsSync } from 'node:fs';
|
|
8
|
+
import { dirname, resolve } from 'node:path';
|
|
9
|
+
import ora from 'ora';
|
|
10
|
+
import pc from 'picocolors';
|
|
11
|
+
import { AuthPreflightError } from '@olam/core/src/world/manager.js';
|
|
12
|
+
import { getDevboxFreshness, formatFreshnessWarning, } from '@olam/core/src/world/devbox-freshness.js';
|
|
13
|
+
import { inferRepos, PICKER_CONFIDENCE_THRESHOLD, } from '@olam/core/src/world/infer-repos.js';
|
|
14
|
+
import { decideWorkspaceMatch, } from '@olam/core/src/world/match-workspace.js';
|
|
15
|
+
import { loadContext } from '../context.js';
|
|
16
|
+
import { printError, printInfo, printHeader, printWarning } from '../output.js';
|
|
17
|
+
import { probeHostCp, gatherProbeFailureDiagnostics, callHostCpProxy, openHostCpUrl } from './host-cp.js';
|
|
18
|
+
const HOST_CP_URL = 'http://127.0.0.1:19000';
|
|
19
|
+
/** Read the host-cp token from ~/.olam/host-cp.token for use in create. */
|
|
20
|
+
async function readHostCpTokenForCreate() {
|
|
21
|
+
try {
|
|
22
|
+
const { default: fs } = await import('node:fs');
|
|
23
|
+
const { default: os } = await import('node:os');
|
|
24
|
+
const { default: path } = await import('node:path');
|
|
25
|
+
const tp = path.join(process.env.OLAM_HOME ?? path.join(os.homedir(), '.olam'), 'host-cp.token');
|
|
26
|
+
if (!fs.existsSync(tp))
|
|
27
|
+
return null;
|
|
28
|
+
return fs.readFileSync(tp, 'utf-8').trim();
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export function registerCreate(program) {
|
|
35
|
+
program
|
|
36
|
+
.command('create')
|
|
37
|
+
.description('Create a new development world')
|
|
38
|
+
.option('--name <name>', 'World name (required unless --from-prompt is set; auto-derived in that case)')
|
|
39
|
+
.option('--repos <repos...>', 'Repos to include (names from .olam/config.yaml; wins over --workspace)')
|
|
40
|
+
.option('--workspace <name>', 'Named workspace from the host catalog (~/.olam/workspaces/<name>.yaml)')
|
|
41
|
+
.option('--task <task>', 'Initial task to dispatch')
|
|
42
|
+
.option('--branch <branch>', 'Override default branch name')
|
|
43
|
+
.option('--plan <file>', 'Path to a plan file to inject')
|
|
44
|
+
.option('--no-auth', 'Skip auto-injecting host credentials')
|
|
45
|
+
// Phase F-2-D (D4): host CP integration. Default: emit a one-line
|
|
46
|
+
// hint if host CP is not running. --no-host-cp suppresses the hint
|
|
47
|
+
// entirely. Real auto-start ships in a future iteration; for now
|
|
48
|
+
// the hint keeps the operator's existing workflow unblocked while
|
|
49
|
+
// surfacing the host CP UI option.
|
|
50
|
+
.option('--no-host-cp', 'Suppress the host CP "you might want to start it" hint')
|
|
51
|
+
// Phase C9 (olam-dogfood-vision): opt-in flag spawns a parallel
|
|
52
|
+
// claude-lane-codex-review session alongside claude-main, prompted
|
|
53
|
+
// to monitor + critique main's work. Lives on the same world; sees
|
|
54
|
+
// the same workspace + thoughts. Auto-spawned at world creation
|
|
55
|
+
// time; the operator can destroy it via `olam lanes destroy <world>
|
|
56
|
+
// codex-review` if it gets noisy.
|
|
57
|
+
.option('--auto-codex-review', 'Spawn a parallel codex-review lane that critiques main as it works')
|
|
58
|
+
// Phase D6 (olam-dogfood-vision): open Host CP UI in browser on
|
|
59
|
+
// successful create. Default-on for interactive sessions; suppress
|
|
60
|
+
// with --no-open. Headless / CI / piped-output runs auto-skip.
|
|
61
|
+
.option('--no-open', 'Suppress auto-opening the Host CP UI in the browser on success')
|
|
62
|
+
// M5 dogfood follow-up (B1): when the devbox image is older than
|
|
63
|
+
// the source files baked into it, fresh worlds run stale code.
|
|
64
|
+
// --rebuild-base auto-invokes the build script; --no-freshness-check
|
|
65
|
+
// skips the warning entirely (CI/automation).
|
|
66
|
+
.option('--rebuild-base', 'Rebuild olam-devbox:latest before creating (slow)')
|
|
67
|
+
.option('--no-freshness-check', 'Skip the devbox image freshness check')
|
|
68
|
+
// CLI parity for the MCP `olam_create_from_prompt` tool. The prompt
|
|
69
|
+
// is dispatched as the world's task AND drives the workspace
|
|
70
|
+
// inference (same heuristic the MCP tool uses). When passed:
|
|
71
|
+
// - --name is auto-derived from the prompt (slugified, capped at 40 chars)
|
|
72
|
+
// - --workspace + --repos are inferred against the host-cp catalog
|
|
73
|
+
// - On low-confidence inference or N-way ambiguity, the CLI prints
|
|
74
|
+
// the picker payload and exits 1 so the operator can re-run with
|
|
75
|
+
// an explicit --workspace / --repos.
|
|
76
|
+
// Mutually exclusive with --task (the prompt IS the task) and
|
|
77
|
+
// overrides --name. --workspace/--repos still win if explicitly set.
|
|
78
|
+
.option('--from-prompt <prompt>', 'NL prompt → infer workspace + dispatch (CLI parity for olam_create_from_prompt MCP tool)')
|
|
79
|
+
.option('--keep-after-merge', "Disable auto-destroy when the world's PR merges (useful for inspection/debugging)")
|
|
80
|
+
// Phase B B3 (olam-session-stability): opt out of B1's strip step
|
|
81
|
+
// so the operator's in-progress edits make it into the world's
|
|
82
|
+
// worktree. Default OFF: world starts with a clean tree (the
|
|
83
|
+
// baseline-diff snapshot still runs so the reaper can scope claude's
|
|
84
|
+
// footprint). Use this when you've explicitly staged or modified
|
|
85
|
+
// files in your local checkout and want claude to continue from
|
|
86
|
+
// there.
|
|
87
|
+
.option('--carry-uncommitted', "Preserve operator's uncommitted edits in the world's worktree")
|
|
88
|
+
.action(async (opts) => {
|
|
89
|
+
// CLI parity for the MCP tool: when --from-prompt is set, treat
|
|
90
|
+
// it as the world's task AND use it to infer workspace + repos.
|
|
91
|
+
// Mutually exclusive with --task; explicit --workspace / --repos
|
|
92
|
+
// still win (operator override).
|
|
93
|
+
let resolvedName = opts.name;
|
|
94
|
+
let resolvedWorkspace = opts.workspace;
|
|
95
|
+
let resolvedRepos = opts.repos;
|
|
96
|
+
let resolvedTask = opts.task;
|
|
97
|
+
if (opts.fromPrompt) {
|
|
98
|
+
if (opts.task) {
|
|
99
|
+
printError('--from-prompt and --task are mutually exclusive (the prompt IS the task).');
|
|
100
|
+
process.exitCode = 1;
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
resolvedTask = opts.fromPrompt;
|
|
104
|
+
if (!resolvedName) {
|
|
105
|
+
resolvedName = defaultNameFromPrompt(opts.fromPrompt);
|
|
106
|
+
}
|
|
107
|
+
// Infer when caller didn't already pin workspace + repos.
|
|
108
|
+
if (!resolvedWorkspace && !resolvedRepos) {
|
|
109
|
+
const inferenceSpinner = ora('Inferring workspace from prompt…').start();
|
|
110
|
+
try {
|
|
111
|
+
const catalog = await fetchHostCpWorkspaces();
|
|
112
|
+
const catalogRepos = Array.from(new Set(catalog.flatMap((w) => w.projects)));
|
|
113
|
+
const inferred = inferRepos({
|
|
114
|
+
prompt: opts.fromPrompt,
|
|
115
|
+
catalog: catalogRepos,
|
|
116
|
+
});
|
|
117
|
+
if (!inferred.proceed) {
|
|
118
|
+
inferenceSpinner.fail('Inference confidence too low');
|
|
119
|
+
const reason = inferred.repos.length === 0
|
|
120
|
+
? 'no repo names extracted from prompt'
|
|
121
|
+
: `inference confidence ${inferred.confidence.toFixed(2)} below ${PICKER_CONFIDENCE_THRESHOLD}`;
|
|
122
|
+
printError(`Picker needed: ${reason}`);
|
|
123
|
+
if (catalogRepos.length > 0) {
|
|
124
|
+
console.log(pc.dim(` available repos: ${catalogRepos.join(', ')}`));
|
|
125
|
+
}
|
|
126
|
+
console.log(pc.dim(' rerun with explicit --workspace <name> or --repos <a> <b> <c>'));
|
|
127
|
+
process.exitCode = 1;
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const exactMatches = await fetchHostCpExactMatches(inferred.repos);
|
|
131
|
+
const decision = decideWorkspaceMatch({
|
|
132
|
+
inferredRepos: inferred.repos,
|
|
133
|
+
exactMatches,
|
|
134
|
+
fullCatalog: catalog,
|
|
135
|
+
});
|
|
136
|
+
if (decision.result === 'exact-1') {
|
|
137
|
+
resolvedWorkspace = decision.workspace.name;
|
|
138
|
+
}
|
|
139
|
+
else if (decision.result === 'subset-1') {
|
|
140
|
+
resolvedWorkspace = decision.workspace.name;
|
|
141
|
+
}
|
|
142
|
+
else if (decision.result === 'exact-N' || decision.result === 'subset-N') {
|
|
143
|
+
inferenceSpinner.fail(`Multiple workspaces match (${decision.result})`);
|
|
144
|
+
const cands = decision.result === 'exact-N'
|
|
145
|
+
? decision.candidates.map((w) => w.name)
|
|
146
|
+
: decision.candidates.map((c) => c.workspace.name);
|
|
147
|
+
printError(`Picker needed: ${cands.join(', ')}`);
|
|
148
|
+
console.log(pc.dim(' rerun with explicit --workspace <name>'));
|
|
149
|
+
process.exitCode = 1;
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
// create-new — no existing workspace covers the inferred
|
|
154
|
+
// repo set. Pass repos through; WorldManager creates one.
|
|
155
|
+
resolvedRepos = [...inferred.repos];
|
|
156
|
+
}
|
|
157
|
+
inferenceSpinner.succeed(resolvedWorkspace
|
|
158
|
+
? `Inferred workspace: ${resolvedWorkspace} (confidence ${inferred.confidence.toFixed(2)})`
|
|
159
|
+
: `Inferred new workspace from repos: ${inferred.repos.join(', ')}`);
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
inferenceSpinner.fail('Inference failed');
|
|
163
|
+
printError(err instanceof Error ? err.message : String(err));
|
|
164
|
+
process.exitCode = 1;
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (!resolvedName) {
|
|
170
|
+
printError('--name is required (omit only when --from-prompt is set).');
|
|
171
|
+
process.exitCode = 1;
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const { ctx, error } = await loadContext();
|
|
175
|
+
if (!ctx) {
|
|
176
|
+
printError(error?.message ?? 'Olam is not configured. Run `olam init` first.');
|
|
177
|
+
process.exitCode = 1;
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
// M5 dogfood follow-up (B1): devbox staleness check. Resolves
|
|
181
|
+
// repo root by walking up from cwd until we hit a directory
|
|
182
|
+
// containing `packages/`. Falls back to cwd if not found.
|
|
183
|
+
if (opts.freshnessCheck) {
|
|
184
|
+
const repoRoot = resolveRepoRoot(process.cwd());
|
|
185
|
+
const freshness = getDevboxFreshness({ repoRoot });
|
|
186
|
+
if (freshness.isStale) {
|
|
187
|
+
if (opts.rebuildBase) {
|
|
188
|
+
const spinner = ora('Rebuilding olam-devbox:latest…').start();
|
|
189
|
+
const rebuild = spawnSync('bash', [resolve(repoRoot, 'packages/adapters/src/docker/build-devbox.sh')], { cwd: repoRoot, stdio: 'inherit' });
|
|
190
|
+
if (rebuild.status !== 0) {
|
|
191
|
+
spinner.fail('Devbox rebuild failed');
|
|
192
|
+
process.exitCode = 1;
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
spinner.succeed('Devbox image rebuilt');
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
const warning = formatFreshnessWarning(freshness);
|
|
199
|
+
if (warning)
|
|
200
|
+
printWarning(warning);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
const spinner = ora('Creating world...').start();
|
|
205
|
+
try {
|
|
206
|
+
const world = await ctx.worldManager.createWorld({
|
|
207
|
+
name: resolvedName,
|
|
208
|
+
repos: resolvedRepos,
|
|
209
|
+
...(resolvedWorkspace ? { workspace: resolvedWorkspace } : {}),
|
|
210
|
+
task: resolvedTask,
|
|
211
|
+
branchName: opts.branch,
|
|
212
|
+
planFile: opts.plan,
|
|
213
|
+
noAuth: !opts.auth,
|
|
214
|
+
// ADV-B3-LOW2: strict-boolean coercion. `?? false` would pass through
|
|
215
|
+
// truthy non-booleans (e.g. if the flag's shape ever grows to
|
|
216
|
+
// `--carry-uncommitted [mode]` where commander returns a string).
|
|
217
|
+
// `=== true` ensures only the literal boolean true reaches the
|
|
218
|
+
// manager, matching the manager's strict `if (!opts.carryUncommitted)`.
|
|
219
|
+
carryUncommitted: opts.carryUncommitted === true,
|
|
220
|
+
});
|
|
221
|
+
spinner.succeed('World created');
|
|
222
|
+
// --keep-after-merge: persist into the registry immediately so
|
|
223
|
+
// the host-cp polling loop sees it even if host-cp starts later.
|
|
224
|
+
if (opts.keepAfterMerge) {
|
|
225
|
+
const { WorldRegistry } = await import('@olam/core/src/world/registry.js');
|
|
226
|
+
const reg2 = new WorldRegistry();
|
|
227
|
+
try {
|
|
228
|
+
reg2.update(world.id, { autoDestroyOnMerge: false });
|
|
229
|
+
}
|
|
230
|
+
finally {
|
|
231
|
+
reg2.close();
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
printHeader(world.name);
|
|
235
|
+
printInfo('ID', world.id);
|
|
236
|
+
printInfo('Status', world.status);
|
|
237
|
+
printInfo('Repos', world.repos.join(', ') || '(all configured)');
|
|
238
|
+
printInfo('Branch', world.branch);
|
|
239
|
+
printInfo('Port Offset', String(world.portOffset));
|
|
240
|
+
printInfo('Provider', world.computeProvider);
|
|
241
|
+
printInfo('Workspace', world.workspacePath);
|
|
242
|
+
if (world.dashboardUrl) {
|
|
243
|
+
printInfo('Dashboard', world.dashboardUrl);
|
|
244
|
+
}
|
|
245
|
+
if (world.appPortUrls && world.appPortUrls.length > 0) {
|
|
246
|
+
world.appPortUrls.forEach((ap, i) => {
|
|
247
|
+
printInfo(i === 0 ? 'Apps' : '', `${ap.repoName} ${ap.url}`);
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
if (resolvedTask) {
|
|
251
|
+
printInfo('Task', resolvedTask);
|
|
252
|
+
}
|
|
253
|
+
if (world.credentialsInjected?.claude) {
|
|
254
|
+
console.log(`\n${pc.green('Credentials injected. World is ready for dispatch.')}`);
|
|
255
|
+
}
|
|
256
|
+
else if (world.dashboardUrl) {
|
|
257
|
+
console.log(`\n${pc.yellow('Authenticate at')} ${world.dashboardUrl}`);
|
|
258
|
+
}
|
|
259
|
+
// host-cp reliability fix: use HTTP probe instead of docker-only detection.
|
|
260
|
+
// Supports both bare-node and container deployments.
|
|
261
|
+
if (opts.hostCp !== false) {
|
|
262
|
+
const probeResult = await probeHostCp().catch(() => null);
|
|
263
|
+
if (!probeResult) {
|
|
264
|
+
// Fail-loud: the world IS created but auto-registration failed.
|
|
265
|
+
const diag = await gatherProbeFailureDiagnostics().catch(() => ({
|
|
266
|
+
bootstrapStatus: 'probe error',
|
|
267
|
+
containerStatus: 'probe error',
|
|
268
|
+
}));
|
|
269
|
+
process.stderr.write([
|
|
270
|
+
'',
|
|
271
|
+
pc.red('Host CP probe failed.'),
|
|
272
|
+
` tried: http://127.0.0.1:19000/api/bootstrap → ${diag.bootstrapStatus}`,
|
|
273
|
+
` tried: docker container "olam-host-cp" → ${diag.containerStatus}`,
|
|
274
|
+
'',
|
|
275
|
+
pc.yellow('World was created but the SPA inbox will not show it until you:'),
|
|
276
|
+
` ${pc.cyan('olam host-cp start')} (start the host CP)`,
|
|
277
|
+
` ${pc.cyan(`olam host-cp register --world ${world.id}`)} (register manually)`,
|
|
278
|
+
` OR pass ${pc.dim('--no-host-cp')} on next create to suppress this check.`,
|
|
279
|
+
'',
|
|
280
|
+
].join('\n'));
|
|
281
|
+
process.exitCode = 1;
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
// Auto-register the new world so it appears in the host CP UI
|
|
285
|
+
// immediately. Per-world CP base port = 19080 + offset.
|
|
286
|
+
const cpPort = 19080 + world.portOffset;
|
|
287
|
+
const hostCpUrl = probeResult.url;
|
|
288
|
+
const reg = await (async () => {
|
|
289
|
+
const token = await readHostCpTokenForCreate();
|
|
290
|
+
if (!token)
|
|
291
|
+
return { ok: false, status: 0, error: 'no token' };
|
|
292
|
+
const url = `${hostCpUrl}/api/admin/registry`;
|
|
293
|
+
try {
|
|
294
|
+
const res = await fetch(url, {
|
|
295
|
+
method: 'POST',
|
|
296
|
+
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
|
|
297
|
+
body: JSON.stringify({ id: world.id, port: cpPort }),
|
|
298
|
+
});
|
|
299
|
+
if (!res.ok) {
|
|
300
|
+
const text = await res.text().catch(() => '');
|
|
301
|
+
return { ok: false, status: res.status, error: text || `HTTP ${res.status}` };
|
|
302
|
+
}
|
|
303
|
+
return { ok: true, status: res.status };
|
|
304
|
+
}
|
|
305
|
+
catch (err) {
|
|
306
|
+
return { ok: false, status: 0, error: err instanceof Error ? err.message : String(err) };
|
|
307
|
+
}
|
|
308
|
+
})();
|
|
309
|
+
if (!reg.ok) {
|
|
310
|
+
process.stderr.write([
|
|
311
|
+
'',
|
|
312
|
+
pc.red('Host CP registry POST failed.'),
|
|
313
|
+
` url: ${hostCpUrl}/api/admin/registry`,
|
|
314
|
+
` status: ${reg.status}`,
|
|
315
|
+
` error: ${reg.error}`,
|
|
316
|
+
'',
|
|
317
|
+
pc.yellow('World was created but not registered. Run manually:'),
|
|
318
|
+
` ${pc.cyan(`olam host-cp register --world ${world.id}`)}`,
|
|
319
|
+
'',
|
|
320
|
+
].join('\n'));
|
|
321
|
+
process.exitCode = 1;
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
printInfo('Host CP', `registered → :${cpPort} (mode: ${probeResult.mode})`);
|
|
325
|
+
// Propagate the friendly name from the CLI's --name flag.
|
|
326
|
+
try {
|
|
327
|
+
const token = await readHostCpTokenForCreate();
|
|
328
|
+
if (token && world.name && world.name !== world.id) {
|
|
329
|
+
await fetch(`${hostCpUrl}/api/worlds/${encodeURIComponent(world.id)}`, {
|
|
330
|
+
method: 'PATCH',
|
|
331
|
+
headers: {
|
|
332
|
+
Authorization: `Bearer ${token}`,
|
|
333
|
+
'Content-Type': 'application/json',
|
|
334
|
+
},
|
|
335
|
+
body: JSON.stringify({ name: world.name }),
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
// --keep-after-merge: record auto_destroy_on_merge=false.
|
|
339
|
+
if (opts.keepAfterMerge && token) {
|
|
340
|
+
await fetch(`${hostCpUrl}/api/admin/world-pr`, {
|
|
341
|
+
method: 'POST',
|
|
342
|
+
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
|
|
343
|
+
body: JSON.stringify({ worldId: world.id, prUrl: null, autoDestroyOnMerge: false }),
|
|
344
|
+
signal: AbortSignal.timeout(3000),
|
|
345
|
+
});
|
|
346
|
+
printInfo('Keep-after-merge', 'auto-destroy disabled for this world');
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
catch {
|
|
350
|
+
// Silent — the world is registered; the name is just UI sugar.
|
|
351
|
+
}
|
|
352
|
+
// Phase C9: spawn the auto-codex-review lane.
|
|
353
|
+
if (opts.autoCodexReview && reg.ok) {
|
|
354
|
+
const reviewTask = 'You are the codex-review sub-lane. Watch the main session ' +
|
|
355
|
+
'(claude-main) as it works on the world\'s primary task. ' +
|
|
356
|
+
'Periodically read its recent thought_nodes (filter by ' +
|
|
357
|
+
'session_id=claude-main) and surface concrete concerns: ' +
|
|
358
|
+
'security risks, plumbing bugs, premature abstractions. ' +
|
|
359
|
+
'Adversarial-reviewer voice; constructive but blunt.';
|
|
360
|
+
try {
|
|
361
|
+
const result = await callHostCpProxy('POST', world.id, '/lanes/create', { name: 'codex-review', task: reviewTask });
|
|
362
|
+
if (result.ok) {
|
|
363
|
+
printInfo('Auto-review', 'spawned claude-lane-codex-review');
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
printWarning(`Auto-review spawn failed (HTTP ${result.status}): ${result.error}. Retry with \`olam lanes create ${world.id} --name codex-review --task '...'\`.`);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
catch (err) {
|
|
370
|
+
printWarning(`Auto-review spawn errored: ${err instanceof Error ? err.message : String(err)}`);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
const worldUrl = `${hostCpUrl}/world/${encodeURIComponent(world.id)}`;
|
|
374
|
+
console.log(`\n${pc.cyan('Host CP UI:')} ${worldUrl}`);
|
|
375
|
+
// Phase D6: auto-open in browser unless --no-open.
|
|
376
|
+
if (opts.open !== false && reg.ok) {
|
|
377
|
+
const openResult = openHostCpUrl(worldUrl);
|
|
378
|
+
if (openResult.opened) {
|
|
379
|
+
printInfo('Browser', 'opened');
|
|
380
|
+
}
|
|
381
|
+
else if (openResult.reason) {
|
|
382
|
+
printInfo('Browser', `not opened (${openResult.reason})`);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
catch (err) {
|
|
388
|
+
spinner.fail('Failed to create world');
|
|
389
|
+
if (err instanceof AuthPreflightError) {
|
|
390
|
+
printError(err.message);
|
|
391
|
+
if (err.remedy)
|
|
392
|
+
console.log(` ${pc.dim(err.remedy)}`);
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
printError(err instanceof Error ? err.message : String(err));
|
|
396
|
+
}
|
|
397
|
+
process.exitCode = 1;
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Walk up from `start` until we find a directory containing `packages/`.
|
|
403
|
+
* Used by the B1 freshness check to locate paths relative to the repo
|
|
404
|
+
* root regardless of which subdirectory the operator invoked the CLI
|
|
405
|
+
* from. Falls back to `start` if no marker is found before /.
|
|
406
|
+
*/
|
|
407
|
+
function resolveRepoRoot(start) {
|
|
408
|
+
let cur = start;
|
|
409
|
+
while (true) {
|
|
410
|
+
// Repo root signature: top-level package.json + packages/ dir.
|
|
411
|
+
if (existsSync(resolve(cur, 'packages')) && existsSync(resolve(cur, 'package.json'))) {
|
|
412
|
+
return cur;
|
|
413
|
+
}
|
|
414
|
+
const parent = dirname(cur);
|
|
415
|
+
if (parent === cur)
|
|
416
|
+
return start; // walked to filesystem root
|
|
417
|
+
cur = parent;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Slugify an NL prompt into a default world name. Lowercase, kebab-
|
|
422
|
+
* case, max 40 chars. Mirrors the MCP tool's `defaultNameFromPrompt`
|
|
423
|
+
* helper at packages/mcp-server/src/tools/create-from-prompt.ts so
|
|
424
|
+
* --from-prompt produces the same slug shape regardless of entry
|
|
425
|
+
* point.
|
|
426
|
+
*/
|
|
427
|
+
function defaultNameFromPrompt(prompt) {
|
|
428
|
+
const slug = prompt
|
|
429
|
+
.toLowerCase()
|
|
430
|
+
.replace(/[^a-z0-9\s-]/g, '')
|
|
431
|
+
.trim()
|
|
432
|
+
.replace(/\s+/g, '-')
|
|
433
|
+
.slice(0, 40);
|
|
434
|
+
return slug || 'unnamed';
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Read host-cp's startup token. Defensive — returns null on every
|
|
438
|
+
* failure (file missing, permissions, etc.) so --from-prompt can
|
|
439
|
+
* still fall through to a "host-cp not running" picker error rather
|
|
440
|
+
* than throwing.
|
|
441
|
+
*/
|
|
442
|
+
async function readHostCpToken() {
|
|
443
|
+
try {
|
|
444
|
+
const { default: fs } = await import('node:fs');
|
|
445
|
+
const { default: os } = await import('node:os');
|
|
446
|
+
const { default: path } = await import('node:path');
|
|
447
|
+
const tp = path.join(os.homedir(), '.olam', 'host-cp.token');
|
|
448
|
+
if (!fs.existsSync(tp))
|
|
449
|
+
return null;
|
|
450
|
+
const raw = fs.readFileSync(tp, 'utf-8').trim();
|
|
451
|
+
return raw.length > 0 ? raw : null;
|
|
452
|
+
}
|
|
453
|
+
catch {
|
|
454
|
+
return null;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Fetch the operator's workspace catalog from host-cp's
|
|
459
|
+
* GET /api/workspaces. Empty array on any failure (host-cp not
|
|
460
|
+
* running, network, parse) — the caller's inference will then run
|
|
461
|
+
* with empty catalog and degrade to a low-confidence picker rather
|
|
462
|
+
* than crash.
|
|
463
|
+
*/
|
|
464
|
+
async function fetchHostCpWorkspaces() {
|
|
465
|
+
try {
|
|
466
|
+
const token = await readHostCpToken();
|
|
467
|
+
if (!token)
|
|
468
|
+
return [];
|
|
469
|
+
const res = await fetch(`${HOST_CP_URL}/api/workspaces`, {
|
|
470
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
471
|
+
});
|
|
472
|
+
if (!res.ok)
|
|
473
|
+
return [];
|
|
474
|
+
const data = (await res.json());
|
|
475
|
+
const arr = Array.isArray(data) ? data : (data.workspaces ?? []);
|
|
476
|
+
return arr
|
|
477
|
+
.filter((w) => typeof w.name === 'string' && Array.isArray(w.projects))
|
|
478
|
+
.map((w) => ({ name: w.name, projects: w.projects ?? [] }));
|
|
479
|
+
}
|
|
480
|
+
catch {
|
|
481
|
+
return [];
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Fetch host-cp's POST /api/workspaces/match exact-match candidates
|
|
486
|
+
* for a given inferred repo set. Empty array on any failure.
|
|
487
|
+
*/
|
|
488
|
+
async function fetchHostCpExactMatches(projects) {
|
|
489
|
+
try {
|
|
490
|
+
const token = await readHostCpToken();
|
|
491
|
+
if (!token)
|
|
492
|
+
return [];
|
|
493
|
+
const res = await fetch(`${HOST_CP_URL}/api/workspaces/match`, {
|
|
494
|
+
method: 'POST',
|
|
495
|
+
headers: {
|
|
496
|
+
Authorization: `Bearer ${token}`,
|
|
497
|
+
'Content-Type': 'application/json',
|
|
498
|
+
},
|
|
499
|
+
body: JSON.stringify({ projects }),
|
|
500
|
+
});
|
|
501
|
+
if (!res.ok)
|
|
502
|
+
return [];
|
|
503
|
+
const data = (await res.json());
|
|
504
|
+
return (data.matches ?? [])
|
|
505
|
+
.filter((w) => typeof w.name === 'string' && Array.isArray(w.projects))
|
|
506
|
+
.map((w) => ({ name: w.name, projects: w.projects ?? [] }));
|
|
507
|
+
}
|
|
508
|
+
catch {
|
|
509
|
+
return [];
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
//# sourceMappingURL=create.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EACL,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,0CAA0C,CAAC;AAClD,OAAO,EACL,UAAU,EACV,2BAA2B,GAC5B,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EACL,oBAAoB,GAErB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,6BAA6B,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE1G,MAAM,WAAW,GAAG,wBAAwB,CAAC;AAE7C,2EAA2E;AAC3E,KAAK,UAAU,wBAAwB;IACrC,IAAI,CAAC;QACH,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;QAChD,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;QAChD,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;QACpD,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAClB,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,EACzD,eAAe,CAChB,CAAC;QACF,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;YAAE,OAAO,IAAI,CAAC;QACpC,OAAO,EAAE,CAAC,YAAY,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,OAAgB;IAC7C,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,gCAAgC,CAAC;SAC7C,MAAM,CAAC,eAAe,EAAE,8EAA8E,CAAC;SACvG,MAAM,CAAC,oBAAoB,EAAE,wEAAwE,CAAC;SACtG,MAAM,CAAC,oBAAoB,EAAE,wEAAwE,CAAC;SACtG,MAAM,CAAC,eAAe,EAAE,0BAA0B,CAAC;SACnD,MAAM,CAAC,mBAAmB,EAAE,8BAA8B,CAAC;SAC3D,MAAM,CAAC,eAAe,EAAE,+BAA+B,CAAC;SACxD,MAAM,CAAC,WAAW,EAAE,sCAAsC,CAAC;QAC5D,kEAAkE;QAClE,mEAAmE;QACnE,iEAAiE;QACjE,kEAAkE;QAClE,mCAAmC;SAClC,MAAM,CAAC,cAAc,EAAE,wDAAwD,CAAC;QACjF,gEAAgE;QAChE,mEAAmE;QACnE,mEAAmE;QACnE,gEAAgE;QAChE,oEAAoE;QACpE,kCAAkC;SACjC,MAAM,CAAC,qBAAqB,EAAE,oEAAoE,CAAC;QACpG,gEAAgE;QAChE,mEAAmE;QACnE,+DAA+D;SAC9D,MAAM,CAAC,WAAW,EAAE,gEAAgE,CAAC;QACtF,iEAAiE;QACjE,+DAA+D;QAC/D,qEAAqE;QACrE,8CAA8C;SAC7C,MAAM,CAAC,gBAAgB,EAAE,mDAAmD,CAAC;SAC7E,MAAM,CAAC,sBAAsB,EAAE,uCAAuC,CAAC;QACxE,oEAAoE;QACpE,6DAA6D;QAC7D,6DAA6D;QAC7D,6EAA6E;QAC7E,qEAAqE;QACrE,qEAAqE;QACrE,qEAAqE;QACrE,yCAAyC;QACzC,8DAA8D;QAC9D,qEAAqE;SACpE,MAAM,CAAC,wBAAwB,EAAE,0FAA0F,CAAC;SAC5H,MAAM,CAAC,oBAAoB,EAAE,mFAAmF,CAAC;QAClH,kEAAkE;QAClE,+DAA+D;QAC/D,6DAA6D;QAC7D,qEAAqE;QACrE,iEAAiE;QACjE,gEAAgE;QAChE,SAAS;SACR,MAAM,CAAC,qBAAqB,EAAE,+DAA+D,CAAC;SAC9F,MAAM,CAAC,KAAK,EAAE,IAgBd,EAAE,EAAE;QACH,gEAAgE;QAChE,gEAAgE;QAChE,iEAAiE;QACjE,iCAAiC;QACjC,IAAI,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC;QAC7B,IAAI,iBAAiB,GAAG,IAAI,CAAC,SAAS,CAAC;QACvC,IAAI,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC;QAC/B,IAAI,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC;QAE7B,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,UAAU,CAAC,2EAA2E,CAAC,CAAC;gBACxF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;gBACrB,OAAO;YACT,CAAC;YACD,YAAY,GAAG,IAAI,CAAC,UAAU,CAAC;YAC/B,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,YAAY,GAAG,qBAAqB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACxD,CAAC;YAED,0DAA0D;YAC1D,IAAI,CAAC,iBAAiB,IAAI,CAAC,aAAa,EAAE,CAAC;gBACzC,MAAM,gBAAgB,GAAG,GAAG,CAAC,kCAAkC,CAAC,CAAC,KAAK,EAAE,CAAC;gBACzE,IAAI,CAAC;oBACH,MAAM,OAAO,GAAG,MAAM,qBAAqB,EAAE,CAAC;oBAC9C,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAC7B,IAAI,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAC5C,CAAC;oBACF,MAAM,QAAQ,GAAG,UAAU,CAAC;wBAC1B,MAAM,EAAE,IAAI,CAAC,UAAU;wBACvB,OAAO,EAAE,YAAY;qBACtB,CAAC,CAAC;oBAEH,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;wBACtB,gBAAgB,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;wBACtD,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;4BACxC,CAAC,CAAC,qCAAqC;4BACvC,CAAC,CAAC,wBAAwB,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,2BAA2B,EAAE,CAAC;wBAClG,UAAU,CAAC,kBAAkB,MAAM,EAAE,CAAC,CAAC;wBACvC,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;4BAC5B,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,sBAAsB,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;wBACvE,CAAC;wBACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,iEAAiE,CAAC,CAAC,CAAC;wBACvF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;wBACrB,OAAO;oBACT,CAAC;oBAED,MAAM,YAAY,GAAG,MAAM,uBAAuB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;oBACnE,MAAM,QAAQ,GAAG,oBAAoB,CAAC;wBACpC,aAAa,EAAE,QAAQ,CAAC,KAAK;wBAC7B,YAAY;wBACZ,WAAW,EAAE,OAAO;qBACrB,CAAC,CAAC;oBAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;wBAClC,iBAAiB,GAAG,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC;oBAC9C,CAAC;yBAAM,IAAI,QAAQ,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;wBAC1C,iBAAiB,GAAG,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC;oBAC9C,CAAC;yBAAM,IAAI,QAAQ,CAAC,MAAM,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;wBAC3E,gBAAgB,CAAC,IAAI,CAAC,8BAA8B,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;wBACxE,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,KAAK,SAAS;4BACzC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;4BACxC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;wBACrD,UAAU,CAAC,kBAAkB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;wBACjD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC,CAAC;wBAChE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;wBACrB,OAAO;oBACT,CAAC;yBAAM,CAAC;wBACN,yDAAyD;wBACzD,0DAA0D;wBAC1D,aAAa,GAAG,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;oBACtC,CAAC;oBAED,gBAAgB,CAAC,OAAO,CACtB,iBAAiB;wBACf,CAAC,CAAC,uBAAuB,iBAAiB,gBAAgB,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG;wBAC3F,CAAC,CAAC,sCAAsC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACtE,CAAC;gBACJ,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,gBAAgB,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;oBAC1C,UAAU,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;oBAC7D,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;oBACrB,OAAO;gBACT,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,UAAU,CAAC,2DAA2D,CAAC,CAAC;YACxE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QAED,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,MAAM,WAAW,EAAE,CAAC;QAC3C,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,UAAU,CAAC,KAAK,EAAE,OAAO,IAAI,gDAAgD,CAAC,CAAC;YAC/E,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QAED,8DAA8D;QAC9D,4DAA4D;QAC5D,0DAA0D;QAC1D,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,MAAM,QAAQ,GAAG,eAAe,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;YAChD,MAAM,SAAS,GAAG,kBAAkB,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;YACnD,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;gBACtB,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;oBACrB,MAAM,OAAO,GAAG,GAAG,CAAC,gCAAgC,CAAC,CAAC,KAAK,EAAE,CAAC;oBAC9D,MAAM,OAAO,GAAG,SAAS,CACvB,MAAM,EACN,CAAC,OAAO,CAAC,QAAQ,EAAE,8CAA8C,CAAC,CAAC,EACnE,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,CACpC,CAAC;oBACF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;wBACzB,OAAO,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;wBACtC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;wBACrB,OAAO;oBACT,CAAC;oBACD,OAAO,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC;gBAC1C,CAAC;qBAAM,CAAC;oBACN,MAAM,OAAO,GAAG,sBAAsB,CAAC,SAAS,CAAC,CAAC;oBAClD,IAAI,OAAO;wBAAE,YAAY,CAAC,OAAO,CAAC,CAAC;gBACrC,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,OAAO,GAAG,GAAG,CAAC,mBAAmB,CAAC,CAAC,KAAK,EAAE,CAAC;QAEjD,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,YAAY,CAAC,WAAW,CAAC;gBAC/C,IAAI,EAAE,YAAY;gBAClB,KAAK,EAAE,aAAa;gBACpB,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC9D,IAAI,EAAE,YAAY;gBAClB,UAAU,EAAE,IAAI,CAAC,MAAM;gBACvB,QAAQ,EAAE,IAAI,CAAC,IAAI;gBACnB,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI;gBAClB,sEAAsE;gBACtE,8DAA8D;gBAC9D,kEAAkE;gBAClE,+DAA+D;gBAC/D,wEAAwE;gBACxE,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,KAAK,IAAI;aACjD,CAAC,CAAC;YAEH,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;YAEjC,+DAA+D;YAC/D,iEAAiE;YACjE,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;gBACxB,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,kCAAkC,CAAC,CAAC;gBAC3E,MAAM,IAAI,GAAG,IAAI,aAAa,EAAE,CAAC;gBACjC,IAAI,CAAC;oBACH,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,kBAAkB,EAAE,KAAK,EAAE,CAAC,CAAC;gBACvD,CAAC;wBAAS,CAAC;oBACT,IAAI,CAAC,KAAK,EAAE,CAAC;gBACf,CAAC;YACH,CAAC;YAED,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACxB,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;YAC1B,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;YAClC,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,kBAAkB,CAAC,CAAC;YACjE,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;YAClC,SAAS,CAAC,aAAa,EAAE,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;YACnD,SAAS,CAAC,UAAU,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;YAC7C,SAAS,CAAC,WAAW,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;YAE5C,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;gBACvB,SAAS,CAAC,WAAW,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;YAC7C,CAAC;YACD,IAAI,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtD,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE;oBAClC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,QAAQ,KAAK,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;gBAChE,CAAC,CAAC,CAAC;YACL,CAAC;YACD,IAAI,YAAY,EAAE,CAAC;gBACjB,SAAS,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;YAClC,CAAC;YAED,IAAI,KAAK,CAAC,mBAAmB,EAAE,MAAM,EAAE,CAAC;gBACtC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,oDAAoD,CAAC,EAAE,CAAC,CAAC;YACrF,CAAC;iBAAM,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;gBAC9B,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC;YACzE,CAAC;YAED,4EAA4E;YAC5E,qDAAqD;YACrD,IAAI,IAAI,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;gBAC1B,MAAM,WAAW,GAAG,MAAM,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;gBAE1D,IAAI,CAAC,WAAW,EAAE,CAAC;oBACjB,gEAAgE;oBAChE,MAAM,IAAI,GAAG,MAAM,6BAA6B,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;wBAC9D,eAAe,EAAE,aAAa;wBAC9B,eAAe,EAAE,aAAa;qBAC/B,CAAC,CAAC,CAAC;oBACJ,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB;wBACE,EAAE;wBACF,EAAE,CAAC,GAAG,CAAC,uBAAuB,CAAC;wBAC/B,mDAAmD,IAAI,CAAC,eAAe,EAAE;wBACzE,8CAA8C,IAAI,CAAC,eAAe,EAAE;wBACpE,EAAE;wBACF,EAAE,CAAC,MAAM,CAAC,iEAAiE,CAAC;wBAC5E,KAAK,EAAE,CAAC,IAAI,CAAC,oBAAoB,CAAC,iCAAiC;wBACnE,KAAK,EAAE,CAAC,IAAI,CAAC,iCAAiC,KAAK,CAAC,EAAE,EAAE,CAAC,wBAAwB;wBACjF,aAAa,EAAE,CAAC,GAAG,CAAC,cAAc,CAAC,yCAAyC;wBAC5E,EAAE;qBACH,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;oBACF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;oBACrB,OAAO;gBACT,CAAC;gBAED,8DAA8D;gBAC9D,wDAAwD;gBACxD,MAAM,MAAM,GAAG,KAAK,GAAG,KAAK,CAAC,UAAU,CAAC;gBACxC,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,CAAC;gBAElC,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE;oBAC5B,MAAM,KAAK,GAAG,MAAM,wBAAwB,EAAE,CAAC;oBAC/C,IAAI,CAAC,KAAK;wBAAE,OAAO,EAAE,EAAE,EAAE,KAAc,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;oBACxE,MAAM,GAAG,GAAG,GAAG,SAAS,qBAAqB,CAAC;oBAC9C,IAAI,CAAC;wBACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;4BAC3B,MAAM,EAAE,MAAM;4BACd,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;4BACjF,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;yBACrD,CAAC,CAAC;wBACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;4BACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;4BAC9C,OAAO,EAAE,EAAE,EAAE,KAAc,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,IAAI,QAAQ,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC;wBACzF,CAAC;wBACD,OAAO,EAAE,EAAE,EAAE,IAAa,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC;oBACnD,CAAC;oBAAC,OAAO,GAAG,EAAE,CAAC;wBACb,OAAO,EAAE,EAAE,EAAE,KAAc,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;oBACpG,CAAC;gBACH,CAAC,CAAC,EAAE,CAAC;gBAEL,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;oBACZ,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB;wBACE,EAAE;wBACF,EAAE,CAAC,GAAG,CAAC,+BAA+B,CAAC;wBACvC,UAAU,SAAS,qBAAqB;wBACxC,aAAa,GAAG,CAAC,MAAM,EAAE;wBACzB,YAAY,GAAG,CAAC,KAAK,EAAE;wBACvB,EAAE;wBACF,EAAE,CAAC,MAAM,CAAC,qDAAqD,CAAC;wBAChE,KAAK,EAAE,CAAC,IAAI,CAAC,iCAAiC,KAAK,CAAC,EAAE,EAAE,CAAC,EAAE;wBAC3D,EAAE;qBACH,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;oBACF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;oBACrB,OAAO;gBACT,CAAC;gBAED,SAAS,CAAC,SAAS,EAAE,iBAAiB,MAAM,WAAW,WAAW,CAAC,IAAI,GAAG,CAAC,CAAC;gBAE5E,0DAA0D;gBAC1D,IAAI,CAAC;oBACH,MAAM,KAAK,GAAG,MAAM,wBAAwB,EAAE,CAAC;oBAC/C,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,EAAE,EAAE,CAAC;wBACnD,MAAM,KAAK,CAAC,GAAG,SAAS,eAAe,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE;4BACrE,MAAM,EAAE,OAAO;4BACf,OAAO,EAAE;gCACP,aAAa,EAAE,UAAU,KAAK,EAAE;gCAChC,cAAc,EAAE,kBAAkB;6BACnC;4BACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;yBAC3C,CAAC,CAAC;oBACL,CAAC;oBACD,0DAA0D;oBAC1D,IAAI,IAAI,CAAC,cAAc,IAAI,KAAK,EAAE,CAAC;wBACjC,MAAM,KAAK,CAAC,GAAG,SAAS,qBAAqB,EAAE;4BAC7C,MAAM,EAAE,MAAM;4BACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE;4BACjF,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,CAAC;4BACnF,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC;yBAClC,CAAC,CAAC;wBACH,SAAS,CAAC,kBAAkB,EAAE,sCAAsC,CAAC,CAAC;oBACxE,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,+DAA+D;gBACjE,CAAC;gBAED,8CAA8C;gBAC9C,IAAI,IAAI,CAAC,eAAe,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;oBACnC,MAAM,UAAU,GACd,4DAA4D;wBAC5D,0DAA0D;wBAC1D,wDAAwD;wBACxD,yDAAyD;wBACzD,yDAAyD;wBACzD,qDAAqD,CAAC;oBACxD,IAAI,CAAC;wBACH,MAAM,MAAM,GAAG,MAAM,eAAe,CAClC,MAAM,EACN,KAAK,CAAC,EAAE,EACR,eAAe,EACf,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,UAAU,EAAE,CAC3C,CAAC;wBACF,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;4BACd,SAAS,CAAC,aAAa,EAAE,kCAAkC,CAAC,CAAC;wBAC/D,CAAC;6BAAM,CAAC;4BACN,YAAY,CACV,kCAAkC,MAAM,CAAC,MAAM,MAAM,MAAM,CAAC,KAAK,oCAAoC,KAAK,CAAC,EAAE,sCAAsC,CACpJ,CAAC;wBACJ,CAAC;oBACH,CAAC;oBAAC,OAAO,GAAG,EAAE,CAAC;wBACb,YAAY,CACV,8BAA8B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CACjF,CAAC;oBACJ,CAAC;gBACH,CAAC;gBAED,MAAM,QAAQ,GAAG,GAAG,SAAS,UAAU,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;gBACtE,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,QAAQ,EAAE,CAAC,CAAC;gBAEvD,mDAAmD;gBACnD,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;oBAClC,MAAM,UAAU,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;oBAC3C,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;wBACtB,SAAS,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;oBACjC,CAAC;yBAAM,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;wBAC7B,SAAS,CAAC,SAAS,EAAE,eAAe,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;oBAC5D,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;YACvC,IAAI,GAAG,YAAY,kBAAkB,EAAE,CAAC;gBACtC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBACxB,IAAI,GAAG,CAAC,MAAM;oBAAE,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACzD,CAAC;iBAAM,CAAC;gBACN,UAAU,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAC/D,CAAC;YACD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC;AAED;;;;;GAKG;AACH,SAAS,eAAe,CAAC,KAAa;IACpC,IAAI,GAAG,GAAG,KAAK,CAAC;IAChB,OAAO,IAAI,EAAE,CAAC;QACZ,+DAA+D;QAC/D,IAAI,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC,IAAI,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC;YACrF,OAAO,GAAG,CAAC;QACb,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,MAAM,KAAK,GAAG;YAAE,OAAO,KAAK,CAAC,CAAC,4BAA4B;QAC9D,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,SAAS,qBAAqB,CAAC,MAAc;IAC3C,MAAM,IAAI,GAAG,MAAM;SAChB,WAAW,EAAE;SACb,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC;SAC5B,IAAI,EAAE;SACN,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAChB,OAAO,IAAI,IAAI,SAAS,CAAC;AAC3B,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,eAAe;IAC5B,IAAI,CAAC;QACH,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;QAChD,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;QAChD,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;QACpD,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,eAAe,CAAC,CAAC;QAC7D,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;YAAE,OAAO,IAAI,CAAC;QACpC,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QAChD,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,qBAAqB;IAClC,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,eAAe,EAAE,CAAC;QACtC,IAAI,CAAC,KAAK;YAAE,OAAO,EAAE,CAAC;QACtB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,WAAW,iBAAiB,EAAE;YACvD,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE;SAC9C,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAEkB,CAAC;QACjD,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;QACjE,OAAO,GAAG;aACP,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;aACtE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,uBAAuB,CACpC,QAA2B;IAE3B,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,eAAe,EAAE,CAAC;QACtC,IAAI,CAAC,KAAK;YAAE,OAAO,EAAE,CAAC;QACtB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,WAAW,uBAAuB,EAAE;YAC7D,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,KAAK,EAAE;gBAChC,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;SACnC,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAE7B,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;aACxB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;aACtE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* olam crystallize <world> — Save a world's thoughts to Pleri Plane.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the MCP server's olam_crystallize tool.
|
|
5
|
+
*/
|
|
6
|
+
import type { Command } from 'commander';
|
|
7
|
+
export declare function registerCrystallize(program: Command): void;
|
|
8
|
+
//# sourceMappingURL=crystallize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crystallize.d.ts","sourceRoot":"","sources":["../../src/commands/crystallize.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMzC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuG1D"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* olam crystallize <world> — Save a world's thoughts to Pleri Plane.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the MCP server's olam_crystallize tool.
|
|
5
|
+
*/
|
|
6
|
+
import * as fs from 'node:fs';
|
|
7
|
+
import * as path from 'node:path';
|
|
8
|
+
import ora from 'ora';
|
|
9
|
+
import { loadContext } from '../context.js';
|
|
10
|
+
import { printError, printInfo, printHeader } from '../output.js';
|
|
11
|
+
import { getWorldDbPath } from '@olam/core/src/world-paths.js';
|
|
12
|
+
export function registerCrystallize(program) {
|
|
13
|
+
program
|
|
14
|
+
.command('crystallize')
|
|
15
|
+
.description('Crystallize thoughts from a world to Pleri Plane')
|
|
16
|
+
.argument('<world>', 'World ID')
|
|
17
|
+
.action(async (worldId) => {
|
|
18
|
+
const { ctx, error } = await loadContext();
|
|
19
|
+
if (!ctx) {
|
|
20
|
+
printError(error?.message ?? 'Olam is not configured. Run `olam init` first.');
|
|
21
|
+
process.exitCode = 1;
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (!ctx.pleriClient) {
|
|
25
|
+
printError('Pleri Plane is not configured. Add pleri section to .olam/config.yaml.');
|
|
26
|
+
process.exitCode = 1;
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const world = ctx.worldManager.getWorld(worldId);
|
|
30
|
+
if (!world) {
|
|
31
|
+
printError(`World "${worldId}" not found.`);
|
|
32
|
+
process.exitCode = 1;
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const thoughtDbPath = getWorldDbPath(world.workspacePath);
|
|
36
|
+
if (!fs.existsSync(thoughtDbPath)) {
|
|
37
|
+
printError(`No thoughts captured yet for "${worldId}". Run a dispatch first.`);
|
|
38
|
+
process.exitCode = 1;
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const spinner = ora('Crystallizing thoughts...').start();
|
|
42
|
+
try {
|
|
43
|
+
const { ThoughtLocalStore } = await import('@olam/core/src/thought/local-store.js');
|
|
44
|
+
const { computeGraphChecksum } = await import('@olam/core/src/crystallize/checksum.js');
|
|
45
|
+
const store = new ThoughtLocalStore(thoughtDbPath);
|
|
46
|
+
const nodes = store.getAllNodes();
|
|
47
|
+
const edges = store.getAllEdges();
|
|
48
|
+
store.close();
|
|
49
|
+
if (nodes.length === 0) {
|
|
50
|
+
spinner.warn('Empty thought store. Run a dispatch first.');
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const checksum = computeGraphChecksum(nodes, edges);
|
|
54
|
+
const result = await ctx.pleriClient.crystallize({
|
|
55
|
+
worldId,
|
|
56
|
+
sessionId: nodes[0].sessionId ?? `session-${Date.now()}`,
|
|
57
|
+
checksum,
|
|
58
|
+
nodes: nodes.map((n) => ({
|
|
59
|
+
id: n.id,
|
|
60
|
+
nodeType: n.nodeType,
|
|
61
|
+
summary: n.summary,
|
|
62
|
+
content: n.content,
|
|
63
|
+
sourceRef: n.sourceRef,
|
|
64
|
+
sequenceNum: n.sequenceNum,
|
|
65
|
+
createdAt: n.createdAt,
|
|
66
|
+
})),
|
|
67
|
+
edges: edges.map((e) => ({
|
|
68
|
+
id: e.id,
|
|
69
|
+
sourceId: e.sourceId,
|
|
70
|
+
targetId: e.targetId,
|
|
71
|
+
edgeType: e.edgeType,
|
|
72
|
+
metadata: e.metadata,
|
|
73
|
+
createdAt: e.createdAt,
|
|
74
|
+
})),
|
|
75
|
+
metadata: {
|
|
76
|
+
worldName: world.name,
|
|
77
|
+
branch: world.branch,
|
|
78
|
+
repos: world.repos,
|
|
79
|
+
totalNodes: nodes.length,
|
|
80
|
+
totalEdges: edges.length,
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
if (result === null) {
|
|
84
|
+
spinner.warn('Could not reach Pleri. Request queued for retry.');
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
spinner.succeed('Crystallization complete');
|
|
88
|
+
printHeader('Crystal');
|
|
89
|
+
printInfo('ID', result.crystallizationId);
|
|
90
|
+
printInfo('Nodes', String(result.nodeCount));
|
|
91
|
+
printInfo('Edges', String(result.edgeCount));
|
|
92
|
+
printInfo('New', String(result.isNew));
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
spinner.fail('Crystallization failed');
|
|
96
|
+
printError(err instanceof Error ? err.message : String(err));
|
|
97
|
+
process.exitCode = 1;
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=crystallize.js.map
|