@hasna/todos 0.11.43 → 0.11.44
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/cli/commands/environment-snapshots.d.ts +3 -0
- package/dist/cli/commands/environment-snapshots.d.ts.map +1 -0
- package/dist/cli/index.js +442 -29
- package/dist/cli-mcp-parity.d.ts +1 -1
- package/dist/cli-mcp-parity.d.ts.map +1 -1
- package/dist/contracts.js +44 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +336 -0
- package/dist/json-contracts.d.ts.map +1 -1
- package/dist/lib/environment-snapshots.d.ts +111 -0
- package/dist/lib/environment-snapshots.d.ts.map +1 -0
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +335 -7
- package/dist/mcp/token-utils.d.ts.map +1 -1
- package/dist/mcp/tools/environment-snapshots.d.ts +8 -0
- package/dist/mcp/tools/environment-snapshots.d.ts.map +1 -0
- package/dist/mcp.js +2 -0
- package/dist/registry.js +58 -0
- package/dist/release-provenance.json +3 -3
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environment-snapshots.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/environment-snapshots.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWzC,wBAAgB,mCAAmC,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA+E1E"}
|
package/dist/cli/index.js
CHANGED
|
@@ -26613,6 +26613,8 @@ var init_token_utils = __esm(() => {
|
|
|
26613
26613
|
"check_file_lock",
|
|
26614
26614
|
"create_comment",
|
|
26615
26615
|
"create_handoff",
|
|
26616
|
+
"capture_environment_snapshot",
|
|
26617
|
+
"compare_environment_snapshots",
|
|
26616
26618
|
"create_inbox_item",
|
|
26617
26619
|
"delete_comment",
|
|
26618
26620
|
"detect_file_relationships",
|
|
@@ -33135,6 +33137,334 @@ var init_templates2 = __esm(() => {
|
|
|
33135
33137
|
init_tasks();
|
|
33136
33138
|
});
|
|
33137
33139
|
|
|
33140
|
+
// src/lib/environment-snapshots.ts
|
|
33141
|
+
var exports_environment_snapshots = {};
|
|
33142
|
+
__export(exports_environment_snapshots, {
|
|
33143
|
+
writeEnvironmentSnapshot: () => writeEnvironmentSnapshot,
|
|
33144
|
+
recordEnvironmentSnapshot: () => recordEnvironmentSnapshot,
|
|
33145
|
+
readEnvironmentSnapshot: () => readEnvironmentSnapshot,
|
|
33146
|
+
compareEnvironmentSnapshots: () => compareEnvironmentSnapshots,
|
|
33147
|
+
compareEnvironmentSnapshotFiles: () => compareEnvironmentSnapshotFiles,
|
|
33148
|
+
captureEnvironmentSnapshot: () => captureEnvironmentSnapshot
|
|
33149
|
+
});
|
|
33150
|
+
import { createHash as createHash6 } from "crypto";
|
|
33151
|
+
import { existsSync as existsSync13, readFileSync as readFileSync9, statSync as statSync6 } from "fs";
|
|
33152
|
+
import { hostname, platform, arch } from "os";
|
|
33153
|
+
import { dirname as dirname10, join as join14, resolve as resolve12 } from "path";
|
|
33154
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
33155
|
+
function sha2563(value) {
|
|
33156
|
+
return createHash6("sha256").update(value).digest("hex");
|
|
33157
|
+
}
|
|
33158
|
+
function fileRecord(root, relativePath) {
|
|
33159
|
+
const path = join14(root, relativePath);
|
|
33160
|
+
if (!existsSync13(path))
|
|
33161
|
+
return null;
|
|
33162
|
+
const stat = statSync6(path);
|
|
33163
|
+
if (!stat.isFile())
|
|
33164
|
+
return null;
|
|
33165
|
+
const content = readFileSync9(path);
|
|
33166
|
+
return { path: relativePath, sha256: sha2563(content), size_bytes: content.length };
|
|
33167
|
+
}
|
|
33168
|
+
function manifestRecord(root, relativePath) {
|
|
33169
|
+
const base = fileRecord(root, relativePath);
|
|
33170
|
+
if (!base)
|
|
33171
|
+
return null;
|
|
33172
|
+
const parsed = readJsonFile(join14(root, relativePath));
|
|
33173
|
+
if (!parsed)
|
|
33174
|
+
return { ...base, redacted: {} };
|
|
33175
|
+
const redacted = redactValue({
|
|
33176
|
+
name: parsed["name"] ?? null,
|
|
33177
|
+
version: parsed["version"] ?? null,
|
|
33178
|
+
packageManager: parsed["packageManager"] ?? null,
|
|
33179
|
+
scripts: parsed["scripts"] ?? {},
|
|
33180
|
+
dependencies: parsed["dependencies"] ?? {},
|
|
33181
|
+
devDependencies: parsed["devDependencies"] ?? {},
|
|
33182
|
+
peerDependencies: parsed["peerDependencies"] ?? {},
|
|
33183
|
+
optionalDependencies: parsed["optionalDependencies"] ?? {}
|
|
33184
|
+
});
|
|
33185
|
+
return { ...base, redacted };
|
|
33186
|
+
}
|
|
33187
|
+
function runLocalCommand(root, args) {
|
|
33188
|
+
const result = Bun.spawnSync({
|
|
33189
|
+
cmd: args,
|
|
33190
|
+
cwd: root,
|
|
33191
|
+
stdout: "pipe",
|
|
33192
|
+
stderr: "pipe",
|
|
33193
|
+
env: { PATH: process.env["PATH"] || "" }
|
|
33194
|
+
});
|
|
33195
|
+
return {
|
|
33196
|
+
exitCode: result.exitCode,
|
|
33197
|
+
stdout: redactEvidenceText(result.stdout.toString("utf8").trim()),
|
|
33198
|
+
stderr: redactEvidenceText(result.stderr.toString("utf8").trim())
|
|
33199
|
+
};
|
|
33200
|
+
}
|
|
33201
|
+
function summarizeGitStatus(lines) {
|
|
33202
|
+
const summary = { added: 0, modified: 0, deleted: 0, renamed: 0, untracked: 0 };
|
|
33203
|
+
for (const line of lines) {
|
|
33204
|
+
if (line.startsWith("??"))
|
|
33205
|
+
summary.untracked += 1;
|
|
33206
|
+
else if (line.includes("R"))
|
|
33207
|
+
summary.renamed += 1;
|
|
33208
|
+
else if (line.includes("D"))
|
|
33209
|
+
summary.deleted += 1;
|
|
33210
|
+
else if (line.includes("A"))
|
|
33211
|
+
summary.added += 1;
|
|
33212
|
+
else if (line.includes("M"))
|
|
33213
|
+
summary.modified += 1;
|
|
33214
|
+
}
|
|
33215
|
+
return summary;
|
|
33216
|
+
}
|
|
33217
|
+
function captureGit(root, warnings) {
|
|
33218
|
+
const inside = runLocalCommand(root, ["git", "rev-parse", "--is-inside-work-tree"]);
|
|
33219
|
+
if (inside.exitCode !== 0 || inside.stdout !== "true") {
|
|
33220
|
+
return { present: false, branch: null, commit: null, is_dirty: false, status_porcelain: [], status_summary: summarizeGitStatus([]) };
|
|
33221
|
+
}
|
|
33222
|
+
const branch = runLocalCommand(root, ["git", "branch", "--show-current"]);
|
|
33223
|
+
const commit = runLocalCommand(root, ["git", "rev-parse", "HEAD"]);
|
|
33224
|
+
const status = runLocalCommand(root, ["git", "status", "--porcelain=v1"]);
|
|
33225
|
+
if (commit.exitCode !== 0)
|
|
33226
|
+
warnings.push(`git commit unavailable: ${commit.stderr || commit.stdout || "unknown error"}`);
|
|
33227
|
+
if (status.exitCode !== 0)
|
|
33228
|
+
warnings.push(`git status unavailable: ${status.stderr || status.stdout || "unknown error"}`);
|
|
33229
|
+
const lines = status.stdout ? status.stdout.split(/\r?\n/).filter(Boolean) : [];
|
|
33230
|
+
return {
|
|
33231
|
+
present: true,
|
|
33232
|
+
branch: branch.stdout || null,
|
|
33233
|
+
commit: commit.stdout || null,
|
|
33234
|
+
is_dirty: lines.length > 0,
|
|
33235
|
+
status_porcelain: lines,
|
|
33236
|
+
status_summary: summarizeGitStatus(lines)
|
|
33237
|
+
};
|
|
33238
|
+
}
|
|
33239
|
+
function packageManager(env, lockfiles) {
|
|
33240
|
+
const userAgent = (env["npm_config_user_agent"] || "").toLowerCase();
|
|
33241
|
+
if (userAgent.includes("bun"))
|
|
33242
|
+
return "bun";
|
|
33243
|
+
if (lockfiles.some((file) => file.path.startsWith("bun.lock")))
|
|
33244
|
+
return "bun";
|
|
33245
|
+
if (userAgent.includes("npm") || lockfiles.some((file) => file.path.includes("package-lock")))
|
|
33246
|
+
return "npm";
|
|
33247
|
+
return "unknown";
|
|
33248
|
+
}
|
|
33249
|
+
function isSecretEnvKey(key) {
|
|
33250
|
+
return /api[_-]?key|token|secret|password|credential|private|session|cookie/i.test(key);
|
|
33251
|
+
}
|
|
33252
|
+
function commandEnv(env, includeValues) {
|
|
33253
|
+
const keys = Object.keys(env).sort();
|
|
33254
|
+
const interesting = keys.filter((key) => isSecretEnvKey(key) || ["CI", "NODE_ENV", "BUN_ENV", "SHELL", "TERM", "PATH", "PWD", "USER", "npm_config_user_agent"].includes(key) || key.startsWith("TODOS_") || key.startsWith("BUN_"));
|
|
33255
|
+
const redactedKeys = interesting.filter(isSecretEnvKey);
|
|
33256
|
+
const values = includeValues ? Object.fromEntries(interesting.map((key) => [key, isSecretEnvKey(key) ? "[REDACTED]" : redactEvidenceText(String(env[key] ?? ""))])) : null;
|
|
33257
|
+
return {
|
|
33258
|
+
command: null,
|
|
33259
|
+
env_keys: interesting,
|
|
33260
|
+
env: values,
|
|
33261
|
+
redacted_keys: redactedKeys
|
|
33262
|
+
};
|
|
33263
|
+
}
|
|
33264
|
+
function defaultSnapshotDir() {
|
|
33265
|
+
const dbPath = getDatabasePath();
|
|
33266
|
+
if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
|
|
33267
|
+
return join14(tmpdir2(), "hasna-todos", "environment-snapshots");
|
|
33268
|
+
return join14(dirname10(resolve12(dbPath)), "environment-snapshots");
|
|
33269
|
+
}
|
|
33270
|
+
function snapshotWithId(snapshot) {
|
|
33271
|
+
const digest = sha2563(JSON.stringify(snapshot)).slice(0, 24);
|
|
33272
|
+
return { id: `env_${digest}`, ...snapshot };
|
|
33273
|
+
}
|
|
33274
|
+
function captureEnvironmentSnapshot(input = {}) {
|
|
33275
|
+
const root = resolve12(input.root || process.cwd());
|
|
33276
|
+
const env = input.env || process.env;
|
|
33277
|
+
const warnings = [];
|
|
33278
|
+
const manifests = MANIFEST_FILES.map((file) => manifestRecord(root, file)).filter((file) => Boolean(file));
|
|
33279
|
+
const lockfiles = LOCKFILES.map((file) => fileRecord(root, file)).filter((file) => Boolean(file));
|
|
33280
|
+
const configHashes = CONFIG_FILES.map((file) => fileRecord(root, file)).filter((file) => Boolean(file));
|
|
33281
|
+
const commandMetadata = commandEnv(env, Boolean(input.include_env_values));
|
|
33282
|
+
commandMetadata.command = input.command ? redactEvidenceText(input.command) : null;
|
|
33283
|
+
if (manifests.length === 0)
|
|
33284
|
+
warnings.push("no package manifest found");
|
|
33285
|
+
if (lockfiles.length === 0)
|
|
33286
|
+
warnings.push("no package lockfile found");
|
|
33287
|
+
return snapshotWithId({
|
|
33288
|
+
schema_version: 1,
|
|
33289
|
+
captured_at: input.now ? new Date(input.now).toISOString() : new Date().toISOString(),
|
|
33290
|
+
root,
|
|
33291
|
+
machine: { hostname: hostname(), platform: platform(), arch: arch() },
|
|
33292
|
+
target: {
|
|
33293
|
+
task_id: input.task_id ?? null,
|
|
33294
|
+
run_id: input.run_id ?? null,
|
|
33295
|
+
agent_id: input.agent_id ?? null
|
|
33296
|
+
},
|
|
33297
|
+
runtime: {
|
|
33298
|
+
bun: Bun.version || null,
|
|
33299
|
+
node: process.version,
|
|
33300
|
+
executable: process.execPath
|
|
33301
|
+
},
|
|
33302
|
+
package_manager: {
|
|
33303
|
+
manager: packageManager(env, lockfiles),
|
|
33304
|
+
user_agent: env["npm_config_user_agent"] ? redactEvidenceText(env["npm_config_user_agent"]) : null,
|
|
33305
|
+
manifests,
|
|
33306
|
+
lockfiles
|
|
33307
|
+
},
|
|
33308
|
+
git: captureGit(root, warnings),
|
|
33309
|
+
config_hashes: configHashes,
|
|
33310
|
+
command_env: commandMetadata,
|
|
33311
|
+
warnings
|
|
33312
|
+
});
|
|
33313
|
+
}
|
|
33314
|
+
function writeEnvironmentSnapshot(snapshot, outputPath) {
|
|
33315
|
+
const path = outputPath ? resolve12(outputPath) : join14(defaultSnapshotDir(), `${snapshot.id}.json`);
|
|
33316
|
+
ensureDir2(dirname10(path));
|
|
33317
|
+
writeJsonFile(path, snapshot);
|
|
33318
|
+
return path;
|
|
33319
|
+
}
|
|
33320
|
+
function readEnvironmentSnapshot(path) {
|
|
33321
|
+
const snapshot = readJsonFile(resolve12(path));
|
|
33322
|
+
if (!snapshot || snapshot.schema_version !== 1 || typeof snapshot.id !== "string") {
|
|
33323
|
+
throw new Error(`Invalid environment snapshot: ${path}`);
|
|
33324
|
+
}
|
|
33325
|
+
return snapshot;
|
|
33326
|
+
}
|
|
33327
|
+
function recordEnvironmentSnapshot(input = {}, db) {
|
|
33328
|
+
let taskId = input.task_id;
|
|
33329
|
+
let runId = input.run_id;
|
|
33330
|
+
const needsDatabase = Boolean(taskId || runId);
|
|
33331
|
+
const d = needsDatabase ? db || getDatabase() : null;
|
|
33332
|
+
if (runId) {
|
|
33333
|
+
runId = resolveTaskRunId(runId, d);
|
|
33334
|
+
const run = getTaskRun(runId, d);
|
|
33335
|
+
if (!run)
|
|
33336
|
+
throw new Error(`Run not found: ${input.run_id}`);
|
|
33337
|
+
taskId = taskId || run.task_id;
|
|
33338
|
+
}
|
|
33339
|
+
if (taskId && d) {
|
|
33340
|
+
taskId = resolvePartialId(d, "tasks", taskId) || taskId;
|
|
33341
|
+
if (!getTask(taskId, d))
|
|
33342
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
33343
|
+
}
|
|
33344
|
+
const snapshot = captureEnvironmentSnapshot({ ...input, task_id: taskId, run_id: runId });
|
|
33345
|
+
const outputPath = writeEnvironmentSnapshot(snapshot, input.output_path);
|
|
33346
|
+
let taskVerificationId = null;
|
|
33347
|
+
let runArtifactId = null;
|
|
33348
|
+
if (runId) {
|
|
33349
|
+
const artifact = addTaskRunArtifact({
|
|
33350
|
+
run_id: runId,
|
|
33351
|
+
path: outputPath,
|
|
33352
|
+
artifact_type: "environment_snapshot",
|
|
33353
|
+
description: "Reproducible local environment snapshot",
|
|
33354
|
+
metadata: { environment_snapshot_id: snapshot.id, schema_version: snapshot.schema_version },
|
|
33355
|
+
store_content: input.store_content ?? true,
|
|
33356
|
+
agent_id: input.agent_id
|
|
33357
|
+
}, d);
|
|
33358
|
+
runArtifactId = artifact.id;
|
|
33359
|
+
} else if (taskId) {
|
|
33360
|
+
const verification = addTaskVerification({
|
|
33361
|
+
task_id: taskId,
|
|
33362
|
+
command: input.command || "capture environment snapshot",
|
|
33363
|
+
status: "unknown",
|
|
33364
|
+
output_summary: `environment snapshot ${snapshot.id}`,
|
|
33365
|
+
artifact_path: outputPath,
|
|
33366
|
+
agent_id: input.agent_id,
|
|
33367
|
+
run_at: snapshot.captured_at
|
|
33368
|
+
}, d);
|
|
33369
|
+
taskVerificationId = verification.id;
|
|
33370
|
+
}
|
|
33371
|
+
return { snapshot, output_path: outputPath, task_verification_id: taskVerificationId, run_artifact_id: runArtifactId };
|
|
33372
|
+
}
|
|
33373
|
+
function keyed(files) {
|
|
33374
|
+
return new Map(files.map((file) => [file.path, file]));
|
|
33375
|
+
}
|
|
33376
|
+
function diffFiles(left, right) {
|
|
33377
|
+
const leftMap = keyed(left);
|
|
33378
|
+
const rightMap = keyed(right);
|
|
33379
|
+
const paths = [...new Set([...leftMap.keys(), ...rightMap.keys()])].sort((a, b) => a.localeCompare(b));
|
|
33380
|
+
return paths.map((path) => ({ path, left_sha256: leftMap.get(path)?.sha256 ?? null, right_sha256: rightMap.get(path)?.sha256 ?? null })).filter((entry) => entry.left_sha256 !== entry.right_sha256);
|
|
33381
|
+
}
|
|
33382
|
+
function compareEnvironmentSnapshots(left, right) {
|
|
33383
|
+
const warnings = [];
|
|
33384
|
+
if (left.schema_version !== right.schema_version)
|
|
33385
|
+
warnings.push("snapshot schema versions differ");
|
|
33386
|
+
return {
|
|
33387
|
+
schema_version: 1,
|
|
33388
|
+
left_id: left.id,
|
|
33389
|
+
right_id: right.id,
|
|
33390
|
+
same_root: left.root === right.root,
|
|
33391
|
+
same_machine: left.machine.hostname === right.machine.hostname && left.machine.platform === right.machine.platform && left.machine.arch === right.machine.arch,
|
|
33392
|
+
same_runtime: left.runtime.bun === right.runtime.bun && left.runtime.node === right.runtime.node,
|
|
33393
|
+
same_git_commit: left.git.commit === right.git.commit,
|
|
33394
|
+
dirty_state_changed: left.git.is_dirty !== right.git.is_dirty,
|
|
33395
|
+
changed_config_hashes: diffFiles(left.config_hashes, right.config_hashes),
|
|
33396
|
+
changed_lockfiles: diffFiles(left.package_manager.lockfiles, right.package_manager.lockfiles),
|
|
33397
|
+
changed_manifests: diffFiles(left.package_manager.manifests, right.package_manager.manifests),
|
|
33398
|
+
warnings
|
|
33399
|
+
};
|
|
33400
|
+
}
|
|
33401
|
+
function compareEnvironmentSnapshotFiles(leftPath, rightPath) {
|
|
33402
|
+
return compareEnvironmentSnapshots(readEnvironmentSnapshot(leftPath), readEnvironmentSnapshot(rightPath));
|
|
33403
|
+
}
|
|
33404
|
+
var MANIFEST_FILES, LOCKFILES, CONFIG_FILES;
|
|
33405
|
+
var init_environment_snapshots = __esm(() => {
|
|
33406
|
+
init_task_runs();
|
|
33407
|
+
init_task_commits();
|
|
33408
|
+
init_database();
|
|
33409
|
+
init_tasks();
|
|
33410
|
+
init_sync_utils();
|
|
33411
|
+
MANIFEST_FILES = ["package.json", "dashboard/package.json", "sdk/package.json"];
|
|
33412
|
+
LOCKFILES = ["bun.lock", "bun.lockb", "package-lock.json", "npm-shrinkwrap.json"];
|
|
33413
|
+
CONFIG_FILES = [
|
|
33414
|
+
"AGENTS.md",
|
|
33415
|
+
"CLAUDE.md",
|
|
33416
|
+
"README.md",
|
|
33417
|
+
"SECURITY.md",
|
|
33418
|
+
"bunfig.toml",
|
|
33419
|
+
"tsconfig.json",
|
|
33420
|
+
"components.json",
|
|
33421
|
+
"next.config.js",
|
|
33422
|
+
"next.config.mjs",
|
|
33423
|
+
"next.config.ts",
|
|
33424
|
+
"vite.config.ts",
|
|
33425
|
+
"dashboard/vite.config.ts"
|
|
33426
|
+
];
|
|
33427
|
+
});
|
|
33428
|
+
|
|
33429
|
+
// src/mcp/tools/environment-snapshots.ts
|
|
33430
|
+
function registerEnvironmentSnapshotTools(server, { shouldRegisterTool, formatError }) {
|
|
33431
|
+
if (shouldRegisterTool("capture_environment_snapshot")) {
|
|
33432
|
+
server.tool("capture_environment_snapshot", "Capture a local reproducible environment snapshot with Bun/node versions, package-manager state, git status, config hashes, command metadata, and redacted manifests. Optionally attach it to a local task or run.", {
|
|
33433
|
+
root: exports_external.string().optional(),
|
|
33434
|
+
task_id: exports_external.string().optional(),
|
|
33435
|
+
run_id: exports_external.string().optional(),
|
|
33436
|
+
agent_id: exports_external.string().optional(),
|
|
33437
|
+
command: exports_external.string().optional(),
|
|
33438
|
+
output_path: exports_external.string().optional(),
|
|
33439
|
+
include_env_values: exports_external.boolean().optional()
|
|
33440
|
+
}, async (params) => {
|
|
33441
|
+
try {
|
|
33442
|
+
const { recordEnvironmentSnapshot: recordEnvironmentSnapshot2 } = await Promise.resolve().then(() => (init_environment_snapshots(), exports_environment_snapshots));
|
|
33443
|
+
const result = recordEnvironmentSnapshot2(params);
|
|
33444
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
33445
|
+
} catch (e) {
|
|
33446
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
33447
|
+
}
|
|
33448
|
+
});
|
|
33449
|
+
}
|
|
33450
|
+
if (shouldRegisterTool("compare_environment_snapshots")) {
|
|
33451
|
+
server.tool("compare_environment_snapshots", "Compare two local environment snapshot JSON files and report runtime, git, manifest, lockfile, and config hash drift.", {
|
|
33452
|
+
left_path: exports_external.string(),
|
|
33453
|
+
right_path: exports_external.string()
|
|
33454
|
+
}, async ({ left_path, right_path }) => {
|
|
33455
|
+
try {
|
|
33456
|
+
const { compareEnvironmentSnapshotFiles: compareEnvironmentSnapshotFiles2 } = await Promise.resolve().then(() => (init_environment_snapshots(), exports_environment_snapshots));
|
|
33457
|
+
return { content: [{ type: "text", text: JSON.stringify(compareEnvironmentSnapshotFiles2(left_path, right_path), null, 2) }] };
|
|
33458
|
+
} catch (e) {
|
|
33459
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
33460
|
+
}
|
|
33461
|
+
});
|
|
33462
|
+
}
|
|
33463
|
+
}
|
|
33464
|
+
var init_environment_snapshots2 = __esm(() => {
|
|
33465
|
+
init_zod();
|
|
33466
|
+
});
|
|
33467
|
+
|
|
33138
33468
|
// src/mcp/index.ts
|
|
33139
33469
|
var exports_mcp = {};
|
|
33140
33470
|
__export(exports_mcp, {
|
|
@@ -33304,6 +33634,7 @@ var init_mcp = __esm(() => {
|
|
|
33304
33634
|
init_machines2();
|
|
33305
33635
|
init_agents2();
|
|
33306
33636
|
init_templates2();
|
|
33637
|
+
init_environment_snapshots2();
|
|
33307
33638
|
init_package_version();
|
|
33308
33639
|
init_token_utils();
|
|
33309
33640
|
if (hasVersionFlag()) {
|
|
@@ -33335,6 +33666,7 @@ var init_mcp = __esm(() => {
|
|
|
33335
33666
|
registerCodeTools(server, toolContext);
|
|
33336
33667
|
registerAgentTools(server, { ...toolContext, agentFocusMap });
|
|
33337
33668
|
registerTemplateTools(server, toolContext);
|
|
33669
|
+
registerEnvironmentSnapshotTools(server, toolContext);
|
|
33338
33670
|
registerMachineTools(server, { shouldRegisterTool, formatError });
|
|
33339
33671
|
registerDispatchTools(server, { shouldRegisterTool, resolveId, formatError });
|
|
33340
33672
|
main().catch(async (err) => {
|
|
@@ -33354,43 +33686,43 @@ __export(exports_mcp_hooks_commands, {
|
|
|
33354
33686
|
});
|
|
33355
33687
|
import chalk8 from "chalk";
|
|
33356
33688
|
import { execSync as execSync3 } from "child_process";
|
|
33357
|
-
import { existsSync as
|
|
33358
|
-
import { dirname as
|
|
33689
|
+
import { existsSync as existsSync14, readFileSync as readFileSync10, writeFileSync as writeFileSync6, mkdirSync as mkdirSync8, chmodSync as chmodSync2 } from "fs";
|
|
33690
|
+
import { dirname as dirname11, join as join15 } from "path";
|
|
33359
33691
|
function getMcpBinaryPath() {
|
|
33360
33692
|
try {
|
|
33361
33693
|
const p = execSync3("which todos-mcp", { encoding: "utf-8" }).trim();
|
|
33362
33694
|
if (p)
|
|
33363
33695
|
return p;
|
|
33364
33696
|
} catch {}
|
|
33365
|
-
const bunBin =
|
|
33366
|
-
if (
|
|
33697
|
+
const bunBin = join15(HOME2, ".bun", "bin", "todos-mcp");
|
|
33698
|
+
if (existsSync14(bunBin))
|
|
33367
33699
|
return bunBin;
|
|
33368
33700
|
return "todos-mcp";
|
|
33369
33701
|
}
|
|
33370
33702
|
function readJsonFile2(path) {
|
|
33371
|
-
if (!
|
|
33703
|
+
if (!existsSync14(path))
|
|
33372
33704
|
return {};
|
|
33373
33705
|
try {
|
|
33374
|
-
return JSON.parse(
|
|
33706
|
+
return JSON.parse(readFileSync10(path, "utf-8"));
|
|
33375
33707
|
} catch {
|
|
33376
33708
|
return {};
|
|
33377
33709
|
}
|
|
33378
33710
|
}
|
|
33379
33711
|
function writeJsonFile2(path, data) {
|
|
33380
|
-
const dir =
|
|
33381
|
-
if (!
|
|
33712
|
+
const dir = dirname11(path);
|
|
33713
|
+
if (!existsSync14(dir))
|
|
33382
33714
|
mkdirSync8(dir, { recursive: true });
|
|
33383
33715
|
writeFileSync6(path, JSON.stringify(data, null, 2) + `
|
|
33384
33716
|
`);
|
|
33385
33717
|
}
|
|
33386
33718
|
function readTomlFile(path) {
|
|
33387
|
-
if (!
|
|
33719
|
+
if (!existsSync14(path))
|
|
33388
33720
|
return "";
|
|
33389
|
-
return
|
|
33721
|
+
return readFileSync10(path, "utf-8");
|
|
33390
33722
|
}
|
|
33391
33723
|
function writeTomlFile(path, content) {
|
|
33392
|
-
const dir =
|
|
33393
|
-
if (!
|
|
33724
|
+
const dir = dirname11(path);
|
|
33725
|
+
if (!existsSync14(dir))
|
|
33394
33726
|
mkdirSync8(dir, { recursive: true });
|
|
33395
33727
|
writeFileSync6(path, content);
|
|
33396
33728
|
}
|
|
@@ -33456,7 +33788,7 @@ function unregisterClaude(_global) {
|
|
|
33456
33788
|
}
|
|
33457
33789
|
}
|
|
33458
33790
|
function registerCodex(binPath) {
|
|
33459
|
-
const configPath =
|
|
33791
|
+
const configPath = join15(HOME2, ".codex", "config.toml");
|
|
33460
33792
|
let content = readTomlFile(configPath);
|
|
33461
33793
|
content = removeTomlBlock(content, "mcp_servers.todos");
|
|
33462
33794
|
const block = `
|
|
@@ -33470,7 +33802,7 @@ args = []
|
|
|
33470
33802
|
console.log(chalk8.green(`Codex CLI: registered in ${configPath}`));
|
|
33471
33803
|
}
|
|
33472
33804
|
function unregisterCodex() {
|
|
33473
|
-
const configPath =
|
|
33805
|
+
const configPath = join15(HOME2, ".codex", "config.toml");
|
|
33474
33806
|
let content = readTomlFile(configPath);
|
|
33475
33807
|
if (!content.includes("[mcp_servers.todos]")) {
|
|
33476
33808
|
console.log(chalk8.dim(`Codex CLI: todos not found in ${configPath}`));
|
|
@@ -33482,7 +33814,7 @@ function unregisterCodex() {
|
|
|
33482
33814
|
console.log(chalk8.green(`Codex CLI: unregistered from ${configPath}`));
|
|
33483
33815
|
}
|
|
33484
33816
|
function registerGemini(binPath) {
|
|
33485
|
-
const configPath =
|
|
33817
|
+
const configPath = join15(HOME2, ".gemini", "settings.json");
|
|
33486
33818
|
const config = readJsonFile2(configPath);
|
|
33487
33819
|
if (!config["mcpServers"]) {
|
|
33488
33820
|
config["mcpServers"] = {};
|
|
@@ -33496,7 +33828,7 @@ function registerGemini(binPath) {
|
|
|
33496
33828
|
console.log(chalk8.green(`Gemini CLI: registered in ${configPath}`));
|
|
33497
33829
|
}
|
|
33498
33830
|
function unregisterGemini() {
|
|
33499
|
-
const configPath =
|
|
33831
|
+
const configPath = join15(HOME2, ".gemini", "settings.json");
|
|
33500
33832
|
const config = readJsonFile2(configPath);
|
|
33501
33833
|
const servers = config["mcpServers"];
|
|
33502
33834
|
if (!servers || !("todos" in servers)) {
|
|
@@ -33553,8 +33885,8 @@ function registerMcpHooksCommands(program2) {
|
|
|
33553
33885
|
if (p)
|
|
33554
33886
|
todosBin = p;
|
|
33555
33887
|
} catch {}
|
|
33556
|
-
const hooksDir =
|
|
33557
|
-
if (!
|
|
33888
|
+
const hooksDir = join15(process.cwd(), ".claude", "hooks");
|
|
33889
|
+
if (!existsSync14(hooksDir))
|
|
33558
33890
|
mkdirSync8(hooksDir, { recursive: true });
|
|
33559
33891
|
const hookScript = `#!/usr/bin/env bash
|
|
33560
33892
|
# Auto-generated by: todos hooks install
|
|
@@ -33579,11 +33911,11 @@ esac
|
|
|
33579
33911
|
|
|
33580
33912
|
exit 0
|
|
33581
33913
|
`;
|
|
33582
|
-
const hookPath =
|
|
33914
|
+
const hookPath = join15(hooksDir, "todos-sync.sh");
|
|
33583
33915
|
writeFileSync6(hookPath, hookScript);
|
|
33584
33916
|
execSync3(`chmod +x "${hookPath}"`);
|
|
33585
33917
|
console.log(chalk8.green(`Hook script created: ${hookPath}`));
|
|
33586
|
-
const settingsPath =
|
|
33918
|
+
const settingsPath = join15(process.cwd(), ".claude", "settings.json");
|
|
33587
33919
|
const settings = readJsonFile2(settingsPath);
|
|
33588
33920
|
if (!settings["hooks"]) {
|
|
33589
33921
|
settings["hooks"] = {};
|
|
@@ -34326,8 +34658,8 @@ Artifacts:`));
|
|
|
34326
34658
|
const gitDir = execSync3("git rev-parse --git-dir", { encoding: "utf-8" }).trim();
|
|
34327
34659
|
const hookPath = `${gitDir}/hooks/post-commit`;
|
|
34328
34660
|
const marker = "# todos-auto-link";
|
|
34329
|
-
if (
|
|
34330
|
-
const existing =
|
|
34661
|
+
if (existsSync14(hookPath)) {
|
|
34662
|
+
const existing = readFileSync10(hookPath, "utf-8");
|
|
34331
34663
|
if (existing.includes(marker)) {
|
|
34332
34664
|
console.log(chalk8.yellow("Hook already installed."));
|
|
34333
34665
|
return;
|
|
@@ -34354,11 +34686,11 @@ $(dirname "$0")/../../scripts/post-commit-hook.sh
|
|
|
34354
34686
|
const gitDir = execSync3("git rev-parse --git-dir", { encoding: "utf-8" }).trim();
|
|
34355
34687
|
const hookPath = `${gitDir}/hooks/post-commit`;
|
|
34356
34688
|
const marker = "# todos-auto-link";
|
|
34357
|
-
if (!
|
|
34689
|
+
if (!existsSync14(hookPath)) {
|
|
34358
34690
|
console.log(chalk8.dim("No post-commit hook found."));
|
|
34359
34691
|
return;
|
|
34360
34692
|
}
|
|
34361
|
-
const content =
|
|
34693
|
+
const content = readFileSync10(hookPath, "utf-8");
|
|
34362
34694
|
if (!content.includes(marker)) {
|
|
34363
34695
|
console.log(chalk8.dim("Hook not managed by todos."));
|
|
34364
34696
|
return;
|
|
@@ -34535,8 +34867,8 @@ __export(exports_machines2, {
|
|
|
34535
34867
|
import chalk10 from "chalk";
|
|
34536
34868
|
import { execSync as execSync4 } from "child_process";
|
|
34537
34869
|
import { writeFileSync as writeFileSync7 } from "fs";
|
|
34538
|
-
import { tmpdir as
|
|
34539
|
-
import { join as
|
|
34870
|
+
import { tmpdir as tmpdir3 } from "os";
|
|
34871
|
+
import { join as join16 } from "path";
|
|
34540
34872
|
function getOrCreateLocalMachineName() {
|
|
34541
34873
|
return process.env["TODOS_MACHINE_NAME"] || __require("os").hostname() || "unknown";
|
|
34542
34874
|
}
|
|
@@ -34730,7 +35062,7 @@ Warning: No primary machine set.`));
|
|
|
34730
35062
|
if (opts.push) {
|
|
34731
35063
|
try {
|
|
34732
35064
|
const localTasks = listTasks3();
|
|
34733
|
-
const tmpFile =
|
|
35065
|
+
const tmpFile = join16(tmpdir3(), `todos-export-${uuid()}.json`);
|
|
34734
35066
|
writeFileSync7(tmpFile, JSON.stringify(localTasks, null, 2));
|
|
34735
35067
|
execSync4(`scp ${tmpFile} ${ssh}:/tmp/todos-import.json`, { timeout: 15000 });
|
|
34736
35068
|
const importCmd = `ssh ${ssh} 'node -e "const fs=require(\\'fs\\');const tasks=JSON.parse(fs.readFileSync(\\'/tmp/todos-import.json\\',\\'utf-8\\'));console.log(JSON.stringify(tasks.length))"'`;
|
|
@@ -34880,6 +35212,84 @@ var init_api_key_commands = __esm(() => {
|
|
|
34880
35212
|
init_helpers();
|
|
34881
35213
|
});
|
|
34882
35214
|
|
|
35215
|
+
// src/cli/commands/environment-snapshots.ts
|
|
35216
|
+
var exports_environment_snapshots2 = {};
|
|
35217
|
+
__export(exports_environment_snapshots2, {
|
|
35218
|
+
registerEnvironmentSnapshotCommands: () => registerEnvironmentSnapshotCommands
|
|
35219
|
+
});
|
|
35220
|
+
import chalk12 from "chalk";
|
|
35221
|
+
function printJson(value) {
|
|
35222
|
+
console.log(JSON.stringify(value, null, 2));
|
|
35223
|
+
}
|
|
35224
|
+
function registerEnvironmentSnapshotCommands(program2) {
|
|
35225
|
+
const envCmd = program2.command("env-snapshot").alias("environment-snapshot").description("Capture and compare local reproducible environment snapshots");
|
|
35226
|
+
envCmd.command("capture").description("Capture runtime, package-manager, git, config hash, and redacted environment metadata").option("--root <path>", "Project root to inspect").option("--task <id>", "Attach snapshot evidence to a task").option("--run <id>", "Attach snapshot artifact to a task run").option("--agent <name>", "Agent name for attached evidence").option("--command <command>", "Command or verification step this snapshot explains").option("--output <path>", "Write snapshot JSON to a specific path").option("--include-env-values", "Include nonsecret environment values; secret-like keys are still redacted").action((opts) => {
|
|
35227
|
+
const globalOpts = program2.opts();
|
|
35228
|
+
try {
|
|
35229
|
+
const result = recordEnvironmentSnapshot({
|
|
35230
|
+
root: opts.root,
|
|
35231
|
+
task_id: opts.task,
|
|
35232
|
+
run_id: opts.run,
|
|
35233
|
+
agent_id: opts.agent || globalOpts.agent,
|
|
35234
|
+
command: opts.command,
|
|
35235
|
+
output_path: opts.output,
|
|
35236
|
+
include_env_values: Boolean(opts.includeEnvValues)
|
|
35237
|
+
});
|
|
35238
|
+
if (globalOpts.json) {
|
|
35239
|
+
printJson(result);
|
|
35240
|
+
return;
|
|
35241
|
+
}
|
|
35242
|
+
console.log(chalk12.green("Captured") + ` ${result.snapshot.id}`);
|
|
35243
|
+
console.log(`path: ${result.output_path}`);
|
|
35244
|
+
console.log(`root: ${result.snapshot.root}`);
|
|
35245
|
+
console.log(`git: ${result.snapshot.git.commit || "none"}${result.snapshot.git.is_dirty ? " dirty" : ""}`);
|
|
35246
|
+
console.log(`runtime: bun ${result.snapshot.runtime.bun || "unknown"} / node ${result.snapshot.runtime.node}`);
|
|
35247
|
+
if (result.run_artifact_id)
|
|
35248
|
+
console.log(`run artifact: ${result.run_artifact_id}`);
|
|
35249
|
+
if (result.task_verification_id)
|
|
35250
|
+
console.log(`task verification: ${result.task_verification_id}`);
|
|
35251
|
+
for (const warning of result.snapshot.warnings)
|
|
35252
|
+
console.log(chalk12.yellow(`warning: ${warning}`));
|
|
35253
|
+
} catch (error) {
|
|
35254
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
35255
|
+
if (globalOpts.json)
|
|
35256
|
+
printJson({ error: message });
|
|
35257
|
+
else
|
|
35258
|
+
console.error(chalk12.red(`Error: ${message}`));
|
|
35259
|
+
process.exit(1);
|
|
35260
|
+
}
|
|
35261
|
+
});
|
|
35262
|
+
envCmd.command("compare").description("Compare two environment snapshot JSON files").argument("<left>", "Left snapshot JSON path").argument("<right>", "Right snapshot JSON path").action((left, right) => {
|
|
35263
|
+
const globalOpts = program2.opts();
|
|
35264
|
+
try {
|
|
35265
|
+
const comparison = compareEnvironmentSnapshotFiles(left, right);
|
|
35266
|
+
if (globalOpts.json) {
|
|
35267
|
+
printJson(comparison);
|
|
35268
|
+
return;
|
|
35269
|
+
}
|
|
35270
|
+
console.log(`left: ${comparison.left_id}`);
|
|
35271
|
+
console.log(`right: ${comparison.right_id}`);
|
|
35272
|
+
console.log(`same root: ${comparison.same_root}`);
|
|
35273
|
+
console.log(`same machine: ${comparison.same_machine}`);
|
|
35274
|
+
console.log(`same runtime: ${comparison.same_runtime}`);
|
|
35275
|
+
console.log(`same git commit: ${comparison.same_git_commit}`);
|
|
35276
|
+
console.log(`dirty state changed: ${comparison.dirty_state_changed}`);
|
|
35277
|
+
const changed = comparison.changed_config_hashes.length + comparison.changed_lockfiles.length + comparison.changed_manifests.length;
|
|
35278
|
+
console.log(`changed files: ${changed}`);
|
|
35279
|
+
} catch (error) {
|
|
35280
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
35281
|
+
if (globalOpts.json)
|
|
35282
|
+
printJson({ error: message });
|
|
35283
|
+
else
|
|
35284
|
+
console.error(chalk12.red(`Error: ${message}`));
|
|
35285
|
+
process.exit(1);
|
|
35286
|
+
}
|
|
35287
|
+
});
|
|
35288
|
+
}
|
|
35289
|
+
var init_environment_snapshots3 = __esm(() => {
|
|
35290
|
+
init_environment_snapshots();
|
|
35291
|
+
});
|
|
35292
|
+
|
|
34883
35293
|
// src/cli/index.tsx
|
|
34884
35294
|
init_esm();
|
|
34885
35295
|
init_package_version();
|
|
@@ -34895,7 +35305,8 @@ var [
|
|
|
34895
35305
|
{ registerMcpHooksCommands: registerMcpHooksCommands2 },
|
|
34896
35306
|
{ registerDispatchCommands: registerDispatchCommands2 },
|
|
34897
35307
|
{ registerMachineCommands: registerMachineCommands2 },
|
|
34898
|
-
{ registerApiKeyCommands: registerApiKeyCommands2 }
|
|
35308
|
+
{ registerApiKeyCommands: registerApiKeyCommands2 },
|
|
35309
|
+
{ registerEnvironmentSnapshotCommands: registerEnvironmentSnapshotCommands2 }
|
|
34899
35310
|
] = await Promise.all([
|
|
34900
35311
|
Promise.resolve().then(() => (init_task_commands(), exports_task_commands)),
|
|
34901
35312
|
Promise.resolve().then(() => (init_plan_template_commands(), exports_plan_template_commands)),
|
|
@@ -34906,7 +35317,8 @@ var [
|
|
|
34906
35317
|
Promise.resolve().then(() => (init_mcp_hooks_commands(), exports_mcp_hooks_commands)),
|
|
34907
35318
|
Promise.resolve().then(() => (init_dispatch3(), exports_dispatch2)),
|
|
34908
35319
|
Promise.resolve().then(() => (init_machines3(), exports_machines2)),
|
|
34909
|
-
Promise.resolve().then(() => (init_api_key_commands(), exports_api_key_commands))
|
|
35320
|
+
Promise.resolve().then(() => (init_api_key_commands(), exports_api_key_commands)),
|
|
35321
|
+
Promise.resolve().then(() => (init_environment_snapshots3(), exports_environment_snapshots2))
|
|
34910
35322
|
]);
|
|
34911
35323
|
registerTaskCommands2(program2);
|
|
34912
35324
|
registerPlanTemplateCommands2(program2);
|
|
@@ -34918,4 +35330,5 @@ registerMcpHooksCommands2(program2);
|
|
|
34918
35330
|
registerDispatchCommands2(program2);
|
|
34919
35331
|
registerMachineCommands2(program2);
|
|
34920
35332
|
registerApiKeyCommands2(program2);
|
|
35333
|
+
registerEnvironmentSnapshotCommands2(program2);
|
|
34921
35334
|
program2.parse();
|
package/dist/cli-mcp-parity.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type TodosCliMcpParityDomain = "tasks" | "local-fields" | "dedupe" | "verification-providers" | "projects" | "plans" | "templates" | "workspace-trust" | "runner-sandbox" | "policy-packs" | "approval-gates" | "local-event-hooks" | "encryption" | "agent-runs" | "handoffs" | "runs" | "comments" | "search" | "context-packs" | "imports" | "exports";
|
|
1
|
+
export type TodosCliMcpParityDomain = "tasks" | "local-fields" | "dedupe" | "verification-providers" | "projects" | "plans" | "templates" | "workspace-trust" | "runner-sandbox" | "policy-packs" | "approval-gates" | "local-event-hooks" | "encryption" | "agent-runs" | "handoffs" | "runs" | "comments" | "search" | "context-packs" | "environment-snapshots" | "imports" | "exports";
|
|
2
2
|
export type TodosCliMcpParityStatus = "matched" | "intentional-gap";
|
|
3
3
|
export interface CreateCliMcpParityManifestOptions {
|
|
4
4
|
version?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-mcp-parity.d.ts","sourceRoot":"","sources":["../src/cli-mcp-parity.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,uBAAuB,GAC/B,OAAO,GACP,cAAc,GACd,QAAQ,GACR,wBAAwB,GACxB,UAAU,GACV,OAAO,GACP,WAAW,GACX,iBAAiB,GACjB,gBAAgB,GAChB,cAAc,GACd,gBAAgB,GAChB,mBAAmB,GACnB,YAAY,GACZ,YAAY,GACZ,UAAU,GACV,MAAM,GACN,UAAU,GACV,QAAQ,GACR,eAAe,GACf,SAAS,GACT,SAAS,CAAC;AAEd,MAAM,MAAM,uBAAuB,GAAG,SAAS,GAAG,iBAAiB,CAAC;AAEpE,MAAM,WAAW,iCAAiC;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,8BAA8B;IAC7C,WAAW,EAAE,cAAc,CAAC;IAC5B,UAAU,EAAE,aAAa,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,uBAAuB,CAAC;IAChC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,MAAM,EAAE,uBAAuB,CAAC;IAChC,eAAe,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE;QACP,GAAG,EAAE,MAAM,CAAC;QACZ,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,yBAAyB;IACxC,aAAa,EAAE,CAAC,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,8BAA8B,CAAC;IACxC,SAAS,EAAE,IAAI,CAAC;IAChB,iBAAiB,EAAE,IAAI,CAAC;IACxB,MAAM,EAAE,sBAAsB,EAAE,CAAC;CAClC;AAUD,eAAO,MAAM,oBAAoB,EAAE,sBAAsB,
|
|
1
|
+
{"version":3,"file":"cli-mcp-parity.d.ts","sourceRoot":"","sources":["../src/cli-mcp-parity.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,uBAAuB,GAC/B,OAAO,GACP,cAAc,GACd,QAAQ,GACR,wBAAwB,GACxB,UAAU,GACV,OAAO,GACP,WAAW,GACX,iBAAiB,GACjB,gBAAgB,GAChB,cAAc,GACd,gBAAgB,GAChB,mBAAmB,GACnB,YAAY,GACZ,YAAY,GACZ,UAAU,GACV,MAAM,GACN,UAAU,GACV,QAAQ,GACR,eAAe,GACf,uBAAuB,GACvB,SAAS,GACT,SAAS,CAAC;AAEd,MAAM,MAAM,uBAAuB,GAAG,SAAS,GAAG,iBAAiB,CAAC;AAEpE,MAAM,WAAW,iCAAiC;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,8BAA8B;IAC7C,WAAW,EAAE,cAAc,CAAC;IAC5B,UAAU,EAAE,aAAa,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,uBAAuB,CAAC;IAChC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,MAAM,EAAE,uBAAuB,CAAC;IAChC,eAAe,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE;QACP,GAAG,EAAE,MAAM,CAAC;QACZ,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,yBAAyB;IACxC,aAAa,EAAE,CAAC,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,8BAA8B,CAAC;IACxC,SAAS,EAAE,IAAI,CAAC;IAChB,iBAAiB,EAAE,IAAI,CAAC;IACxB,MAAM,EAAE,sBAAsB,EAAE,CAAC;CAClC;AAUD,eAAO,MAAM,oBAAoB,EAAE,sBAAsB,EAkkBxD,CAAC;AAYF,wBAAgB,0BAA0B,CACxC,OAAO,GAAE,iCAAsC,GAC9C,yBAAyB,CAW3B;AAED,eAAO,MAAM,6BAA6B,2BAExC,CAAC"}
|