@codio-ai/opencode-authoring-agent 0.1.0 → 0.1.3
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/bin/codio-authoring-register.js +1 -1
- package/dist/agents/orchestrator.d.ts.map +1 -1
- package/dist/agents/page-author.d.ts.map +1 -1
- package/dist/codio-scripts/codio-fetch.js +45931 -0
- package/dist/codio-scripts/codio-publish.js +44984 -0
- package/dist/index.js +46380 -33
- package/dist/tools/create-page.d.ts +1 -0
- package/dist/tools/create-page.d.ts.map +1 -1
- package/dist/tools/fetch-course.d.ts +17 -0
- package/dist/tools/fetch-course.d.ts.map +1 -0
- package/dist/tools/fetch-course.test.d.ts +2 -0
- package/dist/tools/fetch-course.test.d.ts.map +1 -0
- package/dist/tools/index.d.ts +36 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/publish-course.d.ts +20 -0
- package/dist/tools/publish-course.d.ts.map +1 -0
- package/dist/tools/publish-course.test.d.ts +2 -0
- package/dist/tools/publish-course.test.d.ts.map +1 -0
- package/dist/tools/validate-guide.d.ts +1 -1
- package/dist/tools/validate-guide.d.ts.map +1 -1
- package/package.json +8 -18
- package/src/skills/reference-codio-api/SKILL.md +149 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
export declare function validateFreezeDirectives(markdownBody: string): string[];
|
|
2
3
|
export declare const PAGE_TYPES: readonly ["intro", "objectives", "instructional", "assessment", "conclusion"];
|
|
3
4
|
export declare const PAGE_LAYOUTS: readonly ["1-panel", "2-panels-tree"];
|
|
4
5
|
export declare const createPageInputSchema: z.ZodObject<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-page.d.ts","sourceRoot":"","sources":["../../src/tools/create-page.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"create-page.d.ts","sourceRoot":"","sources":["../../src/tools/create-page.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAWxB,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,EAAE,CA6BvE;AAED,eAAO,MAAM,UAAU,+EAMb,CAAC;AAEX,eAAO,MAAM,YAAY,uCAAwC,CAAC;AAElE,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;iBAuB/B,CAAC;AAEJ,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,UAAU,CAAC;IACxB,MAAM,EAAE,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;IACtC,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,eAAe,GAAG,QAAQ,CAgB9D;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,KAAK,EAAE,eAAe,GACrB,gBAAgB,CA6BlB;AAED,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,gBAAgB,CAAC,CAO3B"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const fetchCourseInputSchema: z.ZodObject<{
|
|
3
|
+
workspace: z.ZodString;
|
|
4
|
+
courseId: z.ZodString;
|
|
5
|
+
outputDir: z.ZodOptional<z.ZodString>;
|
|
6
|
+
domain: z.ZodOptional<z.ZodString>;
|
|
7
|
+
}, z.core.$strip>;
|
|
8
|
+
export type FetchCourseInput = z.infer<typeof fetchCourseInputSchema>;
|
|
9
|
+
export interface FetchCourseResult {
|
|
10
|
+
outputDir: string;
|
|
11
|
+
manifestPath: string;
|
|
12
|
+
assignmentsCsvPath: string;
|
|
13
|
+
moduleCount: number;
|
|
14
|
+
assignmentCount: number;
|
|
15
|
+
}
|
|
16
|
+
export declare function fetchCourseHandler(raw: unknown): Promise<FetchCourseResult>;
|
|
17
|
+
//# sourceMappingURL=fetch-course.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch-course.test.d.ts","sourceRoot":"","sources":["../../src/tools/fetch-course.test.ts"],"names":[],"mappings":""}
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -58,5 +58,41 @@ export declare const validate_guide: {
|
|
|
58
58
|
workspace: string;
|
|
59
59
|
}, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
|
|
60
60
|
};
|
|
61
|
+
export declare const fetch_course: {
|
|
62
|
+
description: string;
|
|
63
|
+
args: {
|
|
64
|
+
workspace: import("zod").ZodString;
|
|
65
|
+
courseId: import("zod").ZodString;
|
|
66
|
+
outputDir: import("zod").ZodOptional<import("zod").ZodString>;
|
|
67
|
+
domain: import("zod").ZodOptional<import("zod").ZodString>;
|
|
68
|
+
};
|
|
69
|
+
execute(args: {
|
|
70
|
+
workspace: string;
|
|
71
|
+
courseId: string;
|
|
72
|
+
outputDir?: string | undefined;
|
|
73
|
+
domain?: string | undefined;
|
|
74
|
+
}, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
|
|
75
|
+
};
|
|
76
|
+
export declare const publish_course: {
|
|
77
|
+
description: string;
|
|
78
|
+
args: {
|
|
79
|
+
manifestPath: import("zod").ZodString;
|
|
80
|
+
dryRun: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
81
|
+
force: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
82
|
+
module: import("zod").ZodOptional<import("zod").ZodString>;
|
|
83
|
+
assignment: import("zod").ZodOptional<import("zod").ZodString>;
|
|
84
|
+
changelog: import("zod").ZodOptional<import("zod").ZodString>;
|
|
85
|
+
stack: import("zod").ZodOptional<import("zod").ZodString>;
|
|
86
|
+
};
|
|
87
|
+
execute(args: {
|
|
88
|
+
manifestPath: string;
|
|
89
|
+
dryRun?: boolean | undefined;
|
|
90
|
+
force?: boolean | undefined;
|
|
91
|
+
module?: string | undefined;
|
|
92
|
+
assignment?: string | undefined;
|
|
93
|
+
changelog?: string | undefined;
|
|
94
|
+
stack?: string | undefined;
|
|
95
|
+
}, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
|
|
96
|
+
};
|
|
61
97
|
export declare const tools: Record<string, unknown>;
|
|
62
98
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"
|
|
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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const publishCourseInputSchema: z.ZodObject<{
|
|
3
|
+
manifestPath: z.ZodString;
|
|
4
|
+
dryRun: z.ZodOptional<z.ZodBoolean>;
|
|
5
|
+
force: z.ZodOptional<z.ZodBoolean>;
|
|
6
|
+
module: z.ZodOptional<z.ZodString>;
|
|
7
|
+
assignment: z.ZodOptional<z.ZodString>;
|
|
8
|
+
changelog: z.ZodOptional<z.ZodString>;
|
|
9
|
+
stack: z.ZodOptional<z.ZodString>;
|
|
10
|
+
}, z.core.$strip>;
|
|
11
|
+
export type PublishCourseInput = z.infer<typeof publishCourseInputSchema>;
|
|
12
|
+
export interface PublishCourseResult {
|
|
13
|
+
published: number;
|
|
14
|
+
created: number;
|
|
15
|
+
unchanged: number;
|
|
16
|
+
skipped: number;
|
|
17
|
+
dryRun: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare function publishCourseHandler(raw: unknown): Promise<PublishCourseResult>;
|
|
20
|
+
//# sourceMappingURL=publish-course.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish-course.test.d.ts","sourceRoot":"","sources":["../../src/tools/publish-course.test.ts"],"names":[],"mappings":""}
|
|
@@ -3,7 +3,7 @@ export declare const validateGuideInputSchema: z.ZodObject<{
|
|
|
3
3
|
workspace: z.ZodString;
|
|
4
4
|
}, z.core.$strip>;
|
|
5
5
|
export type ValidateGuideInput = z.infer<typeof validateGuideInputSchema>;
|
|
6
|
-
export type FindingCategory = 'missing_content_dir' | 'invalid_uuid' | 'orphan_order_stem' | 'broken_assessment_ref' | 'taskid_filename_mismatch';
|
|
6
|
+
export type FindingCategory = 'missing_content_dir' | 'invalid_uuid' | 'orphan_order_stem' | 'broken_assessment_ref' | 'taskid_filename_mismatch' | 'double_header' | 'freeze_syntax_error' | 'try_it_syntax_error' | 'missing_referenced_file';
|
|
7
7
|
export interface Finding {
|
|
8
8
|
category: FindingCategory;
|
|
9
9
|
detail: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-guide.d.ts","sourceRoot":"","sources":["../../src/tools/validate-guide.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,wBAAwB;;iBAEnC,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,MAAM,MAAM,eAAe,GACvB,qBAAqB,GACrB,cAAc,GACd,mBAAmB,GACnB,uBAAuB,GACvB,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"validate-guide.d.ts","sourceRoot":"","sources":["../../src/tools/validate-guide.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,wBAAwB;;iBAEnC,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,MAAM,MAAM,eAAe,GACvB,qBAAqB,GACrB,cAAc,GACd,mBAAmB,GACnB,uBAAuB,GACvB,0BAA0B,GAC1B,eAAe,GACf,qBAAqB,GACrB,qBAAqB,GACrB,yBAAyB,CAAC;AAE9B,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,eAAe,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;CAC/B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;CACjB;AAgGD,wBAAsB,oBAAoB,CACxC,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,mBAAmB,CAAC,CA+K9B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codio-ai/opencode-authoring-agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
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",
|
|
@@ -11,16 +11,10 @@
|
|
|
11
11
|
"types": "./dist/index.d.ts"
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
|
-
"files": [
|
|
15
|
-
"dist",
|
|
16
|
-
"src/skills",
|
|
17
|
-
"bin",
|
|
18
|
-
"README.md",
|
|
19
|
-
"LICENSE"
|
|
20
|
-
],
|
|
14
|
+
"files": ["dist", "src/skills", "bin", "README.md", "LICENSE"],
|
|
21
15
|
"bin": {
|
|
22
|
-
"codio-authoring-register": "bin/codio-authoring-register.js",
|
|
23
|
-
"codio-authoring-unregister": "bin/codio-authoring-unregister.js"
|
|
16
|
+
"codio-authoring-register": "./bin/codio-authoring-register.js",
|
|
17
|
+
"codio-authoring-unregister": "./bin/codio-authoring-unregister.js"
|
|
24
18
|
},
|
|
25
19
|
"scripts": {
|
|
26
20
|
"build": "bun build src/index.ts --outdir dist --target node --format esm --external @opencode-ai/plugin --external @opencode-ai/sdk --external zod && tsc --emitDeclarationOnly",
|
|
@@ -33,17 +27,11 @@
|
|
|
33
27
|
"check": "biome check --write .",
|
|
34
28
|
"check:ci": "biome check ."
|
|
35
29
|
},
|
|
36
|
-
"keywords": [
|
|
37
|
-
"opencode",
|
|
38
|
-
"opencode-plugin",
|
|
39
|
-
"codio",
|
|
40
|
-
"assignment-authoring",
|
|
41
|
-
"education"
|
|
42
|
-
],
|
|
30
|
+
"keywords": ["opencode", "opencode-plugin", "codio", "assignment-authoring", "education"],
|
|
43
31
|
"license": "MIT",
|
|
44
32
|
"repository": {
|
|
45
33
|
"type": "git",
|
|
46
|
-
"url": "
|
|
34
|
+
"url": "https://github.com/codio-extensions/codio-authoring-opencode-plugin.git"
|
|
47
35
|
},
|
|
48
36
|
"homepage": "https://github.com/codio-extensions/codio-authoring-opencode-plugin#readme",
|
|
49
37
|
"bugs": "https://github.com/codio-extensions/codio-authoring-opencode-plugin/issues",
|
|
@@ -61,6 +49,8 @@
|
|
|
61
49
|
"@biomejs/biome": "2.4.11",
|
|
62
50
|
"@types/node": "^24.6.1",
|
|
63
51
|
"bun-types": "1.3.12",
|
|
52
|
+
"codio-api-js": "^0.18.0",
|
|
53
|
+
"json-2-csv": "^5.5.10",
|
|
64
54
|
"typescript": "^5.9.3",
|
|
65
55
|
"zod": "~4.1.0"
|
|
66
56
|
},
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: reference-codio-api
|
|
3
|
+
description: Reference for the Codio platform API tools — fetch_course and publish_course. Course manifest format, output structure, credential requirements, and troubleshooting. Use when working with fetched courses or publishing assignments.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Codio API Tools Reference
|
|
7
|
+
|
|
8
|
+
## Credentials
|
|
9
|
+
|
|
10
|
+
Both tools read credentials from environment variables. Set these on the Codio box before using either tool:
|
|
11
|
+
|
|
12
|
+
| Variable | Required | Description |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| `CODIO_CLIENT_ID` | Yes | Codio API client ID |
|
|
15
|
+
| `CODIO_CLIENT_SECRET` | Yes | Codio API client secret |
|
|
16
|
+
| `CODIO_DOMAIN` | No | Codio domain, default `codio.com` |
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## `fetch_course` — Pull a course from Codio
|
|
21
|
+
|
|
22
|
+
Authenticates with the Codio API, downloads the course export, and writes an AI-ready project to the workspace.
|
|
23
|
+
|
|
24
|
+
### Inputs
|
|
25
|
+
|
|
26
|
+
| Field | Required | Description |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| `workspace` | Yes | Absolute path to the Codio workspace root |
|
|
29
|
+
| `courseId` | Yes | Codio course ID (32-char hex string) |
|
|
30
|
+
| `outputDir` | No | Output folder name, default `course-project` |
|
|
31
|
+
| `domain` | No | Codio domain, default `codio.com` |
|
|
32
|
+
|
|
33
|
+
### Output
|
|
34
|
+
|
|
35
|
+
Returns `{ outputDir, manifestPath, assignmentsCsvPath, moduleCount, assignmentCount }`.
|
|
36
|
+
|
|
37
|
+
Writes to `<outputDir>/` inside the workspace:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
<outputDir>/
|
|
41
|
+
├── course-manifest.json ← machine-readable index; source of truth for publish_course
|
|
42
|
+
├── course-assignments.csv ← flat CSV for review
|
|
43
|
+
└── course-content/
|
|
44
|
+
└── <module-folder>/
|
|
45
|
+
└── <assignment-folder>/
|
|
46
|
+
└── .guides/ ← guide pages, assessments, images
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## `publish_course` — Push assignments back to Codio
|
|
52
|
+
|
|
53
|
+
Reads `course-manifest.json` from the project folder and publishes each assignment to Codio.
|
|
54
|
+
|
|
55
|
+
### Inputs
|
|
56
|
+
|
|
57
|
+
| Field | Required | Description |
|
|
58
|
+
|---|---|---|
|
|
59
|
+
| `manifestPath` | Yes | Absolute path to `course-manifest.json` |
|
|
60
|
+
| `dryRun` | No | Preview actions without making changes |
|
|
61
|
+
| `force` | No | Publish all, bypassing change detection |
|
|
62
|
+
| `module` | No | Only process this module (name or folder) |
|
|
63
|
+
| `assignment` | No | Only process this assignment (name or folder) |
|
|
64
|
+
| `changelog` | No | Changelog text applied to all publishes |
|
|
65
|
+
| `stack` | No | Force a specific stack ID for all assignments |
|
|
66
|
+
|
|
67
|
+
### Output
|
|
68
|
+
|
|
69
|
+
Returns `{ published, created, unchanged, skipped }`.
|
|
70
|
+
|
|
71
|
+
Writes back any new IDs to `course-manifest.json` immediately after each resource is created.
|
|
72
|
+
|
|
73
|
+
### Change detection
|
|
74
|
+
|
|
75
|
+
The tool skips existing assignments whose content hash matches the stored `contentHash` in the manifest. Pass `force: true` to bypass. New assignments (no `id`) are always published.
|
|
76
|
+
|
|
77
|
+
### Stacks
|
|
78
|
+
|
|
79
|
+
- **New assignments** always use the default stack.
|
|
80
|
+
- **Existing assignments** preserve their current stack unless `stack` is supplied.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## course-manifest.json format
|
|
85
|
+
|
|
86
|
+
Created by `fetch_course`, consumed by `publish_course`. Both tools write back IDs as resources are created/resolved.
|
|
87
|
+
|
|
88
|
+
```jsonc
|
|
89
|
+
{
|
|
90
|
+
"schemaVersion": 2,
|
|
91
|
+
"courseId": "c87b4540de108faad55c8cefe7847492",
|
|
92
|
+
"exportedAt": "2026-06-12T10:00:00.000Z",
|
|
93
|
+
"counts": { "modules": 2, "assignments": 6 },
|
|
94
|
+
"paths": {
|
|
95
|
+
"assignmentsCsv": "course-assignments.csv",
|
|
96
|
+
"courseContent": "course-content"
|
|
97
|
+
},
|
|
98
|
+
"modules": [
|
|
99
|
+
{
|
|
100
|
+
"id": "...", // Resolved or created by publish_course; written back
|
|
101
|
+
"name": "Module Name",
|
|
102
|
+
"folder": "module-name",
|
|
103
|
+
"path": "course-content/module-name",
|
|
104
|
+
"assignmentCount": 3,
|
|
105
|
+
"assignments": [
|
|
106
|
+
{
|
|
107
|
+
"id": "...", // Created by publish_course if empty; written back
|
|
108
|
+
"name": "Assignment Name",
|
|
109
|
+
"folder": "assignment-name",
|
|
110
|
+
"path": "course-content/module-name/assignment-name",
|
|
111
|
+
"contentHash": "..." // Written after each successful publish; used for change detection
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Folder slug rules
|
|
120
|
+
|
|
121
|
+
Codio uses lowercase slugs: normalise to ASCII, lowercase, replace each non-alphanumeric character with `-`, trim leading/trailing hyphens. Example: `"1.1 – Intro"` → `"1-1---intro"`.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Typical workflow
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
fetch_course(courseId)
|
|
129
|
+
→ course-project/course-manifest.json + course-content/...
|
|
130
|
+
|
|
131
|
+
[edit assignment pages using authoring tools]
|
|
132
|
+
|
|
133
|
+
publish_course(manifestPath, dryRun: true) ← preview first
|
|
134
|
+
publish_course(manifestPath) ← publish for real
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Troubleshooting
|
|
140
|
+
|
|
141
|
+
| Error | Fix |
|
|
142
|
+
|---|---|
|
|
143
|
+
| `CODIO_CLIENT_ID ... must be set` | Set env vars on the box |
|
|
144
|
+
| `course-manifest.json not found` | Pass the absolute path to the manifest; run from or inside the project folder |
|
|
145
|
+
| `path not found` for an assignment | The folder referenced in the manifest doesn't exist — generate content there first |
|
|
146
|
+
| `Required command not found: unzip` | Install `unzip` via the box package manager |
|
|
147
|
+
| API 401 / auth error | Credentials are invalid or expired |
|
|
148
|
+
| API 429 rate limit | Library retries automatically; wait and re-run if still failing |
|
|
149
|
+
| `no module ID available` | Module creation failed earlier in the run — check the error above it |
|