@codio-ai/opencode-authoring-agent 0.1.3 → 0.1.5

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/dist/index.js CHANGED
@@ -3945,7 +3945,7 @@ var require_lodash = __commonJS((exports, module) => {
3945
3945
  }
3946
3946
  return mapped.length && mapped[0] === arrays[0] ? baseIntersection(mapped, undefined2, comparator) : [];
3947
3947
  });
3948
- function join5(array, separator) {
3948
+ function join6(array, separator) {
3949
3949
  return array == null ? "" : nativeJoin.call(array, separator);
3950
3950
  }
3951
3951
  function last(array) {
@@ -5882,7 +5882,7 @@ __p += '`;
5882
5882
  lodash.isUndefined = isUndefined;
5883
5883
  lodash.isWeakMap = isWeakMap;
5884
5884
  lodash.isWeakSet = isWeakSet;
5885
- lodash.join = join5;
5885
+ lodash.join = join6;
5886
5886
  lodash.kebabCase = kebabCase;
5887
5887
  lodash.last = last;
5888
5888
  lodash.lastIndexOf = lastIndexOf;
@@ -16380,11 +16380,11 @@ var require_path_arg = __commonJS((exports, module) => {
16380
16380
 
16381
16381
  // node_modules/tar/node_modules/mkdirp/lib/find-made.js
16382
16382
  var require_find_made = __commonJS((exports, module) => {
16383
- var { dirname: dirname2 } = __require("path");
16383
+ var { dirname: dirname3 } = __require("path");
16384
16384
  var findMade = (opts, parent, path = undefined) => {
16385
16385
  if (path === parent)
16386
16386
  return Promise.resolve();
16387
- return opts.statAsync(parent).then((st) => st.isDirectory() ? path : undefined, (er) => er.code === "ENOENT" ? findMade(opts, dirname2(parent), parent) : undefined);
16387
+ return opts.statAsync(parent).then((st) => st.isDirectory() ? path : undefined, (er) => er.code === "ENOENT" ? findMade(opts, dirname3(parent), parent) : undefined);
16388
16388
  };
16389
16389
  var findMadeSync = (opts, parent, path = undefined) => {
16390
16390
  if (path === parent)
@@ -16392,7 +16392,7 @@ var require_find_made = __commonJS((exports, module) => {
16392
16392
  try {
16393
16393
  return opts.statSync(parent).isDirectory() ? path : undefined;
16394
16394
  } catch (er) {
16395
- return er.code === "ENOENT" ? findMadeSync(opts, dirname2(parent), parent) : undefined;
16395
+ return er.code === "ENOENT" ? findMadeSync(opts, dirname3(parent), parent) : undefined;
16396
16396
  }
16397
16397
  };
16398
16398
  module.exports = { findMade, findMadeSync };
@@ -16400,10 +16400,10 @@ var require_find_made = __commonJS((exports, module) => {
16400
16400
 
16401
16401
  // node_modules/tar/node_modules/mkdirp/lib/mkdirp-manual.js
16402
16402
  var require_mkdirp_manual = __commonJS((exports, module) => {
16403
- var { dirname: dirname2 } = __require("path");
16403
+ var { dirname: dirname3 } = __require("path");
16404
16404
  var mkdirpManual = (path, opts, made) => {
16405
16405
  opts.recursive = false;
16406
- const parent = dirname2(path);
16406
+ const parent = dirname3(path);
16407
16407
  if (parent === path) {
16408
16408
  return opts.mkdirAsync(path, opts).catch((er) => {
16409
16409
  if (er.code !== "EISDIR")
@@ -16426,7 +16426,7 @@ var require_mkdirp_manual = __commonJS((exports, module) => {
16426
16426
  });
16427
16427
  };
16428
16428
  var mkdirpManualSync = (path, opts, made) => {
16429
- const parent = dirname2(path);
16429
+ const parent = dirname3(path);
16430
16430
  opts.recursive = false;
16431
16431
  if (parent === path) {
16432
16432
  try {
@@ -16459,12 +16459,12 @@ var require_mkdirp_manual = __commonJS((exports, module) => {
16459
16459
 
16460
16460
  // node_modules/tar/node_modules/mkdirp/lib/mkdirp-native.js
16461
16461
  var require_mkdirp_native = __commonJS((exports, module) => {
16462
- var { dirname: dirname2 } = __require("path");
16462
+ var { dirname: dirname3 } = __require("path");
16463
16463
  var { findMade, findMadeSync } = require_find_made();
16464
16464
  var { mkdirpManual, mkdirpManualSync } = require_mkdirp_manual();
16465
16465
  var mkdirpNative = (path, opts) => {
16466
16466
  opts.recursive = true;
16467
- const parent = dirname2(path);
16467
+ const parent = dirname3(path);
16468
16468
  if (parent === path)
16469
16469
  return opts.mkdirAsync(path, opts);
16470
16470
  return findMade(opts, path).then((made) => opts.mkdirAsync(path, opts).then(() => made).catch((er) => {
@@ -16476,7 +16476,7 @@ var require_mkdirp_native = __commonJS((exports, module) => {
16476
16476
  };
16477
16477
  var mkdirpNativeSync = (path, opts) => {
16478
16478
  opts.recursive = true;
16479
- const parent = dirname2(path);
16479
+ const parent = dirname3(path);
16480
16480
  if (parent === path)
16481
16481
  return opts.mkdirSync(path, opts);
16482
16482
  const made = findMadeSync(opts, path);
@@ -16865,7 +16865,7 @@ var require_path_reservations = __commonJS((exports, module) => {
16865
16865
  var assert = __require("assert");
16866
16866
  var normalize = require_normalize_unicode();
16867
16867
  var stripSlashes = require_strip_trailing_slashes();
16868
- var { join: join5 } = __require("path");
16868
+ var { join: join6 } = __require("path");
16869
16869
  var platform = process.env.TESTING_TAR_FAKE_PLATFORM || process.platform;
16870
16870
  var isWindows = platform === "win32";
16871
16871
  module.exports = () => {
@@ -16874,7 +16874,7 @@ var require_path_reservations = __commonJS((exports, module) => {
16874
16874
  const getDirs = (path) => {
16875
16875
  const dirs = path.split("/").slice(0, -1).reduce((set, path2) => {
16876
16876
  if (set.length) {
16877
- path2 = join5(set[set.length - 1], path2);
16877
+ path2 = join6(set[set.length - 1], path2);
16878
16878
  }
16879
16879
  set.push(path2 || "/");
16880
16880
  return set;
@@ -16942,7 +16942,7 @@ var require_path_reservations = __commonJS((exports, module) => {
16942
16942
  };
16943
16943
  const reserve = (paths, fn) => {
16944
16944
  paths = isWindows ? ["win32 parallelization disabled"] : paths.map((p) => {
16945
- return stripSlashes(join5(normalize(p))).toLowerCase();
16945
+ return stripSlashes(join6(normalize(p))).toLowerCase();
16946
16946
  });
16947
16947
  const dirs = new Set(paths.map((path) => getDirs(path)).reduce((a, b) => a.concat(b)));
16948
16948
  reservations.set(fn, { dirs, paths });
@@ -18231,7 +18231,7 @@ var require_BufferList = __commonJS((exports, module) => {
18231
18231
  this.head = this.tail = null;
18232
18232
  this.length = 0;
18233
18233
  };
18234
- BufferList.prototype.join = function join5(s) {
18234
+ BufferList.prototype.join = function join6(s) {
18235
18235
  if (this.length === 0)
18236
18236
  return "";
18237
18237
  var p = this.head;
@@ -20411,7 +20411,7 @@ var require_BufferList2 = __commonJS((exports, module) => {
20411
20411
  this.head = this.tail = null;
20412
20412
  this.length = 0;
20413
20413
  };
20414
- BufferList.prototype.join = function join5(s) {
20414
+ BufferList.prototype.join = function join6(s) {
20415
20415
  if (this.length === 0)
20416
20416
  return "";
20417
20417
  var p = this.head;
@@ -22536,7 +22536,7 @@ var require_buffer_list = __commonJS((exports, module) => {
22536
22536
  }
22537
22537
  }, {
22538
22538
  key: "join",
22539
- value: function join5(s) {
22539
+ value: function join6(s) {
22540
22540
  if (this.length === 0)
22541
22541
  return "";
22542
22542
  var p = this.head;
@@ -45914,7 +45914,7 @@ ${enabledAgents}
45914
45914
 
45915
45915
  ### Codio platform tools
45916
45916
  - \`fetch_course({workspace, courseId, outputDir?, domain?})\` — pull an existing Codio course from the platform into an AI-ready local project. Requires \`CODIO_CLIENT_ID\` and \`CODIO_CLIENT_SECRET\` env vars. Returns \`{ outputDir, manifestPath, moduleCount, assignmentCount }\`. Writes \`course-manifest.json\`, \`course-assignments.csv\`, and extracted assignment content under \`course-content/\`. **Delegate when:** user wants to fetch, pull, import, or export an existing Codio course.
45917
- - \`publish_course({manifestPath, dryRun?, force?, module?, assignment?, changelog?, stack?})\` — push course assignments back to the Codio platform using \`course-manifest.json\` as the source of truth. Creates missing courses/modules/assignments automatically. Skips unchanged assignments by content hash. Returns \`{ published, created, unchanged, skipped }\`. **Delegate when:** user wants to publish, push, deploy, or sync assignments to Codio. Always suggest \`dryRun: true\` first to preview.
45917
+ - \`publish_course({workspace, manifestPath, dryRun?, force?, module?, assignment?, changelog?, stack?})\` — push course assignments back to the Codio platform using \`course-manifest.json\` as the source of truth. Creates missing courses/modules/assignments automatically. Skips unchanged assignments by content hash. Returns \`{ published, created, unchanged, skipped }\`. **Delegate when:** user wants to publish, push, deploy, or sync assignments to Codio. Always suggest \`dryRun: true\` first to preview.
45918
45918
 
45919
45919
  ### Platform tool routing
45920
45920
  - User says "fetch/pull/import/export this course" → \`fetch_course\`
@@ -46365,8 +46365,8 @@ function getAgentConfigs(agents) {
46365
46365
  import { existsSync, readFileSync } from "node:fs";
46366
46366
  import { join } from "node:path";
46367
46367
  import { z } from "zod";
46368
- var DEFAULT_PRIMARY = "amazon-bedrock/sonnet-4-6";
46369
- var DEFAULT_CHEAP = "amazon-bedrock/haiku-4-5";
46368
+ var DEFAULT_PRIMARY = "anthropic/claude-sonnet-4-6";
46369
+ var DEFAULT_CHEAP = "anthropic/claude-haiku-4-5-20251001";
46370
46370
  var agentOverrideSchema = z.object({
46371
46371
  model: z.string().optional(),
46372
46372
  prompt: z.string().optional(),
@@ -47032,22 +47032,52 @@ ${freezeErrors.join(`
47032
47032
  }
47033
47033
 
47034
47034
  // src/tools/fetch-course.ts
47035
- var import_codio_api_js = __toESM(require_lib3(), 1);
47036
- var import_json_2_csv = __toESM(require_converter(), 1);
47037
47035
  import { execFile } from "node:child_process";
47038
47036
  import {
47039
- existsSync as existsSync3,
47037
+ copyFileSync,
47038
+ existsSync as existsSync4,
47040
47039
  mkdirSync as mkdirSync2,
47041
47040
  readdirSync,
47042
47041
  rmSync,
47043
47042
  statSync,
47044
47043
  unlinkSync as unlinkSync2
47045
47044
  } from "node:fs";
47046
- import { writeFile, mkdir } from "node:fs/promises";
47045
+ import { mkdir, writeFile } from "node:fs/promises";
47047
47046
  import { tmpdir } from "node:os";
47048
- import { dirname as dirname2, join as join5, relative } from "node:path";
47047
+ import { dirname as dirname3, join as join6 } from "node:path";
47049
47048
  import { promisify } from "node:util";
47050
47049
  import { z as z4 } from "zod";
47050
+
47051
+ // src/utils/load-env.ts
47052
+ import { existsSync as existsSync3, readFileSync as readFileSync2 } from "node:fs";
47053
+ import { dirname as dirname2, join as join5 } from "node:path";
47054
+ function loadEnvWalkUp(startDir) {
47055
+ let dir = startDir.replace(/\/+$/, "");
47056
+ while (true) {
47057
+ const candidate = join5(dir, ".env");
47058
+ if (existsSync3(candidate)) {
47059
+ for (const line of readFileSync2(candidate, "utf8").split(`
47060
+ `)) {
47061
+ const t = line.trim();
47062
+ if (!t || t.startsWith("#"))
47063
+ continue;
47064
+ const eq = t.indexOf("=");
47065
+ if (eq < 1)
47066
+ continue;
47067
+ const key = t.slice(0, eq).trim();
47068
+ const val = t.slice(eq + 1).trim().replace(/^(['"])(.*)\1$/, "$2");
47069
+ process.env[key] = val;
47070
+ }
47071
+ return;
47072
+ }
47073
+ const parent = dirname2(dir);
47074
+ if (parent === dir)
47075
+ return;
47076
+ dir = parent;
47077
+ }
47078
+ }
47079
+
47080
+ // src/tools/fetch-course.ts
47051
47081
  var execFileAsync = promisify(execFile);
47052
47082
  var fetchCourseInputSchema = z4.object({
47053
47083
  workspace: z4.string().min(1).describe("Absolute path to the Codio workspace root"),
@@ -47065,7 +47095,7 @@ async function extractZip(zipPath, destDir) {
47065
47095
  function findTarZstFiles(dir) {
47066
47096
  const results = [];
47067
47097
  for (const name of readdirSync(dir)) {
47068
- const full = join5(dir, name);
47098
+ const full = join6(dir, name);
47069
47099
  if (statSync(full).isDirectory())
47070
47100
  results.push(...findTarZstFiles(full));
47071
47101
  else if (name.endsWith(".tar.zst"))
@@ -47082,10 +47112,10 @@ async function extractTarZstArchives(stagingDir) {
47082
47112
  }
47083
47113
  }
47084
47114
  function removeExportedReadmes(dir) {
47085
- if (!existsSync3(dir))
47115
+ if (!existsSync4(dir))
47086
47116
  return;
47087
47117
  for (const name of readdirSync(dir)) {
47088
- const full = join5(dir, name);
47118
+ const full = join6(dir, name);
47089
47119
  if (statSync(full).isDirectory())
47090
47120
  removeExportedReadmes(full);
47091
47121
  else if (name.toLowerCase() === "readme.md")
@@ -47095,32 +47125,35 @@ function removeExportedReadmes(dir) {
47095
47125
  function copyDir(src, dst) {
47096
47126
  mkdirSync2(dst, { recursive: true });
47097
47127
  for (const name of readdirSync(src)) {
47098
- const srcPath = join5(src, name);
47099
- const dstPath = join5(dst, name);
47128
+ const srcPath = join6(src, name);
47129
+ const dstPath = join6(dst, name);
47100
47130
  if (statSync(srcPath).isDirectory())
47101
47131
  copyDir(srcPath, dstPath);
47102
- else {
47103
- const { copyFileSync } = __require("node:fs");
47132
+ else
47104
47133
  copyFileSync(srcPath, dstPath);
47105
- }
47106
47134
  }
47107
47135
  }
47108
47136
  async function fetchCourseHandler(raw) {
47109
47137
  const input = fetchCourseInputSchema.parse(raw);
47138
+ loadEnvWalkUp(input.workspace);
47139
+ const [{ default: codio }, { json2csv }] = await Promise.all([
47140
+ Promise.resolve().then(() => __toESM(require_lib3(), 1)),
47141
+ Promise.resolve().then(() => __toESM(require_converter(), 1))
47142
+ ]);
47110
47143
  const clientId = process.env["CODIO_CLIENT_ID"];
47111
47144
  const clientSecret = process.env["CODIO_CLIENT_SECRET"];
47112
47145
  if (!clientId || !clientSecret) {
47113
- throw new Error("CODIO_CLIENT_ID and CODIO_CLIENT_SECRET must be set as environment variables on the box.");
47146
+ throw new Error("CODIO_CLIENT_ID and CODIO_CLIENT_SECRET must be set in .env at the workspace root or as environment variables.");
47114
47147
  }
47115
47148
  const domain = input.domain ?? process.env["CODIO_DOMAIN"] ?? "codio.com";
47116
47149
  const outputFolderName = input.outputDir ?? "course-project";
47117
- const outputDir = join5(input.workspace, outputFolderName);
47118
- const contentDir = join5(outputDir, "course-content");
47119
- const manifestPath = join5(outputDir, "course-manifest.json");
47120
- const csvPath = join5(outputDir, "course-assignments.csv");
47121
- import_codio_api_js.default.v1.setDomain(domain);
47122
- await import_codio_api_js.default.v1.auth(clientId, clientSecret);
47123
- const courseInfo = await import_codio_api_js.default.v1.course.info(input.courseId);
47150
+ const outputDir = join6(input.workspace, outputFolderName);
47151
+ const contentDir = join6(outputDir, "course-content");
47152
+ const manifestPath = join6(outputDir, "course-manifest.json");
47153
+ const csvPath = join6(outputDir, "course-assignments.csv");
47154
+ codio.v1.setDomain(domain);
47155
+ await codio.v1.auth(clientId, clientSecret);
47156
+ const courseInfo = await codio.v1.course.info(input.courseId);
47124
47157
  const modules = (courseInfo.modules ?? []).map((mod, mi) => {
47125
47158
  const moduleName = mod.name ?? `Module ${mi + 1}`;
47126
47159
  const moduleFolder = codioFolderSlug(moduleName);
@@ -47156,7 +47189,7 @@ async function fetchCourseHandler(raw) {
47156
47189
  };
47157
47190
  rmSync(outputDir, { recursive: true, force: true });
47158
47191
  mkdirSync2(contentDir, { recursive: true });
47159
- await mkdir(dirname2(manifestPath), { recursive: true });
47192
+ await mkdir(dirname3(manifestPath), { recursive: true });
47160
47193
  await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}
47161
47194
  `, "utf8");
47162
47195
  const rows = modules.flatMap((m) => m.assignments.map((a) => ({
@@ -47168,14 +47201,14 @@ async function fetchCourseHandler(raw) {
47168
47201
  assignmentFolder: a.folder,
47169
47202
  assignmentPath: a.path
47170
47203
  })));
47171
- const csv = await import_json_2_csv.json2csv(rows, { emptyFieldValue: "", prependHeader: true });
47204
+ const csv = await json2csv(rows, { emptyFieldValue: "", prependHeader: true });
47172
47205
  await writeFile(csvPath, csv, "utf8");
47173
- const workDir = join5(tmpdir(), `codio-fetch-${Date.now()}`);
47174
- const zipPath = join5(workDir, "course-export.zip");
47206
+ const workDir = join6(tmpdir(), `codio-fetch-${Date.now()}`);
47207
+ const zipPath = join6(workDir, "course-export.zip");
47175
47208
  mkdirSync2(workDir, { recursive: true });
47176
47209
  try {
47177
- await import_codio_api_js.default.v1.course.downloadSourceExport(input.courseId, zipPath);
47178
- const stagingDir = join5(workDir, "staging");
47210
+ await codio.v1.course.downloadSourceExport(input.courseId, zipPath);
47211
+ const stagingDir = join6(workDir, "staging");
47179
47212
  await extractZip(zipPath, stagingDir);
47180
47213
  await extractTarZstArchives(stagingDir);
47181
47214
  removeExportedReadmes(stagingDir);
@@ -47193,18 +47226,18 @@ async function fetchCourseHandler(raw) {
47193
47226
  }
47194
47227
 
47195
47228
  // src/tools/publish-course.ts
47196
- var import_codio_api_js2 = __toESM(require_lib3(), 1);
47197
47229
  import { createHash } from "node:crypto";
47198
47230
  import {
47199
- existsSync as existsSync4,
47231
+ existsSync as existsSync5,
47200
47232
  readdirSync as readdirSync2,
47201
- readFileSync as readFileSync2,
47202
- writeFileSync as writeFileSync4
47233
+ readFileSync as readFileSync3,
47234
+ writeFileSync as writeFileSync3
47203
47235
  } from "node:fs";
47204
- import { join as join6, relative as relative2 } from "node:path";
47236
+ import { join as join7, relative } from "node:path";
47205
47237
  import { z as z5 } from "zod";
47206
47238
  var DEFAULT_STACK = "e0195698-d647-4490-8834-350583b532eb:latest";
47207
47239
  var publishCourseInputSchema = z5.object({
47240
+ workspace: z5.string().min(1).describe("Absolute path to the Codio workspace root (where .env lives)"),
47208
47241
  manifestPath: z5.string().min(1).describe("Absolute path to course-manifest.json"),
47209
47242
  dryRun: z5.boolean().optional().describe("Preview actions without making changes"),
47210
47243
  force: z5.boolean().optional().describe("Publish all, bypassing change detection"),
@@ -47214,17 +47247,17 @@ var publishCourseInputSchema = z5.object({
47214
47247
  stack: z5.string().optional().describe("Force a specific stack ID for all assignments")
47215
47248
  });
47216
47249
  function saveManifest(manifestPath, manifest) {
47217
- writeFileSync4(manifestPath, `${JSON.stringify(manifest, null, 2)}
47250
+ writeFileSync3(manifestPath, `${JSON.stringify(manifest, null, 2)}
47218
47251
  `, "utf8");
47219
47252
  }
47220
47253
  function findZip(dir) {
47221
47254
  const zip = readdirSync2(dir).find((f) => f.endsWith(".zip"));
47222
- return zip ? join6(dir, zip) : null;
47255
+ return zip ? join7(dir, zip) : null;
47223
47256
  }
47224
47257
  function walkFiles(dir) {
47225
47258
  const results = [];
47226
47259
  for (const entry of readdirSync2(dir, { withFileTypes: true })) {
47227
- const full = join6(dir, entry.name);
47260
+ const full = join7(dir, entry.name);
47228
47261
  if (entry.isDirectory())
47229
47262
  results.push(...walkFiles(full));
47230
47263
  else
@@ -47236,12 +47269,12 @@ function computeContentHash(dir) {
47236
47269
  const hash = createHash("sha256");
47237
47270
  const zipPath = findZip(dir);
47238
47271
  if (zipPath) {
47239
- hash.update(readFileSync2(zipPath));
47272
+ hash.update(readFileSync3(zipPath));
47240
47273
  } else {
47241
47274
  for (const file of walkFiles(dir).sort()) {
47242
- hash.update(relative2(dir, file));
47275
+ hash.update(relative(dir, file));
47243
47276
  hash.update("\x00");
47244
- hash.update(readFileSync2(file));
47277
+ hash.update(readFileSync3(file));
47245
47278
  hash.update("\x00");
47246
47279
  }
47247
47280
  }
@@ -47249,19 +47282,21 @@ function computeContentHash(dir) {
47249
47282
  }
47250
47283
  async function publishCourseHandler(raw) {
47251
47284
  const input = publishCourseInputSchema.parse(raw);
47285
+ loadEnvWalkUp(input.workspace);
47286
+ const { default: codio } = await Promise.resolve().then(() => __toESM(require_lib3(), 1));
47252
47287
  const clientId = process.env["CODIO_CLIENT_ID"];
47253
47288
  const clientSecret = process.env["CODIO_CLIENT_SECRET"];
47254
47289
  if (!clientId || !clientSecret) {
47255
47290
  throw new Error("CODIO_CLIENT_ID and CODIO_CLIENT_SECRET must be set as environment variables on the box.");
47256
47291
  }
47257
- if (!existsSync4(input.manifestPath)) {
47292
+ if (!existsSync5(input.manifestPath)) {
47258
47293
  throw new Error(`course-manifest.json not found at ${input.manifestPath}`);
47259
47294
  }
47260
47295
  const domain = process.env["CODIO_DOMAIN"] ?? "codio.com";
47261
- import_codio_api_js2.default.v1.setDomain(domain);
47262
- await import_codio_api_js2.default.v1.auth(clientId, clientSecret);
47263
- const manifest = JSON.parse(readFileSync2(input.manifestPath, "utf8"));
47264
- const manifestDir = join6(input.manifestPath, "..");
47296
+ codio.v1.setDomain(domain);
47297
+ await codio.v1.auth(clientId, clientSecret);
47298
+ const manifest = JSON.parse(readFileSync3(input.manifestPath, "utf8"));
47299
+ const manifestDir = join7(input.manifestPath, "..");
47265
47300
  if (!manifest.courseId) {
47266
47301
  const courseName = manifest.courseName ?? "Codio Course";
47267
47302
  if (input.dryRun) {
@@ -47269,7 +47304,7 @@ async function publishCourseHandler(raw) {
47269
47304
  } else {
47270
47305
  const start = manifest.start ?? new Date().toISOString().replace(/T.*/, "T00:00:00.000Z");
47271
47306
  const timezone = manifest.timezone ?? "UTC";
47272
- manifest.courseId = await import_codio_api_js2.default.v1.course.createCourse({ name: courseName, start, timezone });
47307
+ manifest.courseId = await codio.v1.course.createCourse({ name: courseName, start, timezone });
47273
47308
  if (!manifest.courseName)
47274
47309
  manifest.courseName = courseName;
47275
47310
  saveManifest(input.manifestPath, manifest);
@@ -47278,7 +47313,7 @@ async function publishCourseHandler(raw) {
47278
47313
  const existingModuleIds = new Map;
47279
47314
  if (manifest.courseId && !input.dryRun) {
47280
47315
  try {
47281
- const courseInfo = await import_codio_api_js2.default.v1.course.info(manifest.courseId);
47316
+ const courseInfo = await codio.v1.course.info(manifest.courseId);
47282
47317
  for (const m of courseInfo.modules ?? []) {
47283
47318
  if (m.id && m.name)
47284
47319
  existingModuleIds.set(m.name, m.id);
@@ -47295,7 +47330,7 @@ async function publishCourseHandler(raw) {
47295
47330
  mod.id = knownId;
47296
47331
  saveManifest(input.manifestPath, manifest);
47297
47332
  } else if (!input.dryRun && mod.assignments.some((a) => !a.id)) {
47298
- mod.id = await import_codio_api_js2.default.v1.course.createModule(manifest.courseId, mod.name);
47333
+ mod.id = await codio.v1.course.createModule(manifest.courseId, mod.name);
47299
47334
  saveManifest(input.manifestPath, manifest);
47300
47335
  created++;
47301
47336
  }
@@ -47303,8 +47338,8 @@ async function publishCourseHandler(raw) {
47303
47338
  for (const asgn of mod.assignments) {
47304
47339
  if (input.assignment && asgn.name !== input.assignment && asgn.folder !== input.assignment)
47305
47340
  continue;
47306
- const asgnAbsPath = join6(manifestDir, asgn.path);
47307
- if (!existsSync4(asgnAbsPath)) {
47341
+ const asgnAbsPath = join7(manifestDir, asgn.path);
47342
+ if (!existsSync5(asgnAbsPath)) {
47308
47343
  skipped++;
47309
47344
  continue;
47310
47345
  }
@@ -47318,7 +47353,7 @@ async function publishCourseHandler(raw) {
47318
47353
  skipped++;
47319
47354
  continue;
47320
47355
  }
47321
- asgn.id = await import_codio_api_js2.default.v1.assignment.createAssignment(manifest.courseId, {
47356
+ asgn.id = await codio.v1.assignment.createAssignment(manifest.courseId, {
47322
47357
  moduleId: mod.id,
47323
47358
  settings: { name: asgn.name }
47324
47359
  });
@@ -47342,9 +47377,9 @@ async function publishCourseHandler(raw) {
47342
47377
  const zipPath = findZip(asgnAbsPath);
47343
47378
  try {
47344
47379
  if (zipPath) {
47345
- await import_codio_api_js2.default.v1.assignment.publishArchive(manifest.courseId, asgn.id, zipPath, publishOpts);
47380
+ await codio.v1.assignment.publishArchive(manifest.courseId, asgn.id, zipPath, publishOpts);
47346
47381
  } else {
47347
- await import_codio_api_js2.default.v1.assignment.publish(manifest.courseId, asgn.id, asgnAbsPath, publishOpts);
47382
+ await codio.v1.assignment.publish(manifest.courseId, asgn.id, asgnAbsPath, publishOpts);
47348
47383
  }
47349
47384
  asgn.contentHash = computeContentHash(asgnAbsPath);
47350
47385
  saveManifest(input.manifestPath, manifest);
@@ -47358,19 +47393,19 @@ async function publishCourseHandler(raw) {
47358
47393
  }
47359
47394
 
47360
47395
  // src/tools/validate-guide.ts
47361
- import { existsSync as existsSync5, readdirSync as readdirSync3, readFileSync as readFileSync3, statSync as statSync3 } from "node:fs";
47362
- import { join as join7, relative as relative3 } from "node:path";
47396
+ import { existsSync as existsSync6, readdirSync as readdirSync3, readFileSync as readFileSync4, statSync as statSync2 } from "node:fs";
47397
+ import { join as join8, relative as relative2 } from "node:path";
47363
47398
  import { z as z6 } from "zod";
47364
47399
  var validateGuideInputSchema = z6.object({
47365
47400
  workspace: z6.string().min(1)
47366
47401
  });
47367
47402
  function walkJsonFiles(root) {
47368
- if (!existsSync5(root))
47403
+ if (!existsSync6(root))
47369
47404
  return [];
47370
47405
  const out = [];
47371
47406
  for (const name of readdirSync3(root)) {
47372
- const p = join7(root, name);
47373
- const s = statSync3(p);
47407
+ const p = join8(root, name);
47408
+ const s = statSync2(p);
47374
47409
  if (s.isDirectory())
47375
47410
  out.push(...walkJsonFiles(p));
47376
47411
  else if (name.endsWith(".json"))
@@ -47396,12 +47431,12 @@ var LANG_COMMENT_PREFIX2 = {
47396
47431
  sql: "--"
47397
47432
  };
47398
47433
  function walkMdFiles(root) {
47399
- if (!existsSync5(root))
47434
+ if (!existsSync6(root))
47400
47435
  return [];
47401
47436
  const out = [];
47402
47437
  for (const name of readdirSync3(root)) {
47403
- const p = join7(root, name);
47404
- const s = statSync3(p);
47438
+ const p = join8(root, name);
47439
+ const s = statSync2(p);
47405
47440
  if (s.isDirectory())
47406
47441
  out.push(...walkMdFiles(p));
47407
47442
  else if (name.endsWith(".md"))
@@ -47474,7 +47509,7 @@ async function validateGuideHandler(raw) {
47474
47509
  directory: input.workspace
47475
47510
  });
47476
47511
  const findings = [];
47477
- if (!existsSync5(content)) {
47512
+ if (!existsSync6(content)) {
47478
47513
  findings.push({
47479
47514
  category: "missing_content_dir",
47480
47515
  detail: `${content} does not exist`,
@@ -47485,7 +47520,7 @@ async function validateGuideHandler(raw) {
47485
47520
  for (const f of walkJsonFiles(guides)) {
47486
47521
  let parsed;
47487
47522
  try {
47488
- parsed = JSON.parse(readFileSync3(f, "utf8"));
47523
+ parsed = JSON.parse(readFileSync4(f, "utf8"));
47489
47524
  } catch {
47490
47525
  continue;
47491
47526
  }
@@ -47495,7 +47530,7 @@ async function validateGuideHandler(raw) {
47495
47530
  if (!isUuidV4(id)) {
47496
47531
  findings.push({
47497
47532
  category: "invalid_uuid",
47498
- detail: `${relative3(input.workspace, f)}: ${id}`,
47533
+ detail: `${relative2(input.workspace, f)}: ${id}`,
47499
47534
  severity: "error"
47500
47535
  });
47501
47536
  }
@@ -47506,45 +47541,45 @@ async function validateGuideHandler(raw) {
47506
47541
  continue;
47507
47542
  let parsed;
47508
47543
  try {
47509
- parsed = JSON.parse(readFileSync3(f, "utf8"));
47544
+ parsed = JSON.parse(readFileSync4(f, "utf8"));
47510
47545
  } catch {
47511
47546
  continue;
47512
47547
  }
47513
47548
  const base = f.slice(0, -"/index.json".length);
47514
47549
  for (const stem of parsed?.order ?? []) {
47515
- const jsonPair = existsSync5(join7(base, `${stem}.json`)) && existsSync5(join7(base, `${stem}.md`));
47516
- const chapter = existsSync5(join7(base, stem, "index.json"));
47550
+ const jsonPair = existsSync6(join8(base, `${stem}.json`)) && existsSync6(join8(base, `${stem}.md`));
47551
+ const chapter = existsSync6(join8(base, stem, "index.json"));
47517
47552
  if (!jsonPair && !chapter) {
47518
47553
  findings.push({
47519
47554
  category: "orphan_order_stem",
47520
- detail: `${relative3(input.workspace, f)} references missing stem '${stem}'`,
47555
+ detail: `${relative2(input.workspace, f)} references missing stem '${stem}'`,
47521
47556
  severity: "error"
47522
47557
  });
47523
47558
  }
47524
47559
  }
47525
47560
  }
47526
47561
  for (const md of walkMdFiles(content)) {
47527
- const body = readFileSync3(md, "utf8");
47562
+ const body = readFileSync4(md, "utf8");
47528
47563
  const re = new RegExp(ANY_TASKID_RE.source, "g");
47529
47564
  for (const match of body.matchAll(re)) {
47530
47565
  const tid = match[0];
47531
- if (!existsSync5(join7(assessments, `${tid}.json`))) {
47566
+ if (!existsSync6(join8(assessments, `${tid}.json`))) {
47532
47567
  findings.push({
47533
47568
  category: "broken_assessment_ref",
47534
- detail: `${relative3(input.workspace, md)} references missing ${tid}.json`,
47569
+ detail: `${relative2(input.workspace, md)} references missing ${tid}.json`,
47535
47570
  severity: "error"
47536
47571
  });
47537
47572
  }
47538
47573
  }
47539
47574
  }
47540
- if (existsSync5(assessments)) {
47575
+ if (existsSync6(assessments)) {
47541
47576
  for (const f of walkJsonFiles(assessments)) {
47542
47577
  if (!f.endsWith(".json"))
47543
47578
  continue;
47544
47579
  const expected = f.split("/").pop().replace(/\.json$/, "");
47545
47580
  let parsed;
47546
47581
  try {
47547
- parsed = JSON.parse(readFileSync3(f, "utf8"));
47582
+ parsed = JSON.parse(readFileSync4(f, "utf8"));
47548
47583
  } catch {
47549
47584
  continue;
47550
47585
  }
@@ -47552,7 +47587,7 @@ async function validateGuideHandler(raw) {
47552
47587
  if (expected !== actual) {
47553
47588
  findings.push({
47554
47589
  category: "taskid_filename_mismatch",
47555
- detail: `${relative3(input.workspace, f)}: filename '${expected}' vs taskId '${actual}'`,
47590
+ detail: `${relative2(input.workspace, f)}: filename '${expected}' vs taskId '${actual}'`,
47556
47591
  severity: "error"
47557
47592
  });
47558
47593
  }
@@ -47563,7 +47598,7 @@ async function validateGuideHandler(raw) {
47563
47598
  continue;
47564
47599
  let pageTitle;
47565
47600
  try {
47566
- const parsed = JSON.parse(readFileSync3(f, "utf8"));
47601
+ const parsed = JSON.parse(readFileSync4(f, "utf8"));
47567
47602
  pageTitle = parsed?.title;
47568
47603
  } catch {
47569
47604
  continue;
@@ -47571,34 +47606,34 @@ async function validateGuideHandler(raw) {
47571
47606
  if (!pageTitle)
47572
47607
  continue;
47573
47608
  const mdPath = f.replace(/\.json$/, ".md");
47574
- if (!existsSync5(mdPath))
47609
+ if (!existsSync6(mdPath))
47575
47610
  continue;
47576
- const body = readFileSync3(mdPath, "utf8");
47611
+ const body = readFileSync4(mdPath, "utf8");
47577
47612
  const firstH1 = findFirstH1(body);
47578
47613
  if (firstH1 && firstH1 === pageTitle) {
47579
47614
  findings.push({
47580
47615
  category: "double_header",
47581
- detail: `${relative3(input.workspace, mdPath)}: first H1 "${firstH1}" duplicates page title — remove H1 from body`,
47616
+ detail: `${relative2(input.workspace, mdPath)}: first H1 "${firstH1}" duplicates page title — remove H1 from body`,
47582
47617
  severity: "warning"
47583
47618
  });
47584
47619
  }
47585
47620
  }
47586
47621
  for (const md of walkMdFiles(content)) {
47587
- const body = readFileSync3(md, "utf8");
47622
+ const body = readFileSync4(md, "utf8");
47588
47623
  for (const err of checkFreezeDirectives(body)) {
47589
47624
  findings.push({
47590
47625
  category: "freeze_syntax_error",
47591
- detail: `${relative3(input.workspace, md)}: ${err}`,
47626
+ detail: `${relative2(input.workspace, md)}: ${err}`,
47592
47627
  severity: "error"
47593
47628
  });
47594
47629
  }
47595
47630
  }
47596
47631
  for (const md of walkMdFiles(content)) {
47597
- const body = readFileSync3(md, "utf8");
47632
+ const body = readFileSync4(md, "utf8");
47598
47633
  for (const err of findMalformedTryIt(body)) {
47599
47634
  findings.push({
47600
47635
  category: "try_it_syntax_error",
47601
- detail: `${relative3(input.workspace, md)}: ${err}`,
47636
+ detail: `${relative2(input.workspace, md)}: ${err}`,
47602
47637
  severity: "error"
47603
47638
  });
47604
47639
  }
@@ -47608,7 +47643,7 @@ async function validateGuideHandler(raw) {
47608
47643
  continue;
47609
47644
  let parsed;
47610
47645
  try {
47611
- parsed = JSON.parse(readFileSync3(f, "utf8"));
47646
+ parsed = JSON.parse(readFileSync4(f, "utf8"));
47612
47647
  } catch {
47613
47648
  continue;
47614
47649
  }
@@ -47616,10 +47651,10 @@ async function validateGuideHandler(raw) {
47616
47651
  const filePath = entry?.path;
47617
47652
  if (!filePath)
47618
47653
  continue;
47619
- if (!existsSync5(join7(input.workspace, filePath))) {
47654
+ if (!existsSync6(join8(input.workspace, filePath))) {
47620
47655
  findings.push({
47621
47656
  category: "missing_referenced_file",
47622
- detail: `${relative3(input.workspace, f)}: references file "${filePath}" which does not exist in workspace`,
47657
+ detail: `${relative2(input.workspace, f)}: references file "${filePath}" which does not exist in workspace`,
47623
47658
  severity: "warning"
47624
47659
  });
47625
47660
  }
@@ -47663,7 +47698,7 @@ var fetch_course = tool({
47663
47698
  }
47664
47699
  });
47665
47700
  var publish_course = tool({
47666
- description: "Publish Codio course assignments to the platform. Reads course-manifest.json, creates missing courses/modules/assignments, and publishes each one. Skips unchanged assignments by content hash. Returns { published, created, unchanged, skipped }.",
47701
+ description: "Publish Codio course assignments to the platform. Reads course-manifest.json from manifestPath, creates missing courses/modules/assignments, and publishes each one. Skips unchanged assignments by content hash. Returns { published, created, unchanged, skipped }.",
47667
47702
  args: publishCourseInputSchema.shape,
47668
47703
  async execute(args) {
47669
47704
  return JSON.stringify(await publishCourseHandler(args));
@@ -1 +1 @@
1
- {"version":3,"file":"fetch-course.d.ts","sourceRoot":"","sources":["../../src/tools/fetch-course.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,sBAAsB;;;;;iBAQjC,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;CACzB;AAoED,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAoGjF"}
1
+ {"version":3,"file":"fetch-course.d.ts","sourceRoot":"","sources":["../../src/tools/fetch-course.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,sBAAsB;;;;;iBAQjC,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;CACzB;AAyDD,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA8GjF"}
@@ -76,6 +76,7 @@ export declare const fetch_course: {
76
76
  export declare const publish_course: {
77
77
  description: string;
78
78
  args: {
79
+ workspace: import("zod").ZodString;
79
80
  manifestPath: import("zod").ZodString;
80
81
  dryRun: import("zod").ZodOptional<import("zod").ZodBoolean>;
81
82
  force: import("zod").ZodOptional<import("zod").ZodBoolean>;
@@ -85,6 +86,7 @@ export declare const publish_course: {
85
86
  stack: import("zod").ZodOptional<import("zod").ZodString>;
86
87
  };
87
88
  execute(args: {
89
+ workspace: string;
88
90
  manifestPath: string;
89
91
  dryRun?: boolean | undefined;
90
92
  force?: boolean | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAOtB,CAAC;AAOH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;CAkB5B,CAAC;AAIH,eAAO,MAAM,cAAc;;;;;;;;CAOzB,CAAC;AAIH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;CAOvB,CAAC;AAIH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;CAOzB,CAAC;AAQH,eAAO,MAAM,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAMzC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAOtB,CAAC;AAOH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;CAkB5B,CAAC;AAIH,eAAO,MAAM,cAAc;;;;;;;;CAOzB,CAAC;AAIH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;CAOvB,CAAC;AAIH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;CAOzB,CAAC;AAQH,eAAO,MAAM,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAMzC,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { z } from 'zod';
2
2
  export declare const publishCourseInputSchema: z.ZodObject<{
3
+ workspace: z.ZodString;
3
4
  manifestPath: z.ZodString;
4
5
  dryRun: z.ZodOptional<z.ZodBoolean>;
5
6
  force: z.ZodOptional<z.ZodBoolean>;
@@ -1 +1 @@
1
- {"version":3,"file":"publish-course.d.ts","sourceRoot":"","sources":["../../src/tools/publish-course.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,wBAAwB;;;;;;;;iBAQnC,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;CACjB;AA6DD,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAoHrF"}
1
+ {"version":3,"file":"publish-course.d.ts","sourceRoot":"","sources":["../../src/tools/publish-course.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,wBAAwB;;;;;;;;;iBASnC,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;CACjB;AA6DD,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA2HrF"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Walk up from startDir looking for a .env file.
3
+ * When found, load it with override semantics — .env values always win
4
+ * over whatever is already in process.env.
5
+ */
6
+ export declare function loadEnvWalkUp(startDir: string): void;
7
+ //# sourceMappingURL=load-env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-env.d.ts","sourceRoot":"","sources":["../../src/utils/load-env.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAoBpD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codio-ai/opencode-authoring-agent",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Opencode plugin for authoring Codio guide assignments — orchestrator, subagents, tools, and skills.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",