@studiolxd/lxd-cli 0.1.0-next.0 → 0.1.0-next.1
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 +2 -0
- package/dist/cli/index.js +130 -62
- package/docs/commands.md +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -53,6 +53,8 @@ lxd tracking --report completion score success
|
|
|
53
53
|
lxd validate # actionable pass/fail across all checks
|
|
54
54
|
lxd handoff # write .agent/** specs + prompts + scaffold generated/
|
|
55
55
|
# → run YOUR agent against .agent/** to produce generated/
|
|
56
|
+
# → also writes .claude/commands/lxd-generate.md; in Claude Code run /project:lxd-generate
|
|
57
|
+
# (operational only — reads .agent/ as the source of truth; generic .agent/ stays agent-agnostic)
|
|
56
58
|
lxd preview --mock-lms # build + serve locally, with a mock LMS
|
|
57
59
|
lxd export --target web --target scorm-1.2 --target scorm-2004
|
|
58
60
|
```
|
package/dist/cli/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import { realpathSync } from "node:fs";
|
|
|
8
8
|
// package.json
|
|
9
9
|
var package_default = {
|
|
10
10
|
name: "@studiolxd/lxd-cli",
|
|
11
|
-
version: "0.1.0-next.
|
|
11
|
+
version: "0.1.0-next.1",
|
|
12
12
|
description: "CLI-first authoring tool for AI-native elearning packages (agent-orchestrated, framework- and export-target-agnostic).",
|
|
13
13
|
type: "module",
|
|
14
14
|
license: "UNLICENSED",
|
|
@@ -16,7 +16,7 @@ var package_default = {
|
|
|
16
16
|
node: ">=20"
|
|
17
17
|
},
|
|
18
18
|
bin: {
|
|
19
|
-
lxd: "
|
|
19
|
+
lxd: "dist/cli/index.js"
|
|
20
20
|
},
|
|
21
21
|
files: [
|
|
22
22
|
"dist",
|
|
@@ -1542,13 +1542,13 @@ function register10(program) {
|
|
|
1542
1542
|
}
|
|
1543
1543
|
|
|
1544
1544
|
// src/cli/commands/handoff.ts
|
|
1545
|
-
import { join as
|
|
1545
|
+
import { join as join10 } from "node:path";
|
|
1546
1546
|
import { access as access4 } from "node:fs/promises";
|
|
1547
1547
|
import { confirm, isCancel } from "@clack/prompts";
|
|
1548
1548
|
|
|
1549
1549
|
// src/agent/handoff/producer.ts
|
|
1550
|
-
import { mkdir as
|
|
1551
|
-
import { join as
|
|
1550
|
+
import { mkdir as mkdir5, writeFile as writeFile5 } from "node:fs/promises";
|
|
1551
|
+
import { join as join7, dirname as dirname2 } from "node:path";
|
|
1552
1552
|
|
|
1553
1553
|
// src/agent/handoff/scorm-skills.ts
|
|
1554
1554
|
import { mkdir as mkdir2, writeFile as writeFile2 } from "node:fs/promises";
|
|
@@ -1608,17 +1608,78 @@ async function writeScormSkillsSnapshot(agentDir, opts = {}) {
|
|
|
1608
1608
|
return { ref: `${ref}@${version}` };
|
|
1609
1609
|
}
|
|
1610
1610
|
|
|
1611
|
-
// src/
|
|
1612
|
-
import { mkdir as mkdir3,
|
|
1611
|
+
// src/agent/handoff/claude-command.ts
|
|
1612
|
+
import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
|
|
1613
1613
|
import { join as join5 } from "node:path";
|
|
1614
|
+
function renderClaudeCommand(opts) {
|
|
1615
|
+
const lines = [
|
|
1616
|
+
"# lxd-generate",
|
|
1617
|
+
"",
|
|
1618
|
+
"Operational instructions for implementing this LXD elearning package with Claude Code",
|
|
1619
|
+
"(invoke as `/project:lxd-generate`). The `.agent/` directory is the SOURCE OF TRUTH \u2014",
|
|
1620
|
+
"read it and implement to it; do not infer the learning design from anything else.",
|
|
1621
|
+
"",
|
|
1622
|
+
"## Read first",
|
|
1623
|
+
"",
|
|
1624
|
+
"1. Read `.agent/spec.md` (the package specification).",
|
|
1625
|
+
"2. Read `.agent/instructions.md` (the agent instructions).",
|
|
1626
|
+
"3. Read all relevant files under `.agent/prompts/` (one per experience, plus the package shell)."
|
|
1627
|
+
];
|
|
1628
|
+
if (opts.scormSkills) {
|
|
1629
|
+
lines.push("4. Read `.agent/scorm-skills/` (SCORM runtime guidance).");
|
|
1630
|
+
}
|
|
1631
|
+
lines.push(
|
|
1632
|
+
"",
|
|
1633
|
+
"Treat `.agent/` as the **source of truth** for the learning design.",
|
|
1634
|
+
"",
|
|
1635
|
+
"## Implement",
|
|
1636
|
+
"",
|
|
1637
|
+
"- Implement the package under `generated/`.",
|
|
1638
|
+
"- Do not modify `.agent/` (the CLI regenerates it).",
|
|
1639
|
+
"- Do not modify the package specification YAML files unless strictly necessary."
|
|
1640
|
+
);
|
|
1641
|
+
if (opts.scorm) {
|
|
1642
|
+
lines.push(
|
|
1643
|
+
"",
|
|
1644
|
+
"## SCORM",
|
|
1645
|
+
"",
|
|
1646
|
+
"- Do not generate a custom SCORM runtime.",
|
|
1647
|
+
"- Use `@studiolxd/scorm` as the runtime integration layer for all SCORM interactions.",
|
|
1648
|
+
"- Follow the SCORM guidance emitted under `.agent/scorm-skills/`."
|
|
1649
|
+
);
|
|
1650
|
+
}
|
|
1651
|
+
lines.push(
|
|
1652
|
+
"",
|
|
1653
|
+
"## Report",
|
|
1654
|
+
"",
|
|
1655
|
+
"When done, report the files you created or modified, then the next commands:",
|
|
1656
|
+
"",
|
|
1657
|
+
"- `lxd validate`",
|
|
1658
|
+
"- `lxd preview`",
|
|
1659
|
+
"- `lxd export`",
|
|
1660
|
+
""
|
|
1661
|
+
);
|
|
1662
|
+
return lines.join("\n");
|
|
1663
|
+
}
|
|
1664
|
+
async function writeClaudeCommand(packageDir, opts) {
|
|
1665
|
+
const dir = join5(packageDir, ".claude", "commands");
|
|
1666
|
+
await mkdir3(dir, { recursive: true });
|
|
1667
|
+
const path = join5(dir, "lxd-generate.md");
|
|
1668
|
+
await writeFile3(path, renderClaudeCommand(opts), "utf8");
|
|
1669
|
+
return path;
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
// src/core/project/assets.ts
|
|
1673
|
+
import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "node:fs/promises";
|
|
1674
|
+
import { join as join6 } from "node:path";
|
|
1614
1675
|
import { parse as parseYaml4, stringify as stringifyYaml2 } from "yaml";
|
|
1615
1676
|
var MANIFEST_PATH = [".elearning", "manifest.lock"];
|
|
1616
1677
|
var RECOMMENDED_ASSETS = {
|
|
1617
|
-
scormLibraryVersion: "^
|
|
1678
|
+
scormLibraryVersion: "^2.0.0",
|
|
1618
1679
|
scormSkillsSnapshot: { version: "main", ref: "github:studiolxd/scorm-skills" }
|
|
1619
1680
|
};
|
|
1620
1681
|
function manifestFile(dir) {
|
|
1621
|
-
return
|
|
1682
|
+
return join6(dir, ...MANIFEST_PATH);
|
|
1622
1683
|
}
|
|
1623
1684
|
async function readManifest(dir) {
|
|
1624
1685
|
try {
|
|
@@ -1628,8 +1689,8 @@ async function readManifest(dir) {
|
|
|
1628
1689
|
}
|
|
1629
1690
|
}
|
|
1630
1691
|
async function writeManifest(dir, manifest) {
|
|
1631
|
-
await
|
|
1632
|
-
await
|
|
1692
|
+
await mkdir4(join6(dir, ".elearning"), { recursive: true });
|
|
1693
|
+
await writeFile4(manifestFile(dir), stringifyYaml2(manifest), "utf8");
|
|
1633
1694
|
}
|
|
1634
1695
|
async function updateAssets(dir, update) {
|
|
1635
1696
|
const manifest = await readManifest(dir);
|
|
@@ -1668,21 +1729,21 @@ function createHandoffProducer() {
|
|
|
1668
1729
|
version: VERSION,
|
|
1669
1730
|
async produce(input) {
|
|
1670
1731
|
const out = input.outputDir;
|
|
1671
|
-
await
|
|
1732
|
+
await mkdir5(join7(out, "prompts"), { recursive: true });
|
|
1672
1733
|
const spec = renderSpec(input);
|
|
1673
|
-
const specPath =
|
|
1674
|
-
await
|
|
1734
|
+
const specPath = join7(out, "spec.md");
|
|
1735
|
+
await writeFile5(specPath, spec, "utf8");
|
|
1675
1736
|
const prompts = [];
|
|
1676
|
-
const shellPath =
|
|
1677
|
-
await
|
|
1737
|
+
const shellPath = join7(out, "prompts", "package-shell.md");
|
|
1738
|
+
await writeFile5(shellPath, renderShellPrompt(input), "utf8");
|
|
1678
1739
|
prompts.push({ id: "package-shell", path: shellPath });
|
|
1679
1740
|
for (const ref of input.package.experienceRefs) {
|
|
1680
|
-
const p =
|
|
1681
|
-
await
|
|
1741
|
+
const p = join7(out, "prompts", `${ref}.md`);
|
|
1742
|
+
await writeFile5(p, renderExperiencePrompt(ref, input), "utf8");
|
|
1682
1743
|
prompts.push({ id: ref, path: p });
|
|
1683
1744
|
}
|
|
1684
1745
|
const instructions = renderInstructions(input);
|
|
1685
|
-
await
|
|
1746
|
+
await writeFile5(join7(out, "instructions.md"), instructions, "utf8");
|
|
1686
1747
|
let scormSkillsSnapshotRef = input.scormSkills?.snapshotRef;
|
|
1687
1748
|
if (input.targets.some((t) => t.startsWith("scorm"))) {
|
|
1688
1749
|
const snap = await writeScormSkillsSnapshot(out, {
|
|
@@ -1691,13 +1752,19 @@ function createHandoffProducer() {
|
|
|
1691
1752
|
});
|
|
1692
1753
|
scormSkillsSnapshotRef = snap.ref;
|
|
1693
1754
|
}
|
|
1694
|
-
|
|
1755
|
+
const scorm = isScormTargeted2(input.targets);
|
|
1756
|
+
const claudeCommandPath = await writeClaudeCommand(dirname2(out), { scorm, scormSkills: scorm });
|
|
1757
|
+
logger.debug(
|
|
1758
|
+
{ outputDir: out, prompts: prompts.length, claudeCommandPath },
|
|
1759
|
+
"Agent handoff produced"
|
|
1760
|
+
);
|
|
1695
1761
|
return {
|
|
1696
1762
|
spec,
|
|
1697
1763
|
prompts,
|
|
1698
1764
|
instructions,
|
|
1699
1765
|
scormSkillsSnapshotRef,
|
|
1700
|
-
producedBy: VERSION
|
|
1766
|
+
producedBy: VERSION,
|
|
1767
|
+
claudeCommandPath
|
|
1701
1768
|
};
|
|
1702
1769
|
}
|
|
1703
1770
|
};
|
|
@@ -1815,13 +1882,13 @@ function renderInstructions(input) {
|
|
|
1815
1882
|
}
|
|
1816
1883
|
|
|
1817
1884
|
// src/adapters/framework/webcomponents/index.ts
|
|
1818
|
-
import { mkdir as
|
|
1819
|
-
import { join as
|
|
1885
|
+
import { mkdir as mkdir6, writeFile as writeFile6, cp, access as access3 } from "node:fs/promises";
|
|
1886
|
+
import { join as join9 } from "node:path";
|
|
1820
1887
|
|
|
1821
1888
|
// src/preview/server.ts
|
|
1822
1889
|
import { createServer } from "node:http";
|
|
1823
1890
|
import { readFile as readFile5, stat } from "node:fs/promises";
|
|
1824
|
-
import { join as
|
|
1891
|
+
import { join as join8, normalize, extname as extname2 } from "node:path";
|
|
1825
1892
|
|
|
1826
1893
|
// src/preview/mock-lms/index.ts
|
|
1827
1894
|
function mockLmsBrowserScript() {
|
|
@@ -1877,13 +1944,13 @@ async function startPreviewServer(opts) {
|
|
|
1877
1944
|
res.writeHead(200, { "content-type": MIME[".js"] }).end(mockLmsBrowserScript());
|
|
1878
1945
|
return;
|
|
1879
1946
|
}
|
|
1880
|
-
const safe = normalize(
|
|
1947
|
+
const safe = normalize(join8(root, rel === "/" ? "index.html" : `.${rel}`));
|
|
1881
1948
|
if (!safe.startsWith(root)) {
|
|
1882
1949
|
res.writeHead(403).end("Forbidden");
|
|
1883
1950
|
return;
|
|
1884
1951
|
}
|
|
1885
1952
|
const info = await stat(safe).catch(() => null);
|
|
1886
|
-
const file = info?.isDirectory() ?
|
|
1953
|
+
const file = info?.isDirectory() ? join8(safe, "index.html") : safe;
|
|
1887
1954
|
const isHtml = extname2(file) === ".html";
|
|
1888
1955
|
if (opts.mockLms && isHtml) {
|
|
1889
1956
|
const html = await readFile5(file, "utf8");
|
|
@@ -1930,21 +1997,21 @@ var webComponentsAdapter = {
|
|
|
1930
1997
|
version: "0.1.0",
|
|
1931
1998
|
optionsSchema: { type: "object", additionalProperties: true },
|
|
1932
1999
|
async scaffold(input) {
|
|
1933
|
-
await
|
|
2000
|
+
await mkdir6(input.outputDir, { recursive: true });
|
|
1934
2001
|
const files = [];
|
|
1935
|
-
const configPath =
|
|
1936
|
-
await
|
|
2002
|
+
const configPath = join9(input.outputDir, "elearning.scaffold.json");
|
|
2003
|
+
await writeFile6(
|
|
1937
2004
|
configPath,
|
|
1938
2005
|
JSON.stringify({ adapter: this.id, packageId: input.package.id }, null, 2),
|
|
1939
2006
|
"utf8"
|
|
1940
2007
|
);
|
|
1941
2008
|
files.push(configPath);
|
|
1942
|
-
const contractPath =
|
|
1943
|
-
await
|
|
2009
|
+
const contractPath = join9(input.outputDir, "AGENT_IMPLEMENTATION.md");
|
|
2010
|
+
await writeFile6(contractPath, IMPLEMENTATION_CONTRACT, "utf8");
|
|
1944
2011
|
files.push(contractPath);
|
|
1945
|
-
const generated =
|
|
1946
|
-
await
|
|
1947
|
-
const seed =
|
|
2012
|
+
const generated = join9(input.outputDir, "generated");
|
|
2013
|
+
await mkdir6(generated, { recursive: true });
|
|
2014
|
+
const seed = join9(generated, "index.html");
|
|
1948
2015
|
const preserved = [];
|
|
1949
2016
|
const overwritten = [];
|
|
1950
2017
|
const seedExists = await exists(seed);
|
|
@@ -1952,7 +2019,7 @@ var webComponentsAdapter = {
|
|
|
1952
2019
|
preserved.push(seed);
|
|
1953
2020
|
logger.debug({ file: seed }, "Preserved existing generated/ file (use force to overwrite)");
|
|
1954
2021
|
} else {
|
|
1955
|
-
await
|
|
2022
|
+
await writeFile6(seed, "<!doctype html><title>elearning package</title>", "utf8");
|
|
1956
2023
|
files.push(seed);
|
|
1957
2024
|
if (seedExists) {
|
|
1958
2025
|
overwritten.push(seed);
|
|
@@ -1966,7 +2033,7 @@ var webComponentsAdapter = {
|
|
|
1966
2033
|
return { files, implementationContract: IMPLEMENTATION_CONTRACT, preserved, overwritten };
|
|
1967
2034
|
},
|
|
1968
2035
|
async build(input) {
|
|
1969
|
-
await
|
|
2036
|
+
await mkdir6(input.outputDir, { recursive: true });
|
|
1970
2037
|
const source = input.generatedDir;
|
|
1971
2038
|
if (source && await exists(source)) {
|
|
1972
2039
|
await cp(source, input.outputDir, { recursive: true });
|
|
@@ -2080,9 +2147,10 @@ function register11(program) {
|
|
|
2080
2147
|
scormLibraryVersion: project.manifest?.scormLibraryVersion,
|
|
2081
2148
|
frameworkContract: webComponentsAdapter.displayName,
|
|
2082
2149
|
targets: opts.target,
|
|
2083
|
-
outputDir:
|
|
2150
|
+
outputDir: join10(dir, ".agent")
|
|
2084
2151
|
});
|
|
2085
2152
|
console.log(`Handoff materials written to .agent/ (${materials.prompts.length} prompts).`);
|
|
2153
|
+
console.log("Claude Code command written to .claude/commands/lxd-generate.md (run /project:lxd-generate).");
|
|
2086
2154
|
const agnostic = checkHandoffAgnostic(`${materials.spec}
|
|
2087
2155
|
${materials.instructions}`);
|
|
2088
2156
|
if (!agnostic.ok) {
|
|
@@ -2091,7 +2159,7 @@ ${materials.instructions}`);
|
|
|
2091
2159
|
}
|
|
2092
2160
|
}
|
|
2093
2161
|
let force = Boolean(opts.force);
|
|
2094
|
-
const seed =
|
|
2162
|
+
const seed = join10(dir, "generated", "index.html");
|
|
2095
2163
|
if (!force && await exists2(seed)) {
|
|
2096
2164
|
if (process.stdin.isTTY) {
|
|
2097
2165
|
const answer = await confirm({
|
|
@@ -2126,15 +2194,15 @@ ${materials.instructions}`);
|
|
|
2126
2194
|
}
|
|
2127
2195
|
|
|
2128
2196
|
// src/cli/commands/preview.ts
|
|
2129
|
-
import { join as
|
|
2197
|
+
import { join as join11 } from "node:path";
|
|
2130
2198
|
function register12(program) {
|
|
2131
2199
|
program.command("preview").description("Build the package and serve it locally").option("--mock-lms", "serve in mock LMS/SCORM mode (US2)").option("-p, --port <n>", "port", "0").action(async (opts, cmd) => {
|
|
2132
2200
|
const dir = cwdOf(cmd);
|
|
2133
2201
|
const project = await loadProjectLenient(dir);
|
|
2134
2202
|
const built = await webComponentsAdapter.build({
|
|
2135
2203
|
package: project.package,
|
|
2136
|
-
outputDir:
|
|
2137
|
-
generatedDir:
|
|
2204
|
+
outputDir: join11(dir, "build"),
|
|
2205
|
+
generatedDir: join11(dir, "generated")
|
|
2138
2206
|
});
|
|
2139
2207
|
const handle = await startPreviewServer({
|
|
2140
2208
|
dir: built.outputDir,
|
|
@@ -2148,7 +2216,7 @@ function register12(program) {
|
|
|
2148
2216
|
}
|
|
2149
2217
|
|
|
2150
2218
|
// src/cli/commands/export.ts
|
|
2151
|
-
import { join as
|
|
2219
|
+
import { join as join14 } from "node:path";
|
|
2152
2220
|
|
|
2153
2221
|
// src/core/authoring/export-builder.ts
|
|
2154
2222
|
function buildExportConfig(targetIds) {
|
|
@@ -2181,7 +2249,7 @@ function createExportRegistry() {
|
|
|
2181
2249
|
}
|
|
2182
2250
|
|
|
2183
2251
|
// src/adapters/export/web/index.ts
|
|
2184
|
-
import { mkdir as
|
|
2252
|
+
import { mkdir as mkdir7, cp as cp2, access as access5 } from "node:fs/promises";
|
|
2185
2253
|
var webExportAdapter = {
|
|
2186
2254
|
id: "web",
|
|
2187
2255
|
displayName: "Web / static package",
|
|
@@ -2203,7 +2271,7 @@ var webExportAdapter = {
|
|
|
2203
2271
|
];
|
|
2204
2272
|
},
|
|
2205
2273
|
async export(input) {
|
|
2206
|
-
await
|
|
2274
|
+
await mkdir7(input.outputDir, { recursive: true });
|
|
2207
2275
|
await cp2(input.builtDir, input.outputDir, { recursive: true });
|
|
2208
2276
|
logger.debug({ outputDir: input.outputDir }, "web export complete");
|
|
2209
2277
|
return { artifactPath: input.outputDir, target: "web", warnings: [] };
|
|
@@ -2211,8 +2279,8 @@ var webExportAdapter = {
|
|
|
2211
2279
|
};
|
|
2212
2280
|
|
|
2213
2281
|
// src/adapters/export/scorm12/index.ts
|
|
2214
|
-
import { mkdir as
|
|
2215
|
-
import { join as
|
|
2282
|
+
import { mkdir as mkdir8, cp as cp3, writeFile as writeFile7, access as access6 } from "node:fs/promises";
|
|
2283
|
+
import { join as join12 } from "node:path";
|
|
2216
2284
|
|
|
2217
2285
|
// src/adapters/export/scorm-common.ts
|
|
2218
2286
|
import archiver from "archiver";
|
|
@@ -2326,11 +2394,11 @@ var scorm12Adapter = {
|
|
|
2326
2394
|
return results;
|
|
2327
2395
|
},
|
|
2328
2396
|
async export(input) {
|
|
2329
|
-
await
|
|
2397
|
+
await mkdir8(input.outputDir, { recursive: true });
|
|
2330
2398
|
await cp3(input.builtDir, input.outputDir, { recursive: true });
|
|
2331
|
-
await
|
|
2332
|
-
await
|
|
2333
|
-
|
|
2399
|
+
await writeFile7(join12(input.outputDir, "imsmanifest.xml"), buildImsManifest12(input.package), "utf8");
|
|
2400
|
+
await writeFile7(
|
|
2401
|
+
join12(input.outputDir, "scorm-runtime.json"),
|
|
2334
2402
|
JSON.stringify(
|
|
2335
2403
|
{ library: "@studiolxd/scorm", version: input.assets.scormLibraryVersion ?? "unspecified", edition: "SCORM 1.2" },
|
|
2336
2404
|
null,
|
|
@@ -2347,8 +2415,8 @@ var scorm12Adapter = {
|
|
|
2347
2415
|
};
|
|
2348
2416
|
|
|
2349
2417
|
// src/adapters/export/scorm2004/index.ts
|
|
2350
|
-
import { mkdir as
|
|
2351
|
-
import { join as
|
|
2418
|
+
import { mkdir as mkdir9, cp as cp4, writeFile as writeFile8, access as access7 } from "node:fs/promises";
|
|
2419
|
+
import { join as join13 } from "node:path";
|
|
2352
2420
|
var scorm2004Adapter = {
|
|
2353
2421
|
id: "scorm-2004",
|
|
2354
2422
|
displayName: "SCORM 2004 (4th Edition)",
|
|
@@ -2380,11 +2448,11 @@ var scorm2004Adapter = {
|
|
|
2380
2448
|
return results;
|
|
2381
2449
|
},
|
|
2382
2450
|
async export(input) {
|
|
2383
|
-
await
|
|
2451
|
+
await mkdir9(input.outputDir, { recursive: true });
|
|
2384
2452
|
await cp4(input.builtDir, input.outputDir, { recursive: true });
|
|
2385
|
-
await
|
|
2386
|
-
await
|
|
2387
|
-
|
|
2453
|
+
await writeFile8(join13(input.outputDir, "imsmanifest.xml"), buildImsManifest2004(input.package), "utf8");
|
|
2454
|
+
await writeFile8(
|
|
2455
|
+
join13(input.outputDir, "scorm-runtime.json"),
|
|
2388
2456
|
JSON.stringify(
|
|
2389
2457
|
{
|
|
2390
2458
|
library: "@studiolxd/scorm",
|
|
@@ -2426,8 +2494,8 @@ function register13(program) {
|
|
|
2426
2494
|
}
|
|
2427
2495
|
const built = await webComponentsAdapter.build({
|
|
2428
2496
|
package: project.package,
|
|
2429
|
-
outputDir:
|
|
2430
|
-
generatedDir:
|
|
2497
|
+
outputDir: join14(dir, "build"),
|
|
2498
|
+
generatedDir: join14(dir, "generated")
|
|
2431
2499
|
});
|
|
2432
2500
|
for (const id of targets) {
|
|
2433
2501
|
if (!registry.has(id)) {
|
|
@@ -2441,7 +2509,7 @@ function register13(program) {
|
|
|
2441
2509
|
package: project.package,
|
|
2442
2510
|
tracking: project.tracking,
|
|
2443
2511
|
options: {},
|
|
2444
|
-
outputDir:
|
|
2512
|
+
outputDir: join14(dir, "dist", id),
|
|
2445
2513
|
assets: {
|
|
2446
2514
|
scormLibraryVersion: manifest.scormLibraryVersion,
|
|
2447
2515
|
scormSkillsSnapshotRef: manifest.scormSkillsSnapshot?.ref
|
|
@@ -2474,7 +2542,7 @@ function register14(program) {
|
|
|
2474
2542
|
}
|
|
2475
2543
|
|
|
2476
2544
|
// src/cli/commands/create.ts
|
|
2477
|
-
import { join as
|
|
2545
|
+
import { join as join15, resolve as resolve5 } from "node:path";
|
|
2478
2546
|
import { rm } from "node:fs/promises";
|
|
2479
2547
|
|
|
2480
2548
|
// src/cli/prompt.ts
|
|
@@ -2664,7 +2732,7 @@ async function runWizard(prompter, opts) {
|
|
|
2664
2732
|
return result;
|
|
2665
2733
|
}
|
|
2666
2734
|
if (replacing) {
|
|
2667
|
-
await rm(
|
|
2735
|
+
await rm(join15(targetDir, "experiences"), { recursive: true, force: true });
|
|
2668
2736
|
}
|
|
2669
2737
|
await saveProject(targetDir, assembleProject(answers, design));
|
|
2670
2738
|
result.committed = true;
|
|
@@ -2687,7 +2755,7 @@ async function runWizard(prompter, opts) {
|
|
|
2687
2755
|
if (await need(prompter.confirm({ message: "Generate agent handoff now?", initialValue: false }))) {
|
|
2688
2756
|
await produceHandoff(await loadProjectLenient(result.dir), {
|
|
2689
2757
|
targets: answers.exportTargets,
|
|
2690
|
-
outputDir:
|
|
2758
|
+
outputDir: join15(result.dir, ".agent")
|
|
2691
2759
|
});
|
|
2692
2760
|
result.handoffGenerated = true;
|
|
2693
2761
|
console.log("Handoff materials written to .agent/.");
|
package/docs/commands.md
CHANGED
|
@@ -19,7 +19,7 @@ revisitable.
|
|
|
19
19
|
| `design -l <level> [-b <brief>] [--a11y <t...>] [--from <file>]` | 6 | Design direction (brief → full constraints). |
|
|
20
20
|
| `evaluation -c <rule> [--assessed --pass-threshold <n>]` | 7 | Feedback + package completion/score rules. |
|
|
21
21
|
| `tracking [--completion-rule] [--score-rule] [--report <fields...>] [--threshold <n>]` | 8 | Experience signals + package roll-up. |
|
|
22
|
-
| `handoff [-t <targets...>] [-f]` | 9 | Generate `.agent/**` specs/prompts/instructions (full instructional context per experience: purpose, scenario, mechanic guidance + plugin enrichment, feedback, tracking; audience + package tone; source-of-truth instruction); scaffold `generated/`. |
|
|
22
|
+
| `handoff [-t <targets...>] [-f]` | 9 | Generate `.agent/**` specs/prompts/instructions (full instructional context per experience: purpose, scenario, mechanic guidance + plugin enrichment, feedback, tracking; audience + package tone; source-of-truth instruction); scaffold `generated/`. Also writes a Claude Code convenience command at `.claude/commands/lxd-generate.md` (run `/project:lxd-generate`) — operational only; `.agent/` stays the source of truth. Generic `.agent/` materials are unchanged for non-Claude agents. |
|
|
23
23
|
| *(your agent)* | 10 | Run YOUR AI coding agent against `.agent/**` to produce `generated/`. |
|
|
24
24
|
| `preview [--mock-lms] [-p <port>]` | 11 | Build + serve locally; optional mock LMS/SCORM mode. |
|
|
25
25
|
| `validate [--json]` | 12 | Run all validation checks on demand. For SCORM-targeted packages, **fails** if `generated/` hand-rolls a SCORM runtime instead of using `@studiolxd/scorm` (`no-custom-scorm-runtime`). |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@studiolxd/lxd-cli",
|
|
3
|
-
"version": "0.1.0-next.
|
|
3
|
+
"version": "0.1.0-next.1",
|
|
4
4
|
"description": "CLI-first authoring tool for AI-native elearning packages (agent-orchestrated, framework- and export-target-agnostic).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"node": ">=20"
|
|
9
9
|
},
|
|
10
10
|
"bin": {
|
|
11
|
-
"lxd": "
|
|
11
|
+
"lxd": "dist/cli/index.js"
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
14
|
"dist",
|