@offworld/sdk 0.2.2 → 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.
@@ -0,0 +1,69 @@
1
+ import { $ as AuthData, $t as getMetaRoot, A as pruneRepos, At as updateRepo, B as resolveFromNpm, Bt as removeGlobalMapEntry, C as RepoStatusOptions, Ct as getCommitDistance, D as discoverRepos, Dt as listRepos, E as UpdateAllResult, Et as isShallowClone, F as matchDependenciesToReferences, Ft as getMapEntry, G as AgentConfig, Gt as PathNotFoundError, H as ManifestType, Ht as writeGlobalMap, I as matchDependenciesToReferencesWithRemoteCheck, It as getProjectMapPath, J as getAgentConfig, Jt as parseRepoInput, K as agents, Kt as RepoSourceError, L as FALLBACK_MAPPINGS, Lt as resolveRepoKey, M as ReferenceMatch, Mt as MapEntry, N as ReferenceStatus, Nt as SearchMapOptions, O as gcRepos, Ot as removeRepo, P as isReferenceInstalled, Pt as SearchResult, Q as installReference, Qt as getMetaPath, R as ResolvedDep, Rt as searchMap, S as PruneResult, St as getClonedRepoPath, T as UpdateAllOptions, Tt as isRepoCloned, U as detectManifestType, Ut as writeProjectMap, V as Dependency, Vt as upsertGlobalMapEntry, W as parseDependencies, Wt as NotGitRepoError, X as InstallReferenceMeta, Xt as expandTilde, Y as getAllAgentConfigs, Yt as Paths, Z as installGlobalSkill, Zt as getConfigPath, _ as DiscoverOptions, _t as RepoExistsError, a as GlobalMap, an as toMetaDirName, at as getAuthPath, b as GcResult, bt as UpdateResult, c as ProjectMapRepoEntry, cn as DEFAULT_IGNORE_PATTERNS, ct as getTokenOrNull, d as ProviderInfo, dt as refreshAccessToken, en as getReferencePath, et as AuthError, f as ProviderWithModels, ft as saveAuthData, g as validateProviderModel, gt as RemoveOptions, h as listProvidersWithModels, ht as GitError, i as FileRole, in as saveConfig, it as clearAuthData, j as updateAllRepos, jt as GetMapEntryOptions, k as getRepoStatus, kt as unshallowRepo, l as RepoSource, ln as VERSION, lt as isLoggedIn, m as listProviders, mt as CloneOptions, n as FileIndex, nn as getRepoRoot, nt as NotLoggedInError, o as GlobalMapRepoEntry, on as toReferenceFileName, ot as getAuthStatus, p as getProvider, pt as CloneError, q as detectInstalledAgents, qt as getReferenceFileNameForSource, r as FileIndexEntry, rn as loadConfig, rt as TokenExpiredError, s as ProjectMap, sn as toReferenceName, st as getToken, t as Config, tn as getRepoPath, tt as AuthStatus, u as ModelInfo, ut as loadAuthData, v as DiscoverResult, vt as RepoNotFoundError, w as RepoStatusSummary, wt as getCommitSha, x as PruneOptions, xt as cloneRepo, y as GcOptions, yt as UpdateOptions, z as resolveDependencyRepo, zt as readGlobalMap } from "./public-MYVLaKUi.mjs";
2
+
3
+ //#region src/agents-md.d.ts
4
+ /**
5
+ * AGENTS.md manipulation utilities
6
+ *
7
+ * Manages updating project AGENTS.md and agent-specific files with reference information.
8
+ */
9
+ interface InstalledReference {
10
+ /** Dependency name */
11
+ dependency: string;
12
+ /** Reference identifier (matches reference file name without .md) */
13
+ reference: string;
14
+ /** Absolute path to reference file */
15
+ path: string;
16
+ }
17
+ /**
18
+ * Update or append Project References section in a markdown file.
19
+ * If the section exists, replaces its content. Otherwise, appends to end.
20
+ *
21
+ * @param filePath - Path to markdown file
22
+ * @param references - Array of installed references
23
+ */
24
+ declare function appendReferencesSection(filePath: string, references: InstalledReference[]): void;
25
+ /**
26
+ * Update AGENTS.md and agent-specific files with project references.
27
+ * Creates files if they don't exist.
28
+ *
29
+ * @param projectRoot - Project root directory
30
+ * @param references - Array of installed references to document
31
+ */
32
+ declare function updateAgentFiles(projectRoot: string, references: InstalledReference[]): void;
33
+ //#endregion
34
+ //#region src/installation.d.ts
35
+ /**
36
+ * Installation utilities for upgrade/uninstall commands
37
+ */
38
+ type InstallMethod = "curl" | "npm" | "pnpm" | "bun" | "brew" | "unknown";
39
+ /**
40
+ * Detect how offworld was installed
41
+ */
42
+ declare function detectInstallMethod(): InstallMethod;
43
+ /**
44
+ * Get current installed version
45
+ */
46
+ declare function getCurrentVersion(): string;
47
+ /**
48
+ * Fetch latest version from appropriate source
49
+ */
50
+ declare function fetchLatestVersion(method?: InstallMethod): Promise<string | null>;
51
+ /**
52
+ * Execute upgrade for given method
53
+ */
54
+ declare function executeUpgrade(method: InstallMethod, version: string): Promise<void>;
55
+ /**
56
+ * Execute uninstall for given method
57
+ */
58
+ declare function executeUninstall(method: InstallMethod): Promise<void>;
59
+ /**
60
+ * Get shell config files to clean
61
+ */
62
+ declare function getShellConfigFiles(): string[];
63
+ /**
64
+ * Clean PATH entries from shell config
65
+ */
66
+ declare function cleanShellConfig(filePath: string): boolean;
67
+ //#endregion
68
+ export { AgentConfig, AuthData, AuthError, AuthStatus, CloneError, CloneOptions, Config, DEFAULT_IGNORE_PATTERNS, Dependency, DiscoverOptions, DiscoverResult, FALLBACK_MAPPINGS, FileIndex, FileIndexEntry, FileRole, GcOptions, GcResult, GetMapEntryOptions, GitError, GlobalMap, GlobalMapRepoEntry, type InstallMethod, InstallReferenceMeta, type InstalledReference, ManifestType, MapEntry, ModelInfo, NotGitRepoError, NotLoggedInError, PathNotFoundError, Paths, ProjectMap, ProjectMapRepoEntry, ProviderInfo, ProviderWithModels, PruneOptions, PruneResult, ReferenceMatch, ReferenceStatus, RemoveOptions, RepoExistsError, RepoNotFoundError, RepoSource, RepoSourceError, RepoStatusOptions, RepoStatusSummary, ResolvedDep, SearchMapOptions, SearchResult, TokenExpiredError, UpdateAllOptions, UpdateAllResult, UpdateOptions, UpdateResult, VERSION, agents, appendReferencesSection, cleanShellConfig, clearAuthData, cloneRepo, detectInstallMethod, detectInstalledAgents, detectManifestType, discoverRepos, executeUninstall, executeUpgrade, expandTilde, fetchLatestVersion, gcRepos, getAgentConfig, getAllAgentConfigs, getAuthPath, getAuthStatus, getClonedRepoPath, getCommitDistance, getCommitSha, getConfigPath, getCurrentVersion, getMapEntry, getMetaPath, getMetaRoot, getProjectMapPath, getProvider, getReferenceFileNameForSource, getReferencePath, getRepoPath, getRepoRoot, getRepoStatus, getShellConfigFiles, getToken, getTokenOrNull, installGlobalSkill, installReference, isLoggedIn, isReferenceInstalled, isRepoCloned, isShallowClone, listProviders, listProvidersWithModels, listRepos, loadAuthData, loadConfig, matchDependenciesToReferences, matchDependenciesToReferencesWithRemoteCheck, parseDependencies, parseRepoInput, pruneRepos, readGlobalMap, refreshAccessToken, removeGlobalMapEntry, removeRepo, resolveDependencyRepo, resolveFromNpm, resolveRepoKey, saveAuthData, saveConfig, searchMap, toMetaDirName, toReferenceFileName, toReferenceName, unshallowRepo, updateAgentFiles, updateAllRepos, updateRepo, upsertGlobalMapEntry, validateProviderModel, writeGlobalMap, writeProjectMap };
69
+ //# sourceMappingURL=internal.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal.d.mts","names":[],"sources":["../src/agents-md.ts","../src/installation.ts"],"mappings":";;;;;;AASA;;UAAiB,kBAAA;EAAkB;EAElC,UAAA;EAEA;EAAA,SAAA;EAEI;EAAJ,IAAA;AAAA;;;;;;;;iBAsCe,uBAAA,CAAwB,QAAA,UAAkB,UAAA,EAAY,kBAAA;AAwBtE;;;;;;;AAAA,iBAAgB,gBAAA,CAAiB,WAAA,UAAqB,UAAA,EAAY,kBAAA;;;;;;KC/DtD,aAAA;;;;iBAKI,mBAAA,CAAA,GAAuB,aAAA;;;;iBAuFvB,iBAAA,CAAA;ADrDhB;;;AAAA,iBC4DsB,kBAAA,CAAmB,MAAA,GAAS,aAAA,GAAgB,OAAA;;;;iBAkClD,cAAA,CAAe,MAAA,EAAQ,aAAA,EAAe,OAAA,WAAkB,OAAA;;ADtExE;;iBCiHgB,gBAAA,CAAiB,MAAA,EAAQ,aAAA,GAAgB,OAAA;;;;iBAkDzC,mBAAA,CAAA;;;;iBA0BA,gBAAA,CAAiB,QAAA"}
@@ -0,0 +1,326 @@
1
+ import { A as getToken, B as NotGitRepoError, C as getAllAgentConfigs, D as clearAuthData, E as TokenExpiredError, F as saveAuthData, G as DEFAULT_IGNORE_PATTERNS, H as RepoSourceError, I as getMapEntry, K as VERSION, L as getProjectMapPath, M as isLoggedIn, N as loadAuthData, O as getAuthPath, P as refreshAccessToken, R as resolveRepoKey, S as getAgentConfig, T as NotLoggedInError, U as getReferenceFileNameForSource, V as PathNotFoundError, W as parseRepoInput, _ as parseDependencies, a as discoverRepos, b as agents, c as pruneRepos, d as matchDependenciesToReferences, f as matchDependenciesToReferencesWithRemoteCheck, g as detectManifestType, h as resolveFromNpm, i as validateProviderModel, j as getTokenOrNull, k as getAuthStatus, l as updateAllRepos, m as resolveDependencyRepo, n as listProviders, o as gcRepos, p as FALLBACK_MAPPINGS, r as listProvidersWithModels, s as getRepoStatus, t as getProvider, u as isReferenceInstalled, v as installGlobalSkill, w as AuthError, x as detectInstalledAgents, y as installReference, z as searchMap } from "./public-DbZeh2Mr.mjs";
2
+ import { a as getRepoPath, c as saveConfig, d as toReferenceName, f as Paths, i as getReferencePath, l as toMetaDirName, n as getMetaPath, o as getRepoRoot, p as expandTilde, r as getMetaRoot, s as loadConfig, t as getConfigPath, u as toReferenceFileName } from "./config-DW8J4gl5.mjs";
3
+ import { _ as upsertGlobalMapEntry, a as cloneRepo, c as getCommitSha, d as listRepos, f as removeRepo, g as removeGlobalMapEntry, h as readGlobalMap, i as RepoNotFoundError, l as isRepoCloned, m as updateRepo, n as GitError, o as getClonedRepoPath, p as unshallowRepo, r as RepoExistsError, s as getCommitDistance, t as CloneError, u as isShallowClone, v as writeGlobalMap, y as writeProjectMap } from "./clone-DyLvmbJZ.mjs";
4
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
5
+ import { join } from "node:path";
6
+ import { NpmPackageResponseSchema } from "@offworld/types";
7
+ import { homedir } from "node:os";
8
+ import { execSync, spawn } from "node:child_process";
9
+
10
+ //#region src/agents-md.ts
11
+ /**
12
+ * AGENTS.md manipulation utilities
13
+ *
14
+ * Manages updating project AGENTS.md and agent-specific files with reference information.
15
+ */
16
+ /**
17
+ * Generate markdown table for project references section.
18
+ *
19
+ * @param references - Array of installed references
20
+ * @returns Markdown string with table
21
+ */
22
+ function generateReferencesTable(references) {
23
+ const lines = [
24
+ "## Project References",
25
+ "",
26
+ "References installed for this project's dependencies:",
27
+ "",
28
+ "| Dependency | Reference | Path |",
29
+ "| --- | --- | --- |"
30
+ ];
31
+ for (const reference of references) lines.push(`| ${reference.dependency} | ${reference.reference} | ${reference.path} |`);
32
+ lines.push("");
33
+ lines.push("To update references: `ow pull <dependency>`");
34
+ lines.push("To regenerate all: `ow project init --all --generate`");
35
+ lines.push("");
36
+ return lines.join("\n");
37
+ }
38
+ /**
39
+ * Update or append Project References section in a markdown file.
40
+ * If the section exists, replaces its content. Otherwise, appends to end.
41
+ *
42
+ * @param filePath - Path to markdown file
43
+ * @param references - Array of installed references
44
+ */
45
+ function appendReferencesSection(filePath, references) {
46
+ const content = existsSync(filePath) ? readFileSync(filePath, "utf-8") : "";
47
+ const referencesMarkdown = generateReferencesTable(references);
48
+ const sectionRegex = /^## Project References\n(?:.*\n)*?(?=^## |$)/m;
49
+ const match = content.match(sectionRegex);
50
+ let updatedContent;
51
+ if (match) updatedContent = content.replace(sectionRegex, referencesMarkdown);
52
+ else updatedContent = content.trim() + "\n\n" + referencesMarkdown;
53
+ writeFileSync(filePath, updatedContent, "utf-8");
54
+ }
55
+ /**
56
+ * Update AGENTS.md and agent-specific files with project references.
57
+ * Creates files if they don't exist.
58
+ *
59
+ * @param projectRoot - Project root directory
60
+ * @param references - Array of installed references to document
61
+ */
62
+ function updateAgentFiles(projectRoot, references) {
63
+ const agentsMdPath = join(projectRoot, "AGENTS.md");
64
+ const claudeMdPath = join(projectRoot, "CLAUDE.md");
65
+ appendReferencesSection(agentsMdPath, references);
66
+ if (existsSync(claudeMdPath)) appendReferencesSection(claudeMdPath, references);
67
+ }
68
+
69
+ //#endregion
70
+ //#region src/installation.ts
71
+ /**
72
+ * Installation utilities for upgrade/uninstall commands
73
+ */
74
+ const GITHUB_REPO = "oscabriel/offworld";
75
+ const NPM_PACKAGE = "offworld";
76
+ /**
77
+ * Detect how offworld was installed
78
+ */
79
+ function detectInstallMethod() {
80
+ const execPath = process.execPath;
81
+ if (execPath.includes(".local/bin")) return "curl";
82
+ const checks = [
83
+ {
84
+ name: "npm",
85
+ test: () => {
86
+ try {
87
+ return execSync("npm list -g --depth=0 2>/dev/null", { encoding: "utf-8" }).includes(NPM_PACKAGE);
88
+ } catch {
89
+ return false;
90
+ }
91
+ }
92
+ },
93
+ {
94
+ name: "pnpm",
95
+ test: () => {
96
+ try {
97
+ return execSync("pnpm list -g --depth=0 2>/dev/null", { encoding: "utf-8" }).includes(NPM_PACKAGE);
98
+ } catch {
99
+ return false;
100
+ }
101
+ }
102
+ },
103
+ {
104
+ name: "bun",
105
+ test: () => {
106
+ try {
107
+ return execSync("bun pm ls -g 2>/dev/null", { encoding: "utf-8" }).includes(NPM_PACKAGE);
108
+ } catch {
109
+ return false;
110
+ }
111
+ }
112
+ },
113
+ {
114
+ name: "brew",
115
+ test: () => {
116
+ try {
117
+ execSync("brew list --formula offworld 2>/dev/null", { encoding: "utf-8" });
118
+ return true;
119
+ } catch {
120
+ return false;
121
+ }
122
+ }
123
+ }
124
+ ];
125
+ if (execPath.includes("npm")) {
126
+ if (checks.find((c) => c.name === "npm")?.test()) return "npm";
127
+ }
128
+ if (execPath.includes("pnpm")) {
129
+ if (checks.find((c) => c.name === "pnpm")?.test()) return "pnpm";
130
+ }
131
+ if (execPath.includes("bun")) {
132
+ if (checks.find((c) => c.name === "bun")?.test()) return "bun";
133
+ }
134
+ if (execPath.includes("Cellar") || execPath.includes("homebrew")) {
135
+ if (checks.find((c) => c.name === "brew")?.test()) return "brew";
136
+ }
137
+ for (const check of checks) if (check.test()) return check.name;
138
+ return "unknown";
139
+ }
140
+ /**
141
+ * Get current installed version
142
+ */
143
+ function getCurrentVersion() {
144
+ return VERSION;
145
+ }
146
+ /**
147
+ * Fetch latest version from appropriate source
148
+ */
149
+ async function fetchLatestVersion(method) {
150
+ const installMethod = method ?? detectInstallMethod();
151
+ try {
152
+ if (installMethod === "npm" || installMethod === "pnpm" || installMethod === "bun") {
153
+ const response = await fetch(`https://registry.npmjs.org/${NPM_PACKAGE}/latest`);
154
+ if (!response.ok) return null;
155
+ const json = await response.json();
156
+ const result = NpmPackageResponseSchema.safeParse(json);
157
+ if (!result.success) return null;
158
+ return result.data.version ?? null;
159
+ }
160
+ const response = await fetch(`https://api.github.com/repos/${GITHUB_REPO}/releases/latest`, { headers: {
161
+ Accept: "application/vnd.github.v3+json",
162
+ "User-Agent": "offworld-cli"
163
+ } });
164
+ if (!response.ok) return null;
165
+ const json = await response.json();
166
+ return (typeof json === "object" && json !== null && "tag_name" in json ? String(json.tag_name) : null)?.replace(/^v/, "") ?? null;
167
+ } catch {
168
+ return null;
169
+ }
170
+ }
171
+ /**
172
+ * Execute upgrade for given method
173
+ */
174
+ function executeUpgrade(method, version) {
175
+ return new Promise((resolve, reject) => {
176
+ let cmd;
177
+ let args;
178
+ switch (method) {
179
+ case "curl":
180
+ cmd = "bash";
181
+ args = ["-c", `curl -fsSL https://offworld.sh/install | VERSION=${version} bash`];
182
+ break;
183
+ case "npm":
184
+ cmd = "npm";
185
+ args = [
186
+ "install",
187
+ "-g",
188
+ `${NPM_PACKAGE}@${version}`
189
+ ];
190
+ break;
191
+ case "pnpm":
192
+ cmd = "pnpm";
193
+ args = [
194
+ "install",
195
+ "-g",
196
+ `${NPM_PACKAGE}@${version}`
197
+ ];
198
+ break;
199
+ case "bun":
200
+ cmd = "bun";
201
+ args = [
202
+ "install",
203
+ "-g",
204
+ `${NPM_PACKAGE}@${version}`
205
+ ];
206
+ break;
207
+ case "brew":
208
+ cmd = "brew";
209
+ args = ["upgrade", "offworld"];
210
+ break;
211
+ default:
212
+ reject(/* @__PURE__ */ new Error(`Cannot upgrade: unknown installation method`));
213
+ return;
214
+ }
215
+ const proc = spawn(cmd, args, { stdio: "inherit" });
216
+ proc.on("close", (code) => {
217
+ if (code === 0) resolve();
218
+ else reject(/* @__PURE__ */ new Error(`Upgrade failed with exit code ${code}`));
219
+ });
220
+ proc.on("error", reject);
221
+ });
222
+ }
223
+ /**
224
+ * Execute uninstall for given method
225
+ */
226
+ function executeUninstall(method) {
227
+ return new Promise((resolve, reject) => {
228
+ let cmd;
229
+ let args;
230
+ switch (method) {
231
+ case "curl":
232
+ try {
233
+ const binPath = join(homedir(), ".local", "bin", "ow");
234
+ if (existsSync(binPath)) execSync(`rm -f "${binPath}"`, { stdio: "inherit" });
235
+ resolve();
236
+ } catch (err) {
237
+ reject(err);
238
+ }
239
+ return;
240
+ case "npm":
241
+ cmd = "npm";
242
+ args = [
243
+ "uninstall",
244
+ "-g",
245
+ NPM_PACKAGE
246
+ ];
247
+ break;
248
+ case "pnpm":
249
+ cmd = "pnpm";
250
+ args = [
251
+ "uninstall",
252
+ "-g",
253
+ NPM_PACKAGE
254
+ ];
255
+ break;
256
+ case "bun":
257
+ cmd = "bun";
258
+ args = [
259
+ "remove",
260
+ "-g",
261
+ NPM_PACKAGE
262
+ ];
263
+ break;
264
+ case "brew":
265
+ cmd = "brew";
266
+ args = ["uninstall", "offworld"];
267
+ break;
268
+ default:
269
+ reject(/* @__PURE__ */ new Error(`Cannot uninstall: unknown installation method`));
270
+ return;
271
+ }
272
+ const proc = spawn(cmd, args, { stdio: "inherit" });
273
+ proc.on("close", (code) => {
274
+ if (code === 0) resolve();
275
+ else reject(/* @__PURE__ */ new Error(`Uninstall failed with exit code ${code}`));
276
+ });
277
+ proc.on("error", reject);
278
+ });
279
+ }
280
+ /**
281
+ * Get shell config files to clean
282
+ */
283
+ function getShellConfigFiles() {
284
+ const home = homedir();
285
+ const configs = [];
286
+ for (const file of [
287
+ ".bashrc",
288
+ ".bash_profile",
289
+ ".profile",
290
+ ".zshrc",
291
+ ".zshenv",
292
+ ".config/fish/config.fish"
293
+ ]) {
294
+ const path = join(home, file);
295
+ if (existsSync(path)) configs.push(path);
296
+ }
297
+ return configs;
298
+ }
299
+ /**
300
+ * Clean PATH entries from shell config
301
+ */
302
+ function cleanShellConfig(filePath) {
303
+ try {
304
+ const lines = readFileSync(filePath, "utf-8").split("\n");
305
+ const filtered = [];
306
+ let modified = false;
307
+ for (const line of lines) {
308
+ const trimmed = line.trim();
309
+ if (trimmed.includes(".local/bin") && (trimmed.startsWith("export PATH=") || trimmed.startsWith("fish_add_path"))) {
310
+ if (trimmed.includes("# offworld") || trimmed === "export PATH=\"$HOME/.local/bin:$PATH\"") {
311
+ modified = true;
312
+ continue;
313
+ }
314
+ }
315
+ filtered.push(line);
316
+ }
317
+ if (modified) writeFileSync(filePath, filtered.join("\n"), "utf-8");
318
+ return modified;
319
+ } catch {
320
+ return false;
321
+ }
322
+ }
323
+
324
+ //#endregion
325
+ export { AuthError, CloneError, DEFAULT_IGNORE_PATTERNS, FALLBACK_MAPPINGS, GitError, NotGitRepoError, NotLoggedInError, PathNotFoundError, Paths, RepoExistsError, RepoNotFoundError, RepoSourceError, TokenExpiredError, VERSION, agents, appendReferencesSection, cleanShellConfig, clearAuthData, cloneRepo, detectInstallMethod, detectInstalledAgents, detectManifestType, discoverRepos, executeUninstall, executeUpgrade, expandTilde, fetchLatestVersion, gcRepos, getAgentConfig, getAllAgentConfigs, getAuthPath, getAuthStatus, getClonedRepoPath, getCommitDistance, getCommitSha, getConfigPath, getCurrentVersion, getMapEntry, getMetaPath, getMetaRoot, getProjectMapPath, getProvider, getReferenceFileNameForSource, getReferencePath, getRepoPath, getRepoRoot, getRepoStatus, getShellConfigFiles, getToken, getTokenOrNull, installGlobalSkill, installReference, isLoggedIn, isReferenceInstalled, isRepoCloned, isShallowClone, listProviders, listProvidersWithModels, listRepos, loadAuthData, loadConfig, matchDependenciesToReferences, matchDependenciesToReferencesWithRemoteCheck, parseDependencies, parseRepoInput, pruneRepos, readGlobalMap, refreshAccessToken, removeGlobalMapEntry, removeRepo, resolveDependencyRepo, resolveFromNpm, resolveRepoKey, saveAuthData, saveConfig, searchMap, toMetaDirName, toReferenceFileName, toReferenceName, unshallowRepo, updateAgentFiles, updateAllRepos, updateRepo, upsertGlobalMapEntry, validateProviderModel, writeGlobalMap, writeProjectMap };
326
+ //# sourceMappingURL=internal.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal.mjs","names":[],"sources":["../src/agents-md.ts","../src/installation.ts"],"sourcesContent":["/**\n * AGENTS.md manipulation utilities\n *\n * Manages updating project AGENTS.md and agent-specific files with reference information.\n */\n\nimport { readFileSync, writeFileSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport interface InstalledReference {\n\t/** Dependency name */\n\tdependency: string;\n\t/** Reference identifier (matches reference file name without .md) */\n\treference: string;\n\t/** Absolute path to reference file */\n\tpath: string;\n}\n\n/**\n * Generate markdown table for project references section.\n *\n * @param references - Array of installed references\n * @returns Markdown string with table\n */\nfunction generateReferencesTable(references: InstalledReference[]): string {\n\tconst lines = [\n\t\t\"## Project References\",\n\t\t\"\",\n\t\t\"References installed for this project's dependencies:\",\n\t\t\"\",\n\t\t\"| Dependency | Reference | Path |\",\n\t\t\"| --- | --- | --- |\",\n\t];\n\n\tfor (const reference of references) {\n\t\tlines.push(`| ${reference.dependency} | ${reference.reference} | ${reference.path} |`);\n\t}\n\n\tlines.push(\"\");\n\tlines.push(\"To update references: `ow pull <dependency>`\");\n\tlines.push(\"To regenerate all: `ow project init --all --generate`\");\n\tlines.push(\"\");\n\n\treturn lines.join(\"\\n\");\n}\n\n/**\n * Update or append Project References section in a markdown file.\n * If the section exists, replaces its content. Otherwise, appends to end.\n *\n * @param filePath - Path to markdown file\n * @param references - Array of installed references\n */\nexport function appendReferencesSection(filePath: string, references: InstalledReference[]): void {\n\tconst content = existsSync(filePath) ? readFileSync(filePath, \"utf-8\") : \"\";\n\tconst referencesMarkdown = generateReferencesTable(references);\n\n\tconst sectionRegex = /^## Project References\\n(?:.*\\n)*?(?=^## |$)/m;\n\tconst match = content.match(sectionRegex);\n\n\tlet updatedContent: string;\n\tif (match) {\n\t\tupdatedContent = content.replace(sectionRegex, referencesMarkdown);\n\t} else {\n\t\tupdatedContent = content.trim() + \"\\n\\n\" + referencesMarkdown;\n\t}\n\n\twriteFileSync(filePath, updatedContent, \"utf-8\");\n}\n\n/**\n * Update AGENTS.md and agent-specific files with project references.\n * Creates files if they don't exist.\n *\n * @param projectRoot - Project root directory\n * @param references - Array of installed references to document\n */\nexport function updateAgentFiles(projectRoot: string, references: InstalledReference[]): void {\n\tconst agentsMdPath = join(projectRoot, \"AGENTS.md\");\n\tconst claudeMdPath = join(projectRoot, \"CLAUDE.md\");\n\n\tappendReferencesSection(agentsMdPath, references);\n\n\tif (existsSync(claudeMdPath)) {\n\t\tappendReferencesSection(claudeMdPath, references);\n\t}\n}\n","/**\n * Installation utilities for upgrade/uninstall commands\n */\n\nimport { execSync, spawn } from \"node:child_process\";\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { NpmPackageResponseSchema } from \"@offworld/types\";\nimport { VERSION } from \"./constants.js\";\n\nconst GITHUB_REPO = \"oscabriel/offworld\";\nconst NPM_PACKAGE = \"offworld\";\n\nexport type InstallMethod = \"curl\" | \"npm\" | \"pnpm\" | \"bun\" | \"brew\" | \"unknown\";\n\n/**\n * Detect how offworld was installed\n */\nexport function detectInstallMethod(): InstallMethod {\n\tconst execPath = process.execPath;\n\n\tif (execPath.includes(\".local/bin\")) return \"curl\";\n\n\tconst checks: Array<{ name: InstallMethod; test: () => boolean }> = [\n\t\t{\n\t\t\tname: \"npm\",\n\t\t\ttest: () => {\n\t\t\t\ttry {\n\t\t\t\t\tconst result = execSync(\"npm list -g --depth=0 2>/dev/null\", {\n\t\t\t\t\t\tencoding: \"utf-8\",\n\t\t\t\t\t});\n\t\t\t\t\treturn result.includes(NPM_PACKAGE);\n\t\t\t\t} catch {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"pnpm\",\n\t\t\ttest: () => {\n\t\t\t\ttry {\n\t\t\t\t\tconst result = execSync(\"pnpm list -g --depth=0 2>/dev/null\", {\n\t\t\t\t\t\tencoding: \"utf-8\",\n\t\t\t\t\t});\n\t\t\t\t\treturn result.includes(NPM_PACKAGE);\n\t\t\t\t} catch {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"bun\",\n\t\t\ttest: () => {\n\t\t\t\ttry {\n\t\t\t\t\tconst result = execSync(\"bun pm ls -g 2>/dev/null\", {\n\t\t\t\t\t\tencoding: \"utf-8\",\n\t\t\t\t\t});\n\t\t\t\t\treturn result.includes(NPM_PACKAGE);\n\t\t\t\t} catch {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"brew\",\n\t\t\ttest: () => {\n\t\t\t\ttry {\n\t\t\t\t\texecSync(\"brew list --formula offworld 2>/dev/null\", {\n\t\t\t\t\t\tencoding: \"utf-8\",\n\t\t\t\t\t});\n\t\t\t\t\treturn true;\n\t\t\t\t} catch {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t];\n\n\tif (execPath.includes(\"npm\")) {\n\t\tconst check = checks.find((c) => c.name === \"npm\");\n\t\tif (check?.test()) return \"npm\";\n\t}\n\tif (execPath.includes(\"pnpm\")) {\n\t\tconst check = checks.find((c) => c.name === \"pnpm\");\n\t\tif (check?.test()) return \"pnpm\";\n\t}\n\tif (execPath.includes(\"bun\")) {\n\t\tconst check = checks.find((c) => c.name === \"bun\");\n\t\tif (check?.test()) return \"bun\";\n\t}\n\tif (execPath.includes(\"Cellar\") || execPath.includes(\"homebrew\")) {\n\t\tconst check = checks.find((c) => c.name === \"brew\");\n\t\tif (check?.test()) return \"brew\";\n\t}\n\n\tfor (const check of checks) {\n\t\tif (check.test()) return check.name;\n\t}\n\n\treturn \"unknown\";\n}\n\n/**\n * Get current installed version\n */\nexport function getCurrentVersion(): string {\n\treturn VERSION;\n}\n\n/**\n * Fetch latest version from appropriate source\n */\nexport async function fetchLatestVersion(method?: InstallMethod): Promise<string | null> {\n\tconst installMethod = method ?? detectInstallMethod();\n\n\ttry {\n\t\tif (installMethod === \"npm\" || installMethod === \"pnpm\" || installMethod === \"bun\") {\n\t\t\tconst response = await fetch(`https://registry.npmjs.org/${NPM_PACKAGE}/latest`);\n\t\t\tif (!response.ok) return null;\n\t\t\tconst json = await response.json();\n\t\t\tconst result = NpmPackageResponseSchema.safeParse(json);\n\t\t\tif (!result.success) return null;\n\t\t\treturn result.data.version ?? null;\n\t\t}\n\n\t\tconst response = await fetch(`https://api.github.com/repos/${GITHUB_REPO}/releases/latest`, {\n\t\t\theaders: {\n\t\t\t\tAccept: \"application/vnd.github.v3+json\",\n\t\t\t\t\"User-Agent\": \"offworld-cli\",\n\t\t\t},\n\t\t});\n\t\tif (!response.ok) return null;\n\t\tconst json = await response.json();\n\t\tconst tagName =\n\t\t\ttypeof json === \"object\" && json !== null && \"tag_name\" in json\n\t\t\t\t? String(json.tag_name)\n\t\t\t\t: null;\n\t\treturn tagName?.replace(/^v/, \"\") ?? null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Execute upgrade for given method\n */\nexport function executeUpgrade(method: InstallMethod, version: string): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tlet cmd: string;\n\t\tlet args: string[];\n\n\t\tswitch (method) {\n\t\t\tcase \"curl\":\n\t\t\t\tcmd = \"bash\";\n\t\t\t\targs = [\"-c\", `curl -fsSL https://offworld.sh/install | VERSION=${version} bash`];\n\t\t\t\tbreak;\n\t\t\tcase \"npm\":\n\t\t\t\tcmd = \"npm\";\n\t\t\t\targs = [\"install\", \"-g\", `${NPM_PACKAGE}@${version}`];\n\t\t\t\tbreak;\n\t\t\tcase \"pnpm\":\n\t\t\t\tcmd = \"pnpm\";\n\t\t\t\targs = [\"install\", \"-g\", `${NPM_PACKAGE}@${version}`];\n\t\t\t\tbreak;\n\t\t\tcase \"bun\":\n\t\t\t\tcmd = \"bun\";\n\t\t\t\targs = [\"install\", \"-g\", `${NPM_PACKAGE}@${version}`];\n\t\t\t\tbreak;\n\t\t\tcase \"brew\":\n\t\t\t\tcmd = \"brew\";\n\t\t\t\targs = [\"upgrade\", \"offworld\"];\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\treject(new Error(`Cannot upgrade: unknown installation method`));\n\t\t\t\treturn;\n\t\t}\n\n\t\tconst proc = spawn(cmd, args, { stdio: \"inherit\" });\n\t\tproc.on(\"close\", (code) => {\n\t\t\tif (code === 0) resolve();\n\t\t\telse reject(new Error(`Upgrade failed with exit code ${code}`));\n\t\t});\n\t\tproc.on(\"error\", reject);\n\t});\n}\n\n/**\n * Execute uninstall for given method\n */\nexport function executeUninstall(method: InstallMethod): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tlet cmd: string;\n\t\tlet args: string[];\n\n\t\tswitch (method) {\n\t\t\tcase \"curl\":\n\t\t\t\ttry {\n\t\t\t\t\tconst binPath = join(homedir(), \".local\", \"bin\", \"ow\");\n\t\t\t\t\tif (existsSync(binPath)) {\n\t\t\t\t\t\texecSync(`rm -f \"${binPath}\"`, { stdio: \"inherit\" });\n\t\t\t\t\t}\n\t\t\t\t\tresolve();\n\t\t\t\t} catch (err) {\n\t\t\t\t\treject(err);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\tcase \"npm\":\n\t\t\t\tcmd = \"npm\";\n\t\t\t\targs = [\"uninstall\", \"-g\", NPM_PACKAGE];\n\t\t\t\tbreak;\n\t\t\tcase \"pnpm\":\n\t\t\t\tcmd = \"pnpm\";\n\t\t\t\targs = [\"uninstall\", \"-g\", NPM_PACKAGE];\n\t\t\t\tbreak;\n\t\t\tcase \"bun\":\n\t\t\t\tcmd = \"bun\";\n\t\t\t\targs = [\"remove\", \"-g\", NPM_PACKAGE];\n\t\t\t\tbreak;\n\t\t\tcase \"brew\":\n\t\t\t\tcmd = \"brew\";\n\t\t\t\targs = [\"uninstall\", \"offworld\"];\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\treject(new Error(`Cannot uninstall: unknown installation method`));\n\t\t\t\treturn;\n\t\t}\n\n\t\tconst proc = spawn(cmd, args, { stdio: \"inherit\" });\n\t\tproc.on(\"close\", (code) => {\n\t\t\tif (code === 0) resolve();\n\t\t\telse reject(new Error(`Uninstall failed with exit code ${code}`));\n\t\t});\n\t\tproc.on(\"error\", reject);\n\t});\n}\n\n/**\n * Get shell config files to clean\n */\nexport function getShellConfigFiles(): string[] {\n\tconst home = homedir();\n\tconst configs: string[] = [];\n\n\tconst candidates = [\n\t\t\".bashrc\",\n\t\t\".bash_profile\",\n\t\t\".profile\",\n\t\t\".zshrc\",\n\t\t\".zshenv\",\n\t\t\".config/fish/config.fish\",\n\t];\n\n\tfor (const file of candidates) {\n\t\tconst path = join(home, file);\n\t\tif (existsSync(path)) {\n\t\t\tconfigs.push(path);\n\t\t}\n\t}\n\n\treturn configs;\n}\n\n/**\n * Clean PATH entries from shell config\n */\nexport function cleanShellConfig(filePath: string): boolean {\n\ttry {\n\t\tconst content = readFileSync(filePath, \"utf-8\");\n\t\tconst lines = content.split(\"\\n\");\n\t\tconst filtered: string[] = [];\n\t\tlet modified = false;\n\n\t\tfor (const line of lines) {\n\t\t\tconst trimmed = line.trim();\n\t\t\tif (\n\t\t\t\ttrimmed.includes(\".local/bin\") &&\n\t\t\t\t(trimmed.startsWith(\"export PATH=\") || trimmed.startsWith(\"fish_add_path\"))\n\t\t\t) {\n\t\t\t\tif (trimmed.includes(\"# offworld\") || trimmed === 'export PATH=\"$HOME/.local/bin:$PATH\"') {\n\t\t\t\t\tmodified = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfiltered.push(line);\n\t\t}\n\n\t\tif (modified) {\n\t\t\twriteFileSync(filePath, filtered.join(\"\\n\"), \"utf-8\");\n\t\t}\n\n\t\treturn modified;\n\t} catch {\n\t\treturn false;\n\t}\n}\n"],"mappings":"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"}