runlist 0.0.0 → 0.94.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/LICENSE +21 -0
- package/README.md +1114 -6
- package/assets/app/app.css +283 -0
- package/assets/app/app.mjs +381 -0
- package/assets/app/block-editor.mjs +182 -0
- package/assets/app/block-model.mjs +52 -0
- package/assets/app/document-create.mjs +86 -0
- package/assets/app/document-lifecycle.mjs +36 -0
- package/assets/app/document-stages.mjs +22 -0
- package/assets/app/document-views.mjs +33 -0
- package/assets/app/document-yardstick.mjs +258 -0
- package/assets/app/editor-navigation.mjs +51 -0
- package/assets/app/filing-navigation.mjs +138 -0
- package/assets/app/git-changes.mjs +80 -0
- package/assets/app/git-commit.mjs +46 -0
- package/assets/app/index.html +70 -0
- package/assets/app/library-navigation.mjs +93 -0
- package/assets/app/outline.mjs +18 -0
- package/assets/app/quick-navigation.mjs +52 -0
- package/assets/app/record-navigation.mjs +78 -0
- package/assets/app/recovery-center.mjs +53 -0
- package/assets/app/semantic-search.mjs +14 -0
- package/assets/app/settings.mjs +15 -0
- package/assets/app/shared.mjs +104 -0
- package/assets/app/stage-source.mjs +75 -0
- package/assets/app/template-editor.mjs +47 -0
- package/assets/app/theme.mjs +25 -0
- package/assets/app/transport.mjs +43 -0
- package/assets/contracts/source-editing-v1.md +232 -0
- package/assets/opencode/plugin.js +162 -0
- package/assets/schemas/runlist-record-v1.schema.json +912 -0
- package/bin/dotmd.mjs +5 -0
- package/bin/runlist.mjs +2714 -0
- package/package.json +53 -6
- package/plugins/runlist-codex/.codex-plugin/plugin.json +18 -0
- package/plugins/runlist-codex/bin/runlist-hook +86 -0
- package/plugins/runlist-codex/hooks/hooks.json +16 -0
- package/plugins/runlist-codex/skills/runlist/SKILL.md +25 -0
- package/runlist.config.example.mjs +370 -0
- package/scripts/postinstall.mjs +56 -0
- package/src/agent-context.mjs +201 -0
- package/src/ai.mjs +30 -0
- package/src/app-create.mjs +169 -0
- package/src/app-filing.mjs +139 -0
- package/src/app-git-commits.mjs +48 -0
- package/src/app-git.mjs +180 -0
- package/src/app-library.mjs +152 -0
- package/src/app-lifecycle-worker.mjs +12 -0
- package/src/app-lifecycle.mjs +79 -0
- package/src/app-records.mjs +134 -0
- package/src/app-search.mjs +80 -0
- package/src/app-semantic-search.mjs +105 -0
- package/src/app-service.mjs +208 -0
- package/src/app-yardstick.mjs +269 -0
- package/src/app.mjs +102 -0
- package/src/atomic-mutation.mjs +1736 -0
- package/src/baton.mjs +435 -0
- package/src/body-link.mjs +48 -0
- package/src/bulk-tag.mjs +174 -0
- package/src/check-collapse.mjs +75 -0
- package/src/claude-commands.mjs +75 -0
- package/src/cli-editor.mjs +8 -0
- package/src/code-refs.mjs +545 -0
- package/src/codex-integration.mjs +81 -0
- package/src/color.mjs +14 -0
- package/src/commands.mjs +374 -0
- package/src/completions.mjs +93 -0
- package/src/config-edit.mjs +606 -0
- package/src/config.mjs +705 -0
- package/src/decision-action.mjs +58 -0
- package/src/decision.mjs +220 -0
- package/src/decisions.mjs +787 -0
- package/src/deps.mjs +317 -0
- package/src/desktop-install.mjs +158 -0
- package/src/desktop-runtime.mjs +4 -0
- package/src/desktop.mjs +25 -0
- package/src/diff.mjs +101 -0
- package/src/doctor.mjs +591 -0
- package/src/durable-rename.mjs +55 -0
- package/src/errors-read.mjs +44 -0
- package/src/export.mjs +496 -0
- package/src/extractors.mjs +101 -0
- package/src/filing.mjs +255 -0
- package/src/fix-membership.mjs +134 -0
- package/src/fix-refs.mjs +174 -0
- package/src/flags.mjs +318 -0
- package/src/frontmatter-fix.mjs +195 -0
- package/src/frontmatter.mjs +252 -0
- package/src/git-commit-filters.mjs +32 -0
- package/src/git-commit-protocol.mjs +198 -0
- package/src/git-commit-signing.mjs +75 -0
- package/src/git-commit-store.mjs +26 -0
- package/src/git-commit-support.mjs +16 -0
- package/src/git-commit-worker.mjs +32 -0
- package/src/git.mjs +909 -0
- package/src/glossary-check.mjs +35 -0
- package/src/glossary.mjs +243 -0
- package/src/graph.mjs +298 -0
- package/src/guard.mjs +488 -0
- package/src/health.mjs +212 -0
- package/src/hints.mjs +129 -0
- package/src/host-integration.mjs +339 -0
- package/src/hub-membership.mjs +284 -0
- package/src/hub.mjs +292 -0
- package/src/hud.mjs +436 -0
- package/src/index-file.mjs +163 -0
- package/src/index.mjs +478 -0
- package/src/init.mjs +512 -0
- package/src/install.mjs +222 -0
- package/src/journal-read.mjs +116 -0
- package/src/journal.mjs +472 -0
- package/src/lifecycle.mjs +1444 -0
- package/src/lint.mjs +386 -0
- package/src/managed-path.mjs +192 -0
- package/src/markdown-code-spans.mjs +58 -0
- package/src/migrate-prompts.mjs +171 -0
- package/src/migrate-template.mjs +170 -0
- package/src/migrate.mjs +90 -0
- package/src/misuse-read.mjs +61 -0
- package/src/model-request.mjs +33 -0
- package/src/model.mjs +523 -0
- package/src/modules.mjs +355 -0
- package/src/naming.mjs +55 -0
- package/src/native-action.mjs +59 -0
- package/src/native-record.mjs +244 -0
- package/src/new.mjs +1321 -0
- package/src/output-identity.mjs +111 -0
- package/src/parent-plan.mjs +58 -0
- package/src/parse-cache.mjs +99 -0
- package/src/path-containment.mjs +15 -0
- package/src/pickup-card.mjs +293 -0
- package/src/pickup.mjs +671 -0
- package/src/prompt.mjs +25 -0
- package/src/prompts.mjs +585 -0
- package/src/query.mjs +977 -0
- package/src/record-action.mjs +11 -0
- package/src/record-create.mjs +82 -0
- package/src/reference-planner.mjs +388 -0
- package/src/reference-values.mjs +11 -0
- package/src/rename.mjs +107 -0
- package/src/render.mjs +678 -0
- package/src/roadmap.mjs +184 -0
- package/src/runlist.mjs +944 -0
- package/src/section.mjs +225 -0
- package/src/semantic-search-client.mjs +58 -0
- package/src/ship.mjs +166 -0
- package/src/show.mjs +101 -0
- package/src/skill-drift.mjs +98 -0
- package/src/source-editor.mjs +491 -0
- package/src/stages.mjs +73 -0
- package/src/state-migration.mjs +123 -0
- package/src/stats.mjs +200 -0
- package/src/status-metadata.mjs +87 -0
- package/src/statuses.mjs +721 -0
- package/src/summary.mjs +74 -0
- package/src/surfaces.mjs +28 -0
- package/src/sync-status.mjs +316 -0
- package/src/template-store.mjs +62 -0
- package/src/update.mjs +338 -0
- package/src/use.mjs +58 -0
- package/src/util.mjs +337 -0
- package/src/validate.mjs +794 -0
- package/src/watch.mjs +56 -0
- package/src/xref.mjs +406 -0
- package/src/yardstick-command.mjs +178 -0
- package/src/yardstick.mjs +112 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { readFileSync, realpathSync, statSync } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { extractFrontmatter, parseSimpleFrontmatter } from './frontmatter.mjs';
|
|
5
|
+
|
|
6
|
+
export const YARDSTICK_FIELDS = ['yardstick_disposition', 'yardstick_into', 'yardstick_reason', 'yardstick_revision'];
|
|
7
|
+
const DISPOSITIONS = new Set(['serves', 'folded', 'closed']);
|
|
8
|
+
const MAX_GOAL_BYTES = 1024 * 1024;
|
|
9
|
+
|
|
10
|
+
export function validateYardstickConfig(value) {
|
|
11
|
+
if (value == null || value === false) return [];
|
|
12
|
+
if (typeof value !== 'string' || !value.trim() || /[\r\n\0]/.test(value)
|
|
13
|
+
|| path.isAbsolute(value) || !value.endsWith('.md')) {
|
|
14
|
+
return ['Config: yardstick must name one repository-relative Markdown file, or be unset/false.'];
|
|
15
|
+
}
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function contained(root, file) {
|
|
20
|
+
const rel = path.relative(root, file);
|
|
21
|
+
return rel !== '..' && !rel.startsWith(`..${path.sep}`) && !path.isAbsolute(rel);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// No provider, index, account or model is involved: this reads a local document.
|
|
25
|
+
export function readYardstick(config) {
|
|
26
|
+
const setting = config.yardstick ?? config.raw?.yardstick;
|
|
27
|
+
if (setting == null || setting === false) return { enabled: false, state: 'disabled' };
|
|
28
|
+
const errors = validateYardstickConfig(setting);
|
|
29
|
+
if (errors.length) return { enabled: true, state: 'unavailable', message: errors[0] };
|
|
30
|
+
const source = setting.trim();
|
|
31
|
+
try {
|
|
32
|
+
const file = path.resolve(config.repoRoot, source);
|
|
33
|
+
const root = realpathSync(config.repoRoot);
|
|
34
|
+
if (!contained(path.resolve(config.repoRoot), file) || !contained(root, realpathSync(file))) {
|
|
35
|
+
throw new Error('The goal must stay inside this repository.');
|
|
36
|
+
}
|
|
37
|
+
const stat = statSync(file);
|
|
38
|
+
if (!stat.isFile() || stat.size > MAX_GOAL_BYTES) throw new Error('The goal must be a regular Markdown file of at most 1 MiB.');
|
|
39
|
+
const raw = readFileSync(file, 'utf8');
|
|
40
|
+
const { frontmatter, body } = extractFrontmatter(raw);
|
|
41
|
+
if (raw.replace(/\r\n/g, '\n').startsWith('---\n') && extractFrontmatter(raw).bodyLineOffset === 0) throw new Error('The goal has malformed frontmatter.');
|
|
42
|
+
if (parseSimpleFrontmatter(frontmatter).type === 'prompt') throw new Error('A saved prompt cannot be the product goal.');
|
|
43
|
+
const statement = body.trim();
|
|
44
|
+
if (!statement) throw new Error('The goal body is empty.');
|
|
45
|
+
const revision = createHash('sha256').update(statement).digest('hex');
|
|
46
|
+
const goal = { enabled: true, state: 'ready', source, statement, revision };
|
|
47
|
+
// Guard the exact bytes from this read without exposing frontmatter in JSON.
|
|
48
|
+
Object.defineProperty(goal, 'snapshot', { value: { path: file, expectedContent: raw } });
|
|
49
|
+
return goal;
|
|
50
|
+
} catch (err) {
|
|
51
|
+
return { enabled: true, state: 'unavailable', source, message: err.message };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function assessmentIssues(fm, archived) {
|
|
56
|
+
if (!YARDSTICK_FIELDS.some(field => Object.hasOwn(fm, field))) return [];
|
|
57
|
+
const issues = [];
|
|
58
|
+
const disposition = fm.yardstick_disposition;
|
|
59
|
+
if (!DISPOSITIONS.has(disposition)) issues.push('Yardstick disposition must be serves, folded or closed.');
|
|
60
|
+
if (typeof fm.yardstick_revision !== 'string' || !/^[a-f0-9]{64}$/.test(fm.yardstick_revision)) {
|
|
61
|
+
issues.push('Yardstick assessment must record a valid goal revision.');
|
|
62
|
+
}
|
|
63
|
+
if (fm.yardstick_reason !== undefined && (typeof fm.yardstick_reason !== 'string' || !fm.yardstick_reason.trim())) {
|
|
64
|
+
issues.push('Yardstick reason must be nonempty text.');
|
|
65
|
+
}
|
|
66
|
+
if (['closed', 'folded'].includes(disposition)) {
|
|
67
|
+
if (typeof fm.yardstick_reason !== 'string' || !fm.yardstick_reason.trim()) issues.push('Closing or folding requires an owner reason.');
|
|
68
|
+
if (!archived) issues.push('Closed/folded yardstick assessment is inconsistent with a live plan; archive explicitly.');
|
|
69
|
+
}
|
|
70
|
+
if (disposition === 'folded') {
|
|
71
|
+
if (typeof fm.yardstick_into !== 'string' || !fm.yardstick_into.trim() || /[\r\n\0]/.test(fm.yardstick_into)) {
|
|
72
|
+
issues.push('Folded yardstick assessment must link one replacement plan.');
|
|
73
|
+
}
|
|
74
|
+
} else if (fm.yardstick_into !== undefined) issues.push('Only a folded assessment can name a replacement plan.');
|
|
75
|
+
return issues;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function compareYardstick(fm, config, goal = readYardstick(config), archived = false) {
|
|
79
|
+
const issues = assessmentIssues(fm, archived);
|
|
80
|
+
const disposition = typeof fm.yardstick_disposition === 'string' ? fm.yardstick_disposition : null;
|
|
81
|
+
const assessment = {
|
|
82
|
+
disposition,
|
|
83
|
+
into: typeof fm.yardstick_into === 'string' ? fm.yardstick_into : null,
|
|
84
|
+
reason: typeof fm.yardstick_reason === 'string' ? fm.yardstick_reason : null,
|
|
85
|
+
revision: typeof fm.yardstick_revision === 'string' ? fm.yardstick_revision : null,
|
|
86
|
+
reviewedEarlierGoal: Boolean(disposition && goal.state === 'ready' && fm.yardstick_revision !== goal.revision),
|
|
87
|
+
issues,
|
|
88
|
+
};
|
|
89
|
+
return { goal, delivers: typeof fm.delivers === 'string' ? fm.delivers.trim() : null, assessment };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function renderYardstick(comparison, { compact = false } = {}) {
|
|
93
|
+
const { goal, delivers, assessment } = comparison;
|
|
94
|
+
if (!goal.enabled) return 'Product goal: Not configured\n';
|
|
95
|
+
const excerpt = (text, cap) => compact && text.length > cap
|
|
96
|
+
? `${text.slice(0, cap).trimEnd()}… [shortened; read the source for the full text]` : text;
|
|
97
|
+
const lines = [goal.state === 'ready'
|
|
98
|
+
? `Product goal: ${excerpt(goal.statement, 600)}`
|
|
99
|
+
: `Product goal: Unavailable — ${goal.message}`];
|
|
100
|
+
if (goal.source) lines.push(`Source: ${goal.source}`);
|
|
101
|
+
if (assessment) {
|
|
102
|
+
lines.push(`This plan delivers: ${delivers ? excerpt(delivers, 400) : 'Unset'}`);
|
|
103
|
+
const label = assessment.issues.length ? 'Invalid assessment'
|
|
104
|
+
: ({ serves: 'Serves the goal', folded: 'Folded into another plan', closed: 'Closed' }[assessment.disposition] ?? 'Not yet reviewed');
|
|
105
|
+
lines.push(`Owner assessment: ${label}`);
|
|
106
|
+
if (assessment.into) lines.push(`Replacement: ${assessment.into}`);
|
|
107
|
+
if (assessment.reason) lines.push(`Reason: ${excerpt(assessment.reason, 400)}`);
|
|
108
|
+
if (assessment.reviewedEarlierGoal) lines.push('Reviewed against an earlier goal — owner review needed.');
|
|
109
|
+
for (const issue of assessment.issues) lines.push(`Warning: ${issue}`);
|
|
110
|
+
}
|
|
111
|
+
return `${lines.join('\n')}\n`;
|
|
112
|
+
}
|