ossplate 0.1.1 → 0.1.3

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 CHANGED
@@ -1,5 +1,9 @@
1
1
  # Ossplate
2
2
 
3
+ <p align="center">
4
+ <img src="https://raw.githubusercontent.com/stefdevscore/ossplate/dev/assets/illustrations/armour05platemail.png" alt="Ossplate armor" width="320">
5
+ </p>
6
+
3
7
  `ossplate` helps you start and maintain a project that ships the same CLI through Rust, npm, and PyPI.
4
8
 
5
9
  Use it to:
Binary file
package/package.json CHANGED
@@ -39,5 +39,5 @@
39
39
  "test": "npm run build && node --test test/cli.test.js"
40
40
  },
41
41
  "type": "module",
42
- "version": "0.1.1"
42
+ "version": "0.1.3"
43
43
  }
@@ -44,8 +44,13 @@ jobs:
44
44
  env:
45
45
  NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
46
46
  run: |
47
+ logfile=$(mktemp)
48
+ cleanup() {
49
+ rm -f "$logfile"
50
+ }
51
+ trap cleanup EXIT
47
52
  set +e
48
- npm publish --access public --provenance 2>&1 | tee npm-publish.log
53
+ npm publish --access public --provenance 2>&1 | tee "$logfile"
49
54
  status=${PIPESTATUS[0]}
50
55
  set -e
51
56
  if [ "$status" -eq 0 ]; then
@@ -56,7 +61,7 @@ jobs:
56
61
  echo "::error title=npm::OIDC publish failed and NPM_TOKEN is not configured."
57
62
  exit "$status"
58
63
  fi
59
- if grep -qiE "already exists|cannot publish over|previously published" npm-publish.log; then
64
+ if grep -qiE "already exists|cannot publish over|previously published" "$logfile"; then
60
65
  echo "::notice title=npm::package version already exists; skipping."
61
66
  exit 0
62
67
  fi
@@ -74,23 +74,28 @@ jobs:
74
74
  env:
75
75
  CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token || secrets.CARGO_TOKEN }}
76
76
  run: |
77
+ logfile=$(mktemp)
78
+ cleanup() {
79
+ rm -f "$logfile"
80
+ }
81
+ trap cleanup EXIT
77
82
  if [ -n "${{ steps.auth.outputs.token }}" ]; then
78
83
  echo "::notice title=cargo::using crates.io OIDC token from trusted publishing."
79
84
  else
80
85
  echo "::notice title=cargo::OIDC token unavailable; falling back to CARGO_TOKEN secret."
81
86
  fi
82
87
  set +e
83
- cargo publish 2>&1 | tee cargo-publish.log
88
+ cargo publish 2>&1 | tee "$logfile"
84
89
  status=${PIPESTATUS[0]}
85
90
  set -e
86
91
  if [ "$status" -eq 0 ]; then
87
92
  exit 0
88
93
  fi
89
- if grep -q "status 429 Too Many Requests" cargo-publish.log; then
94
+ if grep -q "status 429 Too Many Requests" "$logfile"; then
90
95
  echo "::warning title=cargo::crates.io rate limit hit. Treating this publish attempt as non-blocking."
91
96
  exit 0
92
97
  fi
93
- if grep -qi "already exists on crates.io index" cargo-publish.log; then
98
+ if grep -qi "already exists on crates.io index" "$logfile"; then
94
99
  echo "::notice title=cargo::crate version already exists; skipping."
95
100
  exit 0
96
101
  fi
@@ -21,7 +21,12 @@ cargo run --manifest-path core-rs/Cargo.toml -- sync --check
21
21
  cargo run --manifest-path core-rs/Cargo.toml -- sync
22
22
  ```
23
23
 
24
- Release workflow guidance lives in [`docs/releases.md`](./docs/releases.md).
24
+ Read this next:
25
+
26
+ - [`docs/architecture.md`](./docs/architecture.md)
27
+ - [`docs/testing.md`](./docs/testing.md)
28
+ - [`docs/releases.md`](./docs/releases.md)
29
+ - [`docs/adrs/0002-sync-owns-bounded-identity.md`](./docs/adrs/0002-sync-owns-bounded-identity.md)
25
30
 
26
31
  Current ownership model:
27
32
 
@@ -4,7 +4,9 @@
4
4
  Build one project, ship it everywhere.
5
5
  <!-- ossplate:readme-identity:end -->
6
6
 
7
- ![Ossplate chestplate](./assets/illustrations/chestplate.svg)
7
+ <p align="center">
8
+ <img src="https://raw.githubusercontent.com/stefdevscore/ossplate/dev/assets/illustrations/armour05platemail.png" alt="Ossplate armor" width="360">
9
+ </p>
8
10
 
9
11
  `ossplate` helps you start and maintain a project that ships the same CLI through Rust, npm, and PyPI.
10
12
 
@@ -69,6 +71,7 @@ The same command surface is available through the Rust binary and the packaged J
69
71
  ## Learn More
70
72
 
71
73
  - [Documentation](./docs/README.md)
74
+ - [Adoption Guide](./docs/customizing-the-template.md)
72
75
  - [Testing Guide](./docs/testing.md)
73
76
  - [Release Guide](./docs/releases.md)
74
77
  - [Architecture](./docs/architecture.md)
@@ -158,7 +158,7 @@ checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
158
158
 
159
159
  [[package]]
160
160
  name = "ossplate"
161
- version = "0.1.1"
161
+ version = "0.1.3"
162
162
  dependencies = [
163
163
  "anyhow",
164
164
  "clap",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "ossplate"
3
- version = "0.1.1"
3
+ version = "0.1.3"
4
4
  edition = "2021"
5
5
  authors = ["Stef <stefdevscore@github.com>"]
6
6
  description = "Build one project, ship it everywhere."
@@ -1041,9 +1041,18 @@ fn validate_wrapper_readme(
1041
1041
  }
1042
1042
 
1043
1043
  fn render_wrapper_readme(_language: &str, config: &ToolConfig) -> String {
1044
+ let image_url = github_raw_url(
1045
+ &config.project.repository,
1046
+ "dev",
1047
+ "assets/illustrations/armour05platemail.png",
1048
+ );
1044
1049
  format!(
1045
1050
  r#"# {name}
1046
1051
 
1052
+ <p align="center">
1053
+ <img src="{image_url}" alt="{name} armor" width="320">
1054
+ </p>
1055
+
1047
1056
  `{command}` helps you start and maintain a project that ships the same CLI through Rust, npm, and PyPI.
1048
1057
 
1049
1058
  Use it to:
@@ -1071,6 +1080,7 @@ Learn more:
1071
1080
  "#,
1072
1081
  name = config.project.name,
1073
1082
  command = config.packages.command,
1083
+ image_url = image_url,
1074
1084
  )
1075
1085
  }
1076
1086
 
@@ -1081,6 +1091,15 @@ fn render_root_readme_identity(config: &ToolConfig) -> String {
1081
1091
  )
1082
1092
  }
1083
1093
 
1094
+ fn github_raw_url(repository: &str, branch: &str, path: &str) -> String {
1095
+ let trimmed = repository.trim_end_matches('/');
1096
+ if let Some(rest) = trimmed.strip_prefix("https://github.com/") {
1097
+ format!("https://raw.githubusercontent.com/{rest}/{branch}/{path}")
1098
+ } else {
1099
+ format!("{trimmed}/{path}")
1100
+ }
1101
+ }
1102
+
1084
1103
  fn validate_workflow_name(
1085
1104
  path: &str,
1086
1105
  expected_name: &str,
@@ -1405,7 +1424,7 @@ mod tests {
1405
1424
  target.join("core-rs/Cargo.toml"),
1406
1425
  r#"[package]
1407
1426
  name = "bad-core"
1408
- version = "0.1.1"
1427
+ version = "0.1.3"
1409
1428
  "#,
1410
1429
  )
1411
1430
  .unwrap();
@@ -1541,7 +1560,7 @@ command = "ossplate"
1541
1560
  root.join("core-rs/Cargo.toml"),
1542
1561
  r#"[package]
1543
1562
  name = "ossplate"
1544
- version = "0.1.1"
1563
+ version = "0.1.3"
1545
1564
  edition = "2021"
1546
1565
  authors = ["Stef <stefdevscore@github.com>"]
1547
1566
  description = "A practical baseline for shipping one project across Cargo, npm, and PyPI without starting from scratch every time."
@@ -1,24 +1,16 @@
1
1
  # Documentation
2
2
 
3
- This docs area explains how to use `ossplate` as a real tool for validating, synchronizing, and now creating a multi-registry scaffold.
3
+ `ossplate` is a tool for shipping one CLI across Cargo, npm, and PyPI without maintaining three separate implementations.
4
4
 
5
- ## Start Here
5
+ Start here:
6
6
 
7
- - [Customizing The Template](./customizing-the-template.md)
7
+ - [Adoption Guide](./customizing-the-template.md)
8
8
  - [Architecture](./architecture.md)
9
- - [Testing Guide](./testing.md)
10
- - [Release Guide](./releases.md)
11
- - [Phase 1 Contract](./phase-1-contract.md)
12
- - [Upgrade Plan](./upgrade-plan.md)
13
- - `ossplate validate` checks owned metadata drift
14
- - `ossplate sync --check` verifies the repo is already synchronized
15
- - `ossplate create <target>` scaffolds a clean target directory and can apply identity overrides from flags
16
- - `ossplate init --path <dir>` hydrates an existing directory in place and can apply identity overrides from flags
9
+ - [Testing](./testing.md)
10
+ - [Releases](./releases.md)
17
11
 
18
- ## What These Docs Cover
12
+ Decision records:
19
13
 
20
- - the canonical config and command surface
21
- - the required rename and customization surface before first release
22
- - the layered testing and packaging workflow
23
- - the release operator flow and rerun-safe publish expectations
24
- - the phased plan for turning this tool into a broader scaffold product
14
+ - [ADR 0001: Rust Core, Thin Wrappers](./adrs/0001-rust-core-thin-wrappers.md)
15
+ - [ADR 0002: Sync Owns Bounded Identity Surfaces](./adrs/0002-sync-owns-bounded-identity.md)
16
+ - [ADR 0003: Ship A Curated Scaffold Payload](./adrs/0003-curated-scaffold-payload.md)
@@ -0,0 +1,21 @@
1
+ # ADR 0001: Rust Core, Thin Wrappers
2
+
3
+ ## Status
4
+
5
+ Accepted
6
+
7
+ ## Context
8
+
9
+ `ossplate` has to ship one command surface across Cargo, npm, and PyPI. Maintaining separate implementations would create drift quickly and make release verification harder.
10
+
11
+ ## Decision
12
+
13
+ - Rust is the only product implementation.
14
+ - JavaScript and Python packages are adapters that resolve the packaged binary and forward arguments.
15
+ - Wrapper packages preserve stdout, stderr, and exit status from the Rust binary.
16
+
17
+ ## Consequences
18
+
19
+ - New product behavior goes into `core-rs`.
20
+ - JS and Python should stay small and operationally focused.
21
+ - Parity testing can compare wrapper execution with direct Rust execution.
@@ -0,0 +1,31 @@
1
+ # ADR 0002: Sync Owns Bounded Identity Surfaces
2
+
3
+ ## Status
4
+
5
+ Accepted
6
+
7
+ ## Context
8
+
9
+ `ossplate sync` must keep shared project identity aligned without becoming a destructive repo rewriter.
10
+
11
+ ## Decision
12
+
13
+ `sync` owns only bounded, identity-bearing surfaces:
14
+
15
+ - Rust, npm, and Python package metadata
16
+ - wrapper package README content
17
+ - the root README identity block between `ossplate:readme-identity` markers
18
+ - workflow display names between `ossplate:workflow-name` markers
19
+
20
+ `sync` does not own:
21
+
22
+ - workflow logic
23
+ - auth setup
24
+ - arbitrary prose outside markers
25
+ - docs that are not explicitly bounded
26
+
27
+ ## Consequences
28
+
29
+ - Drift checks stay surgical.
30
+ - Contributors can change most prose and workflow logic safely.
31
+ - Any ownership expansion must be explicit and bounded first.
@@ -0,0 +1,21 @@
1
+ # ADR 0003: Ship A Curated Scaffold Payload
2
+
3
+ ## Status
4
+
5
+ Accepted
6
+
7
+ ## Context
8
+
9
+ `create` and `init` need scaffold content even when `ossplate` is installed from npm or PyPI. A broad repo snapshot would work, but it would also ship tests, maintainer-only files, and accidental junk.
10
+
11
+ ## Decision
12
+
13
+ - Installed wrapper artifacts ship a curated scaffold payload.
14
+ - `scaffold-manifest.json` is the allowlist for that payload.
15
+ - Artifact tests assert both required content and excluded content.
16
+
17
+ ## Consequences
18
+
19
+ - Installed distributions can create and initialize projects end to end.
20
+ - Package contents stay intentional.
21
+ - Adding new scaffold files requires updating the manifest and tests.
@@ -0,0 +1,87 @@
1
+ # Architecture
2
+
3
+ `ossplate` is intentionally small. The design goal is simple: one real CLI, three distribution channels.
4
+
5
+ ## Runtime Shape
6
+
7
+ - Rust in [`core-rs/`](../core-rs) is the product.
8
+ - JavaScript in [`wrapper-js/`](../wrapper-js) is a package adapter.
9
+ - Python in [`wrapper-py/`](../wrapper-py) is a package adapter.
10
+ - The scaffold payload bundled into the wrappers is a distribution asset, not another implementation.
11
+
12
+ The main commands are:
13
+
14
+ - `version`
15
+ - `validate`
16
+ - `sync`
17
+ - `create`
18
+ - `init`
19
+
20
+ ## Responsibilities
21
+
22
+ ### Rust
23
+
24
+ - command parsing
25
+ - project identity loading from `ossplate.toml`
26
+ - validation logic
27
+ - metadata synchronization
28
+ - scaffold creation and initialization
29
+
30
+ Rust is the only layer that should know the semantics of project identity and owned metadata surfaces.
31
+
32
+ ### JavaScript and Python
33
+
34
+ The wrappers own:
35
+
36
+ - packaged binary lookup
37
+ - platform/architecture target resolution
38
+ - local binary override support
39
+ - forwarding stdout, stderr, and exit code unchanged
40
+
41
+ They should not implement separate business logic, metadata rules, or command behavior.
42
+
43
+ ### Scaffold Payload
44
+
45
+ The scaffold payload owns the generated-project baseline:
46
+
47
+ - manifests
48
+ - docs
49
+ - workflows
50
+ - wrapper launchers
51
+ - packaged binaries needed for installed-wrapper scaffold operations
52
+
53
+ It is curated by manifest and shipped as part of the wrapper artifacts so `create` and `init` work from installed distributions.
54
+
55
+ ## Ownership Boundaries
56
+
57
+ `ossplate sync` owns only bounded identity-bearing surfaces. The details are in the ADRs, but the practical rule is simple: if a surface is not explicitly bounded, `sync` should not rewrite it.
58
+
59
+ Today that includes:
60
+
61
+ - Cargo, npm, and Python metadata fields
62
+ - wrapper package README identity
63
+ - the root README identity block
64
+ - workflow display names between `ossplate:workflow-name` markers
65
+
66
+ It does not own:
67
+
68
+ - workflow logic
69
+ - auth setup
70
+ - arbitrary prose outside bounded markers
71
+ - separate wrapper-specific product behavior
72
+
73
+ ## Why It Scales
74
+
75
+ If the tool grows, keep the current rules:
76
+
77
+ - add product behavior in Rust
78
+ - treat wrappers as delivery adapters
79
+ - expand scaffold ownership only where the boundary is explicit and non-destructive
80
+
81
+ That gives the project a clean path toward a fuller hexagonal structure without forcing that complexity into the current starter.
82
+
83
+ ## Related Decisions
84
+
85
+ - [ADR 0001: Rust Core, Thin Wrappers](./adrs/0001-rust-core-thin-wrappers.md)
86
+ - [ADR 0002: Sync Owns Bounded Identity Surfaces](./adrs/0002-sync-owns-bounded-identity.md)
87
+ - [ADR 0003: Ship A Curated Scaffold Payload](./adrs/0003-curated-scaffold-payload.md)
@@ -1,6 +1,6 @@
1
- # Adopting The Scaffold
1
+ # Adoption Guide
2
2
 
3
- Use this checklist after creating or cloning a scaffold managed by `ossplate`. The goal is to adopt the scaffold under your own project identity and then use the tool to keep owned metadata in sync.
3
+ Use this guide after creating or cloning a project managed by `ossplate`. The goal is to adopt the scaffold under your own identity and then let the tool keep owned metadata aligned.
4
4
 
5
5
  ## Canonical Source Of Truth
6
6
 
@@ -22,15 +22,6 @@ It currently owns:
22
22
 
23
23
  `ossplate sync` rewrites the owned surfaces back into alignment.
24
24
 
25
- ## Validation Policy
26
-
27
- - Template-source identities are allowed only when the repository is discussing `ossplate` itself.
28
- - Inherited identities are not allowed in shipping metadata or package-facing docs for an adopted project.
29
- - Command and package naming must be chosen intentionally before release.
30
- - Author, repository, and license fields must be set explicitly rather than inherited accidentally.
31
-
32
- The current validator follows this policy through the Rust core rather than a standalone JS rule engine.
33
-
34
25
  ## Required Identity Changes
35
26
 
36
27
  Replace these inherited defaults before reuse:
@@ -45,17 +36,6 @@ Replace these inherited defaults before reuse:
45
36
  | Author/email | `Stef <stefdevscore@github.com>` / `stefdevscore@github.com` | Rust, npm, Python metadata |
46
37
  | Package-facing scaffold branding | `ossplate` identity in wrapper docs | `wrapper-js/README.md`, `wrapper-py/README.md` |
47
38
 
48
- ## Files To Review
49
-
50
- - `README.md`
51
- - `ossplate.toml`
52
- - `core-rs/Cargo.toml`
53
- - `wrapper-js/package.json`
54
- - `wrapper-js/README.md`
55
- - `wrapper-py/pyproject.toml`
56
- - `wrapper-py/README.md`
57
- - `.github/workflows/*.yml`
58
-
59
39
  ## What `ossplate validate` Enforces
60
40
 
61
41
  The tool reports:
@@ -81,15 +61,15 @@ The workflow files now expose a similarly bounded identity surface:
81
61
 
82
62
  `sync` owns only the display name between `ossplate:workflow-name` markers. Trigger logic, jobs, auth, and shell steps remain manual.
83
63
 
84
- ## First-Run Sequence After Cloning
64
+ ## First Run
85
65
 
86
66
  1. Either update `ossplate.toml` directly or use `create` / `init` with identity flags.
87
67
  2. Run `cargo run --manifest-path core-rs/Cargo.toml -- sync`.
88
68
  3. Run `cargo run --manifest-path core-rs/Cargo.toml -- validate`.
89
- 4. Run the layered verification flow from [Testing Guide](./testing.md).
69
+ 4. Run the verification flow from [Testing](./testing.md).
90
70
  5. Only then expand product code or publish configuration.
91
71
 
92
- ## Create Workflow
72
+ ## Create A New Project
93
73
 
94
74
  To scaffold a fresh target from the current template tree:
95
75
 
@@ -107,9 +87,9 @@ cargo run --manifest-path core-rs/Cargo.toml -- create ../my-new-project \
107
87
 
108
88
  That copies the curated scaffold payload into the target directory, applies any identity overrides to `ossplate.toml`, then runs `sync` on the new target.
109
89
 
110
- The packaged scaffold intentionally excludes wrapper test suites and maintainer-only validation scripts. Generated projects get the delivery baseline and operator docs, not the source repo's internal test harness.
90
+ The packaged scaffold intentionally excludes wrapper test suites and maintainer-only utilities. Generated projects get the delivery baseline and operator docs, not the source repo's internal harness.
111
91
 
112
- ## Init Workflow
92
+ ## Adopt An Existing Directory
113
93
 
114
94
  To hydrate an existing directory in place:
115
95
 
@@ -122,7 +102,7 @@ cargo run --manifest-path core-rs/Cargo.toml -- init \
122
102
 
123
103
  `init` ensures the expected scaffold layout exists, copies any missing scaffold files, applies any requested identity overrides, and then runs `sync` so owned metadata matches `ossplate.toml`.
124
104
 
125
- ## Supported Identity Flags
105
+ ## Identity Flags
126
106
 
127
107
  - `--name`
128
108
  - `--description`
@@ -135,10 +115,7 @@ cargo run --manifest-path core-rs/Cargo.toml -- init \
135
115
  - `--python-package`
136
116
  - `--command`
137
117
 
138
- ## Why This Exists
139
-
140
- This tool is trying to optimize for a real delivery baseline:
118
+ ## Related Decisions
141
119
 
142
- - CI should fail before inherited identity reaches a release path.
143
- - package metadata should not be inherited by accident
144
- - future phases can add richer scaffold creation and maintenance without first cleaning up metadata drift
120
+ - [ADR 0002: Sync Owns Bounded Identity Surfaces](./adrs/0002-sync-owns-bounded-identity.md)
121
+ - [ADR 0003: Ship A Curated Scaffold Payload](./adrs/0003-curated-scaffold-payload.md)
@@ -0,0 +1,71 @@
1
+ # Releases
2
+
3
+ Use this guide when cutting a new `ossplate` release.
4
+
5
+ ## Current Registry Setup
6
+
7
+ - PyPI publishes from [`.github/workflows/publish.yml`](../.github/workflows/publish.yml) via GitHub OIDC trusted publishing.
8
+ - crates.io publishes from [`.github/workflows/publish.yml`](../.github/workflows/publish.yml) via OIDC trusted publishing with `CARGO_TOKEN` fallback.
9
+ - npm publishes from [`.github/workflows/publish-npm.yml`](../.github/workflows/publish-npm.yml) via OIDC trusted publishing with `NPM_TOKEN` fallback.
10
+
11
+ ## Before Release
12
+
13
+ Run the full gate before creating a release:
14
+
15
+ ```bash
16
+ ./scripts/verify.sh
17
+ ```
18
+
19
+ Optional local packaging confidence checks:
20
+
21
+ ```bash
22
+ cargo package --manifest-path core-rs/Cargo.toml
23
+ cargo publish --manifest-path core-rs/Cargo.toml --dry-run
24
+ cd wrapper-js && npm pack --dry-run
25
+ cd ../wrapper-py && python -m build --wheel
26
+ ```
27
+
28
+ ## Versioning
29
+
30
+ Keep the registry versions aligned across:
31
+
32
+ - [`core-rs/Cargo.toml`](../core-rs/Cargo.toml)
33
+ - [`wrapper-js/package.json`](../wrapper-js/package.json)
34
+ - [`wrapper-py/pyproject.toml`](../wrapper-py/pyproject.toml)
35
+
36
+ After updating versions, rerun:
37
+
38
+ ```bash
39
+ ./scripts/verify.sh
40
+ ```
41
+
42
+ ## Release Flow
43
+
44
+ 1. Commit the version bump and any release notes.
45
+ 2. Push `dev`.
46
+ 3. Create a GitHub release that targets `dev`, or manually dispatch the publish workflows.
47
+ 4. Monitor:
48
+ - [`.github/workflows/publish.yml`](../.github/workflows/publish.yml)
49
+ - [`.github/workflows/publish-npm.yml`](../.github/workflows/publish-npm.yml)
50
+
51
+ ## Rerun Behavior
52
+
53
+ The publish jobs are intentionally rerun-safe.
54
+
55
+ - Cargo checks whether the crate version already exists before attempting publish.
56
+ - npm checks whether the package version already exists before attempting publish.
57
+ - PyPI uses `skip-existing: true`.
58
+
59
+ So a second run for the same version should usually succeed by skipping work rather than failing destructively.
60
+
61
+ ## Current Published Names
62
+
63
+ - crates.io: `ossplate`
64
+ - npm: `ossplate`
65
+ - PyPI: `ossplate`
66
+ - CLI: `ossplate`
67
+
68
+ ## Maintenance
69
+
70
+ - Refresh GitHub Actions dependencies before the Node 20 runner deprecation becomes a problem.
71
+ - Keep the release auth docs aligned with real registry configuration whenever trusted publishing or token fallback changes.
@@ -1,8 +1,8 @@
1
- # Testing Guide
1
+ # Testing
2
2
 
3
3
  `ossplate` uses layered verification so the scaffold stays usable as both a source checkout and an installed wrapper distribution.
4
4
 
5
- ## Default Layers
5
+ ## Layers
6
6
 
7
7
  ### Smoke
8
8
 
@@ -39,7 +39,7 @@ Artifact assertions are part of the required packaging layer:
39
39
  - Python wheel content must include the curated scaffold files from `scaffold-manifest.json`
40
40
  - Python wheel content must exclude wrapper test files and repo-only validation scripts
41
41
 
42
- ## Recommended Local Order
42
+ ## Default Local Flow
43
43
 
44
44
  Default path:
45
45
 
@@ -59,7 +59,7 @@ Underlying command order:
59
59
  8. `PYTHONPATH=src python3 -m unittest discover -s tests -p 'test_*.py'`
60
60
  9. `python -m build --wheel`
61
61
 
62
- ## CI Expectations
62
+ ## CI
63
63
 
64
64
  CI currently enforces:
65
65
 
@@ -68,6 +68,6 @@ CI currently enforces:
68
68
  - JS build, tests, and package dry-run
69
69
  - Python tests and wheel build
70
70
 
71
- The current artifact tests are the required release-confidence floor. Future phases can add broader platform coverage or slower end-to-end suites without changing the basic layered model.
71
+ The current artifact tests are the required release-confidence floor.
72
72
 
73
73
  For release-specific operator steps, version bumps, and rerun-safe publish expectations, see [`docs/releases.md`](./releases.md).
@@ -1,5 +1,9 @@
1
1
  # Ossplate
2
2
 
3
+ <p align="center">
4
+ <img src="https://raw.githubusercontent.com/stefdevscore/ossplate/dev/assets/illustrations/armour05platemail.png" alt="Ossplate armor" width="320">
5
+ </p>
6
+
3
7
  `ossplate` helps you start and maintain a project that ships the same CLI through Rust, npm, and PyPI.
4
8
 
5
9
  Use it to:
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "ossplate",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "ossplate",
9
- "version": "0.1.1",
9
+ "version": "0.1.3",
10
10
  "license": "Unlicense",
11
11
  "bin": {
12
12
  "ossplate": "bin/ossplate.js"
@@ -39,5 +39,5 @@
39
39
  "test": "npm run build && node --test test/cli.test.js"
40
40
  },
41
41
  "type": "module",
42
- "version": "0.1.1"
42
+ "version": "0.1.3"
43
43
  }
@@ -1,5 +1,9 @@
1
1
  # Ossplate
2
2
 
3
+ <p align="center">
4
+ <img src="https://raw.githubusercontent.com/stefdevscore/ossplate/dev/assets/illustrations/armour05platemail.png" alt="Ossplate armor" width="320">
5
+ </p>
6
+
3
7
  `ossplate` helps you start and maintain a project that ships the same CLI through Rust, npm, and PyPI.
4
8
 
5
9
  Use it to:
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "ossplate"
7
- version = "0.1.1"
7
+ version = "0.1.3"
8
8
  description = "Build one project, ship it everywhere."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -1,46 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 720 420" role="img" aria-labelledby="title desc">
2
- <title id="title">Ossplate chestplate illustration</title>
3
- <desc id="desc">A bronze chestplate with shoulder guards on a warm background.</desc>
4
- <defs>
5
- <linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
6
- <stop offset="0%" stop-color="#f7ecdd"/>
7
- <stop offset="100%" stop-color="#dcb88b"/>
8
- </linearGradient>
9
- <linearGradient id="metal" x1="0%" y1="0%" x2="0%" y2="100%">
10
- <stop offset="0%" stop-color="#ddaf68"/>
11
- <stop offset="50%" stop-color="#b77735"/>
12
- <stop offset="100%" stop-color="#7b491c"/>
13
- </linearGradient>
14
- <linearGradient id="rim" x1="0%" y1="0%" x2="100%" y2="100%">
15
- <stop offset="0%" stop-color="#fff0bf"/>
16
- <stop offset="100%" stop-color="#a05d24"/>
17
- </linearGradient>
18
- <linearGradient id="highlight" x1="0%" y1="0%" x2="100%" y2="100%">
19
- <stop offset="0%" stop-color="#fff8de" stop-opacity="0.95"/>
20
- <stop offset="100%" stop-color="#fff8de" stop-opacity="0"/>
21
- </linearGradient>
22
- <filter id="shadow" x="-20%" y="-20%" width="140%" height="160%">
23
- <feDropShadow dx="0" dy="16" stdDeviation="12" flood-color="#673d18" flood-opacity="0.28"/>
24
- </filter>
25
- </defs>
26
-
27
- <rect width="720" height="420" fill="url(#bg)"/>
28
- <circle cx="110" cy="84" r="58" fill="#fff7de" opacity="0.4"/>
29
- <circle cx="607" cy="314" r="76" fill="#a86e33" opacity="0.12"/>
30
-
31
- <g filter="url(#shadow)" transform="translate(150 28)">
32
- <path d="M151 46c12-18 27-29 59-34 16-2 42-3 59-3s43 1 59 3c32 5 47 16 59 34l24 35c7 10 4 24-6 31l-22 16c-8 6-19 7-29 2l-27-13v90c0 60-26 102-58 129-32 26-64 39-91 45-27-6-59-19-91-45-32-27-58-69-58-129v-90l-27 13c-10 5-21 4-29-2l-22-16c-10-7-13-21-6-31z" fill="url(#metal)"/>
33
- <path d="M151 46c12-18 27-29 59-34 16-2 42-3 59-3s43 1 59 3c32 5 47 16 59 34l24 35c7 10 4 24-6 31l-22 16c-8 6-19 7-29 2l-27-13v90c0 60-26 102-58 129-32 26-64 39-91 45-27-6-59-19-91-45-32-27-58-69-58-129v-90l-27 13c-10 5-21 4-29-2l-22-16c-10-7-13-21-6-31z" fill="none" stroke="#6b4118" stroke-width="10" stroke-linejoin="round"/>
34
- <path d="M210 52c11-14 26-20 44-22 15-2 29-2 46-2s31 0 46 2c18 2 33 8 44 22l15 20c-41 18-92 27-105 29-13-2-64-11-105-29z" fill="#c78741" opacity="0.88"/>
35
- <path d="M126 74l32 16c10 5 21 4 30-2l20-13c18 9 43 16 72 20v204c-56-15-121-61-121-158V93c0-8-12-13-33-19z" fill="#845022" opacity="0.34"/>
36
- <path d="M474 74l-32 16c-10 5-21 4-30-2l-20-13c-18 9-43 16-72 20v204c56-15 121-61 121-158V93c0-8 12-13 33-19z" fill="#f0c27a" opacity="0.2"/>
37
- <path d="M300 92v214" stroke="#6b4118" stroke-width="8" stroke-linecap="round" opacity="0.82"/>
38
- <path d="M196 134c29 12 65 18 104 18s75-6 104-18" stroke="#6b4118" stroke-width="7" stroke-linecap="round" opacity="0.72"/>
39
- <path d="M206 215c24 9 56 14 94 14s70-5 94-14" stroke="#6b4118" stroke-width="6" stroke-linecap="round" opacity="0.62"/>
40
- <path d="M235 42c19 10 40 16 65 19-13 10-23 24-29 41-25-4-48-12-68-25 7-16 17-27 32-35z" fill="url(#highlight)" opacity="0.72"/>
41
- <path d="M300 61c25-3 46-9 65-19 15 8 25 19 32 35-20 13-43 21-68 25-6-17-16-31-29-41z" fill="url(#highlight)" opacity="0.5"/>
42
- <path d="M147 62l-41 58c-5 7-3 17 4 22l18 13c5 4 12 4 18 1l41-19-9-53c-2-11-14-21-31-22z" fill="url(#rim)" opacity="0.95"/>
43
- <path d="M453 62l41 58c5 7 3 17-4 22l-18 13c-5 4-12 4-18 1l-41-19 9-53c2-11 14-21 31-22z" fill="url(#rim)" opacity="0.95"/>
44
- <path d="M214 310c26 14 56 23 86 28 30-5 60-14 86-28" stroke="#f3d39a" stroke-width="6" stroke-linecap="round" opacity="0.45"/>
45
- </g>
46
- </svg>
@@ -1,52 +0,0 @@
1
- # Phase 1 Contract
2
-
3
- Phase 1 establishes a single canonical CLI surface in the Rust core. The JavaScript and Python packages are wrappers that delegate to that binary rather than implementing separate behavior.
4
-
5
- ## Canonical Commands
6
-
7
- - `version`
8
- returns JSON with the tool identity and package version
9
- - `validate [--path <dir>] [--json]`
10
- returns validation results for owned metadata surfaces
11
- - `sync [--path <dir>] [--check]`
12
- rewrites or checks owned metadata surfaces against the canonical project identity
13
- - `create <target>`
14
- copies the curated scaffold payload into a clean target directory, applies optional identity overrides, and synchronizes the owned metadata surfaces there
15
- - `init [--path <dir>]`
16
- hydrates an existing directory with the expected scaffold layout, applies optional identity overrides, and then synchronizes owned metadata in place
17
-
18
- Both commands are available from source checkouts and installed wrapper artifacts that include the staged scaffold payload.
19
-
20
- ## Expected Output Shapes
21
-
22
- ```json
23
- {"tool":"ossplate","version":"0.1.0"}
24
- {"ok":true,"issues":[]}
25
- ```
26
-
27
- ## Wrapper Model
28
-
29
- - Rust is the source of truth for command parsing and output.
30
- - JavaScript and Python are adapter layers that resolve a packaged binary and forward arguments unchanged.
31
- - Wrappers preserve stdout, stderr, and exit status from the core binary.
32
-
33
- ## Local Development Override
34
-
35
- Both wrappers support `OSSPLATE_BINARY` to bypass packaged binary lookup during local development and parity testing.
36
-
37
- `create` and `init` also honor `OSSPLATE_TEMPLATE_ROOT` when the template source needs to be overridden explicitly.
38
-
39
- ## Packaged Binary Layout
40
-
41
- Wrappers expect binaries under:
42
-
43
- ```text
44
- bin/<target>/<executable>
45
- ```
46
-
47
- Supported target identifiers are aligned across wrappers:
48
-
49
- - `darwin-arm64`
50
- - `darwin-x64`
51
- - `linux-x64`
52
- - `win32-x64`
@@ -1,88 +0,0 @@
1
- # Ossplate Roadmap
2
-
3
- ## Current State
4
-
5
- `ossplate` is no longer a placeholder scaffold. It now ships as a real multi-registry tool with:
6
-
7
- - a canonical Rust CLI
8
- - thin npm and Python wrappers
9
- - real `validate`, `sync`, `create`, and `init` commands
10
- - curated scaffold payloads in installed wrapper artifacts
11
- - CI quality gates across Rust, JS, and Python
12
- - OIDC-first publishing for PyPI, Cargo, and npm, with token fallbacks where configured
13
-
14
- Published names are aligned as:
15
-
16
- - crates.io: `ossplate`
17
- - npm: `ossplate`
18
- - PyPI: `ossplate`
19
- - CLI: `ossplate`
20
-
21
- ## Completed
22
-
23
- ### Foundation
24
-
25
- - Placeholder identity validation is wired into CI.
26
- - `ossplate.toml` is the canonical identity source.
27
- - Root docs, testing docs, customization docs, and release docs now exist.
28
-
29
- ### Product Surface
30
-
31
- - Rust is the only source of product logic.
32
- - JS and Python are thin wrappers around the packaged binary.
33
- - The command surface is now real:
34
- `version`, `validate`, `sync`, `create`, `init`.
35
-
36
- ### Packaging And Artifact Reality
37
-
38
- - Installed npm and Python artifacts carry the scaffold payload required by `create` and `init`.
39
- - Scaffold payload staging is curated by manifest rather than broad repo-copy behavior.
40
- - Artifact tests verify required content and exclude known non-shipping content.
41
-
42
- ### Quality Gates
43
-
44
- - CI enforces Rust format, clippy, and tests.
45
- - CI enforces JS build, tests, and package dry-run.
46
- - CI enforces Python tests and wheel build.
47
- - Wrapper parity and installed-artifact smoke paths are exercised.
48
- - `./scripts/verify.sh` mirrors the local gate.
49
-
50
- ### Publishing
51
-
52
- - Publish flows are rerun-safe.
53
- - PyPI uses OIDC.
54
- - Cargo uses OIDC with `CARGO_TOKEN` fallback.
55
- - npm uses OIDC with `NPM_TOKEN` fallback.
56
- - The release operator flow is documented in [`docs/releases.md`](./releases.md).
57
-
58
- ## Remaining Priorities
59
-
60
- ## P1
61
-
62
- - Expand `sync` ownership carefully into a few more identity-only surfaces where bounded ownership is safe.
63
- - Improve `validate` and `sync --check` output further if field-level drift becomes hard to read at scale.
64
- - Add a short architecture note describing the current boundary:
65
- Rust core as product logic, JS/Python as adapters, scaffold payload as distribution asset.
66
-
67
- ## P2
68
-
69
- - Add optional guidance for generated projects that need browser-based live end-to-end tests.
70
- - Add examples of failure triage for packaging, publish, and parity regressions.
71
- - Tighten workflow/docs ownership boundaries further if more fields become sync-managed.
72
-
73
- ## P3
74
-
75
- - Add architecture-shell guidance for teams that want to scale generated projects into a fuller hexagonal layout.
76
- - Add ADR guidance if the scaffold evolves into a broader product platform.
77
-
78
- ## Release Maintenance
79
-
80
- - Refresh GitHub Actions dependencies ahead of the Node 20 runner deprecation.
81
- - Keep trusted publishing and token fallback documentation aligned with real registry configuration.
82
- - Keep release-version bumps aligned across Cargo, npm, and PyPI metadata.
83
-
84
- ## Suggested Next Work
85
-
86
- 1. Decide whether `sync` should own any additional identity-only fields beyond the current bounded set.
87
- 2. Improve `validate` and `sync --check` if larger repos need richer drift output.
88
- 3. Add optional browser-e2e guidance for generated projects that include a UI.