scriveno 2.0.6 → 2.0.8
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 +23 -5
- package/bin/install.js +216 -5
- package/commands/scr/autopilot-publish.md +28 -0
- package/commands/scr/autopilot-translate.md +29 -0
- package/commands/scr/autopilot.md +29 -0
- package/commands/scr/beta-reader.md +22 -0
- package/commands/scr/continuity-check.md +21 -0
- package/commands/scr/draft.md +21 -0
- package/commands/scr/editor-review.md +26 -0
- package/commands/scr/health.md +19 -0
- package/commands/scr/map-manuscript.md +26 -0
- package/commands/scr/new-work.md +1 -1
- package/commands/scr/next.md +51 -0
- package/commands/scr/plan.md +22 -0
- package/commands/scr/progress.md +36 -0
- package/commands/scr/quick-write.md +23 -0
- package/commands/scr/save.md +21 -0
- package/commands/scr/scan.md +20 -0
- package/commands/scr/session-report.md +30 -0
- package/commands/scr/sync.md +61 -2
- package/commands/scr/track.md +20 -0
- package/commands/scr/translate.md +25 -0
- package/commands/scr/voice-check.md +20 -0
- package/data/CONSTRAINTS.json +1 -1
- package/docs/architecture.md +7 -1
- package/docs/auto-invoke-policy.md +103 -0
- package/docs/configuration.md +1 -1
- package/docs/getting-started.md +12 -0
- package/docs/release-notes.md +68 -0
- package/docs/runtime-support.md +42 -11
- package/lib/auto-invoke-engine.js +520 -0
- package/package.json +1 -1
- package/templates/config.json +1 -1
package/README.md
CHANGED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/aihxp/scriveno/actions/workflows/ci.yml)
|
|
4
4
|
[](LICENSE)
|
|
5
|
-
[](CHANGELOG.md)
|
|
6
6
|
[](https://www.npmjs.com/package/scriveno)
|
|
7
7
|
[](https://www.npmjs.com/package/scriveno)
|
|
8
|
+
[](docs/runtime-support.md#shared-auto-invoke-engine)
|
|
8
9
|
|
|
9
10
|
**[scriveno on npm](https://www.npmjs.com/package/scriveno)**
|
|
10
11
|
|
|
@@ -18,6 +19,9 @@ Scriveno is best understood as **AI-native longform writing software built aroun
|
|
|
18
19
|
|
|
19
20
|
```bash
|
|
20
21
|
npx scriveno@latest
|
|
22
|
+
|
|
23
|
+
# Optional project status check
|
|
24
|
+
scriveno status --project .
|
|
21
25
|
```
|
|
22
26
|
|
|
23
27
|
---
|
|
@@ -68,6 +72,19 @@ If you want the shortest proof-first route, read [Proof Artifacts](docs/proof-ar
|
|
|
68
72
|
|
|
69
73
|
---
|
|
70
74
|
|
|
75
|
+
## Proactive status
|
|
76
|
+
|
|
77
|
+
Scriveno ships a shared read-only status engine for every installer target. The public CLI is:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
scriveno status --project .
|
|
81
|
+
scriveno status . --json
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
It inspects disk evidence such as `.manuscript/`, `STATE.md`, `CONTEXT.md`, review files, translation work, exports, and history, then recommends the safest next command. The engine does not mutate files and does not spawn agents by itself. Command surfaces such as `/scr-next`, `/scr:next`, `/scr:progress`, `/scr:session-report`, and `/scr:sync` call it when local command execution is available, then fall back to embedded markdown logic when a host cannot run Node. See [Auto-Invoke Policy](docs/auto-invoke-policy.md) and [Runtime Support](docs/runtime-support.md#shared-auto-invoke-engine).
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
71
88
|
## The Voice DNA system
|
|
72
89
|
|
|
73
90
|
Scriveno's core insight: drafted prose should sound like *you*, not like an AI. Before drafting begins, `/scr:profile-writer` builds a detailed voice profile across 15+ dimensions:
|
|
@@ -171,6 +188,7 @@ Scriveno is built on five principles:
|
|
|
171
188
|
- [Contributing](docs/contributing.md) -- How to add commands, agents, work types, and templates
|
|
172
189
|
- [Architecture](docs/architecture.md) -- How Scriveno works under the hood
|
|
173
190
|
- [Configuration](docs/configuration.md) -- Package, installer, constraints, and `.manuscript/config.json` surfaces
|
|
191
|
+
- [Auto-Invoke Policy](docs/auto-invoke-policy.md) -- Shared status engine, visible automation status, and agent-spawn boundaries
|
|
174
192
|
- [Development](docs/development.md) -- Contributor workflow for changing commands, templates, installer logic, and docs
|
|
175
193
|
- [Testing](docs/testing.md) -- What the test suite covers and which checks to run before shipping
|
|
176
194
|
- [Release Notes](docs/release-notes.md) -- Public summary of what changed between package releases
|
|
@@ -195,7 +213,7 @@ Scriveno currently ships installer targets for these AI tooling environments:
|
|
|
195
213
|
- **Perplexity Desktop** (guided local-MCP setup)
|
|
196
214
|
- **Generic (SKILL.md)** fallback
|
|
197
215
|
|
|
198
|
-
**Installer baseline:** `Node.js >=20.0.0` for `npx scriveno@latest
|
|
216
|
+
**Installer baseline:** `Node.js >=20.0.0` for `npx scriveno@latest`, `bin/install.js`, and `scriveno status --project .`. For new installs, use a currently supported LTS such as Node.js 24; Node.js 20 is now a compatibility floor, not the recommended fresh-install target.
|
|
199
217
|
|
|
200
218
|
**Support note:** Claude Code is the primary reference runtime and now installs a flat `/scr-*` command surface. The environments listed above are installer targets, not a claim that every host runtime has verified parity today. Codex currently installs a skill-native `$scr-*` surface, while Perplexity Desktop is a guided local-MCP target rather than a writable command runtime. See the [runtime compatibility matrix](docs/runtime-support.md) for install type, support level, and verification status.
|
|
201
219
|
|
|
@@ -203,11 +221,11 @@ Scriveno currently ships installer targets for these AI tooling environments:
|
|
|
203
221
|
|
|
204
222
|
## Status
|
|
205
223
|
|
|
206
|
-
**Version:** 2.0.
|
|
224
|
+
**Version:** 2.0.8
|
|
207
225
|
|
|
208
|
-
Scriveno's core command surface is stable across 112 commands, 50 work types, and 11 installer targets. The current repo baseline includes shipped planning milestones through `v2.0 Publishing Cover Packaging`, plus the creative-context, record-store, branching-next, runtime-sync, adaptive concierge, human-first writing-safeguard, authenticity-diagnostic, domain-grilling,
|
|
226
|
+
Scriveno's core command surface is stable across 112 commands, 50 work types, and 11 installer targets. The current repo baseline includes shipped planning milestones through `v2.0 Publishing Cover Packaging`, plus the creative-context, record-store, branching-next, runtime-sync, adaptive concierge, human-first writing-safeguard, authenticity-diagnostic, domain-grilling, installer-marker cleanup, cross-runtime agent metadata, visible automation status, and the shared `scriveno status --project .` auto-invoke engine through `2.0.8`. See [Shipped Assets](docs/shipped-assets.md) for the canonical asset inventory and [Runtime Support](docs/runtime-support.md) for the runtime compatibility matrix.
|
|
209
227
|
|
|
210
|
-
Version `2.0.
|
|
228
|
+
Version `2.0.8` publishes Scriveno under the package name `scriveno`, so the current install command is `npx scriveno@latest`. The older `scriveno-cli` package name is historical and was unpublished during the rename, so npm cannot attach a deprecation notice to it while it has no active registry record. The older `scriven-cli` package remains on npm only as a deprecated legacy name that points users to `scriveno`. Do not treat either legacy package name as active unless a deliberate compatibility shim is republished. See [CHANGELOG](CHANGELOG.md) for the full list and [docs/release-notes.md](docs/release-notes.md) for the public-facing summary.
|
|
211
229
|
|
|
212
230
|
Package history is tracked in [CHANGELOG.md](CHANGELOG.md), and the public-facing summary for this release is in [docs/release-notes.md](docs/release-notes.md).
|
|
213
231
|
|
package/bin/install.js
CHANGED
|
@@ -6,6 +6,7 @@ const os = require('os');
|
|
|
6
6
|
const readline = require('readline');
|
|
7
7
|
const crypto = require('crypto');
|
|
8
8
|
const architecturalProfiles = require('../lib/architectural-profiles.js');
|
|
9
|
+
const autoInvokeEngine = require('../lib/auto-invoke-engine.js');
|
|
9
10
|
|
|
10
11
|
const PKG_ROOT = path.join(__dirname, '..');
|
|
11
12
|
const PKG = require('../package.json');
|
|
@@ -155,6 +156,7 @@ const RUNTIMES = {
|
|
|
155
156
|
agents_dir_global: path.join(os.homedir(), '.codex', 'agents'),
|
|
156
157
|
agents_dir_project: '.codex/agents',
|
|
157
158
|
skill_style: 'per-command',
|
|
159
|
+
agent_metadata: 'toml',
|
|
158
160
|
detect: () => fs.existsSync(path.join(os.homedir(), '.codex')),
|
|
159
161
|
},
|
|
160
162
|
'opencode': {
|
|
@@ -414,6 +416,58 @@ function collectCommandEntries(commandsRoot) {
|
|
|
414
416
|
return entries;
|
|
415
417
|
}
|
|
416
418
|
|
|
419
|
+
function stripMarkdownFrontmatter(content) {
|
|
420
|
+
if (typeof content !== 'string' || content.length === 0) return '';
|
|
421
|
+
const stripped = content.charCodeAt(0) === 0xFEFF ? content.slice(1) : content;
|
|
422
|
+
const lines = stripped.split(/\r?\n/);
|
|
423
|
+
if (lines[0] !== '---') return stripped;
|
|
424
|
+
for (let i = 1; i < lines.length; i++) {
|
|
425
|
+
if (lines[i] === '---' || lines[i] === '...') {
|
|
426
|
+
return lines.slice(i + 1).join('\n').replace(/^\n/, '');
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
return stripped;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function collectAgentEntries(agentsRoot = path.join(PKG_ROOT, 'agents')) {
|
|
433
|
+
if (!fs.existsSync(agentsRoot)) return [];
|
|
434
|
+
const entries = [];
|
|
435
|
+
for (const entry of fs.readdirSync(agentsRoot, { withFileTypes: true })) {
|
|
436
|
+
if (!entry.isFile() || !entry.name.endsWith('.md')) continue;
|
|
437
|
+
const relativePath = entry.name;
|
|
438
|
+
const filePath = path.join(agentsRoot, relativePath);
|
|
439
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
440
|
+
const stem = entry.name.replace(/\.md$/, '');
|
|
441
|
+
const frontmatter = readFrontmatterValues(content);
|
|
442
|
+
const name = frontmatter.name || stem;
|
|
443
|
+
const description = frontmatter.description || `${stem.replace(/-/g, ' ')} agent`;
|
|
444
|
+
entries.push({
|
|
445
|
+
name,
|
|
446
|
+
description,
|
|
447
|
+
relativePath,
|
|
448
|
+
metadataFileName: `${name}.toml`,
|
|
449
|
+
content,
|
|
450
|
+
body: stripMarkdownFrontmatter(content),
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
454
|
+
return entries;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function tomlString(value) {
|
|
458
|
+
return JSON.stringify(String(value));
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
function generateCodexAgentMetadata(entry) {
|
|
462
|
+
return [
|
|
463
|
+
`name = ${tomlString(entry.name)}`,
|
|
464
|
+
`description = ${tomlString(entry.description)}`,
|
|
465
|
+
'sandbox_mode = "workspace-write"',
|
|
466
|
+
`developer_instructions = ${tomlString(entry.body)}`,
|
|
467
|
+
'',
|
|
468
|
+
].join('\n');
|
|
469
|
+
}
|
|
470
|
+
|
|
417
471
|
// Both Claude (flat scr-foo.md filename) and Codex (per-command skill dir
|
|
418
472
|
// scr-foo/SKILL.md) install commands keyed by the same skill-name function:
|
|
419
473
|
// /scr:foo and /scr:foo:bar both flatten under commandRefToCodexSkillName by
|
|
@@ -767,6 +821,8 @@ function printHelp() {
|
|
|
767
821
|
console.log(BANNER);
|
|
768
822
|
console.log(`Usage:
|
|
769
823
|
scriveno
|
|
824
|
+
scriveno status --project .
|
|
825
|
+
scriveno status . --json
|
|
770
826
|
scriveno --runtimes codex,claude-code --global --writer --silent
|
|
771
827
|
|
|
772
828
|
Options:
|
|
@@ -781,6 +837,12 @@ Options:
|
|
|
781
837
|
--help Show this help text
|
|
782
838
|
--version Show the Scriveno package version
|
|
783
839
|
|
|
840
|
+
Status options:
|
|
841
|
+
status Inspect a project and recommend the next command
|
|
842
|
+
--project <path> Project root to inspect (default: current directory)
|
|
843
|
+
--trigger <name> Status trigger label (default: scriveno status)
|
|
844
|
+
--json Print machine-readable status JSON
|
|
845
|
+
|
|
784
846
|
Runtime keys:
|
|
785
847
|
${Object.keys(RUNTIMES).join(', ')}
|
|
786
848
|
`);
|
|
@@ -788,6 +850,7 @@ Runtime keys:
|
|
|
788
850
|
|
|
789
851
|
function parseArgs(argv) {
|
|
790
852
|
const options = {
|
|
853
|
+
command: 'install',
|
|
791
854
|
runtimeKeys: [],
|
|
792
855
|
installDetected: false,
|
|
793
856
|
isGlobal: null,
|
|
@@ -795,8 +858,44 @@ function parseArgs(argv) {
|
|
|
795
858
|
silent: false,
|
|
796
859
|
showHelp: false,
|
|
797
860
|
showVersion: false,
|
|
861
|
+
statusProjectRoot: process.cwd(),
|
|
862
|
+
statusTrigger: 'scriveno status',
|
|
863
|
+
statusJson: false,
|
|
798
864
|
};
|
|
799
865
|
|
|
866
|
+
if (argv[0] === 'status') {
|
|
867
|
+
options.command = 'status';
|
|
868
|
+
for (let i = 1; i < argv.length; i++) {
|
|
869
|
+
const arg = argv[i];
|
|
870
|
+
if (arg === '--help' || arg === '-h') {
|
|
871
|
+
options.showHelp = true;
|
|
872
|
+
} else if (arg === '--version' || arg === '-v') {
|
|
873
|
+
options.showVersion = true;
|
|
874
|
+
} else if (arg === '--json') {
|
|
875
|
+
options.statusJson = true;
|
|
876
|
+
} else if (arg === '--project') {
|
|
877
|
+
const value = argv[i + 1];
|
|
878
|
+
if (!value) throw new Error('--project requires a value for status');
|
|
879
|
+
options.statusProjectRoot = value;
|
|
880
|
+
i++;
|
|
881
|
+
} else if (arg.startsWith('--project=')) {
|
|
882
|
+
options.statusProjectRoot = arg.slice('--project='.length);
|
|
883
|
+
} else if (arg === '--trigger') {
|
|
884
|
+
const value = argv[i + 1];
|
|
885
|
+
if (!value) throw new Error('--trigger requires a value');
|
|
886
|
+
options.statusTrigger = value;
|
|
887
|
+
i++;
|
|
888
|
+
} else if (arg.startsWith('--trigger=')) {
|
|
889
|
+
options.statusTrigger = arg.slice('--trigger='.length);
|
|
890
|
+
} else if (arg.startsWith('-')) {
|
|
891
|
+
throw new Error(`Unknown status argument "${arg}"`);
|
|
892
|
+
} else {
|
|
893
|
+
options.statusProjectRoot = arg;
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
return options;
|
|
897
|
+
}
|
|
898
|
+
|
|
800
899
|
function addRuntimeList(value) {
|
|
801
900
|
for (const key of String(value).split(',').map((item) => item.trim()).filter(Boolean)) {
|
|
802
901
|
if (!Object.prototype.hasOwnProperty.call(RUNTIMES, key)) {
|
|
@@ -848,6 +947,16 @@ function parseArgs(argv) {
|
|
|
848
947
|
return options;
|
|
849
948
|
}
|
|
850
949
|
|
|
950
|
+
function runStatus({ projectRoot, trigger, json }) {
|
|
951
|
+
const analysis = autoInvokeEngine.analyzeProject(projectRoot);
|
|
952
|
+
if (json) {
|
|
953
|
+
console.log(JSON.stringify(analysis, null, 2));
|
|
954
|
+
} else {
|
|
955
|
+
console.log(autoInvokeEngine.formatReport(analysis, { trigger }));
|
|
956
|
+
}
|
|
957
|
+
return analysis;
|
|
958
|
+
}
|
|
959
|
+
|
|
851
960
|
function resolveInstallRequest(parsed, detectedRuntimeKeys, { isTTY }) {
|
|
852
961
|
const hasRuntimeDirective = parsed.runtimeKeys.length > 0 || parsed.installDetected;
|
|
853
962
|
const hasModifierOverrides = parsed.isGlobal !== null || parsed.developerMode !== null;
|
|
@@ -1202,6 +1311,64 @@ function writeCodexSkillManifest(skillsDir, skillNames) {
|
|
|
1202
1311
|
atomicWriteFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
1203
1312
|
}
|
|
1204
1313
|
|
|
1314
|
+
function isScrivenoCodexAgentMetadataFile(filePath) {
|
|
1315
|
+
if (!fs.existsSync(filePath)) return false;
|
|
1316
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
1317
|
+
return content.includes('developer_instructions = ') && (
|
|
1318
|
+
content.includes('# Drafter agent')
|
|
1319
|
+
|| content.includes('# Voice checker agent')
|
|
1320
|
+
|| content.includes('# Continuity checker agent')
|
|
1321
|
+
|| content.includes('# Plan checker agent')
|
|
1322
|
+
|| content.includes('# Researcher agent')
|
|
1323
|
+
|| content.includes('# Translator agent')
|
|
1324
|
+
);
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
function cleanCodexAgentFiles(agentsDir, currentFileNames) {
|
|
1328
|
+
if (!fs.existsSync(agentsDir)) return 0;
|
|
1329
|
+
|
|
1330
|
+
const manifestPath = path.join(agentsDir, '.scriveno-agents-installed.json');
|
|
1331
|
+
const manifest = readJsonIfExists(manifestPath);
|
|
1332
|
+
const currentFileSet = new Set(currentFileNames);
|
|
1333
|
+
const knownFileNames = new Set(Array.isArray(manifest?.files) ? manifest.files : []);
|
|
1334
|
+
|
|
1335
|
+
for (const entry of fs.readdirSync(agentsDir, { withFileTypes: true })) {
|
|
1336
|
+
if (!entry.isFile() || !entry.name.endsWith('.toml')) continue;
|
|
1337
|
+
const filePath = path.join(agentsDir, entry.name);
|
|
1338
|
+
if (isScrivenoCodexAgentMetadataFile(filePath)) {
|
|
1339
|
+
knownFileNames.add(entry.name);
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
removePathIfExists(manifestPath);
|
|
1344
|
+
|
|
1345
|
+
let removed = 0;
|
|
1346
|
+
for (const fileName of knownFileNames) {
|
|
1347
|
+
if (!currentFileSet.has(fileName) && removePathIfExists(path.join(agentsDir, fileName))) {
|
|
1348
|
+
removed++;
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
for (const fileName of currentFileNames) {
|
|
1353
|
+
if (removePathIfExists(path.join(agentsDir, fileName))) {
|
|
1354
|
+
removed++;
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
return removed;
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
function writeCodexAgentManifest(agentsDir, fileNames) {
|
|
1362
|
+
const manifestPath = path.join(agentsDir, '.scriveno-agents-installed.json');
|
|
1363
|
+
const manifest = {
|
|
1364
|
+
installer: 'scriveno',
|
|
1365
|
+
version: VERSION,
|
|
1366
|
+
files: fileNames,
|
|
1367
|
+
generated_at: new Date().toISOString(),
|
|
1368
|
+
};
|
|
1369
|
+
atomicWriteFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1205
1372
|
async function main() {
|
|
1206
1373
|
const parsed = parseArgs(process.argv.slice(2));
|
|
1207
1374
|
if (parsed.showHelp) {
|
|
@@ -1213,6 +1380,15 @@ async function main() {
|
|
|
1213
1380
|
return;
|
|
1214
1381
|
}
|
|
1215
1382
|
|
|
1383
|
+
if (parsed.command === 'status') {
|
|
1384
|
+
runStatus({
|
|
1385
|
+
projectRoot: parsed.statusProjectRoot,
|
|
1386
|
+
trigger: parsed.statusTrigger,
|
|
1387
|
+
json: parsed.statusJson,
|
|
1388
|
+
});
|
|
1389
|
+
return;
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1216
1392
|
const detectedRuntimeKeys = Object.entries(RUNTIMES).filter(([, runtime]) => runtime.detect()).map(([key]) => key);
|
|
1217
1393
|
const installRequest = resolveInstallRequest(parsed, detectedRuntimeKeys, { isTTY: Boolean(process.stdin.isTTY) });
|
|
1218
1394
|
|
|
@@ -1342,6 +1518,26 @@ function installManifestSkillRuntime(runtime, isGlobal, log) {
|
|
|
1342
1518
|
log(` ${c('green', 'OK')} ${runtime.label}: ${agentCount} agent prompts -> ${c('dim', path.join(skillsDir, 'agents'))}`);
|
|
1343
1519
|
}
|
|
1344
1520
|
|
|
1521
|
+
function installCodexAgentsWithMetadata(agentsDir) {
|
|
1522
|
+
const agentEntries = collectAgentEntries(path.join(PKG_ROOT, 'agents'));
|
|
1523
|
+
const currentFileNames = agentEntries.flatMap((entry) => [entry.relativePath, entry.metadataFileName]);
|
|
1524
|
+
|
|
1525
|
+
fs.mkdirSync(agentsDir, { recursive: true });
|
|
1526
|
+
const removed = cleanCodexAgentFiles(agentsDir, currentFileNames);
|
|
1527
|
+
|
|
1528
|
+
for (const entry of agentEntries) {
|
|
1529
|
+
atomicWriteFileSync(path.join(agentsDir, entry.relativePath), entry.content);
|
|
1530
|
+
atomicWriteFileSync(path.join(agentsDir, entry.metadataFileName), generateCodexAgentMetadata(entry));
|
|
1531
|
+
}
|
|
1532
|
+
writeCodexAgentManifest(agentsDir, currentFileNames);
|
|
1533
|
+
|
|
1534
|
+
return {
|
|
1535
|
+
agentCount: agentEntries.length,
|
|
1536
|
+
metadataCount: agentEntries.length,
|
|
1537
|
+
removed,
|
|
1538
|
+
};
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1345
1541
|
function installCodexRuntime(runtime, isGlobal, log) {
|
|
1346
1542
|
const skillsDir = isGlobal ? runtime.skills_dir_global : path.resolve(runtime.skills_dir_project);
|
|
1347
1543
|
const commandsDir = isGlobal ? runtime.commands_dir_global : path.resolve(runtime.commands_dir_project);
|
|
@@ -1355,7 +1551,6 @@ function installCodexRuntime(runtime, isGlobal, log) {
|
|
|
1355
1551
|
removePathIfExists(commandsDir);
|
|
1356
1552
|
fs.mkdirSync(skillsDir, { recursive: true });
|
|
1357
1553
|
const removedSkillDirs = cleanCodexSkillDirs(skillsDir, skillNames);
|
|
1358
|
-
const removedAgentFiles = cleanMirroredFiles(path.join(PKG_ROOT, 'agents'), agentsDir);
|
|
1359
1554
|
|
|
1360
1555
|
// NOTE: `collectCommandEntries` returns .md files only, and the authoritative
|
|
1361
1556
|
// `commands/scr/**` tree is .md-only today. No non-.md assets need mirroring.
|
|
@@ -1373,7 +1568,7 @@ function installCodexRuntime(runtime, isGlobal, log) {
|
|
|
1373
1568
|
commandCount++;
|
|
1374
1569
|
}
|
|
1375
1570
|
|
|
1376
|
-
const
|
|
1571
|
+
const agentInstall = installCodexAgentsWithMetadata(agentsDir);
|
|
1377
1572
|
|
|
1378
1573
|
for (const entry of commandEntries) {
|
|
1379
1574
|
const skillDir = path.join(skillsDir, entry.skillName);
|
|
@@ -1385,7 +1580,7 @@ function installCodexRuntime(runtime, isGlobal, log) {
|
|
|
1385
1580
|
|
|
1386
1581
|
log(` ${c('green', 'OK')} ${runtime.label}: ${commandEntries.length} \$scr-* skills -> ${c('dim', skillsDir)}${removedSkillDirs ? c('dim', ` (cleaned ${removedSkillDirs} stale dirs)`) : ''}`);
|
|
1387
1582
|
log(` ${c('green', 'OK')} ${runtime.label}: ${commandCount} command files -> ${c('dim', commandsDir)}`);
|
|
1388
|
-
log(` ${c('green', 'OK')} ${runtime.label}: ${agentCount} agent prompts -> ${c('dim', agentsDir)}${
|
|
1583
|
+
log(` ${c('green', 'OK')} ${runtime.label}: ${agentInstall.agentCount} agent prompts + ${agentInstall.metadataCount} metadata files -> ${c('dim', agentsDir)}${agentInstall.removed ? c('dim', ` (cleaned ${agentInstall.removed} stale files)`) : ''}`);
|
|
1389
1584
|
}
|
|
1390
1585
|
|
|
1391
1586
|
function installGuidedRuntime(runtime, isGlobal, dataDir, log) {
|
|
@@ -1415,11 +1610,13 @@ function installGuidedRuntime(runtime, isGlobal, dataDir, log) {
|
|
|
1415
1610
|
function writeSharedAssets(dataDir, runtimeKeys, isGlobal, developerMode, installMode, log) {
|
|
1416
1611
|
fs.mkdirSync(path.join(dataDir, 'templates'), { recursive: true });
|
|
1417
1612
|
fs.mkdirSync(path.join(dataDir, 'data'), { recursive: true });
|
|
1613
|
+
fs.mkdirSync(path.join(dataDir, 'lib'), { recursive: true });
|
|
1418
1614
|
const templateResult = copyDirWithPreservation(path.join(PKG_ROOT, 'templates'), path.join(dataDir, 'templates'));
|
|
1419
1615
|
const dataResult = copyDirWithPreservation(path.join(PKG_ROOT, 'data'), path.join(dataDir, 'data'));
|
|
1616
|
+
const libResult = copyDirWithPreservation(path.join(PKG_ROOT, 'lib'), path.join(dataDir, 'lib'));
|
|
1420
1617
|
const sum = (r) => r.fresh + r.replaced + r.backedUp;
|
|
1421
|
-
log(` ${c('green', 'OK')} ${sum(templateResult)} templates + ${sum(dataResult)} data files -> ${c('dim', dataDir)}`);
|
|
1422
|
-
const totalBackedUp = templateResult.backedUp + dataResult.backedUp;
|
|
1618
|
+
log(` ${c('green', 'OK')} ${sum(templateResult)} templates + ${sum(dataResult)} data files + ${sum(libResult)} lib files -> ${c('dim', dataDir)}`);
|
|
1619
|
+
const totalBackedUp = templateResult.backedUp + dataResult.backedUp + libResult.backedUp;
|
|
1423
1620
|
if (totalBackedUp > 0) {
|
|
1424
1621
|
log(` ${c('yellow', 'i')} Preserved ${totalBackedUp} user-modified file(s) as .backup.<timestamp>`);
|
|
1425
1622
|
}
|
|
@@ -1576,17 +1773,25 @@ module.exports = {
|
|
|
1576
1773
|
RUNTIMES,
|
|
1577
1774
|
parseArgs,
|
|
1578
1775
|
resolveInstallRequest,
|
|
1776
|
+
runStatus,
|
|
1579
1777
|
collectCommandEntries,
|
|
1778
|
+
collectAgentEntries,
|
|
1580
1779
|
assertNoSkillNameCollisions,
|
|
1581
1780
|
cleanCodexSkillDirs,
|
|
1781
|
+
cleanCodexAgentFiles,
|
|
1582
1782
|
commandRefToCodexSkillName,
|
|
1583
1783
|
commandRefToClaudeInvocation,
|
|
1584
1784
|
commandRefToCodexInvocation,
|
|
1585
1785
|
commandEntryToFlatCommandFileName,
|
|
1586
1786
|
generateClaudeCommandContent,
|
|
1587
1787
|
generateCodexCommandContent,
|
|
1788
|
+
generateCodexAgentMetadata,
|
|
1588
1789
|
rewriteInstalledCommandRefs,
|
|
1790
|
+
installCommandRuntime,
|
|
1791
|
+
installClaudeCommandRuntime,
|
|
1792
|
+
installManifestSkillRuntime,
|
|
1589
1793
|
installCodexRuntime,
|
|
1794
|
+
installCodexAgentsWithMetadata,
|
|
1590
1795
|
cleanFlatCommandFiles,
|
|
1591
1796
|
generateCodexSkill,
|
|
1592
1797
|
generateSkillManifest,
|
|
@@ -1617,4 +1822,10 @@ module.exports = {
|
|
|
1617
1822
|
// Per-work-type pitfall packs
|
|
1618
1823
|
listPitfallPacks: architecturalProfiles.listPitfallPacks,
|
|
1619
1824
|
getPitfallPackPath: architecturalProfiles.getPitfallPackPath,
|
|
1825
|
+
// Shared proactive status engine
|
|
1826
|
+
autoInvokeEngine,
|
|
1827
|
+
analyzeProject: autoInvokeEngine.analyzeProject,
|
|
1828
|
+
formatAutoInvokeReport: autoInvokeEngine.formatReport,
|
|
1829
|
+
getRuntimeAgentSupport: autoInvokeEngine.getRuntimeAgentSupport,
|
|
1830
|
+
listRuntimeAgentSupport: autoInvokeEngine.listRuntimeAgentSupport,
|
|
1620
1831
|
};
|
|
@@ -182,6 +182,34 @@ If any steps failed, show them in the "Errors" section with actionable fix instr
|
|
|
182
182
|
|
|
183
183
|
---
|
|
184
184
|
|
|
185
|
+
## Automation Status
|
|
186
|
+
|
|
187
|
+
Every progress update and final response must include a compact status trail. This is how the writer can tell whether Scriveno auto-chained commands, spawned agents, or only updated local files.
|
|
188
|
+
|
|
189
|
+
```text
|
|
190
|
+
Automation status:
|
|
191
|
+
Trigger: /scr:autopilot-publish --preset {preset}
|
|
192
|
+
Auto-invoked commands:
|
|
193
|
+
- /scr:voice-check: yes/no
|
|
194
|
+
- /scr:continuity-check: yes/no
|
|
195
|
+
- /scr:front-matter: yes/no
|
|
196
|
+
- /scr:back-matter: yes/no
|
|
197
|
+
- /scr:cover-art: yes/no
|
|
198
|
+
- /scr:export: {count} run(s)
|
|
199
|
+
Spawned agents:
|
|
200
|
+
- voice-checker: {count}
|
|
201
|
+
- continuity-checker: {count}
|
|
202
|
+
Local operations:
|
|
203
|
+
- prerequisite scan: yes/no
|
|
204
|
+
- quality report files written: yes/no
|
|
205
|
+
- export package files written: {count}
|
|
206
|
+
Quality gate:
|
|
207
|
+
- status: warn-only
|
|
208
|
+
- reason: autopilot-publish reports quality findings but continues to export
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
If a quality command cannot spawn its native agent type, use the installed agent prompt in a fresh context and say `prompt-run fallback used` in the status block.
|
|
212
|
+
|
|
185
213
|
## Response Contract
|
|
186
214
|
|
|
187
215
|
Every writer-facing response must end with one to four next-command suggestions. Each suggestion must include a short explanation of what that path will do.
|
|
@@ -213,6 +213,35 @@ Next Steps:
|
|
|
213
213
|
- **NEVER** continue past a blocking error without logging it -- all errors must appear in the completion summary
|
|
214
214
|
- **NEVER** modify the source manuscript -- translation works on copies in `.manuscript/translation/{lang}/`
|
|
215
215
|
|
|
216
|
+
## Automation Status
|
|
217
|
+
|
|
218
|
+
Every progress update and final response must include a compact status trail. This is how the writer can tell whether Scriveno auto-chained commands, spawned agents, or only updated local files.
|
|
219
|
+
|
|
220
|
+
```text
|
|
221
|
+
Automation status:
|
|
222
|
+
Trigger: /scr:autopilot-translate {languages}
|
|
223
|
+
Languages: {count}
|
|
224
|
+
Auto-invoked commands per language:
|
|
225
|
+
- /scr:translation-glossary: yes/no
|
|
226
|
+
- /scr:translate: yes/no
|
|
227
|
+
- /scr:translation-memory --build: yes/no
|
|
228
|
+
- /scr:cultural-adaptation: yes/no
|
|
229
|
+
- /scr:back-translate: yes/no
|
|
230
|
+
- /scr:multi-publish: yes/no
|
|
231
|
+
Spawned agents:
|
|
232
|
+
- translator: {count} fresh-context invocation(s)
|
|
233
|
+
Local operations:
|
|
234
|
+
- glossary files written: {count}
|
|
235
|
+
- translation memory files updated: {count}
|
|
236
|
+
- adaptation reports written: {count}
|
|
237
|
+
- export files written: {count}
|
|
238
|
+
Pause:
|
|
239
|
+
- status: none/blocking-error/writer-requested
|
|
240
|
+
- reason: {one sentence}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
If the translator native agent type is unavailable, use the installed `agents/translator.md` prompt in a fresh context per unit and say `prompt-run fallback used` in the status block.
|
|
244
|
+
|
|
216
245
|
## Response Contract
|
|
217
246
|
|
|
218
247
|
Every writer-facing response must end with one to four next-command suggestions. Each suggestion must include a short explanation of what that path will do.
|
|
@@ -147,6 +147,35 @@ On pause or stop:
|
|
|
147
147
|
2. Include what was just completed and what the next action would be
|
|
148
148
|
3. Record the writer's notes if they provide any
|
|
149
149
|
|
|
150
|
+
## Automation Status
|
|
151
|
+
|
|
152
|
+
Every progress update and final response must include a compact status trail. This is how the writer can tell whether Scriveno auto-chained commands, spawned agents, or only updated local files.
|
|
153
|
+
|
|
154
|
+
```text
|
|
155
|
+
Automation status:
|
|
156
|
+
Trigger: /scr:autopilot --profile {profile}
|
|
157
|
+
Profile: guided/supervised/full-auto
|
|
158
|
+
Auto-invoked commands:
|
|
159
|
+
- /scr:discuss N: yes/no
|
|
160
|
+
- /scr:plan N: yes/no
|
|
161
|
+
- /scr:draft N: yes/no
|
|
162
|
+
- /scr:editor-review N: yes/no
|
|
163
|
+
- /scr:submit N: yes/no
|
|
164
|
+
Spawned agents:
|
|
165
|
+
- plan-checker: {count}
|
|
166
|
+
- drafter: {count}
|
|
167
|
+
- voice-checker: {count}
|
|
168
|
+
- continuity-checker: {count}
|
|
169
|
+
Local operations:
|
|
170
|
+
- STATE.md updated: yes/no
|
|
171
|
+
- HISTORY.log updated: yes/no
|
|
172
|
+
Pause:
|
|
173
|
+
- status: none/guided/supervised/quality-gate/blocker
|
|
174
|
+
- reason: {one sentence}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
If a command in the chain runs local file operations only, say so under `Local operations` rather than listing it as a spawned agent. If a native agent type is unavailable and an installed prompt-run fallback is used, include that in `Spawned agents`.
|
|
178
|
+
|
|
150
179
|
## Response Contract
|
|
151
180
|
|
|
152
181
|
Every writer-facing response must end with one to four next-command suggestions. Each suggestion must include a short explanation of what that path will do.
|
|
@@ -67,12 +67,34 @@ Load `.manuscript/config.json` to get `work_type`. Load Scriveno's installed/sha
|
|
|
67
67
|
</task>
|
|
68
68
|
</beta_reader_agent>
|
|
69
69
|
|
|
70
|
+
If the host runtime cannot spawn a beta reader worker, run the beta reader persona in an isolated fresh context. Report that fallback in the status block.
|
|
71
|
+
|
|
70
72
|
### OUTPUT
|
|
71
73
|
|
|
72
74
|
Save to `.manuscript/{act_num}-BETA-READER-NOTES.md`
|
|
73
75
|
|
|
74
76
|
Present findings conversationally to the writer -- this should feel like getting feedback from a trusted reader, not a technical report.
|
|
75
77
|
|
|
78
|
+
## Agent Status
|
|
79
|
+
|
|
80
|
+
Every response must include a short status block that makes invocation visible:
|
|
81
|
+
|
|
82
|
+
```text
|
|
83
|
+
Agent status:
|
|
84
|
+
Trigger: /scr:beta-reader {scope}
|
|
85
|
+
Spawned agents:
|
|
86
|
+
- beta-reader: 1 fresh-context reader invocation
|
|
87
|
+
Local operations:
|
|
88
|
+
- drafted files checked: {count}
|
|
89
|
+
- focus area applied: yes/no
|
|
90
|
+
- report written: yes/no
|
|
91
|
+
Auto-invoked:
|
|
92
|
+
- none
|
|
93
|
+
Why: beta-reader is experiential feedback only; revision remains a writer decision
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
If native worker spawning is unavailable, say `prompt-run fallback used` in the status block.
|
|
97
|
+
|
|
76
98
|
## Response Contract
|
|
77
99
|
|
|
78
100
|
Every writer-facing response must end with one to four next-command suggestions. Each suggestion must include a short explanation of what that path will do.
|
|
@@ -27,6 +27,8 @@ Invoke the installed `continuity-checker.md` agent for the writer's active Scriv
|
|
|
27
27
|
- DOCTRINES.md, LINEAGES.md, and CHRONOLOGY.md when present (sacred only)
|
|
28
28
|
- The previous continuity report if one exists, so the agent can verify resolved issues stayed resolved instead of re-flagging them
|
|
29
29
|
|
|
30
|
+
If the host runtime cannot spawn a native `continuity-checker` agent type, load the installed `agents/continuity-checker.md` prompt from the active runtime and run it in an isolated fresh context. Record that fallback in the status block.
|
|
31
|
+
|
|
30
32
|
The agent reads all drafted scenes and checks:
|
|
31
33
|
|
|
32
34
|
If RECORD.md contradicts the drafted text, flag the mismatch as a RECORD drift finding. If the drafted text reveals established facts or open threads that are missing from RECORD.md, list compact suggested updates under a "Record updates" section without rewriting the file unless the writer asked for fixes.
|
|
@@ -105,6 +107,25 @@ For each issue:
|
|
|
105
107
|
|
|
106
108
|
Save to `.manuscript/{act_num}-CONTINUITY-REPORT.md` or `.manuscript/FULL-CONTINUITY-REPORT.md`. For technical work types, use `CONSISTENCY-REPORT` in the writer-facing title even if the file path stays the same.
|
|
107
109
|
|
|
110
|
+
## Agent Status
|
|
111
|
+
|
|
112
|
+
Every response must include a short status block that makes invocation visible:
|
|
113
|
+
|
|
114
|
+
```text
|
|
115
|
+
Agent status:
|
|
116
|
+
Trigger: /scr:continuity-check {scope}
|
|
117
|
+
Spawned agents:
|
|
118
|
+
- continuity-checker: 1 fresh-context diagnostic invocation
|
|
119
|
+
Local operations:
|
|
120
|
+
- drafted files checked: {count}
|
|
121
|
+
- RECORD.md checked: yes/no
|
|
122
|
+
- prior report checked: yes/no
|
|
123
|
+
- report written: yes/no
|
|
124
|
+
Auto-invoked:
|
|
125
|
+
- none
|
|
126
|
+
Why: continuity-check is diagnostic only; fixes are writer-chosen handoffs
|
|
127
|
+
```
|
|
128
|
+
|
|
108
129
|
## Response Contract
|
|
109
130
|
|
|
110
131
|
Every writer-facing response must end with one to four next-command suggestions. Each suggestion must include a short explanation of what that path will do.
|
package/commands/scr/draft.md
CHANGED
|
@@ -53,6 +53,27 @@ Require `.manuscript/plans/{N}-*-PLAN.md` files to exist. If none exist, also ch
|
|
|
53
53
|
|
|
54
54
|
8. **Tell the writer:** "Drafted {unit} {N}: X words across Y {atomic_units}. Voice consistency: Z%. Updated RECORD.md with what the draft established. Ready for editor review? Run `/scr:editor-review N` or `/scr:next`."
|
|
55
55
|
|
|
56
|
+
## Agent and Automation Status
|
|
57
|
+
|
|
58
|
+
Every response must include a short status block that makes invocation visible:
|
|
59
|
+
|
|
60
|
+
```text
|
|
61
|
+
Agent status:
|
|
62
|
+
Trigger: /scr:draft N
|
|
63
|
+
Spawned agents:
|
|
64
|
+
- drafter: {count} fresh-context invocation(s)
|
|
65
|
+
- voice-checker: 1 diagnostic pass, or none if no draft was produced
|
|
66
|
+
Local operations:
|
|
67
|
+
- draft files written: {count}
|
|
68
|
+
- RECORD.md updated: yes/no
|
|
69
|
+
- STATE.md updated: yes/no
|
|
70
|
+
Auto-invoked:
|
|
71
|
+
- /scr:editor-review N: yes/no
|
|
72
|
+
Why: {autopilot.enabled true, full-auto profile, supervised pause, or writer-facing manual mode}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
If the host runtime cannot spawn a native `drafter` or `voice-checker` agent type, load the installed agent prompt from the active runtime's `agents/` directory and run it in an isolated fresh context. In the status block, write `Spawned agents: native unavailable; prompt-run fallback used` so the writer can see what happened.
|
|
76
|
+
|
|
56
77
|
## History log
|
|
57
78
|
|
|
58
79
|
After all atomic units in this invocation are drafted, append one line to `.manuscript/HISTORY.log` per `docs/history-protocol.md`:
|
|
@@ -101,6 +101,8 @@ For any issues flagged, spawn a diagnostic agent:
|
|
|
101
101
|
</task>
|
|
102
102
|
</diagnostic_agent>
|
|
103
103
|
|
|
104
|
+
If the host runtime cannot spawn a dedicated diagnostic worker, run the revision diagnosis in an isolated fresh context for each flagged issue group. Report that fallback in the status block.
|
|
105
|
+
|
|
104
106
|
---
|
|
105
107
|
|
|
106
108
|
### STEP 4: GENERATE EDITOR NOTES
|
|
@@ -408,6 +410,30 @@ Together these form a complete accountability trail. Neither party's work is los
|
|
|
408
410
|
|
|
409
411
|
---
|
|
410
412
|
|
|
413
|
+
## Agent and Automation Status
|
|
414
|
+
|
|
415
|
+
Every response must include a short status block that makes invocation visible:
|
|
416
|
+
|
|
417
|
+
```text
|
|
418
|
+
Agent status:
|
|
419
|
+
Trigger: /scr:editor-review {mode}
|
|
420
|
+
Spawned agents:
|
|
421
|
+
- revision-diagnostic: {count} fresh-context invocation(s)
|
|
422
|
+
Local operations:
|
|
423
|
+
- reviewable units checked: {count}
|
|
424
|
+
- review report written: yes/no
|
|
425
|
+
- proposal decisions written: yes/no
|
|
426
|
+
- editor notes written: yes/no
|
|
427
|
+
- writer responses written: yes/no
|
|
428
|
+
Auto-invoked:
|
|
429
|
+
- none
|
|
430
|
+
Why: editor-review surfaces decisions and recommended handoffs; it does not revise prose without writer choice
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
If there were no flagged issues in standard review mode, report `revision-diagnostic: none`. In collaboration modes, report `revision-diagnostic: none` unless diagnosis was explicitly requested.
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
411
437
|
## Writer-Friendly Language Guide
|
|
412
438
|
|
|
413
439
|
This command uses writer-friendly terminology throughout:
|