codiedev 0.10.0-beta.16 → 0.10.0-beta.17

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.
@@ -35,6 +35,8 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.parseArgs = parseArgs;
37
37
  exports.pushFile = pushFile;
38
+ exports.uploadSkillFolder = uploadSkillFolder;
39
+ exports.formatBytes = formatBytes;
38
40
  exports.runPush = runPush;
39
41
  const fs = __importStar(require("fs"));
40
42
  const skillMarker_1 = require("../skillMarker");
@@ -42,6 +44,7 @@ const path = __importStar(require("path"));
42
44
  const shared = __importStar(require("./shared"));
43
45
  const shared_1 = require("./shared");
44
46
  const utils_1 = require("../utils");
47
+ const skillFiles_1 = require("../packs/skillFiles");
45
48
  const VALID_TYPES = new Set([
46
49
  "spec",
47
50
  "bugfix",
@@ -58,6 +61,7 @@ function parseArgs(args) {
58
61
  let force = false;
59
62
  let as;
60
63
  let priv = false;
64
+ let noFiles = false;
61
65
  const tags = [];
62
66
  for (let i = 0; i < args.length; i++) {
63
67
  const a = args[i];
@@ -91,12 +95,15 @@ function parseArgs(args) {
91
95
  else if (a === "--private") {
92
96
  priv = true;
93
97
  }
98
+ else if (a === "--no-files") {
99
+ noFiles = true;
100
+ }
94
101
  else if (!a.startsWith("--") && !file) {
95
102
  file = a;
96
103
  }
97
104
  }
98
105
  if (!file) {
99
- console.error("Usage: codiedev push <file.md> [--as <key>] [--kind doc|skill] [--tag <name>] [--private] [--force]");
106
+ console.error("Usage: codiedev push <file.md> [--as <key>] [--kind doc|skill] [--tag <name>] [--private] [--force] [--no-files]");
100
107
  process.exit(1);
101
108
  }
102
109
  if (type && !VALID_TYPES.has(type)) {
@@ -114,7 +121,7 @@ function parseArgs(args) {
114
121
  process.exit(1);
115
122
  }
116
123
  }
117
- return { file, type, kind, tags, force, as, private: priv };
124
+ return { file, type, kind, tags, force, as, private: priv, noFiles };
118
125
  }
119
126
  async function pushFile(config, opts) {
120
127
  const markdown = (0, skillMarker_1.stripSkillMarker)(fs.readFileSync(opts.absPath, "utf8"));
@@ -131,11 +138,28 @@ async function pushFile(config, opts) {
131
138
  gitRemoteUrl,
132
139
  visibility: opts.visibility,
133
140
  contentHash: opts.contentHash,
141
+ ...(opts.files ? { files: opts.files } : {}),
134
142
  },
135
143
  });
136
144
  }
145
+ async function uploadSkillFolder(config, skillFile, log = () => { }) {
146
+ const folder = (0, skillFiles_1.skillFolderFiles)(skillFile);
147
+ if (!folder)
148
+ return null;
149
+ if ("skipped" in folder) {
150
+ log(` ! Pushing SKILL.md only: ${folder.skipped}. The skill keeps the files it had.`);
151
+ return null;
152
+ }
153
+ for (const note of folder.notes)
154
+ log(` · ${note}`);
155
+ await (0, skillFiles_1.uploadBlobs)(config, folder.files, "/api/cli/skills/files");
156
+ return { files: folder.files.map(skillFiles_1.toRef), bytes: folder.bytes };
157
+ }
158
+ function formatBytes(n) {
159
+ return n >= 1024 * 1024 ? `${(n / (1024 * 1024)).toFixed(1)}MB` : n >= 1024 ? `${Math.round(n / 1024)}KB` : `${n}B`;
160
+ }
137
161
  async function runPush(args) {
138
- const { file, type, kind, tags, force, as, private: priv } = parseArgs(args);
162
+ const { file, type, kind, tags, force, as, private: priv, noFiles } = parseArgs(args);
139
163
  const config = (0, shared_1.requireConfig)();
140
164
  let absolute = file;
141
165
  if (!path.isAbsolute(absolute)) {
@@ -153,6 +177,7 @@ async function runPush(args) {
153
177
  const filename = as ?? path.basename(absolute);
154
178
  const start = Date.now();
155
179
  try {
180
+ const folder = !noFiles && kind !== "doc" ? await uploadSkillFolder(config, absolute, (l) => console.log(l)) : null;
156
181
  const res = await pushFile(config, {
157
182
  absPath: absolute,
158
183
  key: filename,
@@ -161,6 +186,7 @@ async function runPush(args) {
161
186
  tags,
162
187
  force,
163
188
  visibility: priv ? "private" : undefined,
189
+ ...(folder ? { files: folder.files } : {}),
164
190
  });
165
191
  (0, shared_1.recordAgentEvent)(config, {
166
192
  tool: "codiedev_push",
@@ -168,7 +194,10 @@ async function runPush(args) {
168
194
  latencyMs: Date.now() - start,
169
195
  });
170
196
  const tagSummary = res.tags && res.tags.length > 0 ? ` tags=[${res.tags.join(", ")}]` : "";
171
- console.log(`✓ Pushed ${filename} (kind=${res.kind}${tagSummary}).`);
197
+ const fileSummary = folder?.files.length
198
+ ? `, with ${folder.files.length} file${folder.files.length === 1 ? "" : "s"} from its folder, ${formatBytes(folder.bytes)}`
199
+ : "";
200
+ console.log(`✓ Pushed ${filename} (kind=${res.kind}${tagSummary}${fileSummary}).`);
172
201
  console.log(` Visible under: ${res.destination}`);
173
202
  if (res.key && res.key !== filename) {
174
203
  console.log(` Stored as: ${res.key}`);
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runReply = runReply;
4
+ const shared_1 = require("./shared");
5
+ const pingFiles_1 = require("./pingFiles");
6
+ const USAGE = 'Usage: codiedev reply <ping-id> "<message>" [--file <path>]';
7
+ async function runReply(args) {
8
+ const { files, rest } = (0, pingFiles_1.takeFileArgs)(args);
9
+ const positional = rest.filter((a) => !a.startsWith("--"));
10
+ const pingId = positional[0];
11
+ const body = (0, shared_1.stripQuotes)(positional.slice(1).join(" "));
12
+ if (!pingId || (!body && files.length === 0)) {
13
+ console.error(USAGE);
14
+ process.exit(1);
15
+ }
16
+ const config = (0, shared_1.requireConfig)();
17
+ const start = Date.now();
18
+ try {
19
+ const attachmentIds = await (0, pingFiles_1.uploadOrExit)(config, files);
20
+ const res = await (0, shared_1.apiRequest)("POST", "/api/cli/reply", {
21
+ config,
22
+ body: { pingId, body, ...(attachmentIds.length ? { attachmentIds } : {}) },
23
+ });
24
+ (0, shared_1.recordAgentEvent)(config, {
25
+ tool: "codiedev_reply",
26
+ ok: true,
27
+ latencyMs: Date.now() - start,
28
+ });
29
+ const to = res.recipient ? `${res.recipient.name} <${res.recipient.email}>` : "them";
30
+ const withFiles = files.length ? ` with ${files.length} file${files.length === 1 ? "" : "s"}` : "";
31
+ console.log(`✓ Replied to ${to}${withFiles}`);
32
+ }
33
+ catch (err) {
34
+ const e = err;
35
+ (0, shared_1.recordAgentEvent)(config, {
36
+ tool: "codiedev_reply",
37
+ ok: false,
38
+ latencyMs: Date.now() - start,
39
+ error: e.message,
40
+ });
41
+ if (e.status === 404 && /ping not found/.test(e.message)) {
42
+ console.error(`No ping ${pingId} addressed to you. Run 'codiedev inbox' for the ids.`);
43
+ }
44
+ else {
45
+ console.error(`Reply failed: ${e.message}`);
46
+ }
47
+ process.exit(1);
48
+ }
49
+ }
@@ -27,8 +27,7 @@ your credential files and .env files) if your admin allows it. It reads
27
27
  ~/.aws/credentials, ~/.npmrc, ~/.pypirc, ~/.netrc, ~/.git-credentials,
28
28
  ~/.config/gh/hosts.yml, ~/.docker/config.json, ~/.config/hub,
29
29
  ~/.gem/credentials, ~/.config/openai/credentials, and .env / .env.* in the
30
- repos your sessions start in. Values stay on this machine; only if your admin
31
- chose to check uploaded sessions too is a keyed fingerprint of each sent.
30
+ repos your sessions start in. Values stay on this machine.
32
31
  `;
33
32
  function parseScrubArgs(args) {
34
33
  let dryRun = false;
@@ -1,62 +1,22 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sendToPingArgs = sendToPingArgs;
3
4
  exports.runSend = runSend;
5
+ const ping_1 = require("./ping");
4
6
  const shared_1 = require("./shared");
5
- function parseArgs(args) {
7
+ function sendToPingArgs(args) {
6
8
  const positionals = args.filter((a) => !a.startsWith("--"));
7
9
  const [filename, to, ...rest] = positionals;
8
- if (!filename || !to) {
9
- console.error('Usage: codiedev send <filename> <recipient> ["<message>"]');
10
- process.exit(1);
11
- }
12
- const message = rest.length > 0 ? (0, shared_1.stripQuotes)(rest.join(" ")) : undefined;
13
- return { filename, to, message };
10
+ if (!filename || !to)
11
+ return null;
12
+ const message = rest.length > 0 ? (0, shared_1.stripQuotes)(rest.join(" ")) : "";
13
+ return [to, ...(message ? [message] : []), "--with", filename];
14
14
  }
15
15
  async function runSend(args, configOverride) {
16
- const parsed = parseArgs(args);
17
- const config = configOverride ?? (0, shared_1.requireConfig)();
18
- const start = Date.now();
19
- try {
20
- const body = {
21
- filename: parsed.filename,
22
- to: parsed.to,
23
- };
24
- if (parsed.message)
25
- body.message = parsed.message;
26
- const res = await (0, shared_1.apiRequest)("POST", "/api/cli/send-to", {
27
- config,
28
- body,
29
- });
30
- (0, shared_1.recordAgentEvent)(config, {
31
- tool: "codiedev_send_to",
32
- ok: true,
33
- latencyMs: Date.now() - start,
34
- });
35
- const who = res.recipient ? `${res.recipient.name} (${res.recipient.email})` : parsed.to;
36
- if (parsed.message) {
37
- console.log(`Sent ${parsed.filename} to ${who}.`);
38
- }
39
- else {
40
- console.log(`Shared ${parsed.filename} with ${who} (no message).`);
41
- }
42
- }
43
- catch (err) {
44
- (0, shared_1.recordAgentEvent)(config, {
45
- tool: "codiedev_send_to",
46
- ok: false,
47
- latencyMs: Date.now() - start,
48
- error: err.message,
49
- });
50
- const body = err.body;
51
- if (body && Array.isArray(body.candidates) && body.candidates.length > 0) {
52
- console.error(`Recipient "${parsed.to}" is ambiguous. Candidates:`);
53
- for (const c of body.candidates) {
54
- console.error(` - ${c.name} (${c.email})`);
55
- }
56
- }
57
- else {
58
- console.error(`Send failed: ${err.message}`);
59
- }
16
+ const pingArgs = sendToPingArgs(args);
17
+ if (!pingArgs) {
18
+ console.error('Usage: codiedev send <artifact> <recipient> ["<message>"] (same as: codiedev ping <recipient> ["<message>"] --with <artifact>)');
60
19
  process.exit(1);
61
20
  }
21
+ await (0, ping_1.runPing)(pingArgs, configOverride);
62
22
  }
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.applyConfigEnvOverrides = applyConfigEnvOverrides;
37
37
  exports.requireConfig = requireConfig;
38
38
  exports.apiRequest = apiRequest;
39
+ exports.apiRequestBytes = apiRequestBytes;
39
40
  exports.recordAgentEvent = recordAgentEvent;
40
41
  exports.recordInstallEvent = recordInstallEvent;
41
42
  exports.withTelemetry = withTelemetry;
@@ -120,6 +121,56 @@ function apiRequest(method, path, options) {
120
121
  req.end();
121
122
  });
122
123
  }
124
+ function apiRequestBytes(method, path, options) {
125
+ return new Promise((resolve, reject) => {
126
+ const url = new URL(path, options.config.backendUrl);
127
+ for (const [k, v] of Object.entries(options.query ?? {})) {
128
+ if (v !== undefined)
129
+ url.searchParams.set(k, String(v));
130
+ }
131
+ const lib = url.protocol === "https:" ? https : http;
132
+ const req = lib.request({
133
+ hostname: url.hostname,
134
+ port: url.port || (url.protocol === "https:" ? 443 : 80),
135
+ path: url.pathname + url.search,
136
+ method,
137
+ headers: {
138
+ Authorization: `Bearer ${options.config.token}`,
139
+ "X-Codiedev-Cli-Version": version_1.CLI_VERSION,
140
+ ...(options.body ? { "Content-Type": "application/octet-stream", "Content-Length": options.body.length } : {}),
141
+ },
142
+ }, (res) => {
143
+ const chunks = [];
144
+ let size = 0;
145
+ res.on("data", (c) => {
146
+ size += c.length;
147
+ if (options.maxBytes !== undefined && size > options.maxBytes) {
148
+ req.destroy(Object.assign(new Error(`response over ${options.maxBytes} bytes`), { status: res.statusCode }));
149
+ return;
150
+ }
151
+ chunks.push(c);
152
+ });
153
+ res.on("end", () => {
154
+ const buf = Buffer.concat(chunks);
155
+ if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300)
156
+ return resolve(buf);
157
+ let message = `HTTP ${res.statusCode}`;
158
+ try {
159
+ const parsed = JSON.parse(buf.toString("utf8"));
160
+ if (parsed && typeof parsed.error === "string")
161
+ message = parsed.error;
162
+ }
163
+ catch {
164
+ }
165
+ reject(Object.assign(new Error(message), { status: res.statusCode }));
166
+ });
167
+ });
168
+ req.on("error", reject);
169
+ if (options.body)
170
+ req.write(options.body);
171
+ req.end();
172
+ });
173
+ }
123
174
  function recordAgentEvent(config, event) {
124
175
  apiRequest("POST", "/api/telemetry/mcp-event", {
125
176
  config,