offworld 0.1.0 → 0.1.1

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/README.md CHANGED
@@ -1,22 +1,32 @@
1
1
  # Offworld CLI
2
2
 
3
- One skill for your whole stack.
3
+ **One skill for your whole stack.**
4
+
5
+ A single skill file and a CLI tool dedicated to empowering your agent with instant context on any open source repo.
4
6
 
5
7
  ## Installation
6
8
 
7
9
  ```bash
8
- bun add -g offworld
9
- # or
10
+ # curl (recommended)
11
+ curl -fsSL https://offworld.sh/install | bash
12
+
13
+ # npm
10
14
  npm install -g offworld
15
+
16
+ # bun
17
+ bun add -g offworld
18
+
19
+ # Homebrew
20
+ brew install oscabriel/tap/offworld
11
21
  ```
12
22
 
13
23
  ## Quick Start
14
24
 
15
25
  ```bash
16
- # Initialize config
26
+ # One-time setup
17
27
  ow init
18
28
 
19
- # Install references for project deps
29
+ # Install references for your project's dependencies
20
30
  cd your-project
21
31
  ow project init
22
32
 
@@ -31,57 +41,48 @@ ow list
31
41
 
32
42
  ### Core
33
43
 
34
- | Command | Description |
35
- | -------------------- | --------------------------------- |
36
- | `ow pull <repo>` | Clone repo and generate reference |
37
- | `ow generate <repo>` | Generate reference locally |
38
- | `ow push <repo>` | Upload reference to offworld.sh |
39
- | `ow list` | List managed repos |
40
- | `ow remove <repo>` | Remove repo and/or reference |
44
+ | Command | Description |
45
+ | --- | --- |
46
+ | `ow pull <repo>` | Clone repo and generate reference |
47
+ | `ow generate <repo>` | Generate reference locally |
48
+ | `ow push <repo>` | Upload reference to offworld.sh |
49
+ | `ow list` | List managed repos |
50
+ | `ow rm <repo>` | Remove repo and/or reference |
41
51
 
42
52
  ### Configuration
43
53
 
44
- | Command | Description |
45
- | ----------------------------- | --------------------------- |
46
- | `ow init` | Interactive setup |
47
- | `ow config show` | Show all settings |
48
- | `ow config set <key> <value>` | Set a config value |
49
- | `ow config get <key>` | Get a config value |
50
- | `ow config agents` | Select agents interactively |
54
+ | Command | Description |
55
+ | --- | --- |
56
+ | `ow init` | Interactive setup |
57
+ | `ow config show` | Show all settings |
58
+ | `ow config set <key> <value>` | Set a config value |
59
+ | `ow config get <key>` | Get a config value |
60
+ | `ow config agents` | Select agents interactively |
51
61
 
52
- ### Map / Routing
62
+ ### Project
53
63
 
54
- | Command | Description |
55
- | --------------------------- | ------------------------------- |
56
- | `ow map show <repo>` | Show repo info (path, ref, etc) |
57
- | `ow map show <repo> --ref` | Print only reference file path |
58
- | `ow map show <repo> --path` | Print only local clone path |
59
- | `ow map search <term>` | Find repos by name or keyword |
64
+ | Command | Description |
65
+ | --- | --- |
66
+ | `ow project init` | Scan deps, install references |
60
67
 
61
68
  ### Repository Management
62
69
 
63
- | Command | Description |
64
- | ---------------------- | ------------------------- |
65
- | `ow repo list` | List managed repos |
66
- | `ow repo update --all` | Update all repos |
67
- | `ow repo prune` | Remove stale map entries |
68
- | `ow repo status` | Show repo summary |
69
- | `ow repo gc` | Garbage collect old repos |
70
- | `ow repo discover` | Index existing repos |
71
-
72
- ### Project
73
-
74
- | Command | Description |
75
- | ----------------- | ----------------------------- |
76
- | `ow project init` | Scan deps, install references |
70
+ | Command | Description |
71
+ | --- | --- |
72
+ | `ow repo list` | List managed repos |
73
+ | `ow repo update --all` | Update all repos |
74
+ | `ow repo status` | Show repo summary |
75
+ | `ow repo prune` | Remove stale map entries |
76
+ | `ow repo gc` | Garbage collect old repos |
77
+ | `ow repo discover` | Index existing repos |
77
78
 
78
79
  ### Authentication
79
80
 
80
- | Command | Description |
81
- | ---------------- | -------------------- |
82
- | `ow auth login` | Login to offworld.sh |
83
- | `ow auth logout` | Logout |
84
- | `ow auth status` | Show auth status |
81
+ | Command | Description |
82
+ | --- | --- |
83
+ | `ow auth login` | Login to offworld.sh |
84
+ | `ow auth logout` | Logout |
85
+ | `ow auth status` | Show auth status |
85
86
 
86
87
  ## Options
87
88
 
@@ -105,7 +106,7 @@ ow list
105
106
  --pattern <pat> Filter by pattern
106
107
  ```
107
108
 
108
- ### `ow remove`
109
+ ### `ow rm`
109
110
 
110
111
  ```
111
112
  --yes, -y Skip confirmation
@@ -125,29 +126,14 @@ ow list
125
126
  --yes, -y Skip confirmations
126
127
  ```
127
128
 
128
- ### `ow map show`
129
-
130
- ```
131
- --json Output as JSON
132
- --path Print only local clone path
133
- --ref Print only reference file path
134
- ```
135
-
136
- ### `ow map search`
137
-
138
- ```
139
- --limit, -n Max results (default 10)
140
- --json Output as JSON
141
- ```
142
-
143
129
  ## Config Keys
144
130
 
145
- | Key | Type | Description |
146
- | ---------------- | ------- | ----------------------------------------------------- |
147
- | `repoRoot` | string | Where to clone repos (default: `~/ow`) |
148
- | `defaultShallow` | boolean | Use shallow clone by default |
149
- | `defaultModel` | string | AI model (e.g., `anthropic/claude-sonnet-4-20250514`) |
150
- | `agents` | list | Comma-separated agent names |
131
+ | Key | Type | Description |
132
+ | --- | --- | --- |
133
+ | `repoRoot` | string | Where to clone repos (default: `~/ow`) |
134
+ | `defaultShallow` | boolean | Use shallow clone by default |
135
+ | `defaultModel` | string | AI model (e.g., `anthropic/claude-sonnet-4-20250514`) |
136
+ | `agents` | list | Comma-separated agent names |
151
137
 
152
138
  ## Path Discovery
153
139
 
@@ -155,12 +141,12 @@ ow list
155
141
 
156
142
  ```json
157
143
  {
158
- "paths": {
159
- "skillDir": "~/.local/share/offworld/skill/offworld",
160
- "globalMap": "~/.local/share/offworld/skill/offworld/assets/map.json",
161
- "referencesDir": "~/.local/share/offworld/skill/offworld/references",
162
- "projectMap": "/abs/path/to/repo/.offworld/map.json"
163
- }
144
+ "paths": {
145
+ "skillDir": "~/.local/share/offworld/skill/offworld",
146
+ "globalMap": "~/.local/share/offworld/skill/offworld/assets/map.json",
147
+ "referencesDir": "~/.local/share/offworld/skill/offworld/references",
148
+ "projectMap": "/abs/path/to/repo/.offworld/map.json"
149
+ }
164
150
  }
165
151
  ```
166
152
 
@@ -168,19 +154,19 @@ ow list
168
154
 
169
155
  Single skill symlinked to:
170
156
 
171
- - **OpenCode**: `~/.config/opencode/skill/`
172
- - **Claude Code**: `~/.claude/skills/`
173
- - **Codex**: `~/.codex/skills/`
174
- - **Amp**: `~/.config/agents/skills/`
175
- - **Antigravity**: `~/.gemini/antigravity/skills/`
176
- - **Cursor**: `~/.cursor/skills/`
157
+ - OpenCode (`~/.config/opencode/skill/`)
158
+ - Claude Code (`~/.claude/skills/`)
159
+ - Codex (`~/.codex/skills/`)
160
+ - Amp (`~/.config/agents/skills/`)
161
+ - Antigravity (`~/.gemini/antigravity/skills/`)
162
+ - Cursor (`~/.cursor/skills/`)
177
163
 
178
164
  ## Environment Variables
179
165
 
180
- | Variable | Description |
181
- | ------------------- | --------------------------------------- |
166
+ | Variable | Description |
167
+ | --- | --- |
182
168
  | `ANTHROPIC_API_KEY` | Required for local reference generation |
183
- | `WORKOS_CLIENT_ID` | Required for `ow auth login` |
169
+ | `WORKOS_CLIENT_ID` | Required for `ow auth login` |
184
170
 
185
171
  ## License
186
172
 
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { r as version, t as createOwCli } from "./src-CZHUGu1Q.mjs";
2
+ import { r as version, t as createOwCli } from "./src-BIbq5vJB.mjs";
3
3
  import { existsSync, readFileSync } from "node:fs";
4
4
  import { dirname, resolve } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
package/dist/index.d.mts CHANGED
@@ -4,7 +4,7 @@ import { z } from "zod";
4
4
  import * as trpc_cli_dist_json_js0 from "trpc-cli/dist/json.js";
5
5
 
6
6
  //#region src/index.d.ts
7
- declare const version = "0.1.0";
7
+ declare const version = "0.1.1";
8
8
  declare const router: {
9
9
  pull: _orpc_server0.Procedure<_orpc_server0.MergedInitialContext<Record<never, never>, Record<never, never>, Record<never, never>>, Record<never, never>, z.ZodObject<{
10
10
  repo: z.ZodString;
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { n as router, r as version, t as createOwCli } from "./src-CZHUGu1Q.mjs";
1
+ import { n as router, r as version, t as createOwCli } from "./src-BIbq5vJB.mjs";
2
2
 
3
3
  export { createOwCli, router, version };
@@ -5,6 +5,7 @@ import { createCli } from "trpc-cli";
5
5
  import { z } from "zod";
6
6
  import * as p from "@clack/prompts";
7
7
  import { AuthenticationError, CommitExistsError, CommitNotFoundError, GitHubError, InvalidInputError, InvalidReferenceError, LowStarsError, NotLoggedInError, Paths, PrivateRepoError, RateLimitError, RepoExistsError, SyncRepoNotFoundError, TokenExpiredError, checkRemote, checkRemoteByName, cleanShellConfig, clearAuthData, cloneRepo, detectInstallMethod, detectInstalledAgents, discoverRepos, executeUninstall, executeUpgrade, fetchLatestVersion, gcRepos, generateReferenceWithAI, getAllAgentConfigs, getAuthPath, getAuthStatus, getClonedRepoPath, getCommitDistance, getCommitSha, getConfigPath, getCurrentVersion, getMapEntry, getMetaPath, getMetaRoot, getProvider, getReferencePath, getRepoRoot, getRepoStatus, getShellConfigFiles, getToken, installGlobalSkill, installReference, isRepoCloned, listProviders, listRepos, loadAuthData, loadConfig, matchDependenciesToReferences, parseDependencies, parseRepoInput, pruneRepos, pullReference, pullReferenceByName, pushReference, readGlobalMap, removeRepo, resolveDependencyRepo, saveAuthData, saveConfig, searchMap, toReferenceFileName, toReferenceName, updateAgentFiles, updateAllRepos, updateRepo, validateProviderModel, writeProjectMap } from "@offworld/sdk";
8
+ import { ReferenceMetaSchema, WorkOSAuthErrorResponseSchema, WorkOSDeviceAuthResponseSchema, WorkOSTokenResponseSchema } from "@offworld/types";
8
9
  import { AgentSchema, ConfigSchema } from "@offworld/types/schemas";
9
10
  import open from "open";
10
11
  import { homedir } from "node:os";
@@ -47,7 +48,10 @@ function loadLocalMeta(source) {
47
48
  const metaPath = join(getLocalMetaDir(source), "meta.json");
48
49
  if (!existsSync(metaPath)) return null;
49
50
  try {
50
- return JSON.parse(readFileSync(metaPath, "utf-8"));
51
+ const json = JSON.parse(readFileSync(metaPath, "utf-8"));
52
+ const parsed = ReferenceMetaSchema.safeParse(json);
53
+ if (!parsed.success) return null;
54
+ return parsed.data;
51
55
  } catch {
52
56
  return null;
53
57
  }
@@ -714,7 +718,10 @@ function loadLocalReference(metaDir, referencePath, fullName) {
714
718
  if (!existsSync(referencePath) || !existsSync(metaPath)) return null;
715
719
  try {
716
720
  const referenceContent = readFileSync(referencePath, "utf-8");
717
- const meta = JSON.parse(readFileSync(metaPath, "utf-8"));
721
+ const json = JSON.parse(readFileSync(metaPath, "utf-8"));
722
+ const parsed = ReferenceMetaSchema.safeParse(json);
723
+ if (!parsed.success) return null;
724
+ const meta = parsed.data;
718
725
  return {
719
726
  fullName: "",
720
727
  referenceName: toReferenceName(fullName),
@@ -1140,17 +1147,17 @@ async function configSetHandler(options) {
1140
1147
  }
1141
1148
  else if (key === "agents") {
1142
1149
  const agentValues = value.split(",").map((a) => a.trim()).filter(Boolean);
1143
- const validAgents = AgentSchema.options;
1144
- const invalidAgents = agentValues.filter((a) => !validAgents.includes(a));
1145
- if (invalidAgents.length > 0) {
1150
+ const agentsResult = z.array(AgentSchema).safeParse(agentValues);
1151
+ if (!agentsResult.success) {
1152
+ const invalidAgents = agentValues.filter((a) => !AgentSchema.options.includes(a));
1146
1153
  p.log.error(`Invalid agent(s): ${invalidAgents.join(", ")}`);
1147
- p.log.info(`Valid agents: ${validAgents.join(", ")}`);
1154
+ p.log.info(`Valid agents: ${AgentSchema.options.join(", ")}`);
1148
1155
  return {
1149
1156
  success: false,
1150
1157
  message: `Invalid agents: ${invalidAgents.join(", ")}`
1151
1158
  };
1152
1159
  }
1153
- parsedValue = agentValues;
1160
+ parsedValue = agentsResult.data;
1154
1161
  } else parsedValue = value;
1155
1162
  try {
1156
1163
  saveConfig({ [key]: parsedValue });
@@ -1229,7 +1236,8 @@ async function configAgentsHandler() {
1229
1236
  p.log.warn("Cancelled");
1230
1237
  return { success: false };
1231
1238
  }
1232
- const agents = agentsResult;
1239
+ const parsedAgents = z.array(AgentSchema).safeParse(agentsResult);
1240
+ const agents = parsedAgents.success ? parsedAgents.data : [];
1233
1241
  try {
1234
1242
  saveConfig({ agents });
1235
1243
  p.log.success(`Agents set to: ${agents.join(", ") || "(none)"}`);
@@ -1277,7 +1285,8 @@ async function requestDeviceCode() {
1277
1285
  const error = await response.text();
1278
1286
  throw new Error(`Failed to request device code: ${error}`);
1279
1287
  }
1280
- return response.json();
1288
+ const data = await response.json();
1289
+ return WorkOSDeviceAuthResponseSchema.parse(data);
1281
1290
  }
1282
1291
  async function pollForTokens(deviceCode, interval, onStatus) {
1283
1292
  let pollInterval = interval;
@@ -1291,8 +1300,12 @@ async function pollForTokens(deviceCode, interval, onStatus) {
1291
1300
  client_id: getWorkosClientId()
1292
1301
  })
1293
1302
  });
1294
- if (response.ok) return response.json();
1295
- const data = await response.json();
1303
+ if (response.ok) {
1304
+ const data = await response.json();
1305
+ return WorkOSTokenResponseSchema.parse(data);
1306
+ }
1307
+ const errorData = await response.json();
1308
+ const data = WorkOSAuthErrorResponseSchema.parse(errorData);
1296
1309
  switch (data.error) {
1297
1310
  case "authorization_pending":
1298
1311
  onStatus?.("Waiting for approval...");
@@ -1576,7 +1589,7 @@ async function initHandler(options = {}) {
1576
1589
  configPath
1577
1590
  };
1578
1591
  }
1579
- provider = providerResult;
1592
+ provider = String(providerResult);
1580
1593
  spin.start("Fetching models...");
1581
1594
  const providerData = await getProvider(provider);
1582
1595
  spin.stop(`Loaded ${providerData?.models.length ?? 0} models`);
@@ -1607,7 +1620,7 @@ async function initHandler(options = {}) {
1607
1620
  configPath
1608
1621
  };
1609
1622
  }
1610
- model = modelResult;
1623
+ model = String(modelResult);
1611
1624
  }
1612
1625
  const detectedAgents = detectInstalledAgents();
1613
1626
  const allAgentConfigs = getAllAgentConfigs();
@@ -1624,7 +1637,8 @@ async function initHandler(options = {}) {
1624
1637
  if (options.agents) {
1625
1638
  const agentNames = options.agents.split(",").map((a) => a.trim());
1626
1639
  const validAgents = allAgentConfigs.filter((c) => agentNames.includes(c.name)).map((c) => c.name);
1627
- if (validAgents.length === 0) {
1640
+ const agentsResult = z.array(AgentSchema).safeParse(validAgents);
1641
+ if (!agentsResult.success || agentsResult.data.length === 0) {
1628
1642
  p.log.error("No valid agent names provided");
1629
1643
  p.outro("Setup failed");
1630
1644
  return {
@@ -1632,23 +1646,24 @@ async function initHandler(options = {}) {
1632
1646
  configPath
1633
1647
  };
1634
1648
  }
1635
- agents = validAgents;
1649
+ agents = agentsResult.data;
1636
1650
  } else {
1637
1651
  const initialAgents = existingConfig.agents && existingConfig.agents.length > 0 ? existingConfig.agents : detectedAgents;
1638
- const agentsResult = await p.multiselect({
1652
+ const selectResult = await p.multiselect({
1639
1653
  message: "Select agents to install skills to",
1640
1654
  options: agentOptions,
1641
1655
  initialValues: initialAgents,
1642
1656
  required: false
1643
1657
  });
1644
- if (p.isCancel(agentsResult)) {
1658
+ if (p.isCancel(selectResult)) {
1645
1659
  p.outro("Setup cancelled");
1646
1660
  return {
1647
1661
  success: false,
1648
1662
  configPath
1649
1663
  };
1650
1664
  }
1651
- agents = agentsResult;
1665
+ const agentsResult = z.array(AgentSchema).safeParse(selectResult);
1666
+ agents = agentsResult.success ? agentsResult.data : [];
1652
1667
  }
1653
1668
  const defaultModel = `${provider}/${model}`;
1654
1669
  const newConfig = {
@@ -1790,7 +1805,7 @@ async function projectInitHandler(options = {}) {
1790
1805
  message: "Cancelled by user"
1791
1806
  };
1792
1807
  }
1793
- selected = selectedResult;
1808
+ selected = Array.isArray(selectedResult) ? selectedResult : [];
1794
1809
  }
1795
1810
  if (selected.length === 0) {
1796
1811
  p.log.warn("No dependencies selected.");
@@ -2144,7 +2159,7 @@ async function mapSearchHandler(options) {
2144
2159
 
2145
2160
  //#endregion
2146
2161
  //#region src/index.ts
2147
- const version = "0.1.0";
2162
+ const version = "0.1.1";
2148
2163
  const router = os.router({
2149
2164
  pull: os.input(z.object({
2150
2165
  repo: z.string().describe("repo").meta({ positional: true }),
@@ -2444,4 +2459,4 @@ function createOwCli() {
2444
2459
 
2445
2460
  //#endregion
2446
2461
  export { router as n, version as r, createOwCli as t };
2447
- //# sourceMappingURL=src-CZHUGu1Q.mjs.map
2462
+ //# sourceMappingURL=src-BIbq5vJB.mjs.map