coreslopper 0.0.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.0.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: |
@@ -0,0 +1,78 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ workflow_dispatch:
7
+
8
+ concurrency:
9
+ group: release
10
+ cancel-in-progress: false
11
+
12
+ permissions:
13
+ contents: read
14
+
15
+ jobs:
16
+ release-please:
17
+ runs-on: ubuntu-latest
18
+ permissions:
19
+ contents: write
20
+ pull-requests: write
21
+ outputs:
22
+ release_created: ${{ steps.release.outputs.release_created }}
23
+ tag_name: ${{ steps.release.outputs.tag_name }}
24
+ steps:
25
+ - uses: googleapis/release-please-action@v5
26
+ id: release
27
+ with:
28
+ config-file: release-please-config.json
29
+ manifest-file: .release-please-manifest.json
30
+
31
+ publish:
32
+ needs: release-please
33
+ # Publish when release-please just cut a release, or on a manual retry
34
+ # (workflow_dispatch publishes the version currently in package.json).
35
+ if: needs.release-please.outputs.release_created == 'true' || github.event_name == 'workflow_dispatch'
36
+ runs-on: ubuntu-latest
37
+ timeout-minutes: 30
38
+ permissions:
39
+ contents: read
40
+ id-token: write # npm trusted publishing (OIDC) and provenance
41
+ steps:
42
+ - uses: actions/checkout@v7
43
+ with:
44
+ ref: ${{ needs.release-please.outputs.tag_name || github.ref }}
45
+
46
+ # Node 24 ships npm 11, which supports npm trusted publishing.
47
+ - uses: actions/setup-node@v7
48
+ with:
49
+ node-version: 24
50
+ registry-url: https://registry.npmjs.org
51
+ cache: npm
52
+
53
+ - name: Install ffmpeg
54
+ run: sudo apt-get update && sudo apt-get install -y ffmpeg
55
+
56
+ - name: Install dependencies
57
+ run: npm ci
58
+
59
+ - name: Typecheck
60
+ run: npm run typecheck
61
+
62
+ - name: Tests
63
+ run: npm test
64
+
65
+ - name: Build and smoke-test package
66
+ run: |
67
+ mkdir -p "$RUNNER_TEMP/pkg"
68
+ npm pack --pack-destination "$RUNNER_TEMP/pkg"
69
+ TARBALL=$(ls "$RUNNER_TEMP"/pkg/coreslopper-*.tgz)
70
+ npx -y -p "$TARBALL" coreslopper init "$RUNNER_TEMP/coreslopper-npx" --yes --no-install --no-git --skip-project
71
+ npx -y -p "$TARBALL" coreslopper doctor "$RUNNER_TEMP/coreslopper-npx"
72
+
73
+ # Trusted publishing: the npm CLI detects the OIDC environment and exchanges
74
+ # it for a short-lived publish token. No npm token in the repository, no OTP.
75
+ # Provenance is generated automatically for a public package from a public repo.
76
+ # The tarball was already built and tested above, so lifecycle scripts are skipped.
77
+ - name: Publish to npm
78
+ run: npm publish --access public --ignore-scripts
@@ -0,0 +1 @@
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
 
@@ -0,0 +1,34 @@
1
+ # Changelog
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
+
11
+ ## 0.1.0 (2026-11-08)
12
+
13
+
14
+ ### Features
15
+
16
+ * add example brand kit and brand schema ([08ea9d5](https://github.com/hemi1986/coreslopper/commit/08ea9d579fd48e6ff4a4f13e85d4437b3d3b33f5))
17
+ * add Higgsfield provider and setup quickstarts ([6ced780](https://github.com/hemi1986/coreslopper/commit/6ced780ce9effddfb0272e11eff51939610da2f9))
18
+ * add lip-sync clips for storyboard shots ([3403cf6](https://github.com/hemi1986/coreslopper/commit/3403cf6efde67025dafc7ecdee583c31668027ad))
19
+ * add lip-sync shots and lyrics-first alignment ([d6534a9](https://github.com/hemi1986/coreslopper/commit/d6534a954bf6088f01732a525f629da4426a95d9))
20
+ * add npx onboarding and workspace bootstrap ([2393370](https://github.com/hemi1986/coreslopper/commit/2393370392eacb25d9045fb5b700281a4e88b062))
21
+ * add timing hooks, media helpers, stage reset, and MCP docs ([0b9ef19](https://github.com/hemi1986/coreslopper/commit/0b9ef1917aced6a0647f3dc8baa07222997e2f1a))
22
+ * initial coreslopper workflow and motion-only demo ([a088d10](https://github.com/hemi1986/coreslopper/commit/a088d10e63f3312ef94f8acaa29eb8acc4dfeed4))
23
+ * local ffmpeg bootstrap and media command polish ([ab347af](https://github.com/hemi1986/coreslopper/commit/ab347af580ecd4357bc0e4df8390b3d34735bb1c))
24
+
25
+
26
+ ### Bug Fixes
27
+
28
+ * **audio-analysis:** align lyrics first and keep Unicode text ([ac35d0d](https://github.com/hemi1986/coreslopper/commit/ac35d0d33336e61a9bcc68c515f3a85088a8198f))
29
+ * keep character reference media out of git ([bb253f0](https://github.com/hemi1986/coreslopper/commit/bb253f091e7bcc7e761dce64ea90e6aaf6bed367))
30
+
31
+
32
+ ### Documentation
33
+
34
+ * mark workflow as work in progress ([cd5c1e8](https://github.com/hemi1986/coreslopper/commit/cd5c1e8275ebec06f772eb59a313bf3fc7b97b32))
@@ -82,7 +82,7 @@ The `publish` job uses npm trusted publishing (OIDC): no npm token in the reposi
82
82
 
83
83
  ### First time only: placeholder and trusted publisher
84
84
 
85
- A trusted publisher can only be configured for a package that already exists on npm. Publish a placeholder once by hand (this is the only step that needs 2FA):
85
+ A trusted publisher can only be configured for a package that already exists on npm. Publish once by hand (this is the only step that needs 2FA; pass `--otp=<code>` when the shell cannot open a browser):
86
86
 
87
87
  ```bash
88
88
  npm login
@@ -91,6 +91,8 @@ npm publish --access public
91
91
  npm version 0.1.0 --no-git-tag-version # back to the version release-please expects
92
92
  ```
93
93
 
94
+ With staged publishing, npm answers the first publish with a stub `0.0.0-stage` placeholder and holds `0.0.0` for approval on npmjs.com. The stub is enough to configure the trusted publisher; the staged `0.0.0` can be discarded.
95
+
94
96
  Then on npmjs.com → `coreslopper` → Settings → **Trusted publishing** → GitHub Actions:
95
97
 
96
98
  | Field | Value |
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,93 +1,93 @@
1
- Copyright 2020 The Space Grotesk Project Authors (https://github.com/floriankarsten/space-grotesk)
2
-
3
- This Font Software is licensed under the SIL Open Font License, Version 1.1.
4
- This license is copied below, and is also available with a FAQ at:
5
- http://scripts.sil.org/OFL
6
-
7
-
8
- -----------------------------------------------------------
9
- SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10
- -----------------------------------------------------------
11
-
12
- PREAMBLE
13
- The goals of the Open Font License (OFL) are to stimulate worldwide
14
- development of collaborative font projects, to support the font creation
15
- efforts of academic and linguistic communities, and to provide a free and
16
- open framework in which fonts may be shared and improved in partnership
17
- with others.
18
-
19
- The OFL allows the licensed fonts to be used, studied, modified and
20
- redistributed freely as long as they are not sold by themselves. The
21
- fonts, including any derivative works, can be bundled, embedded,
22
- redistributed and/or sold with any software provided that any reserved
23
- names are not used by derivative works. The fonts and derivatives,
24
- however, cannot be released under any other type of license. The
25
- requirement for fonts to remain under this license does not apply
26
- to any document created using the fonts or their derivatives.
27
-
28
- DEFINITIONS
29
- "Font Software" refers to the set of files released by the Copyright
30
- Holder(s) under this license and clearly marked as such. This may
31
- include source files, build scripts and documentation.
32
-
33
- "Reserved Font Name" refers to any names specified as such after the
34
- copyright statement(s).
35
-
36
- "Original Version" refers to the collection of Font Software components as
37
- distributed by the Copyright Holder(s).
38
-
39
- "Modified Version" refers to any derivative made by adding to, deleting,
40
- or substituting -- in part or in whole -- any of the components of the
41
- Original Version, by changing formats or by porting the Font Software to a
42
- new environment.
43
-
44
- "Author" refers to any designer, engineer, programmer, technical
45
- writer or other person who contributed to the Font Software.
46
-
47
- PERMISSION & CONDITIONS
48
- Permission is hereby granted, free of charge, to any person obtaining
49
- a copy of the Font Software, to use, study, copy, merge, embed, modify,
50
- redistribute, and sell modified and unmodified copies of the Font
51
- Software, subject to the following conditions:
52
-
53
- 1) Neither the Font Software nor any of its individual components,
54
- in Original or Modified Versions, may be sold by itself.
55
-
56
- 2) Original or Modified Versions of the Font Software may be bundled,
57
- redistributed and/or sold with any software, provided that each copy
58
- contains the above copyright notice and this license. These can be
59
- included either as stand-alone text files, human-readable headers or
60
- in the appropriate machine-readable metadata fields within text or
61
- binary files as long as those fields can be easily viewed by the user.
62
-
63
- 3) No Modified Version of the Font Software may use the Reserved Font
64
- Name(s) unless explicit written permission is granted by the corresponding
65
- Copyright Holder. This restriction only applies to the primary font name as
66
- presented to the users.
67
-
68
- 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69
- Software shall not be used to promote, endorse or advertise any
70
- Modified Version, except to acknowledge the contribution(s) of the
71
- Copyright Holder(s) and the Author(s) or with their explicit written
72
- permission.
73
-
74
- 5) The Font Software, modified or unmodified, in part or in whole,
75
- must be distributed entirely under this license, and must not be
76
- distributed under any other license. The requirement for fonts to
77
- remain under this license does not apply to any document created
78
- using the Font Software.
79
-
80
- TERMINATION
81
- This license becomes null and void if any of the above conditions are
82
- not met.
83
-
84
- DISCLAIMER
85
- THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88
- OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89
- COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90
- INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91
- DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92
- FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93
- OTHER DEALINGS IN THE FONT SOFTWARE.
1
+ Copyright 2020 The Space Grotesk Project Authors (https://github.com/floriankarsten/space-grotesk)
2
+
3
+ This Font Software is licensed under the SIL Open Font License, Version 1.1.
4
+ This license is copied below, and is also available with a FAQ at:
5
+ http://scripts.sil.org/OFL
6
+
7
+
8
+ -----------------------------------------------------------
9
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10
+ -----------------------------------------------------------
11
+
12
+ PREAMBLE
13
+ The goals of the Open Font License (OFL) are to stimulate worldwide
14
+ development of collaborative font projects, to support the font creation
15
+ efforts of academic and linguistic communities, and to provide a free and
16
+ open framework in which fonts may be shared and improved in partnership
17
+ with others.
18
+
19
+ The OFL allows the licensed fonts to be used, studied, modified and
20
+ redistributed freely as long as they are not sold by themselves. The
21
+ fonts, including any derivative works, can be bundled, embedded,
22
+ redistributed and/or sold with any software provided that any reserved
23
+ names are not used by derivative works. The fonts and derivatives,
24
+ however, cannot be released under any other type of license. The
25
+ requirement for fonts to remain under this license does not apply
26
+ to any document created using the fonts or their derivatives.
27
+
28
+ DEFINITIONS
29
+ "Font Software" refers to the set of files released by the Copyright
30
+ Holder(s) under this license and clearly marked as such. This may
31
+ include source files, build scripts and documentation.
32
+
33
+ "Reserved Font Name" refers to any names specified as such after the
34
+ copyright statement(s).
35
+
36
+ "Original Version" refers to the collection of Font Software components as
37
+ distributed by the Copyright Holder(s).
38
+
39
+ "Modified Version" refers to any derivative made by adding to, deleting,
40
+ or substituting -- in part or in whole -- any of the components of the
41
+ Original Version, by changing formats or by porting the Font Software to a
42
+ new environment.
43
+
44
+ "Author" refers to any designer, engineer, programmer, technical
45
+ writer or other person who contributed to the Font Software.
46
+
47
+ PERMISSION & CONDITIONS
48
+ Permission is hereby granted, free of charge, to any person obtaining
49
+ a copy of the Font Software, to use, study, copy, merge, embed, modify,
50
+ redistribute, and sell modified and unmodified copies of the Font
51
+ Software, subject to the following conditions:
52
+
53
+ 1) Neither the Font Software nor any of its individual components,
54
+ in Original or Modified Versions, may be sold by itself.
55
+
56
+ 2) Original or Modified Versions of the Font Software may be bundled,
57
+ redistributed and/or sold with any software, provided that each copy
58
+ contains the above copyright notice and this license. These can be
59
+ included either as stand-alone text files, human-readable headers or
60
+ in the appropriate machine-readable metadata fields within text or
61
+ binary files as long as those fields can be easily viewed by the user.
62
+
63
+ 3) No Modified Version of the Font Software may use the Reserved Font
64
+ Name(s) unless explicit written permission is granted by the corresponding
65
+ Copyright Holder. This restriction only applies to the primary font name as
66
+ presented to the users.
67
+
68
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69
+ Software shall not be used to promote, endorse or advertise any
70
+ Modified Version, except to acknowledge the contribution(s) of the
71
+ Copyright Holder(s) and the Author(s) or with their explicit written
72
+ permission.
73
+
74
+ 5) The Font Software, modified or unmodified, in part or in whole,
75
+ must be distributed entirely under this license, and must not be
76
+ distributed under any other license. The requirement for fonts to
77
+ remain under this license does not apply to any document created
78
+ using the Font Software.
79
+
80
+ TERMINATION
81
+ This license becomes null and void if any of the above conditions are
82
+ not met.
83
+
84
+ DISCLAIMER
85
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93
+ OTHER DEALINGS IN THE FONT SOFTWARE.
@@ -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.0.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.0.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.0.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.')