openresearchworkspace 0.1.0a1__tar.gz

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.
Files changed (81) hide show
  1. openresearchworkspace-0.1.0a1/.github/workflows/initialize-project.yml +120 -0
  2. openresearchworkspace-0.1.0a1/.github/workflows/release-alpha.yml +215 -0
  3. openresearchworkspace-0.1.0a1/.github/workflows/release-checks.yml +53 -0
  4. openresearchworkspace-0.1.0a1/.github/workflows/test-browser.yml +68 -0
  5. openresearchworkspace-0.1.0a1/.github/workflows/test-core.yml +72 -0
  6. openresearchworkspace-0.1.0a1/CHANGELOG.md +26 -0
  7. openresearchworkspace-0.1.0a1/LICENSE +21 -0
  8. openresearchworkspace-0.1.0a1/MANIFEST.in +15 -0
  9. openresearchworkspace-0.1.0a1/PKG-INFO +69 -0
  10. openresearchworkspace-0.1.0a1/README.md +353 -0
  11. openresearchworkspace-0.1.0a1/browser/app.js +109 -0
  12. openresearchworkspace-0.1.0a1/browser/engine.js +170 -0
  13. openresearchworkspace-0.1.0a1/browser/page.html +80 -0
  14. openresearchworkspace-0.1.0a1/browser/requirements-test.txt +2 -0
  15. openresearchworkspace-0.1.0a1/browser/style.css +1 -0
  16. openresearchworkspace-0.1.0a1/browser/tests/test_ui.py +198 -0
  17. openresearchworkspace-0.1.0a1/docs/AI_READY_WORKSPACE.md +132 -0
  18. openresearchworkspace-0.1.0a1/docs/CAPTURE_GETTING_STARTED.md +177 -0
  19. openresearchworkspace-0.1.0a1/docs/PYPI_README.md +44 -0
  20. openresearchworkspace-0.1.0a1/docs/browser-generator.md +127 -0
  21. openresearchworkspace-0.1.0a1/docs/capabilities.md +102 -0
  22. openresearchworkspace-0.1.0a1/docs/cli.md +108 -0
  23. openresearchworkspace-0.1.0a1/docs/concepts.md +110 -0
  24. openresearchworkspace-0.1.0a1/docs/faq.md +51 -0
  25. openresearchworkspace-0.1.0a1/docs/getting-started.md +338 -0
  26. openresearchworkspace-0.1.0a1/docs/index.md +102 -0
  27. openresearchworkspace-0.1.0a1/docs/isa.md +114 -0
  28. openresearchworkspace-0.1.0a1/docs/portable-implementations.md +411 -0
  29. openresearchworkspace-0.1.0a1/docs/project-structure.md +77 -0
  30. openresearchworkspace-0.1.0a1/docs/releases.md +108 -0
  31. openresearchworkspace-0.1.0a1/docs/ro-crate.md +90 -0
  32. openresearchworkspace-0.1.0a1/pyproject.toml +42 -0
  33. openresearchworkspace-0.1.0a1/schema/data_dictionary.schema.json +47 -0
  34. openresearchworkspace-0.1.0a1/schema/project.schema.json +108 -0
  35. openresearchworkspace-0.1.0a1/schema/quality_status.schema.json +57 -0
  36. openresearchworkspace-0.1.0a1/schema/setup.schema.json +108 -0
  37. openresearchworkspace-0.1.0a1/scripts/build_browser.py +134 -0
  38. openresearchworkspace-0.1.0a1/scripts/capture_getting_started.py +686 -0
  39. openresearchworkspace-0.1.0a1/scripts/initialize_project.py +33 -0
  40. openresearchworkspace-0.1.0a1/scripts/parse_setup_issue.py +88 -0
  41. openresearchworkspace-0.1.0a1/scripts/release.py +251 -0
  42. openresearchworkspace-0.1.0a1/scripts/smoke_installed.py +54 -0
  43. openresearchworkspace-0.1.0a1/scripts/test_distributions.py +43 -0
  44. openresearchworkspace-0.1.0a1/setup.cfg +4 -0
  45. openresearchworkspace-0.1.0a1/src/openresearchworkspace.egg-info/PKG-INFO +69 -0
  46. openresearchworkspace-0.1.0a1/src/openresearchworkspace.egg-info/SOURCES.txt +79 -0
  47. openresearchworkspace-0.1.0a1/src/openresearchworkspace.egg-info/dependency_links.txt +1 -0
  48. openresearchworkspace-0.1.0a1/src/openresearchworkspace.egg-info/entry_points.txt +2 -0
  49. openresearchworkspace-0.1.0a1/src/openresearchworkspace.egg-info/requires.txt +2 -0
  50. openresearchworkspace-0.1.0a1/src/openresearchworkspace.egg-info/top_level.txt +1 -0
  51. openresearchworkspace-0.1.0a1/src/orw/__init__.py +20 -0
  52. openresearchworkspace-0.1.0a1/src/orw/_scaffold.py +357 -0
  53. openresearchworkspace-0.1.0a1/src/orw/_version.py +2 -0
  54. openresearchworkspace-0.1.0a1/src/orw/cli.py +330 -0
  55. openresearchworkspace-0.1.0a1/src/orw/export/__init__.py +23 -0
  56. openresearchworkspace-0.1.0a1/src/orw/export/_rocrate_model.py +1006 -0
  57. openresearchworkspace-0.1.0a1/src/orw/export/rocrate.py +174 -0
  58. openresearchworkspace-0.1.0a1/src/orw/fs_safety.py +86 -0
  59. openresearchworkspace-0.1.0a1/src/orw/initialize.py +160 -0
  60. openresearchworkspace-0.1.0a1/src/orw/model.py +187 -0
  61. openresearchworkspace-0.1.0a1/src/orw/schemas/__init__.py +1 -0
  62. openresearchworkspace-0.1.0a1/src/orw/schemas/project.schema.json +108 -0
  63. openresearchworkspace-0.1.0a1/src/orw/templates/project.yml +41 -0
  64. openresearchworkspace-0.1.0a1/src/orw/templates/workspace.yml +10 -0
  65. openresearchworkspace-0.1.0a1/src/orw/validate.py +448 -0
  66. openresearchworkspace-0.1.0a1/tests/fixtures/rocrate/basic.mapping.json +74 -0
  67. openresearchworkspace-0.1.0a1/tests/fixtures/setup/basic.json +23 -0
  68. openresearchworkspace-0.1.0a1/tests/fixtures/setup/invalid-orcid.json +19 -0
  69. openresearchworkspace-0.1.0a1/tests/fixtures/setup/no-assay.json +20 -0
  70. openresearchworkspace-0.1.0a1/tests/fixtures/setup/orcid-keywords.json +23 -0
  71. openresearchworkspace-0.1.0a1/tests/fixtures/setup/reinitialize.json +21 -0
  72. openresearchworkspace-0.1.0a1/tests/fixtures/setup/restricted-external-data.json +21 -0
  73. openresearchworkspace-0.1.0a1/tests/fixtures/setup/unicode.json +23 -0
  74. openresearchworkspace-0.1.0a1/tests/test_browser_contract.py +189 -0
  75. openresearchworkspace-0.1.0a1/tests/test_cli.py +276 -0
  76. openresearchworkspace-0.1.0a1/tests/test_core.py +183 -0
  77. openresearchworkspace-0.1.0a1/tests/test_filesystem_aliases.py +81 -0
  78. openresearchworkspace-0.1.0a1/tests/test_github_adapter.py +125 -0
  79. openresearchworkspace-0.1.0a1/tests/test_release_process.py +143 -0
  80. openresearchworkspace-0.1.0a1/tests/test_release_safety.py +202 -0
  81. openresearchworkspace-0.1.0a1/tests/test_rocrate.py +187 -0
@@ -0,0 +1,120 @@
1
+ name: Initialize research project
2
+
3
+ on:
4
+ issues:
5
+ types: [opened]
6
+
7
+ permissions:
8
+ contents: write
9
+ issues: write
10
+
11
+ concurrency:
12
+ group: initialize-project-${{ github.repository }}
13
+ cancel-in-progress: false
14
+
15
+ jobs:
16
+ initialize:
17
+ name: Create project structure and metadata
18
+ if: >-
19
+ contains(github.event.issue.body, '### Project title') &&
20
+ contains(github.event.issue.body, '### Ready to initialize') &&
21
+ github.repository != 'dhuzard/OpenResearchWorkspace'
22
+ runs-on: ubuntu-latest
23
+
24
+ steps:
25
+ - name: Check who submitted the setup form
26
+ shell: bash
27
+ env:
28
+ GH_TOKEN: ${{ github.token }}
29
+ REPO: ${{ github.repository }}
30
+ USER: ${{ github.event.issue.user.login }}
31
+ run: |
32
+ permission=$(gh api "repos/$REPO/collaborators/$USER/permission" --jq '.permission')
33
+ case "$permission" in
34
+ admin|maintain|write)
35
+ echo "Setup submitted by authorized repository participant $USER ($permission)."
36
+ ;;
37
+ *)
38
+ echo "::error::Project initialization must be submitted by a repository owner or collaborator with write access."
39
+ exit 1
40
+ ;;
41
+ esac
42
+
43
+ - name: Check out project
44
+ uses: actions/checkout@v4
45
+
46
+ - name: Refuse accidental re-initialization
47
+ shell: bash
48
+ run: |
49
+ if [ -f .research/initialized ]; then
50
+ echo "::error::This project has already been initialized."
51
+ exit 1
52
+ fi
53
+
54
+ - name: Read and validate setup form
55
+ id: setup
56
+ run: python scripts/parse_setup_issue.py
57
+
58
+ - name: Create ISA-aligned project files
59
+ env:
60
+ ORW_SETUP_JSON: ${{ steps.setup.outputs.setup_payload }}
61
+ ORW_PROVIDER: github
62
+ ORW_PROVIDER_USER: ${{ github.event.issue.user.login }}
63
+ run: python scripts/initialize_project.py
64
+
65
+ - name: Commit initialized workspace
66
+ shell: bash
67
+ run: |
68
+ git config user.name "github-actions[bot]"
69
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
70
+ git add README.md .research studies project-docs references
71
+ if git diff --cached --quiet; then
72
+ echo "::error::Initialization produced no changes."
73
+ exit 1
74
+ fi
75
+ git commit -m "Initialize research workspace"
76
+ git push
77
+
78
+ - name: Confirm setup in the form thread
79
+ env:
80
+ GH_TOKEN: ${{ github.token }}
81
+ ISSUE_NUMBER: ${{ github.event.issue.number }}
82
+ REPO: ${{ github.repository }}
83
+ shell: bash
84
+ run: |
85
+ cat > /tmp/orw-success.md <<EOF
86
+ ✅ **Your OpenResearchWorkspace project is initialized.**
87
+
88
+ ORW created your first ISA Study/Assay structure and updated the project metadata and README.
89
+
90
+ ➡️ **[Open your initialized workspace](https://github.com/$REPO)**
91
+
92
+ This setup form is now complete and will be closed automatically.
93
+ EOF
94
+ gh issue comment "$ISSUE_NUMBER" --repo "$REPO" --body-file /tmp/orw-success.md
95
+ gh issue close "$ISSUE_NUMBER" --repo "$REPO" --reason completed
96
+
97
+ - name: Workflow summary
98
+ run: |
99
+ echo "## Research workspace initialized" >> "$GITHUB_STEP_SUMMARY"
100
+ echo "The setup form was validated and the ISA-aligned workspace was created." >> "$GITHUB_STEP_SUMMARY"
101
+
102
+ - name: Explain a failed setup
103
+ if: failure()
104
+ env:
105
+ GH_TOKEN: ${{ github.token }}
106
+ ISSUE_NUMBER: ${{ github.event.issue.number }}
107
+ REPO: ${{ github.repository }}
108
+ RUN_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
109
+ shell: bash
110
+ run: |
111
+ cat > /tmp/orw-failure.md <<EOF
112
+ ❌ **ORW could not finish initialization.**
113
+
114
+ The setup form has been left open so you can ask for help or correct the problem.
115
+
116
+ Technical details: $RUN_URL
117
+
118
+ If you are a beginner, you do not need to understand that log yourself—share the link when asking for help.
119
+ EOF
120
+ gh issue comment "$ISSUE_NUMBER" --repo "$REPO" --body-file /tmp/orw-failure.md
@@ -0,0 +1,215 @@
1
+ name: Publish alpha (TestPyPI first)
2
+ on:
3
+ workflow_dispatch:
4
+ inputs:
5
+ phase:
6
+ description: 'TestPyPI rehearsal, or promote a successful rehearsal to PyPI'
7
+ required: true
8
+ type: choice
9
+ options: [testpypi, pypi]
10
+ default: testpypi
11
+ version:
12
+ description: 'Explicit alpha version'
13
+ required: true
14
+ type: string
15
+ default: '0.1.0a1'
16
+ rehearsal_run:
17
+ description: 'Successful TestPyPI run ID (required for PyPI promotion)'
18
+ type: string
19
+ default: ''
20
+ confirmation:
21
+ description: 'For public promotion enter: publish 0.1.0a1'
22
+ type: string
23
+ default: ''
24
+ permissions:
25
+ contents: read
26
+ actions: read
27
+ concurrency:
28
+ group: orw-alpha-${{ inputs.version }}
29
+ cancel-in-progress: false
30
+ env:
31
+ VERSION: ${{ inputs.version }}
32
+ PHASE: ${{ inputs.phase }}
33
+ REHEARSAL_RUN: ${{ inputs.rehearsal_run }}
34
+ CONFIRMATION: ${{ inputs.confirmation }}
35
+ PYTHONUTF8: '1'
36
+ jobs:
37
+ guard:
38
+ runs-on: ubuntu-latest
39
+ steps:
40
+ - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
41
+ with:
42
+ persist-credentials: false
43
+ - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
44
+ with:
45
+ python-version: '3.12'
46
+ - name: Enforce main, alpha version, environment reviewers and rehearsal provenance
47
+ env:
48
+ GH_TOKEN: ${{ github.token }}
49
+ run: python scripts/release.py guard
50
+
51
+ checks:
52
+ needs: guard
53
+ if: inputs.phase == 'testpypi'
54
+ uses: ./.github/workflows/release-checks.yml
55
+
56
+ build:
57
+ needs: [guard, checks]
58
+ if: inputs.phase == 'testpypi'
59
+ runs-on: ubuntu-latest
60
+ steps:
61
+ - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
62
+ with:
63
+ persist-credentials: false
64
+ - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
65
+ with:
66
+ python-version: '3.12'
67
+ - name: Install build and browser test dependencies
68
+ run: |
69
+ python -m pip install . build twine -r browser/requirements-test.txt
70
+ python -m playwright install --with-deps chromium
71
+ - name: Real browser acceptance tests
72
+ run: python -m unittest discover -s browser/tests -v
73
+ - name: Build and test the immutable candidate
74
+ run: python scripts/release.py build
75
+ - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
76
+ with:
77
+ name: alpha-candidate
78
+ path: candidate/
79
+ if-no-files-found: error
80
+ retention-days: 30
81
+
82
+ publish-testpypi:
83
+ needs: build
84
+ if: inputs.phase == 'testpypi'
85
+ runs-on: ubuntu-latest
86
+ environment: testpypi
87
+ permissions:
88
+ contents: read
89
+ actions: read
90
+ id-token: write
91
+ steps:
92
+ - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5
93
+ with:
94
+ name: alpha-candidate
95
+ path: candidate/
96
+ - name: Upload exact candidate to TestPyPI
97
+ uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
98
+ with:
99
+ repository-url: https://test.pypi.org/legacy/
100
+ packages-dir: candidate/packages/
101
+ skip-existing: true
102
+
103
+ verify-testpypi:
104
+ needs: publish-testpypi
105
+ runs-on: ubuntu-latest
106
+ steps:
107
+ - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
108
+ with:
109
+ persist-credentials: false
110
+ - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
111
+ with:
112
+ python-version: '3.12'
113
+ - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5
114
+ with:
115
+ name: alpha-candidate
116
+ path: candidate/
117
+ - name: Download actual TestPyPI bytes, verify hashes, install wheel and sdist
118
+ run: python scripts/release.py registry --index testpypi
119
+ - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
120
+ with:
121
+ name: alpha-verified
122
+ path: candidate/
123
+ if-no-files-found: error
124
+ retention-days: 30
125
+
126
+ acquire-verified:
127
+ needs: guard
128
+ if: inputs.phase == 'pypi'
129
+ runs-on: ubuntu-latest
130
+ outputs:
131
+ source_sha: ${{ steps.proof.outputs.source_sha }}
132
+ steps:
133
+ - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
134
+ with:
135
+ persist-credentials: false
136
+ fetch-depth: 0
137
+ - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
138
+ with:
139
+ python-version: '3.12'
140
+ - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5
141
+ with:
142
+ name: alpha-verified
143
+ path: candidate/
144
+ run-id: ${{ inputs.rehearsal_run }}
145
+ github-token: ${{ github.token }}
146
+ - name: Verify provenance and TestPyPI again; never rebuild
147
+ id: proof
148
+ env:
149
+ GH_TOKEN: ${{ github.token }}
150
+ run: python scripts/release.py promotion
151
+ - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
152
+ with:
153
+ name: alpha-approved
154
+ path: candidate/
155
+ if-no-files-found: error
156
+ retention-days: 30
157
+
158
+ publish-pypi:
159
+ needs: acquire-verified
160
+ runs-on: ubuntu-latest
161
+ environment: pypi
162
+ permissions:
163
+ contents: read
164
+ actions: read
165
+ id-token: write
166
+ steps:
167
+ - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5
168
+ with:
169
+ name: alpha-approved
170
+ path: candidate/
171
+ - name: Upload the exact rehearsed artifacts to PyPI
172
+ uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
173
+ with:
174
+ packages-dir: candidate/packages/
175
+ skip-existing: true
176
+
177
+ verify-pypi:
178
+ needs: publish-pypi
179
+ runs-on: ubuntu-latest
180
+ steps:
181
+ - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
182
+ with:
183
+ persist-credentials: false
184
+ - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
185
+ with:
186
+ python-version: '3.12'
187
+ - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5
188
+ with:
189
+ name: alpha-approved
190
+ path: candidate/
191
+ - name: Verify public index bytes and clean installations
192
+ run: python scripts/release.py registry --index pypi
193
+
194
+ github-prerelease:
195
+ needs: [verify-pypi, acquire-verified]
196
+ runs-on: ubuntu-latest
197
+ permissions:
198
+ contents: write
199
+ actions: read
200
+ steps:
201
+ - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5
202
+ with:
203
+ name: alpha-approved
204
+ path: candidate/
205
+ - name: Publish matching browser and Python prerelease assets
206
+ env:
207
+ GH_TOKEN: ${{ github.token }}
208
+ GH_REPO: dhuzard/OpenResearchWorkspace
209
+ SOURCE_SHA: ${{ needs.acquire-verified.outputs.source_sha }}
210
+ run: |
211
+ gh release create "v$VERSION" --target "$SOURCE_SHA" --prerelease \
212
+ --title "OpenResearchWorkspace $VERSION" \
213
+ --notes "Evaluation alpha. TestPyPI rehearsal and public package read-back succeeded. Use disposable copies; inspect metadata before sharing. See the release guide and changelog for limitations." \
214
+ candidate/packages/* candidate/orw-browser-generator-*.zip \
215
+ candidate/index.html candidate/manifest.json candidate/rehearsal.json
@@ -0,0 +1,53 @@
1
+ name: Alpha release checks
2
+ on:
3
+ pull_request:
4
+ workflow_dispatch:
5
+ workflow_call:
6
+ permissions:
7
+ contents: read
8
+ jobs:
9
+ distributions:
10
+ strategy:
11
+ fail-fast: false
12
+ matrix:
13
+ os: [ubuntu-latest, windows-latest, macos-latest]
14
+ python: ['3.10', '3.13']
15
+ runs-on: ${{ matrix.os }}
16
+ env:
17
+ PYTHONUTF8: '1'
18
+ steps:
19
+ - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
20
+ with:
21
+ persist-credentials: false
22
+ - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
23
+ with:
24
+ python-version: ${{ matrix.python }}
25
+ - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
26
+ with:
27
+ node-version: '22'
28
+ - name: Install build and test dependencies
29
+ run: python -m pip install . build twine
30
+ - name: Regression and cross-language tests
31
+ run: python -m unittest discover -s tests -v
32
+ - name: Build wheel and source distribution
33
+ run: python -m build --outdir dist/packages
34
+ - name: Check package metadata and Markdown
35
+ run: python -m twine check --strict dist/packages/*
36
+ shell: bash
37
+ - name: Test exact artifacts in separate clean environments
38
+ run: python scripts/test_distributions.py dist/packages --version 0.1.0a1
39
+ - name: Rebuild standalone browser from source
40
+ run: python scripts/build_browser.py
41
+ - name: Exercise the candidate-building path without upload credentials
42
+ if: matrix.os == 'ubuntu-latest' && matrix.python == '3.13'
43
+ run: |
44
+ python scripts/release.py build --directory dist/release-candidate --version 0.1.0a1
45
+ python scripts/release.py verify --directory dist/release-candidate --version 0.1.0a1
46
+ - name: Share non-published review artifacts
47
+ if: matrix.os == 'ubuntu-latest' && matrix.python == '3.13'
48
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
49
+ with:
50
+ name: alpha-review-artifacts
51
+ path: dist/release-candidate/
52
+ if-no-files-found: error
53
+ retention-days: 14
@@ -0,0 +1,68 @@
1
+ name: Browser generator
2
+
3
+ on:
4
+ pull_request:
5
+ paths:
6
+ - 'browser/**'
7
+ - 'scripts/build_browser.py'
8
+ - 'src/orw/**'
9
+ - 'schema/**'
10
+ - 'tests/test_browser_contract.py'
11
+ - 'tests/fixtures/setup/**'
12
+ - '.github/workflows/test-browser.yml'
13
+ push:
14
+ branches: [main]
15
+ paths:
16
+ - 'browser/**'
17
+ - 'scripts/build_browser.py'
18
+ - 'src/orw/**'
19
+ - 'schema/**'
20
+ - 'tests/test_browser_contract.py'
21
+ - 'tests/fixtures/setup/**'
22
+ - '.github/workflows/test-browser.yml'
23
+ workflow_dispatch:
24
+
25
+ permissions:
26
+ contents: read
27
+
28
+ concurrency:
29
+ group: browser-${{ github.ref }}
30
+ cancel-in-progress: true
31
+
32
+ jobs:
33
+ browser:
34
+ runs-on: ubuntu-latest
35
+ timeout-minutes: 10
36
+ steps:
37
+ - uses: actions/checkout@v5
38
+ - uses: actions/setup-python@v6
39
+ with:
40
+ python-version: '3.12'
41
+ - uses: actions/setup-node@v5
42
+ with:
43
+ node-version: '22'
44
+ - name: Install test dependencies
45
+ run: |
46
+ python -m pip install . -r browser/requirements-test.txt
47
+ python -m playwright install --with-deps chromium
48
+ - name: Cross-language contract and ZIP tests
49
+ run: python -m unittest discover -s tests -p test_browser_contract.py -v
50
+ - name: Build standalone application
51
+ run: python scripts/build_browser.py
52
+ - name: Browser acceptance (HTTP, file, offline, downloads)
53
+ env:
54
+ ORW_SCREENSHOT_DIR: dist/browser-evidence
55
+ run: python -m unittest discover -s browser/tests -v
56
+ - name: Share tested static build
57
+ uses: actions/upload-artifact@v4
58
+ with:
59
+ name: orw-browser-generator
60
+ path: dist/browser/index.html
61
+ if-no-files-found: error
62
+ - name: Share synthetic test screenshots
63
+ if: always()
64
+ uses: actions/upload-artifact@v4
65
+ with:
66
+ name: browser-test-screenshots
67
+ path: dist/browser-evidence/
68
+ if-no-files-found: ignore
@@ -0,0 +1,72 @@
1
+ name: Test ORW core and CLI
2
+
3
+ on:
4
+ push:
5
+ paths:
6
+ - "src/orw/**"
7
+ - "tests/**"
8
+ - "scripts/**"
9
+ - "schema/**"
10
+ - "pyproject.toml"
11
+ - ".github/workflows/test-core.yml"
12
+ pull_request:
13
+ paths:
14
+ - "src/orw/**"
15
+ - "tests/**"
16
+ - "scripts/**"
17
+ - "schema/**"
18
+ - "pyproject.toml"
19
+ - ".github/workflows/test-core.yml"
20
+ workflow_dispatch:
21
+
22
+ permissions:
23
+ contents: read
24
+
25
+ jobs:
26
+ test:
27
+ name: Core, CLI, and installed-command tests
28
+ runs-on: ubuntu-latest
29
+
30
+ steps:
31
+ - name: Check out repository
32
+ uses: actions/checkout@v5
33
+
34
+ - name: Set up Python
35
+ uses: actions/setup-python@v6
36
+ with:
37
+ python-version: "3.12"
38
+
39
+ - name: Install ORW package
40
+ run: python -m pip install .
41
+
42
+ - name: Run unit and contract tests
43
+ run: python -m unittest discover -s tests -v
44
+
45
+ - name: Test installed CLI outside checkout
46
+ shell: bash
47
+ run: |
48
+ workdir="$(mktemp -d)"
49
+ cd "$workdir"
50
+
51
+ orw --version
52
+ orw init study --config "$GITHUB_WORKSPACE/tests/fixtures/setup/basic.json"
53
+ orw validate study
54
+ orw validate study --json > validation.json
55
+ orw export study --format ro-crate --output crate
56
+
57
+ python - <<'PY'
58
+ import json
59
+ from pathlib import Path
60
+
61
+ payload = json.loads(Path("validation.json").read_text())
62
+ assert payload["valid"] is True, payload
63
+ assert payload["issues"] == [], payload
64
+ assert Path("study/.research/project.yml").is_file()
65
+
66
+ crate = json.loads(Path("crate/ro-crate-metadata.json").read_text())
67
+ assert crate["@context"] == "https://w3id.org/ro/crate/1.3/context"
68
+ by_id = {entity["@id"]: entity for entity in crate["@graph"]}
69
+ assert by_id["ro-crate-metadata.json"]["conformsTo"]["@id"] == "https://w3id.org/ro/crate/1.3"
70
+ assert by_id["./"]["@type"] == "Dataset"
71
+ assert Path("crate/.research/project.yml").is_file()
72
+ PY
@@ -0,0 +1,26 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0a1 — release candidate; not yet published
4
+
5
+ ### Added
6
+
7
+ - Provider-neutral workspace generation, CLI initialization and validation, and RO-Crate 1.3 directory export.
8
+ - Standalone browser generator with local ZIP creation and Python/browser contract checks.
9
+ - Wheel/source-distribution smoke tests and a staged TestPyPI → public PyPI publishing workflow using the same verified artifacts.
10
+ - Software version in `src/orw/_version.py`; specification/template versions remain independent.
11
+
12
+ ### Safety fixes
13
+
14
+ - Normal initialization refuses every nonempty destination, including unmarked scientific projects and existing README files.
15
+ - Explicit template initialization verifies the original placeholder metadata and preserves the previous overview and metadata in `.research/template-*` files.
16
+ - Export source/output trees must be disjoint, even with `--force`.
17
+ - Forced replacement requires a recognized, unchanged ORW export inventory. Added or edited files, symlinks/junctions, and legacy unmarked exports are not deleted.
18
+ - New export is validated in staging before replacement; the previous export is renamed aside and restored if final promotion fails.
19
+ - Open resource directories cannot silently include separately private/restricted/embargoed/unknown resources. Contradictory access declarations fail before copy.
20
+
21
+ ### Limitations
22
+
23
+ - Evaluation alpha, not a complete OSF replacement or a FAIR certification.
24
+ - Use disposable copies and exclusive access during filesystem mutations; these guards are not a sandbox against malicious concurrent path substitution.
25
+ - Export metadata may contain sensitive names or locations. Inspect before sharing; access labels do not encrypt or control filesystem access.
26
+ - A new output directory is required for exports created before inventory markers were introduced.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Damien Huzard and OpenResearchWorkspace contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,15 @@
1
+ include LICENSE README.md CHANGELOG.md pyproject.toml MANIFEST.in
2
+ recursive-include src *.py *.json *.yml
3
+ recursive-include schema *.json
4
+ recursive-include scripts *.py
5
+ recursive-include tests *.py *.json
6
+ recursive-include browser *.html *.css *.js *.py *.txt
7
+ recursive-include docs *.md
8
+ recursive-include .github/workflows *.yml
9
+ prune docs/assets
10
+ prune dist
11
+ prune build
12
+ prune .git
13
+ prune .venv
14
+ prune .orw-playwright-github
15
+ global-exclude __pycache__ *.py[cod] .DS_Store
@@ -0,0 +1,69 @@
1
+ Metadata-Version: 2.4
2
+ Name: openresearchworkspace
3
+ Version: 0.1.0a1
4
+ Summary: Local-first research workspace creation, validation, and RO-Crate export
5
+ Author: OpenResearchWorkspace contributors
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/dhuzard/OpenResearchWorkspace
8
+ Project-URL: Documentation, https://github.com/dhuzard/OpenResearchWorkspace/blob/main/docs/cli.md
9
+ Project-URL: Repository, https://github.com/dhuzard/OpenResearchWorkspace
10
+ Project-URL: Issues, https://github.com/dhuzard/OpenResearchWorkspace/issues
11
+ Project-URL: Changelog, https://github.com/dhuzard/OpenResearchWorkspace/blob/main/CHANGELOG.md
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3 :: Only
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: PyYAML<7,>=6.0
23
+ Requires-Dist: jsonschema<5,>=4.22
24
+ Dynamic: license-file
25
+
26
+ # OpenResearchWorkspace — public alpha
27
+
28
+ A local-first toolkit for creating, validating, and exporting research workspaces. Git, a hosted forge, and an AI provider are not required. The canonical scientific record is `.research/project.yml`, organized around Investigation, Study, and Assay concepts.
29
+
30
+ ## Install
31
+
32
+ Once the alpha is published:
33
+
34
+ ```bash
35
+ pipx install openresearchworkspace==0.1.0a1
36
+ ```
37
+
38
+ Alternatively, in a Python 3.10+ virtual environment:
39
+
40
+ ```bash
41
+ python -m pip install openresearchworkspace==0.1.0a1
42
+ ```
43
+
44
+ ## Use
45
+
46
+ ```bash
47
+ orw init my-study
48
+ orw validate my-study
49
+ orw validate my-study --json
50
+ orw export my-study --format ro-crate --output my-study-crate
51
+ ```
52
+
53
+ Automated initialization accepts the normalized setup contract through `--config setup.json` or `--config -` for standard input. Normal initialization requires a new or empty destination. Export destinations must be outside the source workspace. `--force` only replaces a previously marked ORW export whose files have not been added, removed, or changed.
54
+
55
+ ## Browser path
56
+
57
+ The matching standalone HTML generator is distributed separately as a versioned release asset. Open it in a browser, describe the project, review the structure and metadata, and download a workspace ZIP. Python is not required by that browser path. The ZIP is not encrypted and exporting it does not publish anything.
58
+
59
+ ## Alpha boundaries
60
+
61
+ This release is for evaluation on disposable copies. It is not a complete research-data repository, a security sandbox, or a guarantee of FAIR compliance. Initialization creates one Study and an optional first Assay. Browser editing of existing workspaces, DOI deposition, richer provenance, and agent integrations remain planned.
62
+
63
+ RO-Crate output is a local package, not a publication. Base checks are bounded to the exporter; a dedicated ORW RO-Crate Profile is not claimed. Metadata and the project README are included, so inspect them for sensitive information before sharing. Only explicitly open local resources are copied; overlapping open/restricted declarations are refused. Metadata access labels are not filesystem permissions or encryption. Mutation operations require exclusive workspace access; concurrent or hostile filesystem mutation is outside the alpha's guarantees.
64
+
65
+ ## Documentation and source
66
+
67
+ [CLI guide](https://github.com/dhuzard/OpenResearchWorkspace/blob/main/docs/cli.md) · [Browser guide](https://github.com/dhuzard/OpenResearchWorkspace/blob/main/docs/browser-generator.md) · [Release process](https://github.com/dhuzard/OpenResearchWorkspace/blob/main/docs/releases.md) · [Issues](https://github.com/dhuzard/OpenResearchWorkspace/issues)
68
+
69
+ The software is MIT licensed. Research outputs do not automatically inherit that license. ORW specification and template versions are independent of the software release version.