@lovelaces-io/storyteller 0.2.0 → 0.3.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/AGENTS.md +262 -0
- package/README.md +194 -27
- package/dist/cli.cjs +221 -0
- package/dist/index.cjs +857 -76
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +446 -37
- package/dist/index.d.ts +446 -37
- package/dist/index.js +844 -76
- package/dist/index.js.map +1 -1
- package/llms.txt +109 -0
- package/package.json +26 -7
- package/snippets/agents-section.md +36 -0
package/dist/cli.cjs
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/cli.ts
|
|
22
|
+
var cli_exports = {};
|
|
23
|
+
__export(cli_exports, {
|
|
24
|
+
detectPackageManager: () => detectPackageManager,
|
|
25
|
+
initializeProject: () => initializeProject,
|
|
26
|
+
readSnippet: () => readSnippet
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(cli_exports);
|
|
29
|
+
var import_node_child_process = require("child_process");
|
|
30
|
+
var import_node_fs = require("fs");
|
|
31
|
+
var import_node_path = require("path");
|
|
32
|
+
var SECTION_START = "<!-- storyteller:begin -->";
|
|
33
|
+
var SECTION_END = "<!-- storyteller:end -->";
|
|
34
|
+
var PACKAGE_NAME = "@lovelaces-io/storyteller";
|
|
35
|
+
var GUIDANCE_FILES = ["AGENTS.md", "CLAUDE.md"];
|
|
36
|
+
var PACKAGE_MANAGERS = [
|
|
37
|
+
{ name: "pnpm", lockfile: "pnpm-lock.yaml", install: ["add"] },
|
|
38
|
+
{ name: "yarn", lockfile: "yarn.lock", install: ["add"] },
|
|
39
|
+
{ name: "bun", lockfile: "bun.lockb", install: ["add"] },
|
|
40
|
+
{ name: "npm", lockfile: "package-lock.json", install: ["install"] }
|
|
41
|
+
];
|
|
42
|
+
function initializeProject(projectRoot, options = {}) {
|
|
43
|
+
const result = { changed: [], skipped: [], notes: [] };
|
|
44
|
+
const packageJsonPath = (0, import_node_path.join)(projectRoot, "package.json");
|
|
45
|
+
if (!(0, import_node_fs.existsSync)(packageJsonPath)) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
"No package.json here. Run this from the root of a Node project."
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
if (options.install !== false) {
|
|
51
|
+
installDependency(projectRoot, packageJsonPath, result);
|
|
52
|
+
}
|
|
53
|
+
writeStarterModule(projectRoot, packageJsonPath, result);
|
|
54
|
+
writeGuidanceSection(projectRoot, result);
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
function installDependency(projectRoot, packageJsonPath, result) {
|
|
58
|
+
const manifest = readJson(packageJsonPath);
|
|
59
|
+
const dependencies = {
|
|
60
|
+
...manifest["dependencies"],
|
|
61
|
+
...manifest["devDependencies"]
|
|
62
|
+
};
|
|
63
|
+
if (dependencies[PACKAGE_NAME]) {
|
|
64
|
+
result.skipped.push(`${PACKAGE_NAME} (already a dependency)`);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const manager = detectPackageManager(projectRoot);
|
|
68
|
+
try {
|
|
69
|
+
(0, import_node_child_process.execFileSync)(manager.name, [...manager.install, PACKAGE_NAME], {
|
|
70
|
+
cwd: projectRoot,
|
|
71
|
+
stdio: "inherit"
|
|
72
|
+
});
|
|
73
|
+
result.changed.push(`installed ${PACKAGE_NAME} with ${manager.name}`);
|
|
74
|
+
} catch {
|
|
75
|
+
result.notes.push(
|
|
76
|
+
`Could not install automatically. Run: ${manager.name} ${manager.install.join(" ")} ${PACKAGE_NAME}`
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function detectPackageManager(projectRoot) {
|
|
81
|
+
for (const manager of PACKAGE_MANAGERS) {
|
|
82
|
+
if ((0, import_node_fs.existsSync)((0, import_node_path.join)(projectRoot, manager.lockfile))) return manager;
|
|
83
|
+
}
|
|
84
|
+
return PACKAGE_MANAGERS[PACKAGE_MANAGERS.length - 1];
|
|
85
|
+
}
|
|
86
|
+
function writeStarterModule(projectRoot, packageJsonPath, result) {
|
|
87
|
+
const sourceDirectory = (0, import_node_fs.existsSync)((0, import_node_path.join)(projectRoot, "src")) ? "src" : ".";
|
|
88
|
+
const starterPath = (0, import_node_path.join)(projectRoot, sourceDirectory, "storyteller.ts");
|
|
89
|
+
if ((0, import_node_fs.existsSync)(starterPath)) {
|
|
90
|
+
result.skipped.push(`${sourceDirectory}/storyteller.ts (already exists)`);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const manifest = readJson(packageJsonPath);
|
|
94
|
+
const projectName = typeof manifest["name"] === "string" && manifest["name"].length ? manifest["name"].replace(/^@[^/]+\//, "") : "app";
|
|
95
|
+
(0, import_node_fs.writeFileSync)(
|
|
96
|
+
starterPath,
|
|
97
|
+
`import { Storyteller } from "${PACKAGE_NAME}";
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* The storyteller for this project. Import it wherever work happens.
|
|
101
|
+
*
|
|
102
|
+
* Set STORYTELLER_NARRATION=live to watch beats stream as they happen.
|
|
103
|
+
*/
|
|
104
|
+
export const story = new Storyteller({
|
|
105
|
+
origin: { who: ${JSON.stringify(projectName)} },
|
|
106
|
+
});
|
|
107
|
+
`,
|
|
108
|
+
"utf8"
|
|
109
|
+
);
|
|
110
|
+
result.changed.push(`${sourceDirectory}/storyteller.ts`);
|
|
111
|
+
}
|
|
112
|
+
function writeGuidanceSection(projectRoot, result) {
|
|
113
|
+
const snippet = readSnippet();
|
|
114
|
+
const block = `${SECTION_START}
|
|
115
|
+
${snippet.trim()}
|
|
116
|
+
${SECTION_END}
|
|
117
|
+
`;
|
|
118
|
+
const existing = GUIDANCE_FILES.map((name) => (0, import_node_path.join)(projectRoot, name)).find(
|
|
119
|
+
(path) => (0, import_node_fs.existsSync)(path)
|
|
120
|
+
);
|
|
121
|
+
const targetPath = existing ?? (0, import_node_path.join)(projectRoot, GUIDANCE_FILES[0]);
|
|
122
|
+
const relativeName = targetPath.slice(projectRoot.length + 1);
|
|
123
|
+
if (!existing) {
|
|
124
|
+
(0, import_node_fs.writeFileSync)(targetPath, `# Agent Guide
|
|
125
|
+
|
|
126
|
+
${block}`, "utf8");
|
|
127
|
+
result.changed.push(`${relativeName} (created)`);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const current = (0, import_node_fs.readFileSync)(targetPath, "utf8");
|
|
131
|
+
const startIndex = current.indexOf(SECTION_START);
|
|
132
|
+
if (startIndex === -1) {
|
|
133
|
+
(0, import_node_fs.writeFileSync)(targetPath, `${current.trimEnd()}
|
|
134
|
+
|
|
135
|
+
${block}`, "utf8");
|
|
136
|
+
result.changed.push(relativeName);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const endIndex = current.indexOf(SECTION_END, startIndex);
|
|
140
|
+
if (endIndex === -1) {
|
|
141
|
+
result.notes.push(
|
|
142
|
+
`${relativeName} has an unterminated ${SECTION_START} block. Fix or remove it, then re-run.`
|
|
143
|
+
);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const before = current.slice(0, startIndex);
|
|
147
|
+
const after = current.slice(endIndex + SECTION_END.length);
|
|
148
|
+
const updated = `${before}${block.trimEnd()}${after}`;
|
|
149
|
+
if (updated === current) {
|
|
150
|
+
result.skipped.push(`${relativeName} (already up to date)`);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
(0, import_node_fs.writeFileSync)(targetPath, updated, "utf8");
|
|
154
|
+
result.changed.push(`${relativeName} (guidance refreshed)`);
|
|
155
|
+
}
|
|
156
|
+
function readSnippet() {
|
|
157
|
+
const candidates = [
|
|
158
|
+
(0, import_node_path.join)(__dirname, "..", "snippets", "agents-section.md"),
|
|
159
|
+
(0, import_node_path.join)(__dirname, "..", "..", "snippets", "agents-section.md")
|
|
160
|
+
];
|
|
161
|
+
for (const candidate of candidates) {
|
|
162
|
+
if ((0, import_node_fs.existsSync)(candidate)) return (0, import_node_fs.readFileSync)(candidate, "utf8");
|
|
163
|
+
}
|
|
164
|
+
throw new Error("Could not find the guidance snippet that ships with this package.");
|
|
165
|
+
}
|
|
166
|
+
function readJson(path) {
|
|
167
|
+
try {
|
|
168
|
+
return JSON.parse((0, import_node_fs.readFileSync)(path, "utf8"));
|
|
169
|
+
} catch (error) {
|
|
170
|
+
throw new Error(`Could not read ${path}: ${error.message}`, {
|
|
171
|
+
cause: error
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function main(argv) {
|
|
176
|
+
const command = argv[0] ?? "init";
|
|
177
|
+
if (command === "--help" || command === "-h" || command === "help") {
|
|
178
|
+
console.log(
|
|
179
|
+
[
|
|
180
|
+
"npx @lovelaces-io/storyteller init [--no-install]",
|
|
181
|
+
" (or `storyteller init` once the package is installed)",
|
|
182
|
+
"",
|
|
183
|
+
" Sets this project up to use Storyteller:",
|
|
184
|
+
" - installs the package",
|
|
185
|
+
" - writes a configured storyteller",
|
|
186
|
+
" - teaches your agents to narrate their work",
|
|
187
|
+
"",
|
|
188
|
+
" Safe to run more than once."
|
|
189
|
+
].join("\n")
|
|
190
|
+
);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
if (command !== "init") {
|
|
194
|
+
console.error(`Unknown command: ${command}
|
|
195
|
+
Try: storyteller init`);
|
|
196
|
+
process.exitCode = 1;
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
try {
|
|
200
|
+
const result = initializeProject(process.cwd(), {
|
|
201
|
+
install: !argv.includes("--no-install")
|
|
202
|
+
});
|
|
203
|
+
for (const change of result.changed) console.log(` added ${change}`);
|
|
204
|
+
for (const skip of result.skipped) console.log(` kept ${skip}`);
|
|
205
|
+
for (const note of result.notes) console.log(` note ${note}`);
|
|
206
|
+
console.log("\nTry it:");
|
|
207
|
+
console.log(" STORYTELLER_NARRATION=live node your-script.js");
|
|
208
|
+
} catch (error) {
|
|
209
|
+
console.error(`storyteller init failed: ${error.message}`);
|
|
210
|
+
process.exitCode = 1;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if (require.main === module) {
|
|
214
|
+
main(process.argv.slice(2));
|
|
215
|
+
}
|
|
216
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
217
|
+
0 && (module.exports = {
|
|
218
|
+
detectPackageManager,
|
|
219
|
+
initializeProject,
|
|
220
|
+
readSnippet
|
|
221
|
+
});
|