@codio-ai/opencode-authoring-agent 0.1.4 → 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\`
@@ -47034,18 +47034,50 @@ ${freezeErrors.join(`
47034
47034
  // src/tools/fetch-course.ts
47035
47035
  import { execFile } from "node:child_process";
47036
47036
  import {
47037
- existsSync as existsSync3,
47037
+ copyFileSync,
47038
+ existsSync as existsSync4,
47038
47039
  mkdirSync as mkdirSync2,
47039
47040
  readdirSync,
47040
47041
  rmSync,
47041
47042
  statSync,
47042
47043
  unlinkSync as unlinkSync2
47043
47044
  } from "node:fs";
47044
- import { writeFile, mkdir } from "node:fs/promises";
47045
+ import { mkdir, writeFile } from "node:fs/promises";
47045
47046
  import { tmpdir } from "node:os";
47046
- import { dirname as dirname2, join as join5, relative } from "node:path";
47047
+ import { dirname as dirname3, join as join6 } from "node:path";
47047
47048
  import { promisify } from "node:util";
47048
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
47049
47081
  var execFileAsync = promisify(execFile);
47050
47082
  var fetchCourseInputSchema = z4.object({
47051
47083
  workspace: z4.string().min(1).describe("Absolute path to the Codio workspace root"),
@@ -47063,7 +47095,7 @@ async function extractZip(zipPath, destDir) {
47063
47095
  function findTarZstFiles(dir) {
47064
47096
  const results = [];
47065
47097
  for (const name of readdirSync(dir)) {
47066
- const full = join5(dir, name);
47098
+ const full = join6(dir, name);
47067
47099
  if (statSync(full).isDirectory())
47068
47100
  results.push(...findTarZstFiles(full));
47069
47101
  else if (name.endsWith(".tar.zst"))
@@ -47080,10 +47112,10 @@ async function extractTarZstArchives(stagingDir) {
47080
47112
  }
47081
47113
  }
47082
47114
  function removeExportedReadmes(dir) {
47083
- if (!existsSync3(dir))
47115
+ if (!existsSync4(dir))
47084
47116
  return;
47085
47117
  for (const name of readdirSync(dir)) {
47086
- const full = join5(dir, name);
47118
+ const full = join6(dir, name);
47087
47119
  if (statSync(full).isDirectory())
47088
47120
  removeExportedReadmes(full);
47089
47121
  else if (name.toLowerCase() === "readme.md")
@@ -47093,18 +47125,17 @@ function removeExportedReadmes(dir) {
47093
47125
  function copyDir(src, dst) {
47094
47126
  mkdirSync2(dst, { recursive: true });
47095
47127
  for (const name of readdirSync(src)) {
47096
- const srcPath = join5(src, name);
47097
- const dstPath = join5(dst, name);
47128
+ const srcPath = join6(src, name);
47129
+ const dstPath = join6(dst, name);
47098
47130
  if (statSync(srcPath).isDirectory())
47099
47131
  copyDir(srcPath, dstPath);
47100
- else {
47101
- const { copyFileSync } = __require("node:fs");
47132
+ else
47102
47133
  copyFileSync(srcPath, dstPath);
47103
- }
47104
47134
  }
47105
47135
  }
47106
47136
  async function fetchCourseHandler(raw) {
47107
47137
  const input = fetchCourseInputSchema.parse(raw);
47138
+ loadEnvWalkUp(input.workspace);
47108
47139
  const [{ default: codio }, { json2csv }] = await Promise.all([
47109
47140
  Promise.resolve().then(() => __toESM(require_lib3(), 1)),
47110
47141
  Promise.resolve().then(() => __toESM(require_converter(), 1))
@@ -47112,14 +47143,14 @@ async function fetchCourseHandler(raw) {
47112
47143
  const clientId = process.env["CODIO_CLIENT_ID"];
47113
47144
  const clientSecret = process.env["CODIO_CLIENT_SECRET"];
47114
47145
  if (!clientId || !clientSecret) {
47115
- 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.");
47116
47147
  }
47117
47148
  const domain = input.domain ?? process.env["CODIO_DOMAIN"] ?? "codio.com";
47118
47149
  const outputFolderName = input.outputDir ?? "course-project";
47119
- const outputDir = join5(input.workspace, outputFolderName);
47120
- const contentDir = join5(outputDir, "course-content");
47121
- const manifestPath = join5(outputDir, "course-manifest.json");
47122
- const csvPath = join5(outputDir, "course-assignments.csv");
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");
47123
47154
  codio.v1.setDomain(domain);
47124
47155
  await codio.v1.auth(clientId, clientSecret);
47125
47156
  const courseInfo = await codio.v1.course.info(input.courseId);
@@ -47158,7 +47189,7 @@ async function fetchCourseHandler(raw) {
47158
47189
  };
47159
47190
  rmSync(outputDir, { recursive: true, force: true });
47160
47191
  mkdirSync2(contentDir, { recursive: true });
47161
- await mkdir(dirname2(manifestPath), { recursive: true });
47192
+ await mkdir(dirname3(manifestPath), { recursive: true });
47162
47193
  await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}
47163
47194
  `, "utf8");
47164
47195
  const rows = modules.flatMap((m) => m.assignments.map((a) => ({
@@ -47172,12 +47203,12 @@ async function fetchCourseHandler(raw) {
47172
47203
  })));
47173
47204
  const csv = await json2csv(rows, { emptyFieldValue: "", prependHeader: true });
47174
47205
  await writeFile(csvPath, csv, "utf8");
47175
- const workDir = join5(tmpdir(), `codio-fetch-${Date.now()}`);
47176
- const zipPath = join5(workDir, "course-export.zip");
47206
+ const workDir = join6(tmpdir(), `codio-fetch-${Date.now()}`);
47207
+ const zipPath = join6(workDir, "course-export.zip");
47177
47208
  mkdirSync2(workDir, { recursive: true });
47178
47209
  try {
47179
47210
  await codio.v1.course.downloadSourceExport(input.courseId, zipPath);
47180
- const stagingDir = join5(workDir, "staging");
47211
+ const stagingDir = join6(workDir, "staging");
47181
47212
  await extractZip(zipPath, stagingDir);
47182
47213
  await extractTarZstArchives(stagingDir);
47183
47214
  removeExportedReadmes(stagingDir);
@@ -47197,15 +47228,16 @@ async function fetchCourseHandler(raw) {
47197
47228
  // src/tools/publish-course.ts
47198
47229
  import { createHash } from "node:crypto";
47199
47230
  import {
47200
- existsSync as existsSync4,
47231
+ existsSync as existsSync5,
47201
47232
  readdirSync as readdirSync2,
47202
- readFileSync as readFileSync2,
47203
- writeFileSync as writeFileSync4
47233
+ readFileSync as readFileSync3,
47234
+ writeFileSync as writeFileSync3
47204
47235
  } from "node:fs";
47205
- import { join as join6, relative as relative2 } from "node:path";
47236
+ import { join as join7, relative } from "node:path";
47206
47237
  import { z as z5 } from "zod";
47207
47238
  var DEFAULT_STACK = "e0195698-d647-4490-8834-350583b532eb:latest";
47208
47239
  var publishCourseInputSchema = z5.object({
47240
+ workspace: z5.string().min(1).describe("Absolute path to the Codio workspace root (where .env lives)"),
47209
47241
  manifestPath: z5.string().min(1).describe("Absolute path to course-manifest.json"),
47210
47242
  dryRun: z5.boolean().optional().describe("Preview actions without making changes"),
47211
47243
  force: z5.boolean().optional().describe("Publish all, bypassing change detection"),
@@ -47215,17 +47247,17 @@ var publishCourseInputSchema = z5.object({
47215
47247
  stack: z5.string().optional().describe("Force a specific stack ID for all assignments")
47216
47248
  });
47217
47249
  function saveManifest(manifestPath, manifest) {
47218
- writeFileSync4(manifestPath, `${JSON.stringify(manifest, null, 2)}
47250
+ writeFileSync3(manifestPath, `${JSON.stringify(manifest, null, 2)}
47219
47251
  `, "utf8");
47220
47252
  }
47221
47253
  function findZip(dir) {
47222
47254
  const zip = readdirSync2(dir).find((f) => f.endsWith(".zip"));
47223
- return zip ? join6(dir, zip) : null;
47255
+ return zip ? join7(dir, zip) : null;
47224
47256
  }
47225
47257
  function walkFiles(dir) {
47226
47258
  const results = [];
47227
47259
  for (const entry of readdirSync2(dir, { withFileTypes: true })) {
47228
- const full = join6(dir, entry.name);
47260
+ const full = join7(dir, entry.name);
47229
47261
  if (entry.isDirectory())
47230
47262
  results.push(...walkFiles(full));
47231
47263
  else
@@ -47237,12 +47269,12 @@ function computeContentHash(dir) {
47237
47269
  const hash = createHash("sha256");
47238
47270
  const zipPath = findZip(dir);
47239
47271
  if (zipPath) {
47240
- hash.update(readFileSync2(zipPath));
47272
+ hash.update(readFileSync3(zipPath));
47241
47273
  } else {
47242
47274
  for (const file of walkFiles(dir).sort()) {
47243
- hash.update(relative2(dir, file));
47275
+ hash.update(relative(dir, file));
47244
47276
  hash.update("\x00");
47245
- hash.update(readFileSync2(file));
47277
+ hash.update(readFileSync3(file));
47246
47278
  hash.update("\x00");
47247
47279
  }
47248
47280
  }
@@ -47250,20 +47282,21 @@ function computeContentHash(dir) {
47250
47282
  }
47251
47283
  async function publishCourseHandler(raw) {
47252
47284
  const input = publishCourseInputSchema.parse(raw);
47285
+ loadEnvWalkUp(input.workspace);
47253
47286
  const { default: codio } = await Promise.resolve().then(() => __toESM(require_lib3(), 1));
47254
47287
  const clientId = process.env["CODIO_CLIENT_ID"];
47255
47288
  const clientSecret = process.env["CODIO_CLIENT_SECRET"];
47256
47289
  if (!clientId || !clientSecret) {
47257
47290
  throw new Error("CODIO_CLIENT_ID and CODIO_CLIENT_SECRET must be set as environment variables on the box.");
47258
47291
  }
47259
- if (!existsSync4(input.manifestPath)) {
47292
+ if (!existsSync5(input.manifestPath)) {
47260
47293
  throw new Error(`course-manifest.json not found at ${input.manifestPath}`);
47261
47294
  }
47262
47295
  const domain = process.env["CODIO_DOMAIN"] ?? "codio.com";
47263
47296
  codio.v1.setDomain(domain);
47264
47297
  await codio.v1.auth(clientId, clientSecret);
47265
- const manifest = JSON.parse(readFileSync2(input.manifestPath, "utf8"));
47266
- const manifestDir = join6(input.manifestPath, "..");
47298
+ const manifest = JSON.parse(readFileSync3(input.manifestPath, "utf8"));
47299
+ const manifestDir = join7(input.manifestPath, "..");
47267
47300
  if (!manifest.courseId) {
47268
47301
  const courseName = manifest.courseName ?? "Codio Course";
47269
47302
  if (input.dryRun) {
@@ -47305,8 +47338,8 @@ async function publishCourseHandler(raw) {
47305
47338
  for (const asgn of mod.assignments) {
47306
47339
  if (input.assignment && asgn.name !== input.assignment && asgn.folder !== input.assignment)
47307
47340
  continue;
47308
- const asgnAbsPath = join6(manifestDir, asgn.path);
47309
- if (!existsSync4(asgnAbsPath)) {
47341
+ const asgnAbsPath = join7(manifestDir, asgn.path);
47342
+ if (!existsSync5(asgnAbsPath)) {
47310
47343
  skipped++;
47311
47344
  continue;
47312
47345
  }
@@ -47360,19 +47393,19 @@ async function publishCourseHandler(raw) {
47360
47393
  }
47361
47394
 
47362
47395
  // src/tools/validate-guide.ts
47363
- import { existsSync as existsSync5, readdirSync as readdirSync3, readFileSync as readFileSync3, statSync as statSync3 } from "node:fs";
47364
- 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";
47365
47398
  import { z as z6 } from "zod";
47366
47399
  var validateGuideInputSchema = z6.object({
47367
47400
  workspace: z6.string().min(1)
47368
47401
  });
47369
47402
  function walkJsonFiles(root) {
47370
- if (!existsSync5(root))
47403
+ if (!existsSync6(root))
47371
47404
  return [];
47372
47405
  const out = [];
47373
47406
  for (const name of readdirSync3(root)) {
47374
- const p = join7(root, name);
47375
- const s = statSync3(p);
47407
+ const p = join8(root, name);
47408
+ const s = statSync2(p);
47376
47409
  if (s.isDirectory())
47377
47410
  out.push(...walkJsonFiles(p));
47378
47411
  else if (name.endsWith(".json"))
@@ -47398,12 +47431,12 @@ var LANG_COMMENT_PREFIX2 = {
47398
47431
  sql: "--"
47399
47432
  };
47400
47433
  function walkMdFiles(root) {
47401
- if (!existsSync5(root))
47434
+ if (!existsSync6(root))
47402
47435
  return [];
47403
47436
  const out = [];
47404
47437
  for (const name of readdirSync3(root)) {
47405
- const p = join7(root, name);
47406
- const s = statSync3(p);
47438
+ const p = join8(root, name);
47439
+ const s = statSync2(p);
47407
47440
  if (s.isDirectory())
47408
47441
  out.push(...walkMdFiles(p));
47409
47442
  else if (name.endsWith(".md"))
@@ -47476,7 +47509,7 @@ async function validateGuideHandler(raw) {
47476
47509
  directory: input.workspace
47477
47510
  });
47478
47511
  const findings = [];
47479
- if (!existsSync5(content)) {
47512
+ if (!existsSync6(content)) {
47480
47513
  findings.push({
47481
47514
  category: "missing_content_dir",
47482
47515
  detail: `${content} does not exist`,
@@ -47487,7 +47520,7 @@ async function validateGuideHandler(raw) {
47487
47520
  for (const f of walkJsonFiles(guides)) {
47488
47521
  let parsed;
47489
47522
  try {
47490
- parsed = JSON.parse(readFileSync3(f, "utf8"));
47523
+ parsed = JSON.parse(readFileSync4(f, "utf8"));
47491
47524
  } catch {
47492
47525
  continue;
47493
47526
  }
@@ -47497,7 +47530,7 @@ async function validateGuideHandler(raw) {
47497
47530
  if (!isUuidV4(id)) {
47498
47531
  findings.push({
47499
47532
  category: "invalid_uuid",
47500
- detail: `${relative3(input.workspace, f)}: ${id}`,
47533
+ detail: `${relative2(input.workspace, f)}: ${id}`,
47501
47534
  severity: "error"
47502
47535
  });
47503
47536
  }
@@ -47508,45 +47541,45 @@ async function validateGuideHandler(raw) {
47508
47541
  continue;
47509
47542
  let parsed;
47510
47543
  try {
47511
- parsed = JSON.parse(readFileSync3(f, "utf8"));
47544
+ parsed = JSON.parse(readFileSync4(f, "utf8"));
47512
47545
  } catch {
47513
47546
  continue;
47514
47547
  }
47515
47548
  const base = f.slice(0, -"/index.json".length);
47516
47549
  for (const stem of parsed?.order ?? []) {
47517
- const jsonPair = existsSync5(join7(base, `${stem}.json`)) && existsSync5(join7(base, `${stem}.md`));
47518
- 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"));
47519
47552
  if (!jsonPair && !chapter) {
47520
47553
  findings.push({
47521
47554
  category: "orphan_order_stem",
47522
- detail: `${relative3(input.workspace, f)} references missing stem '${stem}'`,
47555
+ detail: `${relative2(input.workspace, f)} references missing stem '${stem}'`,
47523
47556
  severity: "error"
47524
47557
  });
47525
47558
  }
47526
47559
  }
47527
47560
  }
47528
47561
  for (const md of walkMdFiles(content)) {
47529
- const body = readFileSync3(md, "utf8");
47562
+ const body = readFileSync4(md, "utf8");
47530
47563
  const re = new RegExp(ANY_TASKID_RE.source, "g");
47531
47564
  for (const match of body.matchAll(re)) {
47532
47565
  const tid = match[0];
47533
- if (!existsSync5(join7(assessments, `${tid}.json`))) {
47566
+ if (!existsSync6(join8(assessments, `${tid}.json`))) {
47534
47567
  findings.push({
47535
47568
  category: "broken_assessment_ref",
47536
- detail: `${relative3(input.workspace, md)} references missing ${tid}.json`,
47569
+ detail: `${relative2(input.workspace, md)} references missing ${tid}.json`,
47537
47570
  severity: "error"
47538
47571
  });
47539
47572
  }
47540
47573
  }
47541
47574
  }
47542
- if (existsSync5(assessments)) {
47575
+ if (existsSync6(assessments)) {
47543
47576
  for (const f of walkJsonFiles(assessments)) {
47544
47577
  if (!f.endsWith(".json"))
47545
47578
  continue;
47546
47579
  const expected = f.split("/").pop().replace(/\.json$/, "");
47547
47580
  let parsed;
47548
47581
  try {
47549
- parsed = JSON.parse(readFileSync3(f, "utf8"));
47582
+ parsed = JSON.parse(readFileSync4(f, "utf8"));
47550
47583
  } catch {
47551
47584
  continue;
47552
47585
  }
@@ -47554,7 +47587,7 @@ async function validateGuideHandler(raw) {
47554
47587
  if (expected !== actual) {
47555
47588
  findings.push({
47556
47589
  category: "taskid_filename_mismatch",
47557
- detail: `${relative3(input.workspace, f)}: filename '${expected}' vs taskId '${actual}'`,
47590
+ detail: `${relative2(input.workspace, f)}: filename '${expected}' vs taskId '${actual}'`,
47558
47591
  severity: "error"
47559
47592
  });
47560
47593
  }
@@ -47565,7 +47598,7 @@ async function validateGuideHandler(raw) {
47565
47598
  continue;
47566
47599
  let pageTitle;
47567
47600
  try {
47568
- const parsed = JSON.parse(readFileSync3(f, "utf8"));
47601
+ const parsed = JSON.parse(readFileSync4(f, "utf8"));
47569
47602
  pageTitle = parsed?.title;
47570
47603
  } catch {
47571
47604
  continue;
@@ -47573,34 +47606,34 @@ async function validateGuideHandler(raw) {
47573
47606
  if (!pageTitle)
47574
47607
  continue;
47575
47608
  const mdPath = f.replace(/\.json$/, ".md");
47576
- if (!existsSync5(mdPath))
47609
+ if (!existsSync6(mdPath))
47577
47610
  continue;
47578
- const body = readFileSync3(mdPath, "utf8");
47611
+ const body = readFileSync4(mdPath, "utf8");
47579
47612
  const firstH1 = findFirstH1(body);
47580
47613
  if (firstH1 && firstH1 === pageTitle) {
47581
47614
  findings.push({
47582
47615
  category: "double_header",
47583
- 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`,
47584
47617
  severity: "warning"
47585
47618
  });
47586
47619
  }
47587
47620
  }
47588
47621
  for (const md of walkMdFiles(content)) {
47589
- const body = readFileSync3(md, "utf8");
47622
+ const body = readFileSync4(md, "utf8");
47590
47623
  for (const err of checkFreezeDirectives(body)) {
47591
47624
  findings.push({
47592
47625
  category: "freeze_syntax_error",
47593
- detail: `${relative3(input.workspace, md)}: ${err}`,
47626
+ detail: `${relative2(input.workspace, md)}: ${err}`,
47594
47627
  severity: "error"
47595
47628
  });
47596
47629
  }
47597
47630
  }
47598
47631
  for (const md of walkMdFiles(content)) {
47599
- const body = readFileSync3(md, "utf8");
47632
+ const body = readFileSync4(md, "utf8");
47600
47633
  for (const err of findMalformedTryIt(body)) {
47601
47634
  findings.push({
47602
47635
  category: "try_it_syntax_error",
47603
- detail: `${relative3(input.workspace, md)}: ${err}`,
47636
+ detail: `${relative2(input.workspace, md)}: ${err}`,
47604
47637
  severity: "error"
47605
47638
  });
47606
47639
  }
@@ -47610,7 +47643,7 @@ async function validateGuideHandler(raw) {
47610
47643
  continue;
47611
47644
  let parsed;
47612
47645
  try {
47613
- parsed = JSON.parse(readFileSync3(f, "utf8"));
47646
+ parsed = JSON.parse(readFileSync4(f, "utf8"));
47614
47647
  } catch {
47615
47648
  continue;
47616
47649
  }
@@ -47618,10 +47651,10 @@ async function validateGuideHandler(raw) {
47618
47651
  const filePath = entry?.path;
47619
47652
  if (!filePath)
47620
47653
  continue;
47621
- if (!existsSync5(join7(input.workspace, filePath))) {
47654
+ if (!existsSync6(join8(input.workspace, filePath))) {
47622
47655
  findings.push({
47623
47656
  category: "missing_referenced_file",
47624
- 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`,
47625
47658
  severity: "warning"
47626
47659
  });
47627
47660
  }
@@ -47665,7 +47698,7 @@ var fetch_course = tool({
47665
47698
  }
47666
47699
  });
47667
47700
  var publish_course = tool({
47668
- 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 }.",
47669
47702
  args: publishCourseInputSchema.shape,
47670
47703
  async execute(args) {
47671
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":"AAcA,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,CA0GjF"}
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":"AASA,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,CAuHrF"}
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.4",
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",