@przeprogramowani/10x-cli 1.7.0 → 1.8.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.
- package/README.md +14 -0
- package/dist/index.mjs +64 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -69,6 +69,7 @@ Once installed, just tell your agent to **set up 10x-cli** and it will pick up t
|
|
|
69
69
|
| `--name <name>` | Filter by artifact name (requires `--type`) |
|
|
70
70
|
| `--dry-run` | Show what would be written without touching the filesystem |
|
|
71
71
|
| `--course <slug>` | Override the course slug (default: `10xdevs3`) |
|
|
72
|
+
| `--no-course-rules` | Skip the course rules block in your rules file (`CLAUDE.md`/`AGENTS.md`); strips an existing one. Use `--course-rules` to re-enable. |
|
|
72
73
|
|
|
73
74
|
#### Examples
|
|
74
75
|
|
|
@@ -88,8 +89,21 @@ Once installed, just tell your agent to **set up 10x-cli** and it will pick up t
|
|
|
88
89
|
|
|
89
90
|
# Use with a different AI coding tool
|
|
90
91
|
10x get m1l1 --tool cursor
|
|
92
|
+
|
|
93
|
+
# Skip the course rules block (use only your rules). Persisted across runs;
|
|
94
|
+
# a previously-applied block is stripped. Re-enable later with --course-rules.
|
|
95
|
+
10x get m1l1 --no-course-rules
|
|
96
|
+
10x get m1l2 --course-rules
|
|
97
|
+
|
|
98
|
+
# An explicit rules request always applies, even with the opt-out persisted
|
|
99
|
+
10x get m1l1 --type rules
|
|
91
100
|
```
|
|
92
101
|
|
|
102
|
+
> The `--no-course-rules` / `--course-rules` choice is saved as `courseRules`
|
|
103
|
+
> in `config.json` and applies to subsequent plain `10x get` runs. An explicit
|
|
104
|
+
> `--type rules` request overrides the opt-out for that run. Skills, prompts,
|
|
105
|
+
> and config-templates are unaffected.
|
|
106
|
+
|
|
93
107
|
### Global Flags
|
|
94
108
|
|
|
95
109
|
- `--json` — Machine-readable JSON output (auto-detected when piped)
|
package/dist/index.mjs
CHANGED
|
@@ -2271,7 +2271,7 @@ var cac = (name = "") => new CAC(name);
|
|
|
2271
2271
|
// package.json
|
|
2272
2272
|
var package_default = {
|
|
2273
2273
|
name: "@przeprogramowani/10x-cli",
|
|
2274
|
-
version: "1.
|
|
2274
|
+
version: "1.8.0",
|
|
2275
2275
|
description: "Open-source CLI for 10xDevs course content",
|
|
2276
2276
|
repository: {
|
|
2277
2277
|
type: "git",
|
|
@@ -2992,6 +2992,9 @@ function readToolConfig() {
|
|
|
2992
2992
|
if (parsed.acknowledgedOrphans !== undefined && (!Array.isArray(parsed.acknowledgedOrphans) || !parsed.acknowledgedOrphans.every((x2) => typeof x2 === "string"))) {
|
|
2993
2993
|
delete parsed.acknowledgedOrphans;
|
|
2994
2994
|
}
|
|
2995
|
+
if (parsed.courseRules !== undefined && typeof parsed.courseRules !== "boolean") {
|
|
2996
|
+
delete parsed.courseRules;
|
|
2997
|
+
}
|
|
2995
2998
|
return parsed;
|
|
2996
2999
|
} catch {
|
|
2997
3000
|
return null;
|
|
@@ -3004,6 +3007,14 @@ function saveToolConfig(config) {
|
|
|
3004
3007
|
}
|
|
3005
3008
|
writeJsonAtomic(toolConfigPath(), config);
|
|
3006
3009
|
}
|
|
3010
|
+
function updateToolConfig(patch) {
|
|
3011
|
+
const current = readToolConfig();
|
|
3012
|
+
const merged = { ...current, ...patch };
|
|
3013
|
+
if (typeof merged.tool !== "string") {
|
|
3014
|
+
throw new Error("updateToolConfig: refusing to persist a config without a `tool` — " + "no prior config exists and the patch did not seed one.");
|
|
3015
|
+
}
|
|
3016
|
+
saveToolConfig(merged);
|
|
3017
|
+
}
|
|
3007
3018
|
|
|
3008
3019
|
// src/lib/api-client.ts
|
|
3009
3020
|
var DEFAULT_API_BASE = "https://10x-toolkit-api.przeprogramowani.workers.dev";
|
|
@@ -4563,6 +4574,7 @@ async function applyBundle(bundle, projectRoot, options = {}) {
|
|
|
4563
4574
|
const course = options.course ?? DEFAULT_COURSE;
|
|
4564
4575
|
const profile = options.profile ?? PROFILES[DEFAULT_TOOL];
|
|
4565
4576
|
const onConflict = options.onConflict;
|
|
4577
|
+
const applyCourseRules = options.applyCourseRules !== false;
|
|
4566
4578
|
const manifestDir = join5(projectRoot, profile.manifestDir);
|
|
4567
4579
|
const prevManifest = readManifest(manifestDir);
|
|
4568
4580
|
for (const skill of bundle.skills) {
|
|
@@ -4672,7 +4684,17 @@ async function applyBundle(bundle, projectRoot, options = {}) {
|
|
|
4672
4684
|
const rulesFilePath = join5(projectRoot, profile.rulesFile);
|
|
4673
4685
|
const existingRules = readFileOrEmpty(rulesFilePath);
|
|
4674
4686
|
let rulesAction;
|
|
4675
|
-
if (
|
|
4687
|
+
if (!applyCourseRules) {
|
|
4688
|
+
const { content: stripped, removed: removed2 } = removeRulesBlockWithMarkers(existingRules, profile.sentinelBegin, profile.sentinelEnd);
|
|
4689
|
+
if (removed2 && stripped !== existingRules) {
|
|
4690
|
+
rulesAction = "removed";
|
|
4691
|
+
if (!dryRun) {
|
|
4692
|
+
writeFileAt(rulesFilePath, stripped);
|
|
4693
|
+
}
|
|
4694
|
+
} else {
|
|
4695
|
+
rulesAction = "unchanged";
|
|
4696
|
+
}
|
|
4697
|
+
} else if (bundle.rules.length === 0) {
|
|
4676
4698
|
rulesAction = "unchanged";
|
|
4677
4699
|
} else {
|
|
4678
4700
|
const rulesBody = bundle.rules.map((r2) => r2.content.trim()).join(`
|
|
@@ -5346,9 +5368,16 @@ var ARTIFACT_TYPES = ["skills", "prompts", "rules", "configs"];
|
|
|
5346
5368
|
function isArtifactType(s) {
|
|
5347
5369
|
return ARTIFACT_TYPES.includes(s);
|
|
5348
5370
|
}
|
|
5371
|
+
function resolveCourseRulesFlag(argv) {
|
|
5372
|
+
if (argv.includes("--no-course-rules"))
|
|
5373
|
+
return false;
|
|
5374
|
+
if (argv.includes("--course-rules"))
|
|
5375
|
+
return true;
|
|
5376
|
+
return;
|
|
5377
|
+
}
|
|
5349
5378
|
var DEFAULT_COURSE2 = "10xdevs3";
|
|
5350
5379
|
function registerGetCommand(cli) {
|
|
5351
|
-
cli.command("get <ref>", "Fetch and apply a lesson pack").option("--dry-run", "Show what would be written without touching the filesystem").option("--course <course>", "Override the course slug (default: 10xdevs3)").option("--tool <tool>", "AI coding tool (claude-code, cursor, copilot, codex, windsurf, gemini, generic)").option("--print", "Print artifact content to stdout instead of writing to files").option("--type <type>", "Artifact type filter: skills, prompts, rules, configs").option("--name <name>", "Artifact name filter (requires --type)").option("--lang <lang>", "Content language: en (default) or pl").action(async (ref, options) => {
|
|
5380
|
+
cli.command("get <ref>", "Fetch and apply a lesson pack").option("--dry-run", "Show what would be written without touching the filesystem").option("--course <course>", "Override the course slug (default: 10xdevs3)").option("--tool <tool>", "AI coding tool (claude-code, cursor, copilot, codex, windsurf, gemini, generic)").option("--print", "Print artifact content to stdout instead of writing to files").option("--type <type>", "Artifact type filter: skills, prompts, rules, configs").option("--name <name>", "Artifact name filter (requires --type)").option("--lang <lang>", "Content language: en (default) or pl").option("--no-course-rules", "Skip applying the course rules block to your rules file (CLAUDE.md/AGENTS.md)").action(async (ref, options) => {
|
|
5352
5381
|
const ctx = resolveContext(options);
|
|
5353
5382
|
await runGet(ctx, ref, options);
|
|
5354
5383
|
});
|
|
@@ -5371,10 +5400,18 @@ async function runGet(ctx, ref, options) {
|
|
|
5371
5400
|
const auth = await requireAuth(ctx);
|
|
5372
5401
|
const course = options.course ?? DEFAULT_COURSE2;
|
|
5373
5402
|
const profile = await resolveToolProfile(options.tool, process.cwd());
|
|
5403
|
+
const dryRun = options.dryRun === true;
|
|
5374
5404
|
const lang = options.lang ?? readToolConfig()?.lang ?? "en";
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5405
|
+
const explicitCourseRules = resolveCourseRulesFlag(process.argv);
|
|
5406
|
+
const resolvedCourseRules = explicitCourseRules ?? readToolConfig()?.courseRules ?? true;
|
|
5407
|
+
if (!dryRun && (options.lang || explicitCourseRules !== undefined)) {
|
|
5408
|
+
const tool = readToolConfig()?.tool ?? profile.toolId;
|
|
5409
|
+
const patch = { tool };
|
|
5410
|
+
if (options.lang)
|
|
5411
|
+
patch.lang = options.lang;
|
|
5412
|
+
if (explicitCourseRules !== undefined)
|
|
5413
|
+
patch.courseRules = explicitCourseRules;
|
|
5414
|
+
updateToolConfig(patch);
|
|
5378
5415
|
}
|
|
5379
5416
|
if (options.print) {
|
|
5380
5417
|
await runPrintMode(ctx, parsed.lessonId, course, profile, auth.access_token, lang, options);
|
|
@@ -5405,15 +5442,18 @@ async function runGet(ctx, ref, options) {
|
|
|
5405
5442
|
if (prevManifest && prevManifest.manifestVersion === 2) {
|
|
5406
5443
|
showUpgradeNotice(isTTY);
|
|
5407
5444
|
}
|
|
5445
|
+
const applyCourseRules = isFiltered ? true : resolvedCourseRules;
|
|
5408
5446
|
const writeResult = await applyBundle(bundle, process.cwd(), {
|
|
5409
|
-
dryRun
|
|
5447
|
+
dryRun,
|
|
5410
5448
|
profile,
|
|
5411
5449
|
partial: isFiltered,
|
|
5412
|
-
onConflict: createConflictResolver(isTTY)
|
|
5450
|
+
onConflict: createConflictResolver(isTTY),
|
|
5451
|
+
applyCourseRules
|
|
5413
5452
|
});
|
|
5414
|
-
renderGetResult(ctx, bundle, writeResult,
|
|
5453
|
+
renderGetResult(ctx, bundle, writeResult, dryRun, profile, {
|
|
5415
5454
|
language: contentLang ?? lang,
|
|
5416
|
-
languageFallback: isFallback
|
|
5455
|
+
languageFallback: isFallback,
|
|
5456
|
+
applyCourseRules
|
|
5417
5457
|
});
|
|
5418
5458
|
}
|
|
5419
5459
|
function filterBundle(ctx, bundle, options) {
|
|
@@ -5553,7 +5593,12 @@ function formatAction(action) {
|
|
|
5553
5593
|
return action;
|
|
5554
5594
|
}
|
|
5555
5595
|
}
|
|
5556
|
-
function renderGetResult(ctx, bundle, writeResult, dryRun, profile, langMeta = {
|
|
5596
|
+
function renderGetResult(ctx, bundle, writeResult, dryRun, profile, langMeta = {
|
|
5597
|
+
language: "en",
|
|
5598
|
+
languageFallback: false,
|
|
5599
|
+
applyCourseRules: true
|
|
5600
|
+
}) {
|
|
5601
|
+
const applyCourseRules = langMeta.applyCourseRules;
|
|
5557
5602
|
const totalRemovals = writeResult.removals.skills.length + writeResult.removals.prompts.length + writeResult.removals.configs.length;
|
|
5558
5603
|
if (ctx.json) {
|
|
5559
5604
|
output(ctx, "", {
|
|
@@ -5574,7 +5619,7 @@ function renderGetResult(ctx, bundle, writeResult, dryRun, profile, langMeta = {
|
|
|
5574
5619
|
counts: {
|
|
5575
5620
|
skills: writeResult.skills.length,
|
|
5576
5621
|
prompts: writeResult.prompts.length,
|
|
5577
|
-
rules: bundle.rules.length,
|
|
5622
|
+
rules: applyCourseRules ? bundle.rules.length : 0,
|
|
5578
5623
|
configs: writeResult.configs.length,
|
|
5579
5624
|
removals: totalRemovals
|
|
5580
5625
|
}
|
|
@@ -5602,7 +5647,13 @@ function renderGetResult(ctx, bundle, writeResult, dryRun, profile, langMeta = {
|
|
|
5602
5647
|
for (const prompt of writeResult.prompts) {
|
|
5603
5648
|
lines.push(` [${formatAction(prompt.action)}] prompt ${prompt.path}`);
|
|
5604
5649
|
}
|
|
5605
|
-
if (
|
|
5650
|
+
if (!applyCourseRules) {
|
|
5651
|
+
if (writeResult.rules.action === "removed") {
|
|
5652
|
+
lines.push(` [removed] rules ${profile.rulesFile}`);
|
|
5653
|
+
} else {
|
|
5654
|
+
verbose(ctx, `course rules disabled — ${profile.rulesFile} left untouched`);
|
|
5655
|
+
}
|
|
5656
|
+
} else if (bundle.rules.length > 0) {
|
|
5606
5657
|
lines.push(` [${writeResult.rules.action}] rules ${profile.rulesFile} (${bundle.rules.length} block${bundle.rules.length === 1 ? "" : "s"})`);
|
|
5607
5658
|
}
|
|
5608
5659
|
for (const config of writeResult.configs) {
|