coreslopper 0.1.0 → 0.2.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/CHANGELOG.md +8 -0
- package/README.md +1 -1
- package/dist/cli.js +340 -63
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/runtime/.github/workflows/ci.yml +8 -6
- package/runtime/.github/workflows/release.yml +3 -3
- package/runtime/.release-please-manifest.json +1 -1
- package/runtime/AGENTS.md +2 -1
- package/runtime/CHANGELOG.md +8 -0
- package/runtime/README.md +1 -1
- package/runtime/docs/adr/0010-npx-onboarding.md +1 -0
- package/runtime/docs/adr/0012-workspace-update.md +27 -0
- package/runtime/docs/adr/README.md +1 -0
- package/runtime/docs/glossary.md +5 -1
- package/runtime/docs/onboarding.md +26 -5
- package/runtime/package-lock.json +2 -2
- package/runtime/package.json +1 -1
- package/runtime/packages/cli/src/init.ts +4 -16
- package/runtime/packages/cli/src/npx.ts +28 -1
- package/runtime/packages/cli/src/update.ts +372 -0
- package/runtime/packages/cli/src/workspace.ts +4 -0
- package/runtime/tests/update.test.ts +185 -0
package/package.json
CHANGED
|
@@ -14,14 +14,14 @@ jobs:
|
|
|
14
14
|
runs-on: ubuntu-latest
|
|
15
15
|
timeout-minutes: 30
|
|
16
16
|
steps:
|
|
17
|
-
- uses: actions/checkout@
|
|
17
|
+
- uses: actions/checkout@v7
|
|
18
18
|
|
|
19
|
-
- uses: actions/setup-node@
|
|
19
|
+
- uses: actions/setup-node@v7
|
|
20
20
|
with:
|
|
21
21
|
node-version: 22
|
|
22
22
|
cache: npm
|
|
23
23
|
|
|
24
|
-
- uses: actions/setup-python@
|
|
24
|
+
- uses: actions/setup-python@v7
|
|
25
25
|
with:
|
|
26
26
|
python-version: "3.12"
|
|
27
27
|
|
|
@@ -29,7 +29,7 @@ jobs:
|
|
|
29
29
|
run: sudo apt-get update && sudo apt-get install -y ffmpeg
|
|
30
30
|
|
|
31
31
|
- name: Install uv
|
|
32
|
-
uses: astral-sh/setup-uv@
|
|
32
|
+
uses: astral-sh/setup-uv@v10.3.3
|
|
33
33
|
|
|
34
34
|
- name: Install Node dependencies
|
|
35
35
|
run: npm ci
|
|
@@ -56,7 +56,7 @@ jobs:
|
|
|
56
56
|
run: npm run cli -- contact-sheet projects/demo
|
|
57
57
|
|
|
58
58
|
- name: Cache Remotion browser
|
|
59
|
-
uses: actions/cache@
|
|
59
|
+
uses: actions/cache@v6
|
|
60
60
|
with:
|
|
61
61
|
path: ~/.cache/remotion
|
|
62
62
|
key: remotion-browser-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
|
|
@@ -79,10 +79,12 @@ jobs:
|
|
|
79
79
|
TARBALL=$(ls "$RUNNER_TEMP"/pkg/coreslopper-*.tgz)
|
|
80
80
|
npx -y -p "$TARBALL" coreslopper init "$RUNNER_TEMP/coreslopper-npx" --yes --no-install --no-git --skip-project
|
|
81
81
|
npx -y -p "$TARBALL" coreslopper doctor "$RUNNER_TEMP/coreslopper-npx"
|
|
82
|
+
npx -y -p "$TARBALL" coreslopper update "$RUNNER_TEMP/coreslopper-npx" --no-install | tee "$RUNNER_TEMP/update.log"
|
|
83
|
+
grep -q "already up to date" "$RUNNER_TEMP/update.log"
|
|
82
84
|
test -f "$RUNNER_TEMP/coreslopper-npx/packages/cli/src/init.ts"
|
|
83
85
|
|
|
84
86
|
- name: Upload demo artifacts
|
|
85
|
-
uses: actions/upload-artifact@
|
|
87
|
+
uses: actions/upload-artifact@v7
|
|
86
88
|
with:
|
|
87
89
|
name: demo-artifacts
|
|
88
90
|
path: |
|
|
@@ -22,7 +22,7 @@ jobs:
|
|
|
22
22
|
release_created: ${{ steps.release.outputs.release_created }}
|
|
23
23
|
tag_name: ${{ steps.release.outputs.tag_name }}
|
|
24
24
|
steps:
|
|
25
|
-
- uses: googleapis/release-please-action@
|
|
25
|
+
- uses: googleapis/release-please-action@v5
|
|
26
26
|
id: release
|
|
27
27
|
with:
|
|
28
28
|
config-file: release-please-config.json
|
|
@@ -39,12 +39,12 @@ jobs:
|
|
|
39
39
|
contents: read
|
|
40
40
|
id-token: write # npm trusted publishing (OIDC) and provenance
|
|
41
41
|
steps:
|
|
42
|
-
- uses: actions/checkout@
|
|
42
|
+
- uses: actions/checkout@v7
|
|
43
43
|
with:
|
|
44
44
|
ref: ${{ needs.release-please.outputs.tag_name || github.ref }}
|
|
45
45
|
|
|
46
46
|
# Node 24 ships npm 11, which supports npm trusted publishing.
|
|
47
|
-
- uses: actions/setup-node@
|
|
47
|
+
- uses: actions/setup-node@v7
|
|
48
48
|
with:
|
|
49
49
|
node-version: 24
|
|
50
50
|
registry-url: https://registry.npmjs.org
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{".":"0.
|
|
1
|
+
{".":"0.2.0"}
|
package/runtime/AGENTS.md
CHANGED
|
@@ -131,6 +131,7 @@ npm run schema
|
|
|
131
131
|
| `npm run cli -- validate-file <file>` | Validate one changed artifact (used by the hook). |
|
|
132
132
|
| `npm run cli -- doctor` | Check workspace, tools, fonts, Remotion, and keys. |
|
|
133
133
|
| `npx coreslopper init [dir]` | Create a workspace, install tools, configure fal.ai, Higgsfield, and Suno. |
|
|
134
|
+
| `npx coreslopper@latest update [dir]` | Update a workspace to the latest workflow; keeps local edits (`--dry-run`, `--force`). |
|
|
134
135
|
| `npx coreslopper doctor` | Check a workspace from outside it. |
|
|
135
136
|
| `npx coreslopper new <slug> --budget <usd>` | Create a project inside a workspace. |
|
|
136
137
|
| `npm run build` | Build `runtime/` and the npx bundle in `dist/`. |
|
|
@@ -140,7 +141,7 @@ In Claude Code: `/new-video`, `/video-next`, `/video-status`.
|
|
|
140
141
|
|
|
141
142
|
## Distribution
|
|
142
143
|
|
|
143
|
-
The root package is published as `coreslopper`. `npm run build` copies the tracked workflow into `runtime/` and bundles `packages/cli/src/npx.ts` into `dist/cli.js`; `prepack` runs the same build. The npm package ships the onboarding CLI (init, doctor, new, status, validate) plus the runtime snapshot, not the Remotion dependency tree. `npx coreslopper init` copies `runtime/` into a private workspace, then the workspace's own `npm install` provides rendering and audio-analysis dependencies. Never publish generated media or `.env`.
|
|
144
|
+
The root package is published as `coreslopper`. `npm run build` copies the tracked workflow into `runtime/` and bundles `packages/cli/src/npx.ts` into `dist/cli.js`; `prepack` runs the same build. The npm package ships the onboarding CLI (init, update, doctor, new, status, validate) plus the runtime snapshot, not the Remotion dependency tree. `npx coreslopper init` copies `runtime/` into a private workspace, then the workspace's own `npm install` provides rendering and audio-analysis dependencies. Never publish generated media or `.env`.
|
|
144
145
|
|
|
145
146
|
## Skills
|
|
146
147
|
|
package/runtime/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.2.0](https://github.com/hemi1986/coreslopper/compare/v0.1.0...v0.2.0) (2026-11-08)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add `coreslopper update` to merge a newer workflow into a workspace ([3eddb5c](https://github.com/hemi1986/coreslopper/commit/3eddb5caa64a534a9bf21ca13d45d24c747976e3))
|
|
9
|
+
* add `coreslopper update` to merge a newer workflow into a workspace ([1d10ffd](https://github.com/hemi1986/coreslopper/commit/1d10ffda2a6639d1a5b2a489564a54c9b2422cda))
|
|
10
|
+
|
|
3
11
|
## 0.1.0 (2026-11-08)
|
|
4
12
|
|
|
5
13
|
|
package/runtime/README.md
CHANGED
|
@@ -72,7 +72,7 @@ cd my-video
|
|
|
72
72
|
claude
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
-
Run `/mcp` once to authenticate Suno, then `/video-next my-video`. The generated workspace contains the full workflow runtime, so every `npm run cli -- ...` command in this README works inside it. Running `npx coreslopper` without arguments inside a workspace prints the available commands. See [docs/onboarding.md](docs/onboarding.md) for all flags and troubleshooting.
|
|
75
|
+
Run `/mcp` once to authenticate Suno, then `/video-next my-video`. The generated workspace contains the full workflow runtime, so every `npm run cli -- ...` command in this README works inside it. Running `npx coreslopper` without arguments inside a workspace prints the available commands. To move a workspace to a newer release, run `npx coreslopper@latest update` inside it; local edits are kept. See [docs/onboarding.md](docs/onboarding.md) for all flags, updating, and troubleshooting.
|
|
76
76
|
|
|
77
77
|
## Quickstarts
|
|
78
78
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# npx onboarding with a versioned runtime snapshot
|
|
2
2
|
|
|
3
3
|
> Extended by [ADR 0011](0011-higgsfield-provider.md): onboarding also checks and stores Higgsfield credentials.
|
|
4
|
+
> Extended by [ADR 0012](0012-workspace-update.md): workspaces are updated with `coreslopper update`, not `init --force`.
|
|
4
5
|
|
|
5
6
|
**Status:** Accepted
|
|
6
7
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Update workspaces with a recorded baseline
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
|
|
5
|
+
Accepted — 2026-11-08
|
|
6
|
+
|
|
7
|
+
## Context
|
|
8
|
+
|
|
9
|
+
A workspace is a runtime snapshot, not a git clone (ADR 0010). Until now the only way to pick up a newer workflow was `npx coreslopper@latest init . --force`, which copies the runtime over the workspace. That overwrites every local edit to a skill, command, or config file, and it never deletes a file that upstream removed, so stale skills keep loading in Claude Code.
|
|
10
|
+
|
|
11
|
+
## Decision
|
|
12
|
+
|
|
13
|
+
Add `npx coreslopper@latest update [dir]`, a three-way merge between the recorded baseline, the workspace, and the new runtime.
|
|
14
|
+
|
|
15
|
+
- `init` and `update` store the SHA-256 of every installed runtime file in `coreslopper.workspace.json` (`files`). This is the **baseline**.
|
|
16
|
+
- A file unchanged since the baseline follows upstream: it is updated, or deleted when upstream removed it.
|
|
17
|
+
- A locally changed file is kept. When upstream changed it as well, the new version is written next to it as `<file>.coreslopper-new` for a manual merge; `--force` overwrites instead.
|
|
18
|
+
- `projects/**` is user-owned: missing upstream files are added, but nothing is overwritten or deleted. `.env`, `.mcp.json`, `GETTING_STARTED.md`, and the marker itself are never touched. `package-lock.json` always follows upstream, because `npm install` rewrites it locally.
|
|
19
|
+
- A downgrade is refused unless `--force` is passed. `--dry-run` reports without writing.
|
|
20
|
+
- A workspace created before this ADR has no baseline. Every file that differs from upstream is then a conflict; the user commits and runs `update --force` once, which records the baseline.
|
|
21
|
+
|
|
22
|
+
## Consequences
|
|
23
|
+
|
|
24
|
+
- Updating keeps local customizations and removes obsolete workflow files.
|
|
25
|
+
- The marker grows by one hash per runtime file (about 200 entries) and is committed with the workspace.
|
|
26
|
+
- `init --force` remains for repairing a workspace but is no longer the documented update path.
|
|
27
|
+
- There is no line-level merge; a file changed on both sides needs a manual merge of the `.coreslopper-new` copy.
|
|
@@ -15,5 +15,6 @@ Short records of decisions that are hard to reverse, surprising without context,
|
|
|
15
15
|
| [0009](0009-mit-open-source.md) | MIT open source with explicit third-party notices. |
|
|
16
16
|
| [0010](0010-npx-onboarding.md) | npx onboarding with a versioned runtime snapshot. |
|
|
17
17
|
| [0011](0011-higgsfield-provider.md) | Higgsfield as a second provider; per-project provider selection and role alternatives. |
|
|
18
|
+
| [0012](0012-workspace-update.md) | `coreslopper update` merges a new runtime against a recorded baseline. |
|
|
18
19
|
|
|
19
20
|
Status values: `Accepted`, `Deprecated`, `Superseded by ADR-NNNN`.
|
package/runtime/docs/glossary.md
CHANGED
|
@@ -9,9 +9,13 @@ A self-contained directory created by `npx coreslopper init` that holds the work
|
|
|
9
9
|
_Avoid_: repo, checkout
|
|
10
10
|
|
|
11
11
|
**Runtime Snapshot**:
|
|
12
|
-
The versioned copy of the workflow files that `npx coreslopper init` writes into a workspace. It is not a git clone and is updated
|
|
12
|
+
The versioned copy of the workflow files that `npx coreslopper init` writes into a workspace. It is not a git clone and is updated with `npx coreslopper@latest update`, which merges against the **Baseline**.
|
|
13
13
|
_Avoid_: install, template
|
|
14
14
|
|
|
15
|
+
**Baseline**:
|
|
16
|
+
The SHA-256 of every runtime file as last installed, stored in `coreslopper.workspace.json`. `coreslopper update` compares it with the workspace to tell local edits from untouched workflow files.
|
|
17
|
+
_Avoid_: lockfile, manifest
|
|
18
|
+
|
|
15
19
|
**Brief**:
|
|
16
20
|
The one-page statement of topic, source, audience, length, formats, and style that anchors every later creative decision.
|
|
17
21
|
_Avoid_: concept, pitch
|
|
@@ -147,15 +147,36 @@ The base install is enough for the motion-only demo and for projects that import
|
|
|
147
147
|
|
|
148
148
|
## Updating a workspace
|
|
149
149
|
|
|
150
|
-
The workspace is a snapshot.
|
|
150
|
+
The workspace is a snapshot. Pick up a newer workflow version with `update`, run from inside the workspace. Commit first, so `git diff` shows exactly what the update changed:
|
|
151
151
|
|
|
152
152
|
```bash
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
153
|
+
git add -A && git commit -m "chore: before coreslopper update"
|
|
154
|
+
npx coreslopper@latest update --dry-run # optional: preview
|
|
155
|
+
npx coreslopper@latest update
|
|
156
156
|
```
|
|
157
157
|
|
|
158
|
-
|
|
158
|
+
`update` compares three states per file: the **baseline** recorded in `coreslopper.workspace.json` at the last init or update, your workspace, and the new runtime.
|
|
159
|
+
|
|
160
|
+
| Your file | Upstream | Result |
|
|
161
|
+
|---|---|---|
|
|
162
|
+
| unchanged | changed | updated |
|
|
163
|
+
| unchanged | removed | deleted |
|
|
164
|
+
| changed | unchanged | kept |
|
|
165
|
+
| changed | changed | kept; new version written as `<file>.coreslopper-new` |
|
|
166
|
+
| changed | removed | kept |
|
|
167
|
+
| deleted | any | stays deleted |
|
|
168
|
+
|
|
169
|
+
Merge each `.coreslopper-new` file into the original and delete it. `--force` overwrites changed files instead.
|
|
170
|
+
|
|
171
|
+
`projects/` belongs to you: `update` adds new upstream files there but never overwrites or deletes anything. `.env`, `.mcp.json`, and `GETTING_STARTED.md` are never touched. `package-lock.json` always follows upstream. Afterwards `update` runs `npm install` and `uv sync`; pass `--no-install` to skip them.
|
|
172
|
+
|
|
173
|
+
| Flag | Effect |
|
|
174
|
+
|---|---|
|
|
175
|
+
| `--dry-run` | List the changes without writing anything. |
|
|
176
|
+
| `--force` | Overwrite locally changed files; also allows a downgrade. |
|
|
177
|
+
| `--no-install` | Skip `npm install` and `uv sync`. |
|
|
178
|
+
|
|
179
|
+
Workspaces created before `update` existed have no baseline, so every file that differs from upstream counts as a conflict. Commit, then run `npx coreslopper@latest update --force` once; it records the baseline for later updates.
|
|
159
180
|
|
|
160
181
|
## Troubleshooting
|
|
161
182
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "coreslopper",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "coreslopper",
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.2.0",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"workspaces": [
|
|
12
12
|
"packages/*"
|
package/runtime/package.json
CHANGED
|
@@ -5,6 +5,7 @@ import { homedir } from 'node:os';
|
|
|
5
5
|
import { basename, isAbsolute, join, parse, relative, resolve, sep } from 'node:path';
|
|
6
6
|
import { ValidationError } from '@coreslopper/core';
|
|
7
7
|
import { createProject } from './new-project.js';
|
|
8
|
+
import { SKIPPED_DIRECTORIES, hashRuntime } from './update.js';
|
|
8
9
|
import {
|
|
9
10
|
commandExists,
|
|
10
11
|
detectTools,
|
|
@@ -59,20 +60,6 @@ export interface InitResult {
|
|
|
59
60
|
warnings: string[];
|
|
60
61
|
}
|
|
61
62
|
|
|
62
|
-
const SKIPPED_DIRECTORIES = new Set([
|
|
63
|
-
'.git',
|
|
64
|
-
'.cache',
|
|
65
|
-
'.tools',
|
|
66
|
-
'.vitest',
|
|
67
|
-
'.venv',
|
|
68
|
-
'__pycache__',
|
|
69
|
-
'.pytest_cache',
|
|
70
|
-
'node_modules',
|
|
71
|
-
'dist',
|
|
72
|
-
'runtime',
|
|
73
|
-
'tmp',
|
|
74
|
-
]);
|
|
75
|
-
|
|
76
63
|
export function sanitizeSlug(value: string): string {
|
|
77
64
|
const slug = value
|
|
78
65
|
.toLowerCase()
|
|
@@ -188,12 +175,13 @@ function writeFileSyncJson(path: string, value: unknown): void {
|
|
|
188
175
|
writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
|
|
189
176
|
}
|
|
190
177
|
|
|
191
|
-
function writeMarker(target: string, projectSlug?: string): void {
|
|
178
|
+
function writeMarker(target: string, files: Record<string, string>, projectSlug?: string): void {
|
|
192
179
|
const marker: WorkspaceMarker = {
|
|
193
180
|
version: 1,
|
|
194
181
|
runtimeVersion: ownVersion(),
|
|
195
182
|
created: new Date().toISOString(),
|
|
196
183
|
...(projectSlug ? { project: projectSlug } : {}),
|
|
184
|
+
files,
|
|
197
185
|
};
|
|
198
186
|
writeFileSyncJson(join(target, WORKSPACE_MARKER), marker);
|
|
199
187
|
}
|
|
@@ -343,7 +331,7 @@ export async function initWorkspace(options: InitOptions): Promise<InitResult> {
|
|
|
343
331
|
? await createFirstProject(target, options.project, warnings)
|
|
344
332
|
: undefined;
|
|
345
333
|
|
|
346
|
-
writeMarker(target, projectSlug);
|
|
334
|
+
writeMarker(target, await hashRuntime(runtime), projectSlug);
|
|
347
335
|
|
|
348
336
|
let installed = false;
|
|
349
337
|
let uvSynced = false;
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
import { createProject } from './new-project.js';
|
|
10
10
|
import { onboard } from './onboarding.js';
|
|
11
11
|
import { printStatus } from './status.js';
|
|
12
|
+
import { printUpdateSummary, updateWorkspace } from './update.js';
|
|
12
13
|
import { formatSeconds, run } from './utils.js';
|
|
13
14
|
import { validateProject } from './validate.js';
|
|
14
15
|
import {
|
|
@@ -50,7 +51,7 @@ function workspaceSummary(root: string): void {
|
|
|
50
51
|
} else {
|
|
51
52
|
console.log('No projects yet. Create one with: npx coreslopper new <slug> --budget 50');
|
|
52
53
|
}
|
|
53
|
-
console.log('Commands: init, doctor, new, status, validate');
|
|
54
|
+
console.log('Commands: init, update, doctor, new, status, validate');
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
const program = new Command();
|
|
@@ -96,6 +97,32 @@ program
|
|
|
96
97
|
}),
|
|
97
98
|
);
|
|
98
99
|
|
|
100
|
+
program
|
|
101
|
+
.command('update [dir]')
|
|
102
|
+
.description('Update the workflow files of a workspace to this coreslopper version; keeps local changes.')
|
|
103
|
+
.option('--dry-run', 'Show what would change without writing anything')
|
|
104
|
+
.option('--force', 'Overwrite locally changed files and allow a downgrade')
|
|
105
|
+
.option('--no-install', 'Skip npm install and uv sync')
|
|
106
|
+
.option('--runtime <dir>', 'Runtime directory (development only)')
|
|
107
|
+
.action(
|
|
108
|
+
(
|
|
109
|
+
dir: string | undefined,
|
|
110
|
+
options: { dryRun?: boolean; force?: boolean; install: boolean; runtime?: string },
|
|
111
|
+
) =>
|
|
112
|
+
run(async () => {
|
|
113
|
+
const target = dir ? resolve(dir) : requireWorkspaceRoot();
|
|
114
|
+
const result = await updateWorkspace({
|
|
115
|
+
targetDir: target,
|
|
116
|
+
runtimeDir: options.runtime,
|
|
117
|
+
dryRun: options.dryRun,
|
|
118
|
+
force: options.force,
|
|
119
|
+
install: options.install,
|
|
120
|
+
onProgress: (message) => console.log(message),
|
|
121
|
+
});
|
|
122
|
+
printUpdateSummary(result);
|
|
123
|
+
}),
|
|
124
|
+
);
|
|
125
|
+
|
|
99
126
|
program
|
|
100
127
|
.command('doctor [dir]')
|
|
101
128
|
.description('Check the workspace, tools, and credentials.')
|