@tostudy-ai/cli 0.17.0 → 0.17.2
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/cli.js +111 -39
- package/dist/cli.js.map +3 -3
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1668,7 +1668,7 @@ function formatLesson(data) {
|
|
|
1668
1668
|
if (lesson.exerciseContent) {
|
|
1669
1669
|
lines.push("", "\u2500\u2500\u2500 Exerc\xEDcio \u2500\u2500\u2500", lesson.exerciseContent);
|
|
1670
1670
|
}
|
|
1671
|
-
if (/^checkpoint/i.test(lesson.title.trim())) {
|
|
1671
|
+
if (lesson.type === "checkpoint" || /^checkpoint/i.test(lesson.title.trim())) {
|
|
1672
1672
|
lines.push(
|
|
1673
1673
|
"",
|
|
1674
1674
|
"\u{1F4A1} Escreva suas respostas num arquivo (ex: checkpoint.md) e valide:",
|
|
@@ -1758,11 +1758,20 @@ function formatModuleStart(data) {
|
|
|
1758
1758
|
if (firstLesson.acceptanceCriteria) {
|
|
1759
1759
|
lines.push("", "Crit\xE9rios de aceita\xE7\xE3o:", firstLesson.acceptanceCriteria);
|
|
1760
1760
|
}
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1761
|
+
if (firstLesson.type === "checkpoint" || /^checkpoint/i.test(firstLesson.title.trim())) {
|
|
1762
|
+
lines.push(
|
|
1763
|
+
"",
|
|
1764
|
+
"\u{1F4A1} Escreva suas respostas num arquivo (ex: checkpoint.md) e valide:",
|
|
1765
|
+
" tostudy validate checkpoint.md",
|
|
1766
|
+
"\u2192 tostudy hint para obter uma dica"
|
|
1767
|
+
);
|
|
1768
|
+
} else {
|
|
1769
|
+
lines.push(
|
|
1770
|
+
"",
|
|
1771
|
+
"\u2192 tostudy validate <resposta> para validar sua solu\xE7\xE3o",
|
|
1772
|
+
"\u2192 tostudy hint para obter uma dica"
|
|
1773
|
+
);
|
|
1774
|
+
}
|
|
1766
1775
|
return lines.join("\n");
|
|
1767
1776
|
}
|
|
1768
1777
|
function formatMoreTheory(data) {
|
|
@@ -1917,6 +1926,13 @@ var init_ide_detector = __esm({
|
|
|
1917
1926
|
});
|
|
1918
1927
|
|
|
1919
1928
|
// src/output/instruction-template-v3.ts
|
|
1929
|
+
var instruction_template_v3_exports = {};
|
|
1930
|
+
__export(instruction_template_v3_exports, {
|
|
1931
|
+
COURSE_TEMPLATE_VERSION: () => COURSE_TEMPLATE_VERSION,
|
|
1932
|
+
UNIVERSAL_TEMPLATE_VERSION: () => UNIVERSAL_TEMPLATE_VERSION,
|
|
1933
|
+
renderCourseInstruction: () => renderCourseInstruction,
|
|
1934
|
+
renderUniversalInstruction: () => renderUniversalInstruction
|
|
1935
|
+
});
|
|
1920
1936
|
function renderCourseInstruction(input2) {
|
|
1921
1937
|
const sections = [];
|
|
1922
1938
|
sections.push(renderTitle(input2));
|
|
@@ -1990,7 +2006,7 @@ Quando \`tostudy next --json\` retornar \`MODULE_COMPLETE\`:
|
|
|
1990
2006
|
Isso garante continuidade entre sess\xF5es e evita estouro de contexto em sess\xF5es longas.`);
|
|
1991
2007
|
sections.push(renderHandlingSituations());
|
|
1992
2008
|
sections.push(renderTechnicalReference());
|
|
1993
|
-
sections.push(`<!-- tostudy-template-version:
|
|
2009
|
+
sections.push(`<!-- tostudy-template-version: ${UNIVERSAL_TEMPLATE_VERSION} -->`);
|
|
1994
2010
|
return sections.join("\n\n") + "\n";
|
|
1995
2011
|
}
|
|
1996
2012
|
function renderTitle(input2) {
|
|
@@ -2235,12 +2251,14 @@ function renderTechnicalReference() {
|
|
|
2235
2251
|
}
|
|
2236
2252
|
function renderFooter(course) {
|
|
2237
2253
|
return `<!-- tostudy-course-id: ${course.courseId} -->
|
|
2238
|
-
<!-- tostudy-template-version:
|
|
2254
|
+
<!-- tostudy-template-version: ${COURSE_TEMPLATE_VERSION} -->`;
|
|
2239
2255
|
}
|
|
2240
|
-
var TONE_LABELS, LEVEL_LABELS;
|
|
2256
|
+
var COURSE_TEMPLATE_VERSION, UNIVERSAL_TEMPLATE_VERSION, TONE_LABELS, LEVEL_LABELS;
|
|
2241
2257
|
var init_instruction_template_v3 = __esm({
|
|
2242
2258
|
"src/output/instruction-template-v3.ts"() {
|
|
2243
2259
|
"use strict";
|
|
2260
|
+
COURSE_TEMPLATE_VERSION = 4;
|
|
2261
|
+
UNIVERSAL_TEMPLATE_VERSION = 5;
|
|
2244
2262
|
TONE_LABELS = {
|
|
2245
2263
|
formal: "formal",
|
|
2246
2264
|
casual: "casual",
|
|
@@ -2972,6 +2990,24 @@ async function writeWorkspaceMarker(workspacePath, input2, options = {}) {
|
|
|
2972
2990
|
}
|
|
2973
2991
|
const existing = await readWorkspaceMarker(workspacePath);
|
|
2974
2992
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2993
|
+
let carried = {};
|
|
2994
|
+
if (existing && existing.courseId === input2.courseId) {
|
|
2995
|
+
try {
|
|
2996
|
+
const raw = JSON.parse(readFileSync2(filePath, "utf-8"));
|
|
2997
|
+
for (const key of [
|
|
2998
|
+
"currentLessonId",
|
|
2999
|
+
"currentModuleId",
|
|
3000
|
+
"courseTags",
|
|
3001
|
+
"courseLevel",
|
|
3002
|
+
"lastInitCourseId",
|
|
3003
|
+
"templateVersion"
|
|
3004
|
+
]) {
|
|
3005
|
+
if (raw[key] !== void 0) carried[key] = raw[key];
|
|
3006
|
+
}
|
|
3007
|
+
} catch {
|
|
3008
|
+
carried = {};
|
|
3009
|
+
}
|
|
3010
|
+
}
|
|
2975
3011
|
const marker = {
|
|
2976
3012
|
version: CURRENT_VERSION,
|
|
2977
3013
|
courseId: input2.courseId,
|
|
@@ -2981,7 +3017,7 @@ async function writeWorkspaceMarker(workspacePath, input2, options = {}) {
|
|
|
2981
3017
|
createdAt: existing?.createdAt ?? now,
|
|
2982
3018
|
updatedAt: now
|
|
2983
3019
|
};
|
|
2984
|
-
writeFileSync3(filePath, JSON.stringify(marker, null, 2), { mode: 384 });
|
|
3020
|
+
writeFileSync3(filePath, JSON.stringify({ ...carried, ...marker }, null, 2), { mode: 384 });
|
|
2985
3021
|
return filePath;
|
|
2986
3022
|
}
|
|
2987
3023
|
var CURRENT_VERSION, SUPPORTED_VERSIONS;
|
|
@@ -3026,6 +3062,7 @@ async function readWorkspaceState(workspacePath) {
|
|
|
3026
3062
|
state.courseLevel = raw.courseLevel;
|
|
3027
3063
|
}
|
|
3028
3064
|
if (typeof raw.lastInitCourseId === "string") state.lastInitCourseId = raw.lastInitCourseId;
|
|
3065
|
+
if (typeof raw.templateVersion === "number") state.templateVersion = raw.templateVersion;
|
|
3029
3066
|
return state;
|
|
3030
3067
|
} catch {
|
|
3031
3068
|
return null;
|
|
@@ -3079,16 +3116,31 @@ async function setLastInitCourseId(courseId, _configDir) {
|
|
|
3079
3116
|
}
|
|
3080
3117
|
async function checkCourseDrift() {
|
|
3081
3118
|
const { findWorkspaceState: findWorkspaceState2 } = await Promise.resolve().then(() => (init_workspace_state(), workspace_state_exports));
|
|
3119
|
+
const { COURSE_TEMPLATE_VERSION: COURSE_TEMPLATE_VERSION2 } = await Promise.resolve().then(() => (init_instruction_template_v3(), instruction_template_v3_exports));
|
|
3082
3120
|
const result = await findWorkspaceState2();
|
|
3083
3121
|
if (!result) return null;
|
|
3084
3122
|
const state = result.state;
|
|
3085
|
-
|
|
3086
|
-
if (state.lastInitCourseId
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3123
|
+
const warnings = [];
|
|
3124
|
+
if (state.lastInitCourseId && state.lastInitCourseId !== state.courseId) {
|
|
3125
|
+
warnings.push(
|
|
3126
|
+
[
|
|
3127
|
+
`\u26A0\uFE0F Curso ativo mudou para "${state.courseTitle}".`,
|
|
3128
|
+
` Rode \`tostudy init\` para atualizar o contexto do assistente.`,
|
|
3129
|
+
""
|
|
3130
|
+
].join("\n")
|
|
3131
|
+
);
|
|
3132
|
+
}
|
|
3133
|
+
if ((state.templateVersion ?? 0) < COURSE_TEMPLATE_VERSION2) {
|
|
3134
|
+
const from = state.templateVersion ? `v${state.templateVersion}` : "vers\xE3o antiga";
|
|
3135
|
+
warnings.push(
|
|
3136
|
+
[
|
|
3137
|
+
`\u26A0\uFE0F As instru\xE7\xF5es do tutor neste workspace est\xE3o desatualizadas (${from} < v${COURSE_TEMPLATE_VERSION2}).`,
|
|
3138
|
+
` Rode \`tostudy sync\` para atualizar as regras do tutor.`,
|
|
3139
|
+
""
|
|
3140
|
+
].join("\n")
|
|
3141
|
+
);
|
|
3142
|
+
}
|
|
3143
|
+
return warnings.length > 0 ? warnings.join("\n") : null;
|
|
3092
3144
|
}
|
|
3093
3145
|
var init_course_drift = __esm({
|
|
3094
3146
|
"src/onboarding/course-drift.ts"() {
|
|
@@ -3479,7 +3531,7 @@ var CLI_VERSION;
|
|
|
3479
3531
|
var init_version = __esm({
|
|
3480
3532
|
"src/version.ts"() {
|
|
3481
3533
|
"use strict";
|
|
3482
|
-
CLI_VERSION = true ? "0.17.
|
|
3534
|
+
CLI_VERSION = true ? "0.17.2" : "0.7.1";
|
|
3483
3535
|
}
|
|
3484
3536
|
});
|
|
3485
3537
|
|
|
@@ -4195,13 +4247,18 @@ async function resolveAndGenerate(input2, options = {}, context) {
|
|
|
4195
4247
|
} catch (err) {
|
|
4196
4248
|
logger6.warn("Failed to write workspace marker", { err });
|
|
4197
4249
|
}
|
|
4250
|
+
let workspaceStateRecorded = false;
|
|
4198
4251
|
if (markerPath) {
|
|
4199
4252
|
try {
|
|
4200
4253
|
await updateWorkspaceState(context.cwd, {
|
|
4201
4254
|
courseTags: courseMeta.courseTags,
|
|
4202
4255
|
courseLevel: courseMeta.courseLevel,
|
|
4203
|
-
lastInitCourseId: input2.courseId
|
|
4256
|
+
lastInitCourseId: input2.courseId,
|
|
4257
|
+
// GH #1534: record which template generated the instruction files so
|
|
4258
|
+
// checkCourseDrift() can flag stale workspaces after a template bump.
|
|
4259
|
+
templateVersion: COURSE_TEMPLATE_VERSION
|
|
4204
4260
|
});
|
|
4261
|
+
workspaceStateRecorded = true;
|
|
4205
4262
|
} catch (err) {
|
|
4206
4263
|
logger6.warn("Failed to update workspace state v2 fields", {
|
|
4207
4264
|
error: err instanceof Error ? err.message : String(err)
|
|
@@ -4215,7 +4272,8 @@ async function resolveAndGenerate(input2, options = {}, context) {
|
|
|
4215
4272
|
usedT1: studentBrief !== null,
|
|
4216
4273
|
usedT2: enrollmentProfile !== null,
|
|
4217
4274
|
bootstrapped,
|
|
4218
|
-
renderedInstruction: content
|
|
4275
|
+
renderedInstruction: content,
|
|
4276
|
+
workspaceStateRecorded
|
|
4219
4277
|
};
|
|
4220
4278
|
}
|
|
4221
4279
|
var logger6, defaultDeps2;
|
|
@@ -4873,12 +4931,15 @@ function adjustTimeEstimate(type, baseMinutes) {
|
|
|
4873
4931
|
if (type === "exercise") return Math.max(baseMinutes, 30);
|
|
4874
4932
|
return baseMinutes;
|
|
4875
4933
|
}
|
|
4876
|
-
function isCheckpoint(title) {
|
|
4877
|
-
return /^checkpoint/i.test(title.trim());
|
|
4934
|
+
function isCheckpoint(type, title) {
|
|
4935
|
+
return type === "checkpoint" || /^checkpoint/i.test(title.trim());
|
|
4936
|
+
}
|
|
4937
|
+
function isPracticalType(type) {
|
|
4938
|
+
return type === "exercise" || type === "checkpoint" || type === "realworld" || type === "project";
|
|
4878
4939
|
}
|
|
4879
4940
|
function formatLessonContent(data, workspacePath, courseTitle) {
|
|
4880
4941
|
const time3 = adjustTimeEstimate(data.type, data.estimatedTimeMinutes);
|
|
4881
|
-
const isPractical = data.type
|
|
4942
|
+
const isPractical = isPracticalType(data.type) || isCheckpoint(data.type, data.title);
|
|
4882
4943
|
const lines = [`\u2501\u2501\u2501 Li\xE7\xE3o: ${data.title} \u2501\u2501\u2501`];
|
|
4883
4944
|
if (isPractical && workspacePath) {
|
|
4884
4945
|
const base = path13.basename(workspacePath) === ".tostudy" ? path13.dirname(workspacePath) : workspacePath;
|
|
@@ -4899,7 +4960,7 @@ function formatLessonContent(data, workspacePath, courseTitle) {
|
|
|
4899
4960
|
if (data.hints && data.hints.length > 0) {
|
|
4900
4961
|
lines.push("", `Dicas dispon\xEDveis: ${data.hints.length}`);
|
|
4901
4962
|
}
|
|
4902
|
-
if (isCheckpoint(data.title)) {
|
|
4963
|
+
if (isCheckpoint(data.type, data.title)) {
|
|
4903
4964
|
lines.push(
|
|
4904
4965
|
"",
|
|
4905
4966
|
"\u{1F4A1} Escreva suas respostas num arquivo (ex: checkpoint.md) e valide:",
|
|
@@ -4975,7 +5036,7 @@ var init_lesson = __esm({
|
|
|
4975
5036
|
{ json: false }
|
|
4976
5037
|
);
|
|
4977
5038
|
}
|
|
4978
|
-
if (content.type
|
|
5039
|
+
if (isPracticalType(content.type) && !ws.found) {
|
|
4979
5040
|
process.stderr.write(
|
|
4980
5041
|
"\n\u{1F4A1} Dica: rode `tostudy select` desta pasta para us\xE1-la como workspace, ou `tostudy workspace setup` para criar em ~/study/.\n"
|
|
4981
5042
|
);
|
|
@@ -21609,6 +21670,7 @@ var init_sync = __esm({
|
|
|
21609
21670
|
init_guards();
|
|
21610
21671
|
init_formatter();
|
|
21611
21672
|
init_instruction_pipeline();
|
|
21673
|
+
init_workspace_state();
|
|
21612
21674
|
init_root_agents_consent();
|
|
21613
21675
|
init_pipeline_deps();
|
|
21614
21676
|
logger22 = createLogger("cli:sync");
|
|
@@ -21622,8 +21684,10 @@ var init_sync = __esm({
|
|
|
21622
21684
|
try {
|
|
21623
21685
|
await requireSession();
|
|
21624
21686
|
const activeCourse = await requireActiveCourse();
|
|
21687
|
+
const found = await findWorkspaceState();
|
|
21688
|
+
const workspaceCwd = found?.workspacePath ?? process.cwd();
|
|
21625
21689
|
const rootAgents = await resolveRootAgentsConsent({
|
|
21626
|
-
cwd:
|
|
21690
|
+
cwd: workspaceCwd,
|
|
21627
21691
|
flag: opts.rootAgents,
|
|
21628
21692
|
interactive: isInteractiveTerminal(opts.json)
|
|
21629
21693
|
});
|
|
@@ -21631,7 +21695,7 @@ var init_sync = __esm({
|
|
|
21631
21695
|
{ courseId: activeCourse.courseId, enrollmentId: activeCourse.enrollmentId },
|
|
21632
21696
|
{ forceRefresh: true, collectT1Interactive: false, collectT2Interactive: false },
|
|
21633
21697
|
{
|
|
21634
|
-
cwd:
|
|
21698
|
+
cwd: workspaceCwd,
|
|
21635
21699
|
deps: buildPipelineDeps({
|
|
21636
21700
|
allRuntimes: opts.allRuntimes,
|
|
21637
21701
|
rootAgentsConsent: rootAgents.consent
|
|
@@ -21651,21 +21715,25 @@ var init_sync = __esm({
|
|
|
21651
21715
|
markerPath: pipelineResult.markerPath,
|
|
21652
21716
|
usedT0: pipelineResult.usedT0,
|
|
21653
21717
|
usedT1: pipelineResult.usedT1,
|
|
21654
|
-
usedT2: pipelineResult.usedT2
|
|
21718
|
+
usedT2: pipelineResult.usedT2,
|
|
21719
|
+
workspaceStateRecorded: pipelineResult.workspaceStateRecorded
|
|
21655
21720
|
},
|
|
21656
21721
|
{ json: true }
|
|
21657
21722
|
);
|
|
21658
21723
|
} else {
|
|
21659
|
-
|
|
21660
|
-
|
|
21661
|
-
|
|
21662
|
-
|
|
21663
|
-
|
|
21664
|
-
|
|
21665
|
-
|
|
21666
|
-
|
|
21667
|
-
|
|
21668
|
-
|
|
21724
|
+
const lines = [
|
|
21725
|
+
`\u2713 Instru\xE7\xF5es sincronizadas para "${activeCourse.courseTitle}"`,
|
|
21726
|
+
` - T0 (persona): ${pipelineResult.usedT0 ? "presente" : "ausente"}`,
|
|
21727
|
+
` - T1 (brief base): ${pipelineResult.usedT1 ? "presente" : "ausente"}`,
|
|
21728
|
+
` - T2 (curso): ${pipelineResult.usedT2 ? "presente" : "ausente"}`,
|
|
21729
|
+
` - Arquivos: ${pipelineResult.wroteFiles.join(", ")}`
|
|
21730
|
+
];
|
|
21731
|
+
if (!pipelineResult.workspaceStateRecorded) {
|
|
21732
|
+
lines.push(
|
|
21733
|
+
`\u26A0 N\xE3o consegui gravar .tostudy/workspace.json \u2014 o aviso de template pode continuar aparecendo. Verifique as permiss\xF5es do diret\xF3rio do workspace.`
|
|
21734
|
+
);
|
|
21735
|
+
}
|
|
21736
|
+
output(lines.join("\n"), { json: false });
|
|
21669
21737
|
}
|
|
21670
21738
|
} catch (err) {
|
|
21671
21739
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -21920,6 +21988,7 @@ var init_context = __esm({
|
|
|
21920
21988
|
init_dist();
|
|
21921
21989
|
init_workspace_state();
|
|
21922
21990
|
init_storage();
|
|
21991
|
+
init_course_state();
|
|
21923
21992
|
init_formatter();
|
|
21924
21993
|
init_errors();
|
|
21925
21994
|
logger27 = createLogger("cli:context");
|
|
@@ -21930,6 +21999,8 @@ var init_context = __esm({
|
|
|
21930
21999
|
if (opts.json) jsonError("no_workspace");
|
|
21931
22000
|
error(getErrors().noActiveCourse.trimEnd());
|
|
21932
22001
|
}
|
|
22002
|
+
const driftWarning = await checkCourseDrift();
|
|
22003
|
+
if (driftWarning && !opts.json) process.stderr.write(driftWarning + "\n");
|
|
21933
22004
|
const sessionCtx = await loadSessionContext(ws.workspacePath);
|
|
21934
22005
|
const result = {
|
|
21935
22006
|
workspace: {
|
|
@@ -21948,7 +22019,8 @@ var init_context = __esm({
|
|
|
21948
22019
|
summary: s.summary,
|
|
21949
22020
|
savedAt: s.savedAt
|
|
21950
22021
|
})),
|
|
21951
|
-
totalModulesCompleted: sessionCtx.moduleSummaries.length
|
|
22022
|
+
totalModulesCompleted: sessionCtx.moduleSummaries.length,
|
|
22023
|
+
driftWarning: driftWarning ?? null
|
|
21952
22024
|
};
|
|
21953
22025
|
logger27.debug("Context loaded", {
|
|
21954
22026
|
courseId: ws.state.courseId,
|