@iowarp/clio-coder 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +407 -0
- package/CODE_OF_CONDUCT.md +21 -0
- package/CONTRIBUTING.md +224 -0
- package/LICENSE +202 -0
- package/NOTICE +9 -0
- package/README.md +798 -0
- package/SECURITY.md +72 -0
- package/assets/clio-coder-logo-128.webp +0 -0
- package/damage-control-rules.yaml +419 -0
- package/dist/acp-UMLFVA3F.js +92 -0
- package/dist/agents-Q4MYPMUW.js +91 -0
- package/dist/auth-O6HYIJ6J.js +521 -0
- package/dist/chunk-262G75JS.js +35 -0
- package/dist/chunk-26BZQOAD.js +1281 -0
- package/dist/chunk-2J63S4SF.js +508 -0
- package/dist/chunk-3DANZDGR.js +717 -0
- package/dist/chunk-4UQA7NCT.js +29 -0
- package/dist/chunk-527KG6XR.js +497 -0
- package/dist/chunk-5LDRNKX2.js +1063 -0
- package/dist/chunk-5N2FG33Q.js +25 -0
- package/dist/chunk-67MTHP2E.js +135 -0
- package/dist/chunk-6CWDTGUC.js +20 -0
- package/dist/chunk-7BHLZB3A.js +2115 -0
- package/dist/chunk-7RBKDI66.js +348 -0
- package/dist/chunk-AMFR5YA3.js +541 -0
- package/dist/chunk-BBUH4VAA.js +1224 -0
- package/dist/chunk-BYEU76JP.js +899 -0
- package/dist/chunk-CLJ5HLUD.js +458 -0
- package/dist/chunk-D5YD55AR.js +116 -0
- package/dist/chunk-DXQNI4PC.js +61 -0
- package/dist/chunk-E3NYWENM.js +1004 -0
- package/dist/chunk-GNGDQYDU.js +34688 -0
- package/dist/chunk-GOTUR54M.js +9 -0
- package/dist/chunk-HBU5MTAM.js +41 -0
- package/dist/chunk-HMYNFFY4.js +28 -0
- package/dist/chunk-JPOWPFCU.js +1010 -0
- package/dist/chunk-JWHCJDCI.js +1215 -0
- package/dist/chunk-KBR4MZZR.js +41 -0
- package/dist/chunk-KKKPTZLM.js +93 -0
- package/dist/chunk-ME6DNWIU.js +66 -0
- package/dist/chunk-NI4DEJMC.js +88 -0
- package/dist/chunk-O4EJEDHO.js +659 -0
- package/dist/chunk-PIDUD6M2.js +31 -0
- package/dist/chunk-PS4PFJQP.js +29459 -0
- package/dist/chunk-QV47YRF4.js +48 -0
- package/dist/chunk-RQDWMVRB.js +279 -0
- package/dist/chunk-TFSSEXL6.js +136 -0
- package/dist/chunk-TKHQ4DGZ.js +8290 -0
- package/dist/chunk-TPOCL34A.js +2876 -0
- package/dist/chunk-UGYAX5YI.js +565 -0
- package/dist/chunk-UHTSULZS.js +461 -0
- package/dist/chunk-UU3R62TT.js +128 -0
- package/dist/chunk-UWIJNAOB.js +3906 -0
- package/dist/chunk-VOO7NYPP.js +914 -0
- package/dist/chunk-VPAWTYLY.js +117 -0
- package/dist/chunk-WD6AJM35.js +1216 -0
- package/dist/chunk-X3BR7HWV.js +115 -0
- package/dist/chunk-X3NE4WVW.js +120 -0
- package/dist/chunk-XNISANGE.js +1395 -0
- package/dist/chunk-XV4ZJ6ZM.js +3177 -0
- package/dist/cli/index.js +236 -0
- package/dist/clio-KIQ5SNDS.js +53 -0
- package/dist/components-JVHMUBEB.js +653 -0
- package/dist/config-ZFCDBMDC.js +372 -0
- package/dist/configure-G4E3A2PG.js +27 -0
- package/dist/context-CDXTP2MP.js +293 -0
- package/dist/context-E3KIFVXI.js +185 -0
- package/dist/context-clear-3F4PLXOS.js +102 -0
- package/dist/context-index-Q7YSYTR3.js +106 -0
- package/dist/docs-YIETIWZI.js +280 -0
- package/dist/doctor-M5HJJZOL.js +61 -0
- package/dist/domains/agents/builtins/architect.md +33 -0
- package/dist/domains/agents/builtins/coder.md +31 -0
- package/dist/domains/agents/builtins/context-bootstrap.md +38 -0
- package/dist/domains/agents/builtins/debugger.md +30 -0
- package/dist/domains/agents/builtins/documenter.md +31 -0
- package/dist/domains/agents/builtins/git-master.md +30 -0
- package/dist/domains/agents/builtins/provenance.md +30 -0
- package/dist/domains/agents/builtins/researcher.md +71 -0
- package/dist/domains/agents/builtins/scout.md +42 -0
- package/dist/domains/agents/builtins/tester.md +31 -0
- package/dist/domains/agents/builtins/verifier.md +30 -0
- package/dist/domains/agents/builtins/wiki-writer.md +41 -0
- package/dist/eval-B3KZZESM.js +2674 -0
- package/dist/evidence-V67CHM35.js +233 -0
- package/dist/evolve-YDZSUQYA.js +518 -0
- package/dist/extensions-SRG7XCAH.js +207 -0
- package/dist/fleet-CA2CRTVG.js +760 -0
- package/dist/fleet-preflight-CLIAX7YR.js +21 -0
- package/dist/init-2OZDJE2D.js +227 -0
- package/dist/memory-3PIQQAKX.js +207 -0
- package/dist/models-DY35XI7Y.js +237 -0
- package/dist/paths-5OMXW7Z4.js +57 -0
- package/dist/preload-KZVHET2B.js +11 -0
- package/dist/reset-PIFYNOS3.js +216 -0
- package/dist/run-3VSPP24F.js +735 -0
- package/dist/share-D36RQCXM.js +241 -0
- package/dist/skills-F2MRLELY.js +445 -0
- package/dist/skills-eval-E2ZTW4PL.js +932 -0
- package/dist/targets-DZMEZAH4.js +977 -0
- package/dist/trace-7NYCUI2J.js +250 -0
- package/dist/uninstall-AD3JWHBB.js +322 -0
- package/dist/upgrade-WYYBKGDY.js +301 -0
- package/dist/usage-ULIDAGFF.js +755 -0
- package/dist/version-ROZ6CZKH.js +16 -0
- package/dist/wiki-generate-PKFIX6OB.js +377 -0
- package/dist/worker/entry.js +1739 -0
- package/docs/README.md +93 -0
- package/docs/acp.md +120 -0
- package/docs/alcf-provider.md +72 -0
- package/docs/architecture.md +172 -0
- package/docs/artifact-versions.md +54 -0
- package/docs/built-in-agents.md +265 -0
- package/docs/capacity-and-scheduling.md +97 -0
- package/docs/commands-and-modes.md +554 -0
- package/docs/config-knobs-audit.md +115 -0
- package/docs/configuration-and-targets.md +812 -0
- package/docs/context-engine.md +236 -0
- package/docs/dispatch-architecture-rationale.md +126 -0
- package/docs/documentation-coverage.md +46 -0
- package/docs/documentation-guide.md +166 -0
- package/docs/environment-variables.md +105 -0
- package/docs/eval-runner.md +205 -0
- package/docs/evals-internal.md +298 -0
- package/docs/evidence-and-memory.md +243 -0
- package/docs/evolution.md +143 -0
- package/docs/exit-codes-and-output.md +74 -0
- package/docs/extensions-and-sharing.md +306 -0
- package/docs/fleet-demo-runbook.md +179 -0
- package/docs/fleet-dispatch.md +591 -0
- package/docs/glossary.md +75 -0
- package/docs/html/agents_blueprint.html +936 -0
- package/docs/html/alcf_blueprint.html +324 -0
- package/docs/html/architecture_blueprint.html +850 -0
- package/docs/html/commands_blueprint.html +794 -0
- package/docs/html/config_knobs_audit_blueprint.html +178 -0
- package/docs/html/configuration_blueprint.html +1080 -0
- package/docs/html/context_blueprint.html +603 -0
- package/docs/html/documentation_blueprint.html +832 -0
- package/docs/html/environment_blueprint.html +404 -0
- package/docs/html/eval_blueprint.html +743 -0
- package/docs/html/evals_internal_blueprint.html +190 -0
- package/docs/html/evolution_blueprint.html +674 -0
- package/docs/html/extensions_blueprint.html +2065 -0
- package/docs/html/fleet_dispatch_blueprint.html +286 -0
- package/docs/html/index.html +919 -0
- package/docs/html/lifecycle_blueprint.html +723 -0
- package/docs/html/memory_blueprint.html +699 -0
- package/docs/html/middleware_blueprint.html +664 -0
- package/docs/html/models_blueprint.html +2366 -0
- package/docs/html/observability_blueprint.html +683 -0
- package/docs/html/provider_adapter_blueprint.html +245 -0
- package/docs/html/safety_blueprint.html +1386 -0
- package/docs/html/shared.css +571 -0
- package/docs/html/shared.js +143 -0
- package/docs/html/skills_blueprint.html +671 -0
- package/docs/html/soak_blueprint.html +182 -0
- package/docs/html/tool_usage_blueprint.html +350 -0
- package/docs/html/tools_blueprint.html +2249 -0
- package/docs/html/trace_blueprint.html +235 -0
- package/docs/html/tui_design_blueprint.html +314 -0
- package/docs/html/validation_blueprint.html +961 -0
- package/docs/html/worker_dispatch_blueprint.html +231 -0
- package/docs/installation-and-lifecycle.md +308 -0
- package/docs/middleware-and-components.md +148 -0
- package/docs/model-catalog.md +189 -0
- package/docs/observability.md +233 -0
- package/docs/proactive-memory.md +452 -0
- package/docs/prompt-envelope-and-tools.md +142 -0
- package/docs/provider-adapter-cookbook.md +148 -0
- package/docs/release-cut-checklist.md +138 -0
- package/docs/safety-model.md +357 -0
- package/docs/scientific-validation.md +105 -0
- package/docs/session-lifecycle.md +156 -0
- package/docs/skills-marketplace.md +46 -0
- package/docs/tool-usage.md +527 -0
- package/docs/trace-store.md +132 -0
- package/docs/troubleshooting.md +33 -0
- package/docs/tui-design.md +239 -0
- package/docs/worker-dispatch-mechanics.md +242 -0
- package/package.json +132 -0
- package/skills/README.md +408 -0
- package/skills/git/commit-crafting/SKILL.md +79 -0
- package/skills/git/commit-crafting/evals.md +92 -0
- package/skills/git/create-pr/SKILL.md +116 -0
- package/skills/git/create-pr/evals.md +114 -0
- package/skills/git/investigate-issue/SKILL.md +139 -0
- package/skills/git/investigate-issue/evals.md +94 -0
- package/skills/git/resolve-merge-conflicts/SKILL.md +96 -0
- package/skills/git/resolve-merge-conflicts/evals.md +58 -0
- package/skills/git/review-changes/SKILL.md +103 -0
- package/skills/git/review-changes/evals.md +85 -0
- package/skills/git/worktree-create/SKILL.md +92 -0
- package/skills/git/worktree-create/evals.md +97 -0
- package/skills/git/worktree-create/references/worktree-setup.md +66 -0
- package/skills/git/worktree-merge/SKILL.md +95 -0
- package/skills/git/worktree-merge/evals.md +114 -0
- package/skills/skill-marketplace.json +261 -0
- package/skills/workflow/cut-it/SKILL.md +86 -0
- package/skills/workflow/cut-it/evals.md +42 -0
- package/src/domains/agents/builtins/architect.md +33 -0
- package/src/domains/agents/builtins/coder.md +31 -0
- package/src/domains/agents/builtins/context-bootstrap.md +38 -0
- package/src/domains/agents/builtins/debugger.md +30 -0
- package/src/domains/agents/builtins/documenter.md +31 -0
- package/src/domains/agents/builtins/git-master.md +30 -0
- package/src/domains/agents/builtins/provenance.md +30 -0
- package/src/domains/agents/builtins/researcher.md +71 -0
- package/src/domains/agents/builtins/scout.md +42 -0
- package/src/domains/agents/builtins/tester.md +31 -0
- package/src/domains/agents/builtins/verifier.md +30 -0
- package/src/domains/agents/builtins/wiki-writer.md +41 -0
- package/src/domains/agents/fleets/build-review.md +34 -0
- package/src/domains/agents/fleets/build-test.md +35 -0
- package/src/domains/agents/fleets/sdlc.md +86 -0
- package/src/domains/prompts/fragments/identity/clio-worker.md +11 -0
- package/src/domains/prompts/fragments/identity/clio.md +26 -0
- package/src/domains/prompts/fragments/operating/contract.md +64 -0
- package/src/domains/prompts/fragments/safety/auto-edit.md +14 -0
- package/src/domains/prompts/fragments/safety/full-auto.md +14 -0
- package/src/domains/prompts/fragments/safety/read-only.md +13 -0
- package/src/domains/prompts/fragments/safety/suggest.md +13 -0
- package/src/domains/prompts/fragments/wiki/page.md +75 -0
- package/src/domains/prompts/fragments/wiki/plan.md +48 -0
- package/src/domains/providers/models/cloud-models/alcf.yaml +40 -0
- package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +993 -0
|
@@ -0,0 +1,541 @@
|
|
|
1
|
+
import {
|
|
2
|
+
readSettings,
|
|
3
|
+
settingsPath,
|
|
4
|
+
updateSettings
|
|
5
|
+
} from "./chunk-JWHCJDCI.js";
|
|
6
|
+
import {
|
|
7
|
+
DEFAULT_SETTINGS
|
|
8
|
+
} from "./chunk-UHTSULZS.js";
|
|
9
|
+
import {
|
|
10
|
+
safeResourceBackupPath,
|
|
11
|
+
safeResourceWrite
|
|
12
|
+
} from "./chunk-VPAWTYLY.js";
|
|
13
|
+
import {
|
|
14
|
+
clioConfigDir,
|
|
15
|
+
resolveClioDirs
|
|
16
|
+
} from "./chunk-X3NE4WVW.js";
|
|
17
|
+
import {
|
|
18
|
+
readClioVersion
|
|
19
|
+
} from "./chunk-DXQNI4PC.js";
|
|
20
|
+
|
|
21
|
+
// src/domains/share/archive.ts
|
|
22
|
+
import { createHash } from "node:crypto";
|
|
23
|
+
import { existsSync, lstatSync, readdirSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
24
|
+
import path from "node:path";
|
|
25
|
+
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
26
|
+
var PROJECT_CONTEXT_FILES = ["CLIO-CODER.md", "AGENTS.md", "CODEX.md", "GEMINI.md", "CLAUDE.md"];
|
|
27
|
+
var SETTINGS_FRAGMENT_PATH = "settings.fragment.yaml";
|
|
28
|
+
function sha256(buffer) {
|
|
29
|
+
return createHash("sha256").update(buffer).digest("hex");
|
|
30
|
+
}
|
|
31
|
+
function isRecord(value) {
|
|
32
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
33
|
+
}
|
|
34
|
+
function isErrorWithCode(value) {
|
|
35
|
+
return value instanceof Error && "code" in value;
|
|
36
|
+
}
|
|
37
|
+
function stableJson(value) {
|
|
38
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
39
|
+
if (Array.isArray(value)) return `[${value.map((entry) => stableJson(entry)).join(",")}]`;
|
|
40
|
+
return `{${Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, entry]) => `${JSON.stringify(key)}:${stableJson(entry)}`).join(",")}}`;
|
|
41
|
+
}
|
|
42
|
+
function readDirRecursive(root) {
|
|
43
|
+
if (!existsSync(root)) return [];
|
|
44
|
+
const out = [];
|
|
45
|
+
const walk = (dir) => {
|
|
46
|
+
for (const entry of readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
47
|
+
if (entry.name === ".DS_Store") continue;
|
|
48
|
+
const fullPath = path.join(dir, entry.name);
|
|
49
|
+
const relativePath = path.relative(root, fullPath).split(path.sep).join("/");
|
|
50
|
+
const stat = statSync(fullPath);
|
|
51
|
+
if (entry.isDirectory()) {
|
|
52
|
+
walk(fullPath);
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (entry.isFile()) out.push({ fullPath, relativePath, stat });
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
try {
|
|
59
|
+
if (statSync(root).isDirectory()) walk(root);
|
|
60
|
+
} catch {
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
return out;
|
|
64
|
+
}
|
|
65
|
+
function addBufferFile(files, input) {
|
|
66
|
+
files.push({
|
|
67
|
+
type: input.type,
|
|
68
|
+
scope: input.scope,
|
|
69
|
+
archivePath: input.archivePath.split(path.sep).join("/"),
|
|
70
|
+
relativePath: input.relativePath.split(path.sep).join("/"),
|
|
71
|
+
sha256: sha256(input.buffer),
|
|
72
|
+
size: input.buffer.byteLength,
|
|
73
|
+
encoding: "base64",
|
|
74
|
+
data: input.buffer.toString("base64")
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
function addTree(files, type, scope, root, archivePrefix, filter) {
|
|
78
|
+
for (const entry of readDirRecursive(root)) {
|
|
79
|
+
if (filter && !filter(entry.relativePath)) continue;
|
|
80
|
+
const buffer = readFileSync(entry.fullPath);
|
|
81
|
+
addBufferFile(files, {
|
|
82
|
+
type,
|
|
83
|
+
scope,
|
|
84
|
+
archivePath: `${archivePrefix}/${entry.relativePath}`,
|
|
85
|
+
relativePath: entry.relativePath,
|
|
86
|
+
buffer
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function settingsFragment(settings) {
|
|
91
|
+
return {
|
|
92
|
+
autonomy: settings.autonomy,
|
|
93
|
+
scope: settings.scope,
|
|
94
|
+
budget: settings.budget,
|
|
95
|
+
theme: settings.theme,
|
|
96
|
+
terminal: settings.terminal,
|
|
97
|
+
keybindings: settings.keybindings,
|
|
98
|
+
compaction: settings.compaction,
|
|
99
|
+
retry: settings.retry
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function requestedScopes(scope) {
|
|
103
|
+
if (scope === "both") return ["project", "user"];
|
|
104
|
+
return [scope ?? "project"];
|
|
105
|
+
}
|
|
106
|
+
function defaultedIncludes(options) {
|
|
107
|
+
const hasExplicitInclude = options.includeContext !== void 0 || options.includePrompts !== void 0 || options.includeSkills !== void 0 || options.includeSettings !== void 0 || options.includeExtensions !== void 0;
|
|
108
|
+
return {
|
|
109
|
+
includeContext: hasExplicitInclude ? options.includeContext === true : true,
|
|
110
|
+
includePrompts: hasExplicitInclude ? options.includePrompts === true : true,
|
|
111
|
+
includeSkills: hasExplicitInclude ? options.includeSkills === true : true,
|
|
112
|
+
includeSettings: hasExplicitInclude ? options.includeSettings === true : true,
|
|
113
|
+
includeExtensions: hasExplicitInclude ? options.includeExtensions === true : true
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function createShareArchive(options = {}) {
|
|
117
|
+
const cwd = path.resolve(options.cwd ?? process.cwd());
|
|
118
|
+
const files = [];
|
|
119
|
+
const includes = defaultedIncludes(options);
|
|
120
|
+
const scopes = requestedScopes(options.scope);
|
|
121
|
+
if (includes.includeContext && scopes.includes("project")) {
|
|
122
|
+
for (const name of PROJECT_CONTEXT_FILES) {
|
|
123
|
+
const full = path.join(cwd, name);
|
|
124
|
+
try {
|
|
125
|
+
if (!statSync(full).isFile()) continue;
|
|
126
|
+
addBufferFile(files, {
|
|
127
|
+
type: "project-context",
|
|
128
|
+
scope: "project",
|
|
129
|
+
archivePath: `project/${name}`,
|
|
130
|
+
relativePath: name,
|
|
131
|
+
buffer: readFileSync(full)
|
|
132
|
+
});
|
|
133
|
+
} catch {
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (includes.includePrompts) {
|
|
138
|
+
for (const scope of scopes) {
|
|
139
|
+
const root = scope === "user" ? path.join(clioConfigDir(), "prompts") : path.join(cwd, ".clio-coder", "prompts");
|
|
140
|
+
addTree(files, "prompt", scope, root, `${scope}/prompts`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (includes.includeSkills) {
|
|
144
|
+
for (const scope of scopes) {
|
|
145
|
+
const root = scope === "user" ? path.join(clioConfigDir(), "skills") : path.join(cwd, ".clio-coder", "skills");
|
|
146
|
+
addTree(files, "skill", scope, root, `${scope}/skills`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (includes.includeExtensions) {
|
|
150
|
+
for (const scope of scopes) {
|
|
151
|
+
const root = scope === "user" ? path.join(clioConfigDir(), "extensions") : path.join(cwd, ".clio-coder", "extensions");
|
|
152
|
+
addTree(files, "extension", scope, root, `${scope}/extensions`, (rel) => path.basename(rel) !== "state.json");
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (includes.includeSettings) {
|
|
156
|
+
const buffer = Buffer.from(stringifyYaml(settingsFragment(readSettings())), "utf8");
|
|
157
|
+
addBufferFile(files, {
|
|
158
|
+
type: "settings",
|
|
159
|
+
scope: "user",
|
|
160
|
+
archivePath: SETTINGS_FRAGMENT_PATH,
|
|
161
|
+
relativePath: SETTINGS_FRAGMENT_PATH,
|
|
162
|
+
buffer
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
const manifestFiles = files.map(({ data: _data, encoding: _encoding, ...entry }) => entry);
|
|
166
|
+
return {
|
|
167
|
+
kind: "clio-share-archive",
|
|
168
|
+
formatVersion: 1,
|
|
169
|
+
manifest: {
|
|
170
|
+
format: "clio.share.v1",
|
|
171
|
+
clioVersion: readClioVersion(),
|
|
172
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
173
|
+
files: manifestFiles
|
|
174
|
+
},
|
|
175
|
+
files: files.sort((a, b) => a.archivePath.localeCompare(b.archivePath))
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
function writeShareArchive(outPath, options = {}) {
|
|
179
|
+
const archive = createShareArchive(options);
|
|
180
|
+
safeResourceWrite(path.resolve(outPath), `${stableJson(archive)}
|
|
181
|
+
`, { encoding: "utf8" });
|
|
182
|
+
return archive;
|
|
183
|
+
}
|
|
184
|
+
function decodeArchiveFile(entry) {
|
|
185
|
+
return Buffer.from(entry.data, entry.encoding);
|
|
186
|
+
}
|
|
187
|
+
function parseArchive(raw) {
|
|
188
|
+
if (!isRecord(raw) || raw.kind !== "clio-share-archive" || raw.formatVersion !== 1 || !isRecord(raw.manifest)) {
|
|
189
|
+
throw new Error("not a Clio share archive v1");
|
|
190
|
+
}
|
|
191
|
+
if (raw.manifest.format !== "clio.share.v1" || !Array.isArray(raw.files)) {
|
|
192
|
+
throw new Error("share archive manifest is malformed");
|
|
193
|
+
}
|
|
194
|
+
const archive = raw;
|
|
195
|
+
for (const file of archive.files) {
|
|
196
|
+
if (!isRecord(file) || typeof file.archivePath !== "string" || typeof file.relativePath !== "string" || typeof file.sha256 !== "string" || file.encoding !== "base64" || typeof file.data !== "string") {
|
|
197
|
+
throw new Error("share archive file entry is malformed");
|
|
198
|
+
}
|
|
199
|
+
const actual = sha256(decodeArchiveFile(file));
|
|
200
|
+
if (actual !== file.sha256) throw new Error(`share archive checksum mismatch for ${file.archivePath}`);
|
|
201
|
+
}
|
|
202
|
+
return archive;
|
|
203
|
+
}
|
|
204
|
+
function readShareArchive(filePath) {
|
|
205
|
+
let parsed;
|
|
206
|
+
try {
|
|
207
|
+
parsed = JSON.parse(readFileSync(filePath, "utf8"));
|
|
208
|
+
} catch (err) {
|
|
209
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
210
|
+
throw new Error(`share archive could not be read: ${reason}`);
|
|
211
|
+
}
|
|
212
|
+
return parseArchive(parsed);
|
|
213
|
+
}
|
|
214
|
+
function configDirPath() {
|
|
215
|
+
return path.resolve(resolveClioDirs().config);
|
|
216
|
+
}
|
|
217
|
+
function settingsFilePath() {
|
|
218
|
+
return path.join(configDirPath(), "settings.yaml");
|
|
219
|
+
}
|
|
220
|
+
function relativePathSegments(relativePath) {
|
|
221
|
+
if (relativePath.length === 0 || relativePath.includes("\0")) return null;
|
|
222
|
+
if (path.isAbsolute(relativePath) || path.win32.isAbsolute(relativePath)) return null;
|
|
223
|
+
const segments = relativePath.replace(/\\/g, "/").split("/");
|
|
224
|
+
if (segments.some((segment) => segment.length === 0 || segment === "." || segment === "..")) return null;
|
|
225
|
+
return segments;
|
|
226
|
+
}
|
|
227
|
+
function targetRootForFile(entry, options) {
|
|
228
|
+
const cwd = path.resolve(options.cwd ?? process.cwd());
|
|
229
|
+
const config = configDirPath();
|
|
230
|
+
const scope = options.scope ?? entry.scope;
|
|
231
|
+
switch (entry.type) {
|
|
232
|
+
case "project-context":
|
|
233
|
+
return { root: cwd, containmentRoot: cwd, scope: "project" };
|
|
234
|
+
case "prompt":
|
|
235
|
+
return scope === "user" ? { root: path.join(config, "prompts"), containmentRoot: config, scope } : { root: path.join(cwd, ".clio-coder", "prompts"), containmentRoot: cwd, scope };
|
|
236
|
+
case "skill":
|
|
237
|
+
return scope === "user" ? { root: path.join(config, "skills"), containmentRoot: config, scope } : { root: path.join(cwd, ".clio-coder", "skills"), containmentRoot: cwd, scope };
|
|
238
|
+
case "extension":
|
|
239
|
+
return scope === "user" ? { root: path.join(config, "extensions"), containmentRoot: config, scope } : { root: path.join(cwd, ".clio-coder", "extensions"), containmentRoot: cwd, scope };
|
|
240
|
+
case "settings":
|
|
241
|
+
return { root: config, containmentRoot: config, scope };
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
function isInsideOrEqual(candidate, root) {
|
|
245
|
+
const relative = path.relative(root, candidate);
|
|
246
|
+
return relative === "" || !relative.startsWith("..") && !path.isAbsolute(relative);
|
|
247
|
+
}
|
|
248
|
+
function lstatExists(candidate) {
|
|
249
|
+
try {
|
|
250
|
+
lstatSync(candidate);
|
|
251
|
+
return true;
|
|
252
|
+
} catch (err) {
|
|
253
|
+
if (isErrorWithCode(err) && (err.code === "ENOENT" || err.code === "ENOTDIR")) return false;
|
|
254
|
+
throw err;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
function nearestExistingPath(candidate) {
|
|
258
|
+
let current = path.resolve(candidate);
|
|
259
|
+
while (!lstatExists(current)) {
|
|
260
|
+
const parent = path.dirname(current);
|
|
261
|
+
if (parent === current) return null;
|
|
262
|
+
current = parent;
|
|
263
|
+
}
|
|
264
|
+
return current;
|
|
265
|
+
}
|
|
266
|
+
function pathDiagnostic(entry) {
|
|
267
|
+
return `${entry.archivePath} -> ${entry.relativePath}`;
|
|
268
|
+
}
|
|
269
|
+
function validateRealPathContainment(entry, target, containmentRoot) {
|
|
270
|
+
const rootAnchor = nearestExistingPath(containmentRoot);
|
|
271
|
+
const targetAnchor = nearestExistingPath(lstatExists(target) ? target : path.dirname(target));
|
|
272
|
+
if (!rootAnchor || !targetAnchor) {
|
|
273
|
+
return {
|
|
274
|
+
type: "error",
|
|
275
|
+
message: `share archive target could not be resolved safely: ${pathDiagnostic(entry)}`,
|
|
276
|
+
path: entry.relativePath
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
let realRoot;
|
|
280
|
+
let realTarget;
|
|
281
|
+
try {
|
|
282
|
+
realRoot = realpathSync(rootAnchor);
|
|
283
|
+
realTarget = realpathSync(targetAnchor);
|
|
284
|
+
} catch {
|
|
285
|
+
return {
|
|
286
|
+
type: "error",
|
|
287
|
+
message: `share archive target could not be resolved safely: ${pathDiagnostic(entry)}`,
|
|
288
|
+
path: entry.relativePath
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
if (!isInsideOrEqual(realTarget, realRoot)) {
|
|
292
|
+
return {
|
|
293
|
+
type: "error",
|
|
294
|
+
message: `share archive target escapes import root: ${pathDiagnostic(entry)}`,
|
|
295
|
+
path: entry.relativePath
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
function resolveImportTarget(entry, options) {
|
|
301
|
+
const segments = relativePathSegments(entry.relativePath);
|
|
302
|
+
if (!segments) {
|
|
303
|
+
return {
|
|
304
|
+
type: "error",
|
|
305
|
+
message: `share archive relativePath is not safe: ${pathDiagnostic(entry)}`,
|
|
306
|
+
path: entry.relativePath
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
const targetRoot = targetRootForFile(entry, options);
|
|
310
|
+
const target = entry.type === "settings" ? settingsFilePath() : path.resolve(targetRoot.root, ...segments);
|
|
311
|
+
if (!isInsideOrEqual(target, targetRoot.root)) {
|
|
312
|
+
return {
|
|
313
|
+
type: "error",
|
|
314
|
+
message: `share archive target escapes import root: ${pathDiagnostic(entry)}`,
|
|
315
|
+
path: entry.relativePath
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
const realPathDiagnostic = validateRealPathContainment(entry, target, targetRoot.containmentRoot);
|
|
319
|
+
if (realPathDiagnostic) return realPathDiagnostic;
|
|
320
|
+
return { entry, target, scope: targetRoot.scope, buffer: decodeArchiveFile(entry) };
|
|
321
|
+
}
|
|
322
|
+
function preflightImportTargets(archive, options) {
|
|
323
|
+
const targets = [];
|
|
324
|
+
const diagnostics = [];
|
|
325
|
+
for (const entry of archive.files) {
|
|
326
|
+
const resolved = resolveImportTarget(entry, options);
|
|
327
|
+
if ("type" in resolved) {
|
|
328
|
+
diagnostics.push(resolved);
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
targets.push(resolved);
|
|
332
|
+
}
|
|
333
|
+
if (diagnostics.length > 0) return { targets: [], diagnostics };
|
|
334
|
+
return { targets, diagnostics };
|
|
335
|
+
}
|
|
336
|
+
function versionDiagnostics(archive) {
|
|
337
|
+
const current = readClioVersion();
|
|
338
|
+
const [curMajor, curMinor] = current.split(".");
|
|
339
|
+
const [arcMajor, arcMinor] = archive.manifest.clioVersion.split(".");
|
|
340
|
+
if (curMajor !== arcMajor || curMinor !== arcMinor) {
|
|
341
|
+
return [
|
|
342
|
+
{
|
|
343
|
+
type: "warning",
|
|
344
|
+
message: `archive was created by Clio ${archive.manifest.clioVersion}; current Clio is ${current}`
|
|
345
|
+
}
|
|
346
|
+
];
|
|
347
|
+
}
|
|
348
|
+
return [];
|
|
349
|
+
}
|
|
350
|
+
function settingsPlan(buffer, options) {
|
|
351
|
+
const parsed = parseYaml(buffer.toString("utf8"));
|
|
352
|
+
if (!isRecord(parsed)) return [{ type: "error", message: "settings fragment must be a YAML object" }];
|
|
353
|
+
const settingsTarget = settingsFilePath();
|
|
354
|
+
const current = settingsFragment(existsSync(settingsTarget) ? readSettings() : DEFAULT_SETTINGS);
|
|
355
|
+
const diagnostics = [];
|
|
356
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
357
|
+
if (key in current && JSON.stringify(current[key]) !== JSON.stringify(value)) {
|
|
358
|
+
diagnostics.push({
|
|
359
|
+
type: "conflict",
|
|
360
|
+
message: `settings fragment changes ${key}`,
|
|
361
|
+
path: settingsTarget
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
return options.force ? diagnostics.filter((diag) => diag.type !== "conflict") : diagnostics;
|
|
366
|
+
}
|
|
367
|
+
function prepareShareImport(filePath, options = {}) {
|
|
368
|
+
let archive;
|
|
369
|
+
try {
|
|
370
|
+
archive = readShareArchive(filePath);
|
|
371
|
+
} catch (err) {
|
|
372
|
+
return {
|
|
373
|
+
archive: null,
|
|
374
|
+
actions: [],
|
|
375
|
+
diagnostics: [{ type: "error", message: err instanceof Error ? err.message : String(err), path: filePath }],
|
|
376
|
+
targets: []
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
const diagnostics = [...versionDiagnostics(archive)];
|
|
380
|
+
const actions = [];
|
|
381
|
+
const preflight = preflightImportTargets(archive, options);
|
|
382
|
+
if (preflight.diagnostics.length > 0) {
|
|
383
|
+
return { archive, actions: [], diagnostics: [...diagnostics, ...preflight.diagnostics], targets: [] };
|
|
384
|
+
}
|
|
385
|
+
for (const targetInfo of preflight.targets) {
|
|
386
|
+
const { entry, target, scope, buffer } = targetInfo;
|
|
387
|
+
if (entry.type === "settings") {
|
|
388
|
+
diagnostics.push(...settingsPlan(buffer, options));
|
|
389
|
+
actions.push({ action: "settings", type: entry.type, scope, path: target });
|
|
390
|
+
continue;
|
|
391
|
+
}
|
|
392
|
+
if (existsSync(target)) {
|
|
393
|
+
const same = sha256(readFileSync(target)) === entry.sha256;
|
|
394
|
+
if (same) {
|
|
395
|
+
actions.push({ action: "skip", type: entry.type, scope, path: target });
|
|
396
|
+
} else if (options.force) {
|
|
397
|
+
actions.push({ action: "overwrite", type: entry.type, scope, path: target });
|
|
398
|
+
} else {
|
|
399
|
+
diagnostics.push({ type: "conflict", message: `destination already exists with different content`, path: target });
|
|
400
|
+
actions.push({ action: "skip", type: entry.type, scope, path: target });
|
|
401
|
+
}
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
actions.push({ action: "write", type: entry.type, scope, path: target });
|
|
405
|
+
}
|
|
406
|
+
return { archive, actions, diagnostics, targets: preflight.targets };
|
|
407
|
+
}
|
|
408
|
+
function publicImportPlan(prepared, recovery) {
|
|
409
|
+
return {
|
|
410
|
+
archive: prepared.archive,
|
|
411
|
+
actions: prepared.actions,
|
|
412
|
+
diagnostics: prepared.diagnostics,
|
|
413
|
+
...recovery ? { recovery } : {}
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
function planShareImport(filePath, options = {}) {
|
|
417
|
+
return publicImportPlan(prepareShareImport(filePath, options));
|
|
418
|
+
}
|
|
419
|
+
function mergeSettingsFragment(buffer) {
|
|
420
|
+
const parsed = parseYaml(buffer.toString("utf8"));
|
|
421
|
+
if (!isRecord(parsed)) throw new Error("settings fragment must be a YAML object");
|
|
422
|
+
updateSettings((settings) => {
|
|
423
|
+
const next = settings;
|
|
424
|
+
for (const key of [
|
|
425
|
+
"autonomy",
|
|
426
|
+
"scope",
|
|
427
|
+
"budget",
|
|
428
|
+
"theme",
|
|
429
|
+
"terminal",
|
|
430
|
+
"keybindings",
|
|
431
|
+
"compaction",
|
|
432
|
+
"retry"
|
|
433
|
+
]) {
|
|
434
|
+
if (key in parsed) next[key] = parsed[key];
|
|
435
|
+
}
|
|
436
|
+
});
|
|
437
|
+
return settingsPath();
|
|
438
|
+
}
|
|
439
|
+
function importShareArchive(filePath, options = {}) {
|
|
440
|
+
const prepared = prepareShareImport(filePath, options);
|
|
441
|
+
const plan = publicImportPlan(prepared);
|
|
442
|
+
if (!prepared.archive || options.dryRun) return plan;
|
|
443
|
+
if (prepared.diagnostics.some((diag) => diag.type === "error" || diag.type === "conflict")) return plan;
|
|
444
|
+
const written = [];
|
|
445
|
+
const backups = [];
|
|
446
|
+
const rememberWrite = (result) => {
|
|
447
|
+
if (!written.includes(result.path)) written.push(result.path);
|
|
448
|
+
if (result.backupPath && !backups.includes(result.backupPath)) backups.push(result.backupPath);
|
|
449
|
+
};
|
|
450
|
+
let failed;
|
|
451
|
+
try {
|
|
452
|
+
for (let index = 0; index < prepared.targets.length; index += 1) {
|
|
453
|
+
const targetInfo = prepared.targets[index];
|
|
454
|
+
const action = prepared.actions[index];
|
|
455
|
+
if (!targetInfo || !action || action.action === "skip") continue;
|
|
456
|
+
failed = targetInfo.target;
|
|
457
|
+
if (targetInfo.entry.type === "settings") {
|
|
458
|
+
const path2 = mergeSettingsFragment(targetInfo.buffer);
|
|
459
|
+
if (!written.includes(path2)) written.push(path2);
|
|
460
|
+
failed = void 0;
|
|
461
|
+
continue;
|
|
462
|
+
}
|
|
463
|
+
rememberWrite(
|
|
464
|
+
safeResourceWrite(targetInfo.target, targetInfo.buffer, {
|
|
465
|
+
backup: action.action === "overwrite"
|
|
466
|
+
})
|
|
467
|
+
);
|
|
468
|
+
failed = void 0;
|
|
469
|
+
}
|
|
470
|
+
return plan;
|
|
471
|
+
} catch (err) {
|
|
472
|
+
if (failed) {
|
|
473
|
+
const expectedBackup = safeResourceBackupPath(failed);
|
|
474
|
+
if (existsSync(expectedBackup) && !backups.includes(expectedBackup)) backups.push(expectedBackup);
|
|
475
|
+
}
|
|
476
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
477
|
+
const recovery = {
|
|
478
|
+
written,
|
|
479
|
+
backups,
|
|
480
|
+
...failed ? { failed } : {}
|
|
481
|
+
};
|
|
482
|
+
return publicImportPlan(
|
|
483
|
+
{
|
|
484
|
+
...prepared,
|
|
485
|
+
diagnostics: [
|
|
486
|
+
...prepared.diagnostics,
|
|
487
|
+
{
|
|
488
|
+
type: "error",
|
|
489
|
+
message: `share import failed while writing${failed ? ` ${failed}` : ""}: ${reason}`,
|
|
490
|
+
...failed ? { path: failed } : {}
|
|
491
|
+
}
|
|
492
|
+
]
|
|
493
|
+
},
|
|
494
|
+
recovery
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// src/domains/share/extension.ts
|
|
500
|
+
function createShareBundle(_context) {
|
|
501
|
+
const extension = {
|
|
502
|
+
start() {
|
|
503
|
+
return void 0;
|
|
504
|
+
}
|
|
505
|
+
};
|
|
506
|
+
const contract = {
|
|
507
|
+
createArchive(options) {
|
|
508
|
+
return createShareArchive(options);
|
|
509
|
+
},
|
|
510
|
+
writeArchive(outPath, options) {
|
|
511
|
+
return writeShareArchive(outPath, options);
|
|
512
|
+
},
|
|
513
|
+
planImport(filePath, options) {
|
|
514
|
+
return planShareImport(filePath, options);
|
|
515
|
+
},
|
|
516
|
+
importArchive(filePath, options) {
|
|
517
|
+
return importShareArchive(filePath, options);
|
|
518
|
+
}
|
|
519
|
+
};
|
|
520
|
+
return { extension, contract };
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// src/domains/share/manifest.ts
|
|
524
|
+
var ShareManifest = {
|
|
525
|
+
name: "share",
|
|
526
|
+
dependsOn: ["config", "extensions", "resources"]
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
// src/domains/share/index.ts
|
|
530
|
+
var ShareDomainModule = {
|
|
531
|
+
manifest: ShareManifest,
|
|
532
|
+
createExtension: createShareBundle
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
export {
|
|
536
|
+
writeShareArchive,
|
|
537
|
+
planShareImport,
|
|
538
|
+
importShareArchive,
|
|
539
|
+
ShareDomainModule
|
|
540
|
+
};
|
|
541
|
+
//# sourceMappingURL=chunk-AMFR5YA3.js.map
|