@skrr-ai/cli 0.1.12 → 0.1.14

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.
Files changed (57) hide show
  1. package/dist/base-command.d.ts +1 -39
  2. package/dist/base-command.js +36 -10
  3. package/dist/commands/agents/list.d.ts +10 -0
  4. package/dist/commands/agents/list.js +16 -1
  5. package/dist/commands/browser.js +5 -5
  6. package/dist/commands/commitments/create.d.ts +2 -0
  7. package/dist/commands/commitments/create.js +30 -13
  8. package/dist/commands/commitments/update.d.ts +2 -0
  9. package/dist/commands/commitments/update.js +24 -4
  10. package/dist/commands/daemon/byok.js +5 -5
  11. package/dist/commands/daemon/index.js +7 -4
  12. package/dist/commands/daemon/install.js +8 -5
  13. package/dist/commands/daemon/login.js +5 -5
  14. package/dist/commands/daemon/logs.js +5 -5
  15. package/dist/commands/daemon/restart.js +5 -5
  16. package/dist/commands/daemon/start.js +5 -5
  17. package/dist/commands/daemon/status.js +5 -5
  18. package/dist/commands/daemon/stop.js +5 -5
  19. package/dist/commands/daemon/uninstall.js +5 -5
  20. package/dist/commands/daemon/unlock.js +5 -5
  21. package/dist/commands/daemon/usage.js +6 -6
  22. package/dist/commands/login.js +7 -2
  23. package/dist/commands/spaces/list.d.ts +13 -0
  24. package/dist/commands/spaces/list.js +20 -1
  25. package/dist/commands/tasks/list.d.ts +11 -0
  26. package/dist/commands/tasks/list.js +82 -11
  27. package/dist/commands/wiki/cat.js +2 -1
  28. package/dist/commands/wiki/mv.js +5 -1
  29. package/dist/commands/wiki/write.js +5 -1
  30. package/dist/help.d.ts +20 -1
  31. package/dist/help.js +26 -1
  32. package/dist/lib/api-fetch.d.ts +2 -1
  33. package/dist/lib/api-fetch.js +9 -2
  34. package/dist/lib/commitments.d.ts +44 -0
  35. package/dist/lib/commitments.js +123 -0
  36. package/dist/lib/daemon-binding.d.ts +3 -4
  37. package/dist/lib/daemon-binding.js +11 -10
  38. package/dist/lib/daemon-handoff-opt-out.d.ts +8 -0
  39. package/dist/lib/daemon-handoff-opt-out.js +17 -0
  40. package/dist/lib/daemon-installer.d.ts +1 -1
  41. package/dist/lib/daemon-installer.js +2 -2
  42. package/dist/lib/daemon-setup.js +13 -7
  43. package/dist/lib/daemonHandoff.d.ts +1 -1
  44. package/dist/lib/daemonHandoff.js +20 -7
  45. package/dist/lib/delegated-cli.d.ts +0 -9
  46. package/dist/lib/delegated-cli.js +149 -6
  47. package/dist/lib/{exec-oversky.d.ts → exec-runtime-binary.d.ts} +15 -4
  48. package/dist/lib/{exec-oversky.js → exec-runtime-binary.js} +93 -37
  49. package/dist/lib/node-adapter.js +6 -0
  50. package/dist/lib/sky-code.d.ts +1 -1
  51. package/dist/lib/sky-code.js +1 -1
  52. package/dist/lib/usage-discovery.js +1 -1
  53. package/dist/lib/web-url.d.ts +16 -0
  54. package/dist/lib/web-url.js +25 -0
  55. package/dist/node_modules/@skrr-ai/data-provider/index.js +3931 -3884
  56. package/oclif.manifest.json +9932 -9904
  57. package/package.json +2 -2
@@ -5,12 +5,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.RUNTIME_BINARY_NAMES = void 0;
7
7
  exports.forwardedFlagsNote = forwardedFlagsNote;
8
- exports.findOverskyBinary = findOverskyBinary;
8
+ exports.findRuntimeBinary = findRuntimeBinary;
9
+ exports.isCurrentRuntimeBinary = isCurrentRuntimeBinary;
10
+ exports.normalizeRuntimeGlobalArgs = normalizeRuntimeGlobalArgs;
9
11
  exports.notInstalledMessage = notInstalledMessage;
10
- exports.execOversky = execOversky;
11
- exports.overskySupportsSubcommand = overskySupportsSubcommand;
12
+ exports.execRuntimeBinary = execRuntimeBinary;
13
+ exports.runtimeBinarySupportsSubcommand = runtimeBinarySupportsSubcommand;
12
14
  /**
13
- * exec-oversky.ts — locate and forward to the local runtime binary.
15
+ * exec-runtime-binary.ts — locate and forward to the local runtime binary.
14
16
  *
15
17
  * The `gh → git` pattern: `skrr daemon ...` is a thin proxy. `skrr` is a REST
16
18
  * client; `skrrd` is the long-running runtime. Keeping them as separate
@@ -60,9 +62,13 @@ exports.RUNTIME_BINARY_NAMES = ['skrrd', 'oversky'];
60
62
  * `description` alone.
61
63
  */
62
64
  function forwardedFlagsNote(verb, opts = {}) {
63
- const base = `Flags are forwarded to \`skrrd ${verb}\` unchanged, so they are not listed here —` +
64
- ` run \`skrrd ${verb} --help\` for this verb's own flags, or \`skrrd --help\` for` +
65
- ' global ones such as `--profile`.';
65
+ const base = opts.bootstrapsRuntime
66
+ ? `If no local runtime exists, this command first fetches the signed release. After it is ` +
67
+ `installed, flags are forwarded to \`skrrd ${verb}\` unchanged; run \`skrrd ${verb} --help\` ` +
68
+ `for this verb's own flags, or \`skrrd --help\` for global ones such as \`--profile\`.`
69
+ : `Flags are forwarded to \`skrrd ${verb}\` unchanged, so they are not listed here —` +
70
+ ` run \`skrrd ${verb} --help\` for this verb's own flags, or \`skrrd --help\` for` +
71
+ ' global ones such as `--profile`.';
66
72
  // `install` and `login` are not pure pass-throughs: they fill in the server
67
73
  // and profile from the CLI's own session when the caller named neither, so a
68
74
  // daemon cannot silently end up on a different deployment than the CLI that
@@ -72,41 +78,91 @@ function forwardedFlagsNote(verb, opts = {}) {
72
78
  ? `${base} \`--server\` and \`--profile\` are filled in from your CLI session unless you pass them.`
73
79
  : base;
74
80
  }
75
- /** Extra well-known install locations to check when PATH lookup misses. */
76
- const FALLBACK_PATHS = exports.RUNTIME_BINARY_NAMES.flatMap((name) => [
77
- `/opt/homebrew/bin/${name}`,
78
- `/usr/local/bin/${name}`,
79
- // Linux script-installer default; the daemon's install script drops here.
80
- `/usr/local/bin/${name}-daemon`,
81
- // EC2 / pm2 layout used in daemon/CLAUDE.md examples.
82
- `${process.env.HOME ?? ''}/.skrr/bin/${name}`,
83
- ]);
84
- /** Resolve the absolute path of `oversky` if it exists, else return null. */
85
- function findOverskyBinary() {
81
+ /** Extra well-known install locations for one runtime name, checked after PATH. */
82
+ function fallbackPathsForRuntime(name) {
83
+ return [
84
+ `/opt/homebrew/bin/${name}`,
85
+ `/usr/local/bin/${name}`,
86
+ // Linux script-installer default; the daemon's install script drops here.
87
+ `/usr/local/bin/${name}-daemon`,
88
+ // EC2 / pm2 layout used in daemon/CLAUDE.md examples.
89
+ `${process.env.HOME ?? ''}/.skrr/bin/${name}`,
90
+ ];
91
+ }
92
+ /** Resolve the local runtime binary — `skrrd`, or the legacy `oversky` still on older PATHs. */
93
+ function findRuntimeBinary() {
86
94
  // PATH lookup — Node 20 doesn't ship `which()` but we can mimic it.
87
95
  // On Windows, npm globals install a `.cmd` wrapper (not `.exe`) so we
88
96
  // must check both; installers that ship a native build still win
89
97
  // because `.exe` is checked first.
90
98
  const PATH = process.env.PATH ?? '';
91
99
  const sep = process.platform === 'win32' ? ';' : ':';
92
- const exeNames = process.platform === 'win32'
93
- ? exports.RUNTIME_BINARY_NAMES.flatMap((n) => [`${n}.exe`, `${n}.cmd`])
94
- : [...exports.RUNTIME_BINARY_NAMES];
95
- for (const dir of PATH.split(sep)) {
96
- if (!dir)
97
- continue;
98
- for (const exeName of exeNames) {
99
- const candidate = node_path_1.default.join(dir, exeName);
100
- if (isExecutable(candidate))
100
+ const executableNamesFor = (name) => process.platform === 'win32' ? [`${name}.exe`, `${name}.cmd`] : [name];
101
+ // Check EVERY location for the current name before falling back to the
102
+ // legacy name. The former loop was directory-first, so an `oversky` binary
103
+ // in an early PATH entry won over a current `skrrd` in a later managed
104
+ // location. That stranded onboarding on the old binary precisely when it
105
+ // needed the current runtime to bootstrap its service.
106
+ const dirs = PATH.split(sep).filter(Boolean);
107
+ for (const runtimeName of exports.RUNTIME_BINARY_NAMES) {
108
+ for (const exeName of executableNamesFor(runtimeName)) {
109
+ for (const dir of dirs) {
110
+ const candidate = node_path_1.default.join(dir, exeName);
111
+ if (isExecutable(candidate))
112
+ return candidate;
113
+ }
114
+ }
115
+ for (const candidate of fallbackPathsForRuntime(runtimeName)) {
116
+ if (candidate && isExecutable(candidate))
101
117
  return candidate;
102
118
  }
103
119
  }
104
- for (const candidate of FALLBACK_PATHS) {
105
- if (candidate && isExecutable(candidate))
106
- return candidate;
107
- }
108
120
  return null;
109
121
  }
122
+ /** Whether a resolved path names the current runtime rather than legacy oversky. */
123
+ function isCurrentRuntimeBinary(binary) {
124
+ if (!binary)
125
+ return false;
126
+ const basename = node_path_1.default.basename(binary).toLowerCase();
127
+ return process.platform === 'win32'
128
+ ? basename === 'skrrd.exe' || basename === 'skrrd.cmd'
129
+ : basename === 'skrrd';
130
+ }
131
+ /**
132
+ * Commander reads runtime global options before the subcommand. The CLI
133
+ * wrappers naturally receive pass-through flags after a verb (`install
134
+ * --profile work`), which otherwise silently resolves the runtime profile as
135
+ * default. Move a well-formed profile flag ahead of the verb without changing
136
+ * the order of any command-specific flags or `--` payload.
137
+ */
138
+ function normalizeRuntimeGlobalArgs(args) {
139
+ const rest = [];
140
+ let profile = null;
141
+ for (let index = 0; index < args.length; index += 1) {
142
+ const arg = args[index];
143
+ if (arg === '--') {
144
+ rest.push(...args.slice(index));
145
+ break;
146
+ }
147
+ if (arg === '--profile') {
148
+ const value = args[index + 1];
149
+ if (value && !value.startsWith('-')) {
150
+ profile = value;
151
+ index += 1;
152
+ continue;
153
+ }
154
+ }
155
+ if (arg.startsWith('--profile=')) {
156
+ const value = arg.slice('--profile='.length);
157
+ if (value) {
158
+ profile = value;
159
+ continue;
160
+ }
161
+ }
162
+ rest.push(arg);
163
+ }
164
+ return profile ? ['--profile', profile, ...rest] : rest;
165
+ }
110
166
  function isExecutable(p) {
111
167
  try {
112
168
  (0, node_fs_1.accessSync)(p, node_fs_1.constants.X_OK);
@@ -155,11 +211,11 @@ function notInstalledMessage() {
155
211
  * preserving "exit code = the daemon's exit code" semantics that scripts
156
212
  * may depend on.
157
213
  */
158
- function execOversky(args) {
214
+ function execRuntimeBinary(args) {
159
215
  return new Promise((resolve, reject) => {
160
- const bin = findOverskyBinary();
216
+ const bin = findRuntimeBinary();
161
217
  if (!bin) {
162
- reject(new Error('oversky-not-installed'));
218
+ reject(new Error('runtime-binary-not-installed'));
163
219
  return;
164
220
  }
165
221
  // On Windows, `.cmd` / `.bat` wrappers cannot be executed directly by
@@ -169,7 +225,7 @@ function execOversky(args) {
169
225
  // by package.json engines `>=20.0.0` — pin at install time) quotes
170
226
  // args when shell:true on Windows per CVE-2024-27980's fix.
171
227
  const isWinShim = process.platform === 'win32' && /\.(cmd|bat)$/i.test(bin);
172
- const child = (0, node_child_process_1.spawn)(bin, args, {
228
+ const child = (0, node_child_process_1.spawn)(bin, normalizeRuntimeGlobalArgs(args), {
173
229
  stdio: 'inherit',
174
230
  ...(isWinShim ? { shell: true } : {}),
175
231
  });
@@ -195,8 +251,8 @@ function execOversky(args) {
195
251
  * This invokes only `oversky --help`: it never starts, stops, configures, or
196
252
  * otherwise mutates the local daemon.
197
253
  */
198
- function overskySupportsSubcommand(subcommand) {
199
- const bin = findOverskyBinary();
254
+ function runtimeBinarySupportsSubcommand(subcommand) {
255
+ const bin = findRuntimeBinary();
200
256
  if (!bin)
201
257
  return Promise.resolve(null);
202
258
  return new Promise((resolve) => {
@@ -317,9 +317,15 @@ function createNodeAdapter(opts = {}) {
317
317
  // can contain internal stack traces we don't want to echo to
318
318
  // terminals by default.
319
319
  const text = await res.text().catch(() => '');
320
+ // `method` is attached because the 403 branch of `handleApiError` needs
321
+ // to know whether the failing request even HAD a body before it can
322
+ // advise the user to "try again with less of the request body"
323
+ // (OSK-6765): `agents show` is a GET and had no body, so the advice
324
+ // could not be followed.
320
325
  const err = new Error(`HTTP ${res.status} ${res.statusText} — ${method} ${url}`);
321
326
  err.status = res.status;
322
327
  err.body = text;
328
+ err.method = method;
323
329
  throw err;
324
330
  }
325
331
  if (options?.responseType === 'arraybuffer') {
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * WL-2.2 — locate and forward to the local `sky-code` engine.
3
3
  *
4
- * The same `gh → git` shape `exec-oversky.ts` uses, for the same reason: the
4
+ * The same `gh → git` shape `exec-runtime-binary.ts` uses, for the same reason: the
5
5
  * Sky CLI is a REST client, the engine is a separately-built, separately-
6
6
  * released binary with its own lifetime and failure model. Unifying them at
7
7
  * the command surface (`skrr code`) gives users one thing to type without
@@ -2,7 +2,7 @@
2
2
  /**
3
3
  * WL-2.2 — locate and forward to the local `sky-code` engine.
4
4
  *
5
- * The same `gh → git` shape `exec-oversky.ts` uses, for the same reason: the
5
+ * The same `gh → git` shape `exec-runtime-binary.ts` uses, for the same reason: the
6
6
  * Sky CLI is a REST client, the engine is a separately-built, separately-
7
7
  * released binary with its own lifetime and failure model. Unifying them at
8
8
  * the command surface (`skrr code`) gives users one thing to type without
@@ -108,7 +108,7 @@ function renderUsageReference(reference, bin = 'skrr') {
108
108
  ];
109
109
  for (const command of reference.data) {
110
110
  const flags = command.keyFlags.length > 0 ? ` Flags: ${command.keyFlags.join(', ')}.` : '';
111
- lines.push(`sky ${command.command} — ${command.description}.${flags} Example: ${command.example}`);
111
+ lines.push(`${bin} ${command.command} — ${command.description}.${flags} Example: ${command.example}`);
112
112
  }
113
113
  if (reference.nextPage)
114
114
  lines.push(`Next: ${bin} usage ${reference.domain} --page ${reference.nextPage}`);
@@ -69,6 +69,10 @@ export type WebUrlRef = {
69
69
  } | {
70
70
  kind: 'groupChat';
71
71
  groupChatId: string;
72
+ } | {
73
+ kind: 'wikiPage';
74
+ spaceId: string;
75
+ pageId: string;
72
76
  };
73
77
  /**
74
78
  * Site-relative canonical path for an entity, or `null` when the required id is
@@ -146,6 +150,18 @@ export declare function projectUrlFrom(baseURL: string, project: EntityRecord):
146
150
  export declare function withProjectUrl<T extends EntityRecord>(baseURL: string, project: T): T & {
147
151
  url: string | null;
148
152
  };
153
+ /**
154
+ * Build a wiki-page URL from a raw server page record.
155
+ *
156
+ * The server returns `pageId`, never `id`; the fallback reads exist so a
157
+ * caller that has already normalized the record still gets a link back
158
+ * instead of null.
159
+ */
160
+ export declare function wikiPageUrlFrom(baseURL: string, page: EntityRecord): string | null;
161
+ /** Return a shallow copy of a wiki-page record with a `url` field attached. */
162
+ export declare function withWikiPageUrl<T extends EntityRecord>(baseURL: string, page: T): T & {
163
+ url: string | null;
164
+ };
149
165
  /** Return a shallow copy of a commitment record with a `url` field attached. */
150
166
  export declare function withCommitmentUrl<T extends EntityRecord>(baseURL: string, commitment: T): T & {
151
167
  url: string | null;
@@ -35,6 +35,8 @@ exports.withSpaceUrl = withSpaceUrl;
35
35
  exports.withGoalUrl = withGoalUrl;
36
36
  exports.projectUrlFrom = projectUrlFrom;
37
37
  exports.withProjectUrl = withProjectUrl;
38
+ exports.wikiPageUrlFrom = wikiPageUrlFrom;
39
+ exports.withWikiPageUrl = withWikiPageUrl;
38
40
  exports.withCommitmentUrl = withCommitmentUrl;
39
41
  exports.withNorthstarUrl = withNorthstarUrl;
40
42
  exports.withAgentUrl = withAgentUrl;
@@ -103,6 +105,11 @@ function webPath(ref) {
103
105
  const projectId = encodeId(ref.projectId);
104
106
  return projectId ? `/spaces/${spaceId}/projects/${projectId}` : `/spaces/${spaceId}/projects`;
105
107
  }
108
+ case 'wikiPage': {
109
+ const spaceId = encodeId(ref.spaceId);
110
+ const pageId = encodeId(ref.pageId);
111
+ return spaceId && pageId ? `/spaces/${spaceId}/wiki?page=${pageId}` : null;
112
+ }
106
113
  case 'workflow': {
107
114
  const spaceId = encodeId(ref.spaceId);
108
115
  if (!spaceId)
@@ -282,6 +289,24 @@ function projectUrlFrom(baseURL, project) {
282
289
  function withProjectUrl(baseURL, project) {
283
290
  return { ...project, url: projectUrlFrom(baseURL, project) };
284
291
  }
292
+ /**
293
+ * Build a wiki-page URL from a raw server page record.
294
+ *
295
+ * The server returns `pageId`, never `id`; the fallback reads exist so a
296
+ * caller that has already normalized the record still gets a link back
297
+ * instead of null.
298
+ */
299
+ function wikiPageUrlFrom(baseURL, page) {
300
+ const pageId = idOf(page, 'pageId', 'id', '_id');
301
+ const spaceId = idOf(page, 'spaceId');
302
+ if (!pageId || !spaceId)
303
+ return null;
304
+ return webUrl(baseURL, { kind: 'wikiPage', spaceId, pageId });
305
+ }
306
+ /** Return a shallow copy of a wiki-page record with a `url` field attached. */
307
+ function withWikiPageUrl(baseURL, page) {
308
+ return { ...page, url: wikiPageUrlFrom(baseURL, page) };
309
+ }
285
310
  /** Return a shallow copy of a commitment record with a `url` field attached. */
286
311
  function withCommitmentUrl(baseURL, commitment) {
287
312
  return { ...commitment, url: commitmentUrlFrom(baseURL, commitment) };