@tutorflow/cli 0.3.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/README.md +261 -659
  2. package/dist/client.d.ts +16 -2
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +76 -16
  5. package/dist/client.js.map +1 -1
  6. package/dist/commands/agent.d.ts.map +1 -1
  7. package/dist/commands/agent.js +38 -23
  8. package/dist/commands/agent.js.map +1 -1
  9. package/dist/commands/auth.d.ts.map +1 -1
  10. package/dist/commands/auth.js +20 -12
  11. package/dist/commands/auth.js.map +1 -1
  12. package/dist/commands/classroom.d.ts +3 -0
  13. package/dist/commands/classroom.d.ts.map +1 -0
  14. package/dist/commands/classroom.js +27 -0
  15. package/dist/commands/classroom.js.map +1 -0
  16. package/dist/commands/config.d.ts.map +1 -1
  17. package/dist/commands/config.js +4 -4
  18. package/dist/commands/config.js.map +1 -1
  19. package/dist/commands/course.d.ts.map +1 -1
  20. package/dist/commands/course.js +27 -96
  21. package/dist/commands/course.js.map +1 -1
  22. package/dist/commands/credits.d.ts +3 -0
  23. package/dist/commands/credits.d.ts.map +1 -0
  24. package/dist/commands/credits.js +39 -0
  25. package/dist/commands/credits.js.map +1 -0
  26. package/dist/commands/evaluate.d.ts +3 -0
  27. package/dist/commands/evaluate.d.ts.map +1 -1
  28. package/dist/commands/evaluate.js +98 -57
  29. package/dist/commands/evaluate.js.map +1 -1
  30. package/dist/commands/interactive.d.ts +13 -0
  31. package/dist/commands/interactive.d.ts.map +1 -0
  32. package/dist/commands/interactive.js +105 -0
  33. package/dist/commands/interactive.js.map +1 -0
  34. package/dist/commands/learner.d.ts +4 -0
  35. package/dist/commands/learner.d.ts.map +1 -0
  36. package/dist/commands/learner.js +76 -0
  37. package/dist/commands/learner.js.map +1 -0
  38. package/dist/commands/module.d.ts.map +1 -1
  39. package/dist/commands/module.js +20 -98
  40. package/dist/commands/module.js.map +1 -1
  41. package/dist/commands/platform.d.ts.map +1 -1
  42. package/dist/commands/platform.js +10 -2
  43. package/dist/commands/platform.js.map +1 -1
  44. package/dist/commands/run.d.ts +3 -0
  45. package/dist/commands/run.d.ts.map +1 -0
  46. package/dist/commands/run.js +69 -0
  47. package/dist/commands/run.js.map +1 -0
  48. package/dist/commands/slide.d.ts.map +1 -1
  49. package/dist/commands/slide.js +27 -97
  50. package/dist/commands/slide.js.map +1 -1
  51. package/dist/commands/test.d.ts.map +1 -1
  52. package/dist/commands/test.js +40 -106
  53. package/dist/commands/test.js.map +1 -1
  54. package/dist/commands/video.d.ts.map +1 -1
  55. package/dist/commands/video.js +143 -86
  56. package/dist/commands/video.js.map +1 -1
  57. package/dist/commands/webhook.d.ts +3 -0
  58. package/dist/commands/webhook.d.ts.map +1 -0
  59. package/dist/commands/webhook.js +75 -0
  60. package/dist/commands/webhook.js.map +1 -0
  61. package/dist/config.d.ts +3 -0
  62. package/dist/config.d.ts.map +1 -1
  63. package/dist/config.js +17 -16
  64. package/dist/config.js.map +1 -1
  65. package/dist/content/context.d.ts +26 -0
  66. package/dist/content/context.d.ts.map +1 -0
  67. package/dist/content/context.js +74 -0
  68. package/dist/content/context.js.map +1 -0
  69. package/dist/content/resource.d.ts +66 -0
  70. package/dist/content/resource.d.ts.map +1 -0
  71. package/dist/content/resource.js +181 -0
  72. package/dist/content/resource.js.map +1 -0
  73. package/dist/content/runs.d.ts +51 -0
  74. package/dist/content/runs.d.ts.map +1 -0
  75. package/dist/content/runs.js +171 -0
  76. package/dist/content/runs.js.map +1 -0
  77. package/dist/content/sharing.d.ts +24 -0
  78. package/dist/content/sharing.d.ts.map +1 -0
  79. package/dist/content/sharing.js +88 -0
  80. package/dist/content/sharing.js.map +1 -0
  81. package/dist/index.js +71 -21
  82. package/dist/index.js.map +1 -1
  83. package/dist/types.d.ts +15 -65
  84. package/dist/types.d.ts.map +1 -1
  85. package/dist/types.js +4 -4
  86. package/dist/utils/args.d.ts +15 -0
  87. package/dist/utils/args.d.ts.map +1 -0
  88. package/dist/utils/args.js +91 -0
  89. package/dist/utils/args.js.map +1 -0
  90. package/dist/utils/keys.d.ts +11 -0
  91. package/dist/utils/keys.d.ts.map +1 -0
  92. package/dist/utils/keys.js +29 -0
  93. package/dist/utils/keys.js.map +1 -0
  94. package/dist/utils/output.d.ts.map +1 -1
  95. package/dist/utils/output.js +21 -6
  96. package/dist/utils/output.js.map +1 -1
  97. package/dist/utils/runtime.d.ts +14 -4
  98. package/dist/utils/runtime.d.ts.map +1 -1
  99. package/dist/utils/runtime.js +42 -7
  100. package/dist/utils/runtime.js.map +1 -1
  101. package/package.json +4 -3
  102. package/dist/utils/spinner.d.ts +0 -8
  103. package/dist/utils/spinner.d.ts.map +0 -1
  104. package/dist/utils/spinner.js +0 -26
  105. package/dist/utils/spinner.js.map +0 -1
package/dist/config.js CHANGED
@@ -40,28 +40,29 @@ exports.deleteConfig = deleteConfig;
40
40
  const fs = __importStar(require("fs/promises"));
41
41
  const path = __importStar(require("path"));
42
42
  const os = __importStar(require("os"));
43
- const CONFIG_PATH = path.join(os.homedir(), '.tutorflow', 'config.json');
44
- async function ensureConfigDir() {
45
- const dir = path.dirname(CONFIG_PATH);
46
- try {
47
- await fs.mkdir(dir, { recursive: true });
48
- }
49
- catch (error) {
50
- // Already exists or permission denied - both OK here
51
- }
43
+ /** The file holds an API key: owner read/write only. */
44
+ const CONFIG_FILE_MODE = 0o600;
45
+ const CONFIG_DIR_MODE = 0o700;
46
+ // Resolved per call so tests (and users) can point HOME elsewhere.
47
+ function configPath() {
48
+ return path.join(os.homedir(), '.tutorflow', 'config.json');
52
49
  }
53
50
  async function readConfig() {
54
51
  try {
55
- const content = await fs.readFile(CONFIG_PATH, 'utf-8');
56
- return JSON.parse(content);
52
+ const content = await fs.readFile(configPath(), 'utf-8');
53
+ const parsed = JSON.parse(content);
54
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {};
57
55
  }
58
- catch (error) {
56
+ catch {
59
57
  return {};
60
58
  }
61
59
  }
62
60
  async function writeConfig(config) {
63
- await ensureConfigDir();
64
- await fs.writeFile(CONFIG_PATH, JSON.stringify(config, null, 2));
61
+ const file = configPath();
62
+ await fs.mkdir(path.dirname(file), { recursive: true, mode: CONFIG_DIR_MODE });
63
+ await fs.writeFile(file, JSON.stringify(config, null, 2), { mode: CONFIG_FILE_MODE });
64
+ // writeFile's mode applies only on creation; tighten files written by 0.x.
65
+ await fs.chmod(file, CONFIG_FILE_MODE);
65
66
  }
66
67
  async function updateConfig(updates) {
67
68
  const current = await readConfig();
@@ -71,9 +72,9 @@ async function updateConfig(updates) {
71
72
  }
72
73
  async function deleteConfig() {
73
74
  try {
74
- await fs.unlink(CONFIG_PATH);
75
+ await fs.unlink(configPath());
75
76
  }
76
- catch (error) {
77
+ catch {
77
78
  // Already deleted
78
79
  }
79
80
  }
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqBA,gCAOC;AAED,kCAGC;AAED,oCAKC;AAED,oCAMC;AAhDD,gDAAkC;AAClC,2CAA6B;AAC7B,uCAAyB;AAQzB,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,aAAa,CAAC,CAAC;AAEzE,KAAK,UAAU,eAAe;IAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACtC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,qDAAqD;IACvD,CAAC;AACH,CAAC;AAEM,KAAK,UAAU,UAAU;IAC9B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACxD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAEM,KAAK,UAAU,WAAW,CAAC,MAAe;IAC/C,MAAM,eAAe,EAAE,CAAC;IACxB,MAAM,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AACnE,CAAC;AAEM,KAAK,UAAU,YAAY,CAAC,OAAyB;IAC1D,MAAM,OAAO,GAAG,MAAM,UAAU,EAAE,CAAC;IACnC,MAAM,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC;IAC3C,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC;IAC3B,OAAO,OAAO,CAAC;AACjB,CAAC;AAEM,KAAK,UAAU,YAAY;IAChC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,kBAAkB;IACpB,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsBA,gCAQC;AAED,kCAMC;AAED,oCAKC;AAED,oCAMC;AArDD,gDAAkC;AAClC,2CAA6B;AAC7B,uCAAyB;AAWzB,wDAAwD;AACxD,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAC/B,MAAM,eAAe,GAAG,KAAK,CAAC;AAE9B,mEAAmE;AACnE,SAAS,UAAU;IACjB,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,aAAa,CAAC,CAAC;AAC9D,CAAC;AAEM,KAAK,UAAU,UAAU;IAC9B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;QACzD,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC5C,OAAO,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAE,MAAkB,CAAC,CAAC,CAAC,EAAE,CAAC;IACnG,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAEM,KAAK,UAAU,WAAW,CAAC,MAAe;IAC/C,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;IAC1B,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,CAAC;IAC/E,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC,CAAC;IACtF,2EAA2E;IAC3E,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;AACzC,CAAC;AAEM,KAAK,UAAU,YAAY,CAAC,OAAyB;IAC1D,MAAM,OAAO,GAAG,MAAM,UAAU,EAAE,CAAC;IACnC,MAAM,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC;IAC3C,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC;IAC3B,OAAO,OAAO,CAAC;AACjB,CAAC;AAEM,KAAK,UAAU,YAAY;IAChC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,kBAAkB;IACpB,CAAC;AACH,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { ApiClient } from '../client';
2
+ /**
3
+ * Everything a classroom-scoped content command needs: an authenticated
4
+ * client holding a tf_content_ key, and the classroom to act in.
5
+ */
6
+ export interface ContentContext {
7
+ client: ApiClient;
8
+ classroomId: string;
9
+ }
10
+ /** Authenticated client that refuses deprecated tf_platform_ keys up front. */
11
+ export declare function createContentClient(): Promise<ApiClient>;
12
+ /**
13
+ * Classroom resolution, first match wins:
14
+ * 1. --classroom <id>
15
+ * 2. TUTORFLOW_CLASSROOM_ID
16
+ * 3. classroomId in ~/.tutorflow/config.json
17
+ * 4. GET /v1/platform/agent/account → sandboxClassroomId for a test key,
18
+ * defaultClassroomId otherwise
19
+ * 5. GET /v1/content/classrooms when the account route refuses the key
20
+ * (a classroom Settings key): the only classroom, or the sandbox one for
21
+ * a test key
22
+ */
23
+ export declare function resolveContentContext(): Promise<ContentContext>;
24
+ export declare function classroomPath(ctx: ContentContext, suffix?: string): string;
25
+ export declare function segment(id: string): string;
26
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/content/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAY,MAAM,WAAW,CAAC;AAKhD;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,SAAS,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAaD,+EAA+E;AAC/E,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,SAAS,CAAC,CAU9D;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,cAAc,CAAC,CAWrE;AA+BD,wBAAgB,aAAa,CAAC,GAAG,EAAE,cAAc,EAAE,MAAM,SAAK,GAAG,MAAM,CAEtE;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE1C"}
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createContentClient = createContentClient;
4
+ exports.resolveContentContext = resolveContentContext;
5
+ exports.classroomPath = classroomPath;
6
+ exports.segment = segment;
7
+ const client_1 = require("../client");
8
+ const config_1 = require("../config");
9
+ const keys_1 = require("../utils/keys");
10
+ const runtime_1 = require("../utils/runtime");
11
+ /** Authenticated client that refuses deprecated tf_platform_ keys up front. */
12
+ async function createContentClient() {
13
+ const client = await client_1.ApiClient.createAuthenticated();
14
+ if ((0, keys_1.getApiKeyKind)(client.apiKey) === 'platform') {
15
+ throw new runtime_1.CliError(keys_1.PLATFORM_KEY_MESSAGE, {
16
+ code: 'EPLATFORMKEY',
17
+ exitCode: 1,
18
+ details: { hint: 'tutorflow agent register --name <name> --slug <slug>' },
19
+ });
20
+ }
21
+ return client;
22
+ }
23
+ /**
24
+ * Classroom resolution, first match wins:
25
+ * 1. --classroom <id>
26
+ * 2. TUTORFLOW_CLASSROOM_ID
27
+ * 3. classroomId in ~/.tutorflow/config.json
28
+ * 4. GET /v1/platform/agent/account → sandboxClassroomId for a test key,
29
+ * defaultClassroomId otherwise
30
+ * 5. GET /v1/content/classrooms when the account route refuses the key
31
+ * (a classroom Settings key): the only classroom, or the sandbox one for
32
+ * a test key
33
+ */
34
+ async function resolveContentContext() {
35
+ const client = await createContentClient();
36
+ const pinned = (0, runtime_1.getClassroomOverride)() ?? (0, client_1.envValue)('TUTORFLOW_CLASSROOM_ID') ?? (await (0, config_1.readConfig)()).classroomId;
37
+ if (pinned)
38
+ return { client, classroomId: pinned };
39
+ const isTestKey = (0, keys_1.getApiKeyKind)(client.apiKey) === 'content_test';
40
+ const fromAccount = await classroomFromAccount(client, isTestKey);
41
+ if (fromAccount)
42
+ return { client, classroomId: fromAccount };
43
+ return { client, classroomId: await classroomFromList(client, isTestKey) };
44
+ }
45
+ async function classroomFromAccount(client, isTestKey) {
46
+ try {
47
+ const account = await client.request('GET', '/v1/platform/agent/account');
48
+ const id = isTestKey ? account.sandboxClassroomId : account.defaultClassroomId;
49
+ return id ?? undefined;
50
+ }
51
+ catch (error) {
52
+ // Not an agent key (or not a full one): try the classroom list instead.
53
+ if (error instanceof runtime_1.CliError && /^EHTTP_(401|403)$/.test(error.code))
54
+ return undefined;
55
+ throw error;
56
+ }
57
+ }
58
+ async function classroomFromList(client, isTestKey) {
59
+ const classrooms = await client.request('GET', '/v1/content/classrooms');
60
+ const candidates = isTestKey ? classrooms.filter((c) => c.isSandbox) : classrooms;
61
+ if (candidates.length === 1)
62
+ return candidates[0].id;
63
+ const listed = candidates.map((c) => `${c.id} (${c.name ?? 'unnamed'})`).join(', ');
64
+ throw new runtime_1.CliError(candidates.length === 0
65
+ ? 'This key reaches no classroom. Check the key with `tutorflow auth whoami`.'
66
+ : `This key reaches several classrooms; pass --classroom <id> or set TUTORFLOW_CLASSROOM_ID. Classrooms: ${listed}`, { code: 'ECLASSROOM', exitCode: 2 });
67
+ }
68
+ function classroomPath(ctx, suffix = '') {
69
+ return `/v1/content/classrooms/${encodeURIComponent(ctx.classroomId)}${suffix}`;
70
+ }
71
+ function segment(id) {
72
+ return encodeURIComponent(id);
73
+ }
74
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/content/context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ import { Command } from 'commander';
2
+ import { type ContentContext } from './context';
3
+ import { type GenerationRun } from './runs';
4
+ /**
5
+ * Builders for the subcommands every classroom resource shares
6
+ * (list, get, open, delete, generate) so each resource file only declares
7
+ * what is particular to it.
8
+ */
9
+ export interface ResourceSpec {
10
+ /** Path segment under /v1/content/classrooms/{id}, e.g. "courses". */
11
+ path: string;
12
+ /** Singular noun for help text and messages, e.g. "course". */
13
+ noun: string;
14
+ }
15
+ export interface ContentResource {
16
+ id: string;
17
+ title?: string | null;
18
+ name?: string | null;
19
+ status?: string | null;
20
+ renderStatus?: string | null;
21
+ visibility?: string | null;
22
+ updatedAt?: string | null;
23
+ createdAt?: string | null;
24
+ editorUrl?: string | null;
25
+ publicUrl?: string | null;
26
+ [key: string]: unknown;
27
+ }
28
+ export interface ListPage<T> {
29
+ data?: T[];
30
+ items?: T[];
31
+ meta?: {
32
+ hasNextPage?: boolean;
33
+ nextCursor?: string | null;
34
+ [key: string]: unknown;
35
+ };
36
+ [key: string]: unknown;
37
+ }
38
+ export declare function rowsOf<T>(page: ListPage<T> | T[]): T[];
39
+ /** Text-mode table for any list of classroom resources. */
40
+ export declare function printResourceList(page: ListPage<ContentResource> | ContentResource[]): void;
41
+ export declare function resourcePath(ctx: ContentContext, spec: ResourceSpec, id?: string, suffix?: string): string;
42
+ export declare function addListCommand(parent: Command, spec: ResourceSpec): void;
43
+ export declare function addGetCommand(parent: Command, spec: ResourceSpec): void;
44
+ export declare function addOpenCommand(parent: Command, spec: ResourceSpec): void;
45
+ export declare function addDeleteCommand(parent: Command, spec: ResourceSpec): void;
46
+ /** list + get + open + delete. */
47
+ export declare function addCrudCommands(parent: Command, spec: ResourceSpec): void;
48
+ export interface WaitOptions {
49
+ wait?: boolean;
50
+ timeout?: string;
51
+ }
52
+ export declare function addWaitOptions(cmd: Command, defaultTimeoutSeconds?: number): Command;
53
+ export declare function parseTimeout(options: WaitOptions): number;
54
+ export interface GenerateSpec<O> extends ResourceSpec {
55
+ description: string;
56
+ promptLabel: string;
57
+ example: string;
58
+ /** Adds the resource's own flags. */
59
+ configure: (cmd: Command) => Command;
60
+ /** Validates flags and builds the request body; runs before any API call. */
61
+ buildBody: (prompt: string, options: O) => Record<string, unknown>;
62
+ }
63
+ /** `<resource> generate [prompt]` (alias `create`): POST …/generate → 202 run. */
64
+ export declare function addGenerateCommand<O>(parent: Command, spec: GenerateSpec<O>): void;
65
+ export declare function printFinishedRun(ctx: ContentContext, run: GenerationRun): Promise<void>;
66
+ //# sourceMappingURL=resource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../../src/content/resource.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,181 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.rowsOf = rowsOf;
7
+ exports.printResourceList = printResourceList;
8
+ exports.resourcePath = resourcePath;
9
+ exports.addListCommand = addListCommand;
10
+ exports.addGetCommand = addGetCommand;
11
+ exports.addOpenCommand = addOpenCommand;
12
+ exports.addDeleteCommand = addDeleteCommand;
13
+ exports.addCrudCommands = addCrudCommands;
14
+ exports.addWaitOptions = addWaitOptions;
15
+ exports.parseTimeout = parseTimeout;
16
+ exports.addGenerateCommand = addGenerateCommand;
17
+ exports.printFinishedRun = printFinishedRun;
18
+ const open_1 = __importDefault(require("open"));
19
+ const output_1 = require("../utils/output");
20
+ const runtime_1 = require("../utils/runtime");
21
+ const args_1 = require("../utils/args");
22
+ const context_1 = require("./context");
23
+ const runs_1 = require("./runs");
24
+ const DEFAULT_PAGE_SIZE = '20';
25
+ function rowsOf(page) {
26
+ if (Array.isArray(page))
27
+ return page;
28
+ return page.data ?? page.items ?? [];
29
+ }
30
+ /** Text-mode table for any list of classroom resources. */
31
+ function printResourceList(page) {
32
+ if ((0, runtime_1.isJsonMode)()) {
33
+ (0, output_1.printResult)(page);
34
+ return;
35
+ }
36
+ (0, output_1.printResult)(rowsOf(page).map((row) => ({
37
+ ID: row.id,
38
+ Title: row.title ?? row.name ?? 'Untitled',
39
+ Status: row.status ?? row.renderStatus ?? row.visibility ?? '',
40
+ Updated: formatDate(row.updatedAt ?? row.createdAt),
41
+ })));
42
+ const meta = Array.isArray(page) ? undefined : page.meta;
43
+ if (meta?.nextCursor)
44
+ (0, output_1.printStatus)(`More: --cursor ${meta.nextCursor}`);
45
+ else if (meta?.hasNextPage)
46
+ (0, output_1.printStatus)('More results: pass --page <n+1>');
47
+ }
48
+ function formatDate(value) {
49
+ if (!value)
50
+ return '';
51
+ const date = new Date(value);
52
+ return Number.isNaN(date.getTime()) ? value : date.toISOString().slice(0, 10);
53
+ }
54
+ function resourcePath(ctx, spec, id, suffix = '') {
55
+ return (0, context_1.classroomPath)(ctx, `/${spec.path}${id ? `/${(0, context_1.segment)(id)}` : ''}${suffix}`);
56
+ }
57
+ function addListCommand(parent, spec) {
58
+ parent
59
+ .command('list')
60
+ .description(`List ${spec.noun}s in the classroom`)
61
+ .option('-l, --limit <number>', 'Items per page (max 100)', DEFAULT_PAGE_SIZE)
62
+ .option('-p, --page <number>', 'Page number, from 1', '1')
63
+ .option('-s, --search <text>', 'Search term')
64
+ .action((0, runtime_1.command)(async (options) => {
65
+ const limit = (0, args_1.parsePositiveInt)(options.limit, '--limit');
66
+ const page = (0, args_1.parsePositiveInt)(options.page, '--page');
67
+ const ctx = await (0, context_1.resolveContentContext)();
68
+ const qs = new URLSearchParams({ page: String(page), limit: String(limit) });
69
+ if (options.search)
70
+ qs.set('search', options.search);
71
+ const response = await ctx.client.request('GET', `${resourcePath(ctx, spec)}?${qs.toString()}`);
72
+ printResourceList(response);
73
+ }));
74
+ }
75
+ function addGetCommand(parent, spec) {
76
+ parent
77
+ .command('get <id>')
78
+ .description(`Fetch one ${spec.noun}`)
79
+ .action((0, runtime_1.command)(async (id) => {
80
+ const ctx = await (0, context_1.resolveContentContext)();
81
+ (0, output_1.printResult)(await ctx.client.request('GET', resourcePath(ctx, spec, id)));
82
+ }));
83
+ }
84
+ function addOpenCommand(parent, spec) {
85
+ parent
86
+ .command('open <id>')
87
+ .description(`Print the ${spec.noun}'s editor and public URLs; opens one in a browser on a TTY`)
88
+ .option('--editor', 'Open the classroom editor even when a public page exists')
89
+ .action((0, runtime_1.command)(async (id, options) => {
90
+ const ctx = await (0, context_1.resolveContentContext)();
91
+ const resource = await ctx.client.request('GET', resourcePath(ctx, spec, id));
92
+ const editorUrl = resource.editorUrl ?? null;
93
+ const publicUrl = resource.publicUrl ?? null;
94
+ const target = options.editor ? editorUrl : publicUrl ?? editorUrl;
95
+ if (!target) {
96
+ throw new runtime_1.CliError(`No editor or public URL for this ${spec.noun}`, {
97
+ code: 'ENOPREVIEW',
98
+ exitCode: 1,
99
+ });
100
+ }
101
+ (0, output_1.printResult)({ id, editorUrl, publicUrl });
102
+ if ((0, runtime_1.isInteractive)() && !(0, runtime_1.isJsonMode)()) {
103
+ await (0, open_1.default)(target);
104
+ (0, output_1.printStatus)('Opening in browser...', 'success');
105
+ }
106
+ }));
107
+ }
108
+ function addDeleteCommand(parent, spec) {
109
+ parent
110
+ .command('delete <id>')
111
+ .description(`Delete a ${spec.noun}`)
112
+ .option('-y, --yes', 'Skip the confirmation prompt (required without a TTY)')
113
+ .action((0, runtime_1.command)(async (id, options) => {
114
+ await (0, args_1.confirmOrRequireYes)(options.yes, `Delete ${spec.noun} ${id}?`);
115
+ const ctx = await (0, context_1.resolveContentContext)();
116
+ await ctx.client.request('DELETE', resourcePath(ctx, spec, id));
117
+ (0, output_1.printResult)({ id, deleted: true });
118
+ }));
119
+ }
120
+ /** list + get + open + delete. */
121
+ function addCrudCommands(parent, spec) {
122
+ addListCommand(parent, spec);
123
+ addGetCommand(parent, spec);
124
+ addOpenCommand(parent, spec);
125
+ addDeleteCommand(parent, spec);
126
+ }
127
+ function addWaitOptions(cmd, defaultTimeoutSeconds = runs_1.DEFAULT_WAIT_TIMEOUT_SECONDS) {
128
+ return cmd
129
+ .option('-w, --wait', 'Wait until the work finishes and print the result')
130
+ .option('--timeout <seconds>', 'Give up waiting after this many seconds', String(defaultTimeoutSeconds));
131
+ }
132
+ function parseTimeout(options) {
133
+ return (0, args_1.parseNonNegativeNumber)(options.timeout, '--timeout') ?? runs_1.DEFAULT_WAIT_TIMEOUT_SECONDS;
134
+ }
135
+ /** `<resource> generate [prompt]` (alias `create`): POST …/generate → 202 run. */
136
+ function addGenerateCommand(parent, spec) {
137
+ const cmd = parent
138
+ .command('generate')
139
+ .alias('create')
140
+ .description(spec.description)
141
+ .argument('[prompt]', spec.promptLabel);
142
+ spec.configure(cmd);
143
+ addWaitOptions(cmd).option('--idempotency-key <key>', 'Idempotency key for safe retries');
144
+ cmd.action((0, runtime_1.command)(async (prompt, options) => {
145
+ const text = await (0, args_1.valueOrPrompt)(prompt, `${spec.promptLabel}:`, `Pass a prompt argument: ${spec.example}`);
146
+ const body = (0, args_1.compact)(spec.buildBody(text, options));
147
+ const timeoutSeconds = parseTimeout(options);
148
+ const ctx = await (0, context_1.resolveContentContext)();
149
+ const accepted = await ctx.client.request('POST', resourcePath(ctx, spec, undefined, '/generate'), body, (0, args_1.idempotencyHeaders)(options.idempotencyKey));
150
+ if (!options.wait) {
151
+ (0, output_1.printResult)(accepted);
152
+ (0, output_1.printStatus)(`Follow it with: tutorflow run wait ${accepted.runId}`);
153
+ return;
154
+ }
155
+ await printFinishedRun(ctx, await (0, runs_1.waitForRun)(ctx, accepted.runId, timeoutSeconds));
156
+ }));
157
+ }
158
+ async function printFinishedRun(ctx, run) {
159
+ // The run is done and paid for; a failed follow-up read must not hide it.
160
+ let resource;
161
+ try {
162
+ resource = (await (0, runs_1.fetchRunResource)(ctx, run));
163
+ }
164
+ catch (error) {
165
+ (0, runtime_1.printProgress)(`Run ${run.runId} completed, but reading ${run.resourceId ?? 'its resource'} failed: ${error instanceof Error ? error.message : String(error)}`);
166
+ }
167
+ if ((0, runtime_1.isJsonMode)()) {
168
+ (0, output_1.printResult)({ run, resource: resource ?? null });
169
+ return;
170
+ }
171
+ (0, output_1.printResult)({
172
+ runId: run.runId,
173
+ status: run.status,
174
+ creditsCharged: run.creditsCharged,
175
+ resourceId: run.resourceId,
176
+ title: resource?.title,
177
+ editorUrl: resource?.editorUrl,
178
+ publicUrl: resource?.publicUrl,
179
+ });
180
+ }
181
+ //# sourceMappingURL=resource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource.js","sourceRoot":"","sources":["../../src/content/resource.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ import { type ContentContext } from './context';
2
+ export declare const DEFAULT_WAIT_TIMEOUT_SECONDS = 900;
3
+ export declare const DEFAULT_RENDER_TIMEOUT_SECONDS = 1800;
4
+ export type RunState = 'queued' | 'running' | 'completed' | 'failed';
5
+ export type RunKind = 'course' | 'slide' | 'test' | 'module';
6
+ export interface GenerationRun {
7
+ runId: string;
8
+ kind?: RunKind;
9
+ status: RunState;
10
+ stage?: string | null;
11
+ progress?: RunProgress | null;
12
+ resourceId?: string | null;
13
+ error?: string | null;
14
+ [key: string]: unknown;
15
+ }
16
+ export interface RunProgress {
17
+ completed: number;
18
+ total: number;
19
+ unit: string;
20
+ }
21
+ /** Path segment of the resource a generation run of each kind produces. */
22
+ export declare const RUN_KIND_PATHS: Record<RunKind, string>;
23
+ interface ResourceRunStep {
24
+ runId: string;
25
+ phase: string;
26
+ stage?: string | null;
27
+ status?: 'done' | 'failed';
28
+ message?: string;
29
+ [key: string]: unknown;
30
+ }
31
+ export interface ResourceRunStatus {
32
+ active: ResourceRunStep | null;
33
+ last: ResourceRunStep | null;
34
+ }
35
+ export interface RenderStatus {
36
+ renderStatus: 'IDLE' | 'RENDERING' | 'COMPLETED' | 'FAILED';
37
+ renderError?: string | null;
38
+ progress?: number | null;
39
+ [key: string]: unknown;
40
+ }
41
+ export declare function waitForRun(ctx: ContentContext, runId: string, timeoutSeconds: number): Promise<GenerationRun>;
42
+ /** Fetch what a completed run produced, or undefined when it names nothing. */
43
+ export declare function fetchRunResource(ctx: ContentContext, run: GenerationRun): Promise<unknown | undefined>;
44
+ /**
45
+ * Wait for a game or simulation brief/build/revise. The resource run route
46
+ * reports an `active` step while one runs and the `last` finished one after.
47
+ */
48
+ export declare function waitForResourceRun(ctx: ContentContext, resourcePath: string, id: string, runId: string | undefined, timeoutSeconds: number): Promise<ResourceRunStatus>;
49
+ export declare function waitForRender(ctx: ContentContext, videoId: string, timeoutSeconds: number): Promise<RenderStatus>;
50
+ export {};
51
+ //# sourceMappingURL=runs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runs.d.ts","sourceRoot":"","sources":["../../src/content/runs.ts"],"names":[],"mappings":"AAEA,OAAO,EAA0B,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAWxE,eAAO,MAAM,4BAA4B,MAAM,CAAC;AAChD,eAAO,MAAM,8BAA8B,OAAQ,CAAC;AAEpD,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;AACrE,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE7D,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,QAAQ,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,2EAA2E;AAC3E,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAKlD,CAAC;AAEF,UAAU,eAAe;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;IAC/B,IAAI,EAAE,eAAe,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,GAAG,WAAW,GAAG,WAAW,GAAG,QAAQ,CAAC;IAC5D,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAuDD,wBAAsB,UAAU,CAC9B,GAAG,EAAE,cAAc,EACnB,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,aAAa,CAAC,CA4BxB;AAaD,+EAA+E;AAC/E,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,cAAc,EACnB,GAAG,EAAE,aAAa,GACjB,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAM9B;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,cAAc,EACnB,YAAY,EAAE,MAAM,EACpB,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,iBAAiB,CAAC,CAkC5B;AAMD,wBAAsB,aAAa,CACjC,GAAG,EAAE,cAAc,EACnB,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,YAAY,CAAC,CA2CvB"}