@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
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parsePositiveInt = parsePositiveInt;
4
+ exports.parseNonNegativeNumber = parseNonNegativeNumber;
5
+ exports.parseChoice = parseChoice;
6
+ exports.splitList = splitList;
7
+ exports.collect = collect;
8
+ exports.compact = compact;
9
+ exports.idempotencyHeaders = idempotencyHeaders;
10
+ exports.valueOrPrompt = valueOrPrompt;
11
+ exports.confirmOrRequireYes = confirmOrRequireYes;
12
+ const prompts_1 = require("@clack/prompts");
13
+ const runtime_1 = require("./runtime");
14
+ /** Shared flag parsing. Every failure is EINVAL with exit code 2. */
15
+ function invalid(message) {
16
+ return new runtime_1.CliError(message, { code: 'EINVAL', exitCode: 2 });
17
+ }
18
+ function parsePositiveInt(value, flag) {
19
+ if (value === undefined)
20
+ return undefined;
21
+ const parsed = Number(value);
22
+ if (!Number.isInteger(parsed) || parsed < 1) {
23
+ throw invalid(`${flag} must be a positive integer (got "${value}")`);
24
+ }
25
+ return parsed;
26
+ }
27
+ function parseNonNegativeNumber(value, flag) {
28
+ if (value === undefined)
29
+ return undefined;
30
+ const parsed = Number(value);
31
+ if (!Number.isFinite(parsed) || parsed < 0) {
32
+ throw invalid(`${flag} must be a non-negative number (got "${value}")`);
33
+ }
34
+ return parsed;
35
+ }
36
+ function parseChoice(value, flag, choices) {
37
+ if (value === undefined)
38
+ return undefined;
39
+ if (!choices.includes(value)) {
40
+ throw invalid(`${flag} must be one of: ${choices.join(', ')} (got "${value}")`);
41
+ }
42
+ return value;
43
+ }
44
+ /** "a, b,c" → ["a", "b", "c"]; undefined stays undefined. */
45
+ function splitList(value) {
46
+ if (value === undefined)
47
+ return undefined;
48
+ const items = value
49
+ .split(',')
50
+ .map((item) => item.trim())
51
+ .filter(Boolean);
52
+ return items.length ? items : undefined;
53
+ }
54
+ /** Commander collector for repeatable flags (`--event a --event b`). */
55
+ function collect(value, previous = []) {
56
+ return [...previous, value];
57
+ }
58
+ /** Drop undefined / empty-string fields so the API sees only what was set. */
59
+ function compact(input) {
60
+ return Object.fromEntries(Object.entries(input).filter(([, value]) => value !== undefined && value !== ''));
61
+ }
62
+ function idempotencyHeaders(key) {
63
+ return key ? { 'Idempotency-Key': key } : undefined;
64
+ }
65
+ /** Use the given value, or prompt for it on a TTY, or fail with ENOINTERACTIVE. */
66
+ async function valueOrPrompt(value, message, hint) {
67
+ if (value?.trim())
68
+ return value.trim();
69
+ (0, runtime_1.requireInteractive)(hint);
70
+ const result = await (0, prompts_1.text)({ message });
71
+ if (!result || typeof result === 'symbol') {
72
+ throw new runtime_1.CliError('Cancelled', { code: 'ECANCELLED', exitCode: 130 });
73
+ }
74
+ return result;
75
+ }
76
+ /** Destructive actions need --yes, or a confirmation on a TTY. */
77
+ async function confirmOrRequireYes(yes, message) {
78
+ if (yes)
79
+ return;
80
+ if (!(0, runtime_1.canPrompt)()) {
81
+ throw new runtime_1.CliError(`${message} Pass --yes to confirm in non-interactive or JSON mode.`, {
82
+ code: 'ENOINTERACTIVE',
83
+ exitCode: 2,
84
+ });
85
+ }
86
+ const confirmed = await (0, prompts_1.confirm)({ message });
87
+ if (confirmed !== true) {
88
+ throw new runtime_1.CliError('Cancelled', { code: 'ECANCELLED', exitCode: 130 });
89
+ }
90
+ }
91
+ //# sourceMappingURL=args.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.js","sourceRoot":"","sources":["../../src/utils/args.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * TutorFlow API key kinds, told apart by prefix:
3
+ * tf_content_test_… Content API test key (sandbox classroom, spends nothing)
4
+ * tf_content_… Content API live key (every content command)
5
+ * tf_platform_… deprecated Agent Platform key (account routes only)
6
+ */
7
+ export type ApiKeyKind = 'content_live' | 'content_test' | 'platform' | 'unknown';
8
+ export declare function getApiKeyKind(apiKey: string): ApiKeyKind;
9
+ export declare function maskApiKey(apiKey: string): string;
10
+ export declare const PLATFORM_KEY_MESSAGE: string;
11
+ //# sourceMappingURL=keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/utils/keys.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG,cAAc,GAAG,UAAU,GAAG,SAAS,CAAC;AAOlF,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAMxD;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGjD;AAED,eAAO,MAAM,oBAAoB,QAIuC,CAAC"}
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PLATFORM_KEY_MESSAGE = void 0;
4
+ exports.getApiKeyKind = getApiKeyKind;
5
+ exports.maskApiKey = maskApiKey;
6
+ const CONTENT_TEST_PREFIX = 'tf_content_test_';
7
+ const CONTENT_PREFIX = 'tf_content_';
8
+ const PLATFORM_PREFIX = 'tf_platform_';
9
+ const VISIBLE_KEY_CHARS = 10;
10
+ function getApiKeyKind(apiKey) {
11
+ const key = apiKey.trim();
12
+ if (key.startsWith(CONTENT_TEST_PREFIX))
13
+ return 'content_test';
14
+ if (key.startsWith(CONTENT_PREFIX))
15
+ return 'content_live';
16
+ if (key.startsWith(PLATFORM_PREFIX))
17
+ return 'platform';
18
+ return 'unknown';
19
+ }
20
+ function maskApiKey(apiKey) {
21
+ if (apiKey.length <= VISIBLE_KEY_CHARS)
22
+ return '***';
23
+ return `${apiKey.slice(0, VISIBLE_KEY_CHARS)}...`;
24
+ }
25
+ exports.PLATFORM_KEY_MESSAGE = 'tf_platform_ keys no longer work for content commands: TutorFlow moved courses, slides, ' +
26
+ 'tests, modules, videos, games and evaluations to the Content API. Use a tf_content_ key: ' +
27
+ '`tutorflow agent register` returns one (contentApiKey), or create one in the Agent Platform ' +
28
+ 'dashboard, then run `tutorflow auth login --api-key tf_content_...`.';
29
+ //# sourceMappingURL=keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/utils/keys.ts"],"names":[],"mappings":";;;AAaA,sCAMC;AAED,gCAGC;AAhBD,MAAM,mBAAmB,GAAG,kBAAkB,CAAC;AAC/C,MAAM,cAAc,GAAG,aAAa,CAAC;AACrC,MAAM,eAAe,GAAG,cAAc,CAAC;AACvC,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAE7B,SAAgB,aAAa,CAAC,MAAc;IAC1C,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;IAC1B,IAAI,GAAG,CAAC,UAAU,CAAC,mBAAmB,CAAC;QAAE,OAAO,cAAc,CAAC;IAC/D,IAAI,GAAG,CAAC,UAAU,CAAC,cAAc,CAAC;QAAE,OAAO,cAAc,CAAC;IAC1D,IAAI,GAAG,CAAC,UAAU,CAAC,eAAe,CAAC;QAAE,OAAO,UAAU,CAAC;IACvD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAgB,UAAU,CAAC,MAAc;IACvC,IAAI,MAAM,CAAC,MAAM,IAAI,iBAAiB;QAAE,OAAO,KAAK,CAAC;IACrD,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,iBAAiB,CAAC,KAAK,CAAC;AACpD,CAAC;AAEY,QAAA,oBAAoB,GAC/B,0FAA0F;IAC1F,2FAA2F;IAC3F,8FAA8F;IAC9F,sEAAsE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/utils/output.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AAEH,4EAA4E;AAC5E,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAmB/C;AAED,0EAA0E;AAC1E,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,GAAG,SAAkB,GAAG,IAAI,CAIpF;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,MAAM,CAgCnE"}
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/utils/output.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AAEH,4EAA4E;AAC5E,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAmB/C;AAaD,0EAA0E;AAC1E,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,GAAG,SAAkB,GAAG,IAAI,CAIpF;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,MAAM,CAiCnE"}
@@ -38,13 +38,23 @@ function printResult(data) {
38
38
  for (const [k, v] of Object.entries(data)) {
39
39
  if (v === undefined || v === null)
40
40
  continue;
41
- process.stdout.write(chalk_1.default.gray(` ${k}: ${v}\n`));
41
+ process.stdout.write(chalk_1.default.gray(` ${k}: ${formatValue(v)}\n`));
42
42
  }
43
43
  }
44
44
  else {
45
45
  process.stdout.write(String(data) + '\n');
46
46
  }
47
47
  }
48
+ const MAX_TEXT_VALUE_LENGTH = 200;
49
+ /** Nested values print as compact JSON instead of "[object Object]". */
50
+ function formatValue(value) {
51
+ if (typeof value !== 'object')
52
+ return String(value);
53
+ const json = JSON.stringify(value);
54
+ return json.length > MAX_TEXT_VALUE_LENGTH
55
+ ? `${json.slice(0, MAX_TEXT_VALUE_LENGTH)}… (use --json for the full value)`
56
+ : json;
57
+ }
48
58
  /** Status/progress line. Suppressed in JSON mode to keep stdout clean. */
49
59
  function printStatus(message, kind = 'info') {
50
60
  if ((0, runtime_1.isJsonMode)())
@@ -58,23 +68,28 @@ function formatTable(rows) {
58
68
  const columns = Object.keys(rows[0]);
59
69
  const colWidths = {};
60
70
  columns.forEach((col) => {
61
- colWidths[col] = Math.max(col.length, ...rows.map((r) => String(r[col] ?? '').length));
71
+ colWidths[col] = Math.max(col.length, ...rows.map((r) => formatCell(r[col]).length));
62
72
  });
63
- const border = columns.map((c) => '─'.repeat(colWidths[c] + 2)).join('┼');
73
+ const border = (junction) => columns.map((c) => '─'.repeat(colWidths[c] + 2)).join(junction);
64
74
  const header = columns
65
75
  .map((c) => ` ${c}${' '.repeat(colWidths[c] - c.length)} `)
66
76
  .join('│');
67
77
  const body = rows
68
78
  .map((r) => columns
69
79
  .map((c) => {
70
- const v = String(r[c] ?? '');
80
+ const v = formatCell(r[c]);
71
81
  return ` ${v}${' '.repeat(colWidths[c] - v.length)} `;
72
82
  })
73
83
  .join('│'))
74
84
  .join('\n');
75
- return `┌${border}┐\n│${header}│\n├${border}┤\n${body
85
+ return `┌${border('┬')}┐\n│${header}│\n├${border('┼')}┤\n${body
76
86
  .split('\n')
77
87
  .map((r) => `│${r}│`)
78
- .join('\n')}\n└${border}┘`;
88
+ .join('\n')}\n└${border('┴')}┘`;
89
+ }
90
+ function formatCell(value) {
91
+ if (value === undefined || value === null)
92
+ return '';
93
+ return typeof value === 'object' ? JSON.stringify(value) : String(value);
79
94
  }
80
95
  //# sourceMappingURL=output.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/utils/output.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/utils/output.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,14 @@
1
1
  /**
2
2
  * Runtime helpers shared by every command.
3
3
  *
4
- * Output mode and debug are set once on the root program and read here so
5
- * subcommands don't need to thread options through. They are the *only*
6
- * pieces of mutable global state in the CLI.
4
+ * Output mode, debug and the classroom override are set once on the root
5
+ * program and read here so subcommands don't need to thread options through.
6
+ * They are the *only* pieces of mutable global state in the CLI.
7
7
  */
8
8
  export declare function setJsonMode(on: boolean): void;
9
9
  export declare function setDebugMode(on: boolean): void;
10
+ export declare function setClassroomOverride(classroomId: string | undefined): void;
11
+ export declare function getClassroomOverride(): string | undefined;
10
12
  export declare function isJsonMode(): boolean;
11
13
  export declare function isDebugMode(): boolean;
12
14
  /**
@@ -14,20 +16,26 @@ export declare function isDebugMode(): boolean;
14
16
  * AI agent sandboxes, etc. — i.e. anywhere `@clack/prompts` would crash.
15
17
  */
16
18
  export declare function isInteractive(): boolean;
19
+ /** Prompts write to stdout, so JSON mode never prompts even on a TTY. */
20
+ export declare function canPrompt(): boolean;
17
21
  /**
18
22
  * Wrap a command action so:
19
23
  * - thrown errors always set exit code 1 (or the error's `exitCode`)
20
- * - in JSON mode, errors are serialized as { error: { message, code? } }
24
+ * - in JSON mode, errors are serialized as { error: { message, code, ...details } }
21
25
  * - in text mode, errors are formatted via `printError`
22
26
  * - stack traces are printed only when DEBUG / --debug is on
23
27
  */
24
28
  export declare function command<T extends unknown[]>(fn: (...args: T) => Promise<void> | void): (...args: T) => Promise<void>;
29
+ export type CliErrorDetails = Record<string, unknown>;
25
30
  export declare class CliError extends Error {
26
31
  readonly code: string;
27
32
  readonly exitCode: number;
33
+ /** Extra machine-readable fields merged into the JSON error (status, apiCode, hint, …). */
34
+ readonly details?: CliErrorDetails;
28
35
  constructor(message: string, opts?: {
29
36
  code?: string;
30
37
  exitCode?: number;
38
+ details?: CliErrorDetails;
31
39
  });
32
40
  }
33
41
  export declare function printError(error: unknown): void;
@@ -36,4 +44,6 @@ export declare function printError(error: unknown): void;
36
44
  * `hint` should describe the flags the caller could use instead.
37
45
  */
38
46
  export declare function requireInteractive(hint: string): void;
47
+ /** Progress line for long waits: stderr, text mode only, never in JSON mode. */
48
+ export declare function printProgress(message: string): void;
39
49
  //# sourceMappingURL=runtime.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/utils/runtime.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,wBAAgB,WAAW,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAE7C;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAE9C;AAED,wBAAgB,UAAU,IAAI,OAAO,CAGpC;AAED,wBAAgB,WAAW,IAAI,OAAO,CAErC;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,OAAO,EAAE,EACzC,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,GACvC,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAS/B;AAED,qBAAa,QAAS,SAAQ,KAAK;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAEd,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAO;CAK7E;AAiBD,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAc/C;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAMrD"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/utils/runtime.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,wBAAgB,WAAW,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAE7C;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAE9C;AAED,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAE1E;AAED,wBAAgB,oBAAoB,IAAI,MAAM,GAAG,SAAS,CAEzD;AAED,wBAAgB,UAAU,IAAI,OAAO,CAGpC;AAED,wBAAgB,WAAW,IAAI,OAAO,CAErC;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAED,yEAAyE;AACzE,wBAAgB,SAAS,IAAI,OAAO,CAEnC;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,OAAO,EAAE,EACzC,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,GACvC,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAS/B;AAED,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEtD,qBAAa,QAAS,SAAQ,KAAK;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,2FAA2F;IAC3F,QAAQ,CAAC,OAAO,CAAC,EAAE,eAAe,CAAC;gBAGjC,OAAO,EAAE,MAAM,EACf,IAAI,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,eAAe,CAAA;KAAO;CAO7E;AA0BD,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAqB/C;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAMrD;AAED,gFAAgF;AAChF,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAGnD"}
@@ -2,28 +2,39 @@
2
2
  /**
3
3
  * Runtime helpers shared by every command.
4
4
  *
5
- * Output mode and debug are set once on the root program and read here so
6
- * subcommands don't need to thread options through. They are the *only*
7
- * pieces of mutable global state in the CLI.
5
+ * Output mode, debug and the classroom override are set once on the root
6
+ * program and read here so subcommands don't need to thread options through.
7
+ * They are the *only* pieces of mutable global state in the CLI.
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.CliError = void 0;
11
11
  exports.setJsonMode = setJsonMode;
12
12
  exports.setDebugMode = setDebugMode;
13
+ exports.setClassroomOverride = setClassroomOverride;
14
+ exports.getClassroomOverride = getClassroomOverride;
13
15
  exports.isJsonMode = isJsonMode;
14
16
  exports.isDebugMode = isDebugMode;
15
17
  exports.isInteractive = isInteractive;
18
+ exports.canPrompt = canPrompt;
16
19
  exports.command = command;
17
20
  exports.printError = printError;
18
21
  exports.requireInteractive = requireInteractive;
22
+ exports.printProgress = printProgress;
19
23
  let jsonMode = false;
20
24
  let debugMode = false;
25
+ let classroomOverride;
21
26
  function setJsonMode(on) {
22
27
  jsonMode = on;
23
28
  }
24
29
  function setDebugMode(on) {
25
30
  debugMode = on;
26
31
  }
32
+ function setClassroomOverride(classroomId) {
33
+ classroomOverride = classroomId?.trim() || undefined;
34
+ }
35
+ function getClassroomOverride() {
36
+ return classroomOverride;
37
+ }
27
38
  function isJsonMode() {
28
39
  // Env var override lets agents set this once globally without a flag.
29
40
  return jsonMode || process.env.TUTORFLOW_JSON === '1';
@@ -38,10 +49,14 @@ function isDebugMode() {
38
49
  function isInteractive() {
39
50
  return Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY);
40
51
  }
52
+ /** Prompts write to stdout, so JSON mode never prompts even on a TTY. */
53
+ function canPrompt() {
54
+ return isInteractive() && !isJsonMode();
55
+ }
41
56
  /**
42
57
  * Wrap a command action so:
43
58
  * - thrown errors always set exit code 1 (or the error's `exitCode`)
44
- * - in JSON mode, errors are serialized as { error: { message, code? } }
59
+ * - in JSON mode, errors are serialized as { error: { message, code, ...details } }
45
60
  * - in text mode, errors are formatted via `printError`
46
61
  * - stack traces are printed only when DEBUG / --debug is on
47
62
  */
@@ -61,6 +76,7 @@ class CliError extends Error {
61
76
  super(message);
62
77
  this.code = opts.code ?? 'EGENERIC';
63
78
  this.exitCode = opts.exitCode ?? 1;
79
+ this.details = opts.details;
64
80
  }
65
81
  }
66
82
  exports.CliError = CliError;
@@ -79,15 +95,28 @@ function getErrorMessage(error) {
79
95
  return error.message;
80
96
  return String(error);
81
97
  }
98
+ function getErrorDetails(error) {
99
+ if (error instanceof CliError && error.details) {
100
+ return Object.fromEntries(Object.entries(error.details).filter(([, value]) => value !== undefined));
101
+ }
102
+ return {};
103
+ }
82
104
  function printError(error) {
83
105
  const message = getErrorMessage(error);
84
106
  const code = getErrorCode(error);
107
+ const details = getErrorDetails(error);
85
108
  if (isJsonMode()) {
86
- process.stderr.write(JSON.stringify({ error: { message, code } }) + '\n');
109
+ process.stderr.write(JSON.stringify({ error: { message, code, ...details } }) + '\n');
87
110
  }
88
111
  else {
89
112
  // chalk is loaded by callers; keep this dependency-free and use ANSI directly.
90
113
  process.stderr.write(`\x1b[31m✗ ${message}\x1b[0m\n`);
114
+ if (typeof details.hint === 'string') {
115
+ process.stderr.write(`\x1b[90m ${details.hint}\x1b[0m\n`);
116
+ }
117
+ if (typeof details.requestId === 'string') {
118
+ process.stderr.write(`\x1b[90m request id: ${details.requestId}\x1b[0m\n`);
119
+ }
91
120
  }
92
121
  if (isDebugMode() && error instanceof Error && error.stack) {
93
122
  process.stderr.write(error.stack + '\n');
@@ -98,8 +127,14 @@ function printError(error) {
98
127
  * `hint` should describe the flags the caller could use instead.
99
128
  */
100
129
  function requireInteractive(hint) {
101
- if (isInteractive())
130
+ if (canPrompt())
131
+ return;
132
+ throw new CliError(`Required input not provided and no prompt is possible (no terminal, or JSON mode). ${hint}`, { code: 'ENOINTERACTIVE', exitCode: 2 });
133
+ }
134
+ /** Progress line for long waits: stderr, text mode only, never in JSON mode. */
135
+ function printProgress(message) {
136
+ if (isJsonMode())
102
137
  return;
103
- throw new CliError(`Required input not provided and stdin is not a terminal. ${hint}`, { code: 'ENOINTERACTIVE', exitCode: 2 });
138
+ process.stderr.write(`\x1b[90m${message}\x1b[0m\n`);
104
139
  }
105
140
  //# sourceMappingURL=runtime.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/utils/runtime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/utils/runtime.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tutorflow/cli",
3
- "version": "0.3.1",
4
- "description": "TutorFlow CLI - agent-friendly tool for creating AI-powered educational content (slides, videos, courses) and evaluating student responses. Supports --json output, env-var auth, and non-interactive use.",
3
+ "version": "0.5.0",
4
+ "description": "TutorFlow CLI - agent-friendly command line for the TutorFlow Content API: generate courses, slides, tests, modules, videos, games and simulations, grade learner answers, and manage learners and webhooks. Supports --json output, env-var auth, --wait polling, and non-interactive use.",
5
5
  "keywords": [
6
6
  "tutorflow",
7
7
  "education",
@@ -14,12 +14,13 @@
14
14
  "tutor",
15
15
  "lesson",
16
16
  "evaluation",
17
+ "content-api",
17
18
  "cli",
18
19
  "agent",
19
20
  "automation"
20
21
  ],
21
22
  "bin": {
22
- "tutorflow": "./dist/index.js"
23
+ "tutorflow": "dist/index.js"
23
24
  },
24
25
  "main": "./dist/index.js",
25
26
  "types": "./dist/index.d.ts",
@@ -1,8 +0,0 @@
1
- import { spinner as clackSpinner } from '@clack/prompts';
2
- export type Spinner = ReturnType<typeof clackSpinner>;
3
- export declare function createSpinner(): Spinner;
4
- export declare function startSpinner(message: string): Spinner;
5
- export declare function stopSpinner(s: Spinner, message: string): void;
6
- export declare function successSpinner(s: Spinner, message: string): void;
7
- export declare function errorSpinner(s: Spinner, message: string): void;
8
- //# sourceMappingURL=spinner.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"spinner.d.ts","sourceRoot":"","sources":["../../src/utils/spinner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEzD,MAAM,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AAEtD,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAIrD;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAE7D;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAEhE;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAE9D"}
@@ -1,26 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createSpinner = createSpinner;
4
- exports.startSpinner = startSpinner;
5
- exports.stopSpinner = stopSpinner;
6
- exports.successSpinner = successSpinner;
7
- exports.errorSpinner = errorSpinner;
8
- const prompts_1 = require("@clack/prompts");
9
- function createSpinner() {
10
- return (0, prompts_1.spinner)();
11
- }
12
- function startSpinner(message) {
13
- const s = (0, prompts_1.spinner)();
14
- s.start(message);
15
- return s;
16
- }
17
- function stopSpinner(s, message) {
18
- s.stop(message);
19
- }
20
- function successSpinner(s, message) {
21
- s.stop(`✓ ${message}`);
22
- }
23
- function errorSpinner(s, message) {
24
- s.stop(`✗ ${message}`);
25
- }
26
- //# sourceMappingURL=spinner.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"spinner.js","sourceRoot":"","sources":["../../src/utils/spinner.ts"],"names":[],"mappings":";;AAIA,sCAEC;AAED,oCAIC;AAED,kCAEC;AAED,wCAEC;AAED,oCAEC;AAxBD,4CAAyD;AAIzD,SAAgB,aAAa;IAC3B,OAAO,IAAA,iBAAY,GAAE,CAAC;AACxB,CAAC;AAED,SAAgB,YAAY,CAAC,OAAe;IAC1C,MAAM,CAAC,GAAG,IAAA,iBAAY,GAAE,CAAC;IACzB,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACjB,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAgB,WAAW,CAAC,CAAU,EAAE,OAAe;IACrD,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AAClB,CAAC;AAED,SAAgB,cAAc,CAAC,CAAU,EAAE,OAAe;IACxD,CAAC,CAAC,IAAI,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC;AACzB,CAAC;AAED,SAAgB,YAAY,CAAC,CAAU,EAAE,OAAe;IACtD,CAAC,CAAC,IAAI,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC;AACzB,CAAC"}