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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coreslopper",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "An open-source, Claude Code-native workflow for producing music videos from brief to render.",
@@ -14,14 +14,14 @@ jobs:
14
14
  runs-on: ubuntu-latest
15
15
  timeout-minutes: 30
16
16
  steps:
17
- - uses: actions/checkout@v4
17
+ - uses: actions/checkout@v7
18
18
 
19
- - uses: actions/setup-node@v4
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@v5
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@v6
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@v4
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@v4
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@v4
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@v4
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@v4
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"}
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
 
@@ -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`.
@@ -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 by re-running init.
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. To pick up a newer workflow version, commit your projects first, then merge the runtime in place:
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
- npx coreslopper@latest init . --force --skip-project --no-install
154
- npm install
155
- npm run python:sync
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
- This replaces the workflow files (skills, commands, config, packages, scripts, docs) but leaves your project artifacts under `projects/<your-slug>/` and your `.env` untouched. It merges files; workflow files removed upstream are not deleted from the workspace.
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.1.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.1.0",
9
+ "version": "0.2.0",
10
10
  "license": "MIT",
11
11
  "workspaces": [
12
12
  "packages/*"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coreslopper",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "An open-source, Claude Code-native workflow for producing music videos from brief to render.",
@@ -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.')