Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions .github/workflows/vscode-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,34 @@ jobs:
name: vscode-publication-${{ github.sha }}
path: vs-code-terraphim-it/publication.json
if-no-files-found: error
marketplace:
marketplace-plan:
needs: release
runs-on: ubuntu-24.04
outputs:
registries: ${{ steps.plan.outputs.registries }}
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
with:
persist-credentials: false
- name: Report disabled targets and plan explicitly enabled attempts
id: plan
env:
VSCODE_PUBLISH_VISUAL_STUDIO_MARKETPLACE: ${{ vars.VSCODE_PUBLISH_VISUAL_STUDIO_MARKETPLACE }}
VSCODE_PUBLISH_OPEN_VSX: ${{ vars.VSCODE_PUBLISH_OPEN_VSX }}
run: python3 vs-code-terraphim-it/scripts/plan_marketplaces.py --receipt marketplace-plan.json
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
if: always()
with:
name: vscode-marketplace-plan-${{ github.sha }}
path: marketplace-plan.json
if-no-files-found: error
marketplace:
needs: [release, marketplace-plan]
if: needs.marketplace-plan.outputs.registries != '[]' && needs.marketplace-plan.outputs.registries != ''
strategy:
fail-fast: false
matrix:
registry: [visual-studio-marketplace, open-vsx]
registry: ${{ fromJSON(needs.marketplace-plan.outputs.registries) }}
runs-on: ubuntu-24.04
environment: ${{ matrix.registry }}
permissions:
Expand Down
7 changes: 7 additions & 0 deletions vs-code-terraphim-it/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## 0.1.1 (preview)

- Bundle the verified editor v0.1.0-rc.2 release built with public Terraphim crate dependencies.
- Check the editor release manifest against its pinned source commit before importing any assets.
- Verify and retain the public source repository and Cargo.lock checksum when the editor release supplies them.
- Publish the qualified GitHub VSIX independently of marketplace setup; disabled marketplace targets are explicitly reported as not published.

## 0.1.0 (preview)

- Extend the existing Terraphim It extension with the shared Alternative Control Markdown editor.
Expand Down
15 changes: 13 additions & 2 deletions vs-code-terraphim-it/README-alternative-control.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
# Alternative Control in the existing Terraphim It extension

Version 0.1.0 is an opt-in custom Markdown editor in `applied-knowledge-systems.terraphim-it`. Open a Markdown file with **Terraphim: Open Alternative Control**. Click the word counter for Write_On. Existing server and Atomic commands remain available in trusted workspaces.
This preview is an opt-in custom Markdown editor in `applied-knowledge-systems.terraphim-it`. Open a Markdown file with **Terraphim: Open Alternative Control**. Click the word counter for Write_On. Existing server and Atomic commands remain available in trusted workspaces.

The view bundles the released terraphim-editor v0.1.0-rc.1 UI, WASM and source-pinned host bridge. Each view has its own session; VS Code owns document revisions, persistence and undo/redo. Exact source/revision checks protect asynchronous proposals. External edits retain conflicting drafts for recovery. Native export refuses the source itself and dirty output buffers. Browser persistence is disabled in this host.
The view bundles the released terraphim-editor v0.1.0-rc.2 UI, WASM and source-pinned host bridge. The bundle records its public source repository and Cargo.lock checksum. Each view has its own session; VS Code owns document revisions, persistence and undo/redo. Exact source/revision checks protect asynchronous proposals. External edits retain conflicting drafts for recovery. Native export refuses the source itself and dirty output buffers. Browser persistence is disabled in this host.

**Export Document Knowledge Graph** waits for the current edit to be acknowledged, reads that exact source, and uses the shared Rust `synonyms::` parser/types to create the portable graph. It refuses malformed annotations or ambiguous concepts. The document and active role are unchanged. Save, undo, redo and reopen determine which aliases exist in the export.

A fresh checkout runs `npm ci --ignore-scripts`, `npm run editor:fetch`, `npm run compile`, `npm run lint`, `npm run test:assets`, `npm run test:host`, `npm run test:export`, then `npm run package:vsix`. Release inputs are pinned by URL/commit/SHA-256 in `editor-release.json`; every imported file is checked. Runtime dependencies are included. Generated binaries stay out of Git.

CI builds one VSIX and tests that package in native Linux, macOS and Windows VS Code profiles. Tag release and marketplace workflows promote the same verified package. Publisher identity setup is documented in `docs/plans/design-extension-marketplaces.md` in the repository.

The GitHub preview release does not depend on marketplace account setup. After
its exact package passes qualification and anonymous download verification,
`vscode-release.yml` reads the repository readiness variables
`VSCODE_PUBLISH_VISUAL_STUDIO_MARKETPLACE` and `VSCODE_PUBLISH_OPEN_VSX`.
Unset or `false` skips that marketplace and records `NOT_PUBLISHED` in the run
summary and `vscode-marketplace-plan-*` artifact. Only exact `true` schedules
an attempt; other values refuse all attempts. Set a gate only after its existing
publisher, protected environment and federated identity are ready. Enabled
targets remain `PENDING_PUBLICATION` until the separate registry readback passes.
These gates do not create access, weaken tag policies or provide a PAT fallback.

Acceptance reports distinguish actual saved files, engine tests and visual UI checks. The original 41 visual requirements are not all accepted. This is a scoped preview; stock Zed visual limitations and the separate Zed fork remain outside this VSIX's claims.
18 changes: 10 additions & 8 deletions vs-code-terraphim-it/editor-release.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
{
"release": "https://github.com/terraphim/terraphim-editor/releases/tag/v0.1.0-rc.1",
"sourceCommit": "05d0aa50151c131db4a3b30b56aba67c00add5fc",
"release": "https://github.com/terraphim/terraphim-editor/releases/tag/v0.1.0-rc.2",
"sourceCommit": "25ad3b16a1bebab6edd767a7efd1ace7b25c82ad",
"archive": {
"name": "editor-candidate.tar.gz",
"url": "https://github.com/terraphim/terraphim-editor/releases/download/v0.1.0-rc.1/editor-candidate.tar.gz",
"sha256": "a514f45276397b93f38d8e14c9e3bde6203bd9c625bc13c81829de31ffa9eb79"
"url": "https://github.com/terraphim/terraphim-editor/releases/download/v0.1.0-rc.2/editor-candidate.tar.gz",
"sha256": "daa104aecdca43df5ca6dcf36b420351be09784a8436ab61bd3fc9acb1504e73"
},
"manifest": {
"name": "assets-manifest.json",
"url": "https://github.com/terraphim/terraphim-editor/releases/download/v0.1.0-rc.1/assets-manifest.json",
"sha256": "d8d65165263c237f4c3c65d97b69b1083850daaea556fcd9a01241758ec2a4a7"
"url": "https://github.com/terraphim/terraphim-editor/releases/download/v0.1.0-rc.2/assets-manifest.json",
"sha256": "4331adf222fedeeba04eb5986878bb4011f833e051b1a4f484274302ae4465a3"
},
"bridge": {
"name": "host-session.js",
"url": "https://raw.githubusercontent.com/terraphim/terraphim-editor/05d0aa50151c131db4a3b30b56aba67c00add5fc/public/js/host-session.js",
"url": "https://raw.githubusercontent.com/terraphim/terraphim-editor/25ad3b16a1bebab6edd767a7efd1ace7b25c82ad/public/js/host-session.js",
"sha256": "9e5efc4c3f1f2003cd86f05b266b6666e546c68a065eaca67c897c2328a09388"
}
},
"sourceRepository": "https://github.com/terraphim/terraphim-editor",
"cargoLockSha256": "b485926b2353bd8d045d6ba252247b05dd302c5211fbc8f63602fa0c5b91c24b"
}
22 changes: 12 additions & 10 deletions vs-code-terraphim-it/media/editor-build.json
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
{
"protocol": 1,
"sourceHead": "05d0aa50151c131db4a3b30b56aba67c00add5fc",
"release": "https://github.com/terraphim/terraphim-editor/releases/tag/v0.1.0-rc.1",
"archiveSha256": "a514f45276397b93f38d8e14c9e3bde6203bd9c625bc13c81829de31ffa9eb79",
"sourceHead": "25ad3b16a1bebab6edd767a7efd1ace7b25c82ad",
"release": "https://github.com/terraphim/terraphim-editor/releases/tag/v0.1.0-rc.2",
"archiveSha256": "daa104aecdca43df5ca6dcf36b420351be09784a8436ab61bd3fc9acb1504e73",
"assets": {
"alternatives-panel-f7a68a7707d04dfa.css": "a99a407d3f6aa52f48e3013bf865ef4b44bd0b9e4028d9e68c1a6dd32f8a68a8",
"blocks-b2480c8f9f3d63b3.css": "383c0e9197f015d651363e3abd31fdf67b56a6b4bde72ebe764a7b1e417c5b4c",
"example.html": "fda475be8b87ff7a0789f167b4906357c3d8d7e7d1fcd0348f8c908d65e731d3",
"host-session.js": "9e5efc4c3f1f2003cd86f05b266b6666e546c68a065eaca67c897c2328a09388",
"index.html": "3092fd19c610baface73dccee3c70de285b4c11850b2827f947943027e72ae1b",
"index.html": "a9334870599b5656b377655bf78a066bd526aa430d4eefa4e1bdba4c3062e3d7",
"js/rolegraph-worker.js": "8240803c0aef05acd66b6ec91eaee16e53a556252aa48c8487a4c3bd9a8924d9",
"lab-3fee6e89acf44fa1.css": "1fe0441a83177e9713ac112fac85336ad3315b3ac755ec8a625e008c4ca1f967",
"overflow-cc1be2ca3843f438.css": "8fa1a611df91541508b1532d3628addffecec02b2516a3f7a2c98bc385ada218",
"persistence-c4310be97ce197ef.css": "2d9825e27391a177e65032952923eb03f505fa95f86590f98e24f753fa2ba660",
"rolegraph/rolegraph-worker.js": "8240803c0aef05acd66b6ec91eaee16e53a556252aa48c8487a4c3bd9a8924d9",
"rolegraph/terraphim_rolegraph_browser.d.ts": "95094622b3805fed54e96cdcbb1c732d1244fbecceadb24dd13e0f28c1d8f7e2",
"rolegraph/terraphim_rolegraph_browser.js": "0f155f7ebe48ffd9958266c153f965447f98e26724e8fa994d1e18d879a9f4dc",
"rolegraph/terraphim_rolegraph_browser_bg.wasm": "7002fd7e4614ae03acc1593c7225fc82d586641ee96d991780339244ed5eea8a",
"rolegraph/terraphim_rolegraph_browser_bg.wasm": "128bf553be2185e2140e68dcd47ff4127aeed47ea49fcf1dae942b99ac84a0d1",
"rolegraph/terraphim_rolegraph_browser_bg.wasm.d.ts": "f6cc0427ac07ca31fc3882c5f9487347717f887a0c9ebba69a1323eda3a822ea",
"roles/default.json": "e850422ec72faa06aae0d6c2893a9f1d2e36d60a5aef79bd8f863daa2d71b015",
"selection-menu-317cedafb0e3952e.css": "7d0790ed1bf0c6e3955e5305d31ace2bd67f6df5f5f2b7be9692f9c79843891e",
"terraphim-editor-438d353659f8cd7.js": "6f55bfce550053ab0cd8a1f4ffd101436f9de3e2610702269ed53bf0dc2ca7cd",
"terraphim-editor-438d353659f8cd7_bg.wasm": "f167a40fb0934703269a3bfe34adcfbc28994933f939f03bab7bf59425021dc6",
"terraphim-editor-2718c4e298c1b7b6.js": "9ccd7ddee55764ca47067c809d6dbf9881843b6649fd3a8677871df0e5601b24",
"terraphim-editor-2718c4e298c1b7b6_bg.wasm": "93796edac11424d45457a77c3e635d5d59b139c21a08bf09126c88c5ed28ea18",
"terraphim-editor.min.css": "147cd5ce172f00873b002ac215b004631c7c17aaadf23fb7c786a90628dfe1f3",
"terraphim-editor.min.js": "a650ab15ac36d0868268099175d60da1e228283fc0f2a46b61dd1fa752ef4fba",
"terraphim_editor.js": "6f55bfce550053ab0cd8a1f4ffd101436f9de3e2610702269ed53bf0dc2ca7cd",
"terraphim_editor_bg.wasm": "f167a40fb0934703269a3bfe34adcfbc28994933f939f03bab7bf59425021dc6",
"terraphim_editor.js": "9ccd7ddee55764ca47067c809d6dbf9881843b6649fd3a8677871df0e5601b24",
"terraphim_editor_bg.wasm": "93796edac11424d45457a77c3e635d5d59b139c21a08bf09126c88c5ed28ea18",
"tokens-36540e1e0e83eb54.css": "71e359d23d7ec44c9c838f74cf77f6e33aa3c33c57757cfc4cfb96e22a09de55",
"trim-a64aceacb4246fba.css": "fe79acb70b9906e404d30e19b7d5e1cf6589bc0aa155f1c1dc93ed18e6dee81d",
"vendor/fontawesome/6.5.2/LICENSE.txt": "9b914eae88817d63b576eab5aafde7068c7a1abae125d7cdfb034f1da43a9afc",
Expand Down Expand Up @@ -138,5 +138,7 @@
"vendor/shoelace/2.12.0/third-party-notices/shoelace-style_localize/LICENSE.md": "ac9ffacbfc877b6f4253a481b3c0edbad0c019ac3506a3b51415b336f4a0c054",
"write-on-6a8fd9449457dd74.css": "bd3b7471c8a7ba32c38927d47eefe26e5680ffa6ec96262380f4cf383340674c"
},
"qualification": "Released editor assets; host acceptance is separate"
"qualification": "Released editor assets; host acceptance is separate",
"sourceRepository": "https://github.com/terraphim/terraphim-editor",
"cargoLockSha256": "b485926b2353bd8d045d6ba252247b05dd302c5211fbc8f63602fa0c5b91c24b"
}
4 changes: 2 additions & 2 deletions vs-code-terraphim-it/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion vs-code-terraphim-it/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "terraphim-it",
"displayName": "Terraphim It",
"description": "Intelligent Markdown editor with alternatives, knowledge-graph synonyms and role-based suggestions",
"version": "0.1.0",
"version": "0.1.1",
"publisher": "applied-knowledge-systems",
"private": true,
"license": "Apache-2.0",
Expand Down
78 changes: 78 additions & 0 deletions vs-code-terraphim-it/scripts/plan_marketplaces.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#!/usr/bin/env python3
"""Plan explicit marketplace attempts after the independent GitHub release."""
import argparse
import json
import os
from pathlib import Path
import re

from verify_vsix import check_tag

ROOT = Path(__file__).resolve().parents[1]
TARGETS = (
("visual-studio-marketplace", "VSCODE_PUBLISH_VISUAL_STUDIO_MARKETPLACE"),
("open-vsx", "VSCODE_PUBLISH_OPEN_VSX"),
)


def plan(environment):
"""Unset gates skip publication; malformed gates refuse every target."""
report = {"schema": 1, "scope": "Publication routing only; live registry readback is separate",
"registries": [], "targets": [], "configurationValid": True}
for registry, flag in TARGETS:
value = environment.get(flag, "")
valid = value in ("", "false", "true")
enabled = value == "true"
report["configurationValid"] &= valid
report["targets"].append({
"registry": registry, "readinessVariable": flag,
"status": "PENDING_PUBLICATION" if enabled else "NOT_PUBLISHED",
"reason": "Explicit readiness gate enabled; publication/readback still required"
if enabled else "Readiness gate is unset or disabled",
})
if enabled:
report["registries"].append(registry)
if not report["configurationValid"]:
report["registries"] = []
for target in report["targets"]:
target.update(status="NOT_PUBLISHED", reason="Invalid readiness configuration; all attempts refused")
return report


def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--receipt", type=Path, required=True)
args = parser.parse_args()
report = plan(os.environ)
source = os.environ.get("GITHUB_SHA", "")
tag = os.environ.get("GITHUB_REF_NAME", "")
try:
check_tag(tag, json.loads((ROOT / "package.json").read_text())["version"])
if re.fullmatch(r"[0-9a-f]{40}", source) is None:
raise ValueError("Expected exact GitHub source commit")
except ValueError:
report["configurationValid"] = False
report["registries"] = []
for target in report["targets"]:
target.update(status="NOT_PUBLISHED", reason="Invalid release identity; all attempts refused")
else:
report.update(sourceCommit=source, tag=tag)
# Retain failed/disabled plans as evidence. Never overwrite an earlier plan.
with args.receipt.open("x") as output:
output.write(json.dumps(report, indent=2) + "\n")
if path := os.environ.get("GITHUB_OUTPUT"):
with Path(path).open("a") as output:
output.write("registries=" + json.dumps(report["registries"], separators=(",", ":")) + "\n")
summary = "Marketplace readiness (not publication verification):\n\n" + "\n".join(
f"- {target['registry']}: **{target['status']}** — {target['reason']}"
for target in report["targets"]
) + "\n"
if path := os.environ.get("GITHUB_STEP_SUMMARY"):
with Path(path).open("a") as output:
output.write(summary)
print(summary, end="")
return 0 if report["configurationValid"] else 1


if __name__ == "__main__":
raise SystemExit(main())
36 changes: 35 additions & 1 deletion vs-code-terraphim-it/scripts/released_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@
import io
import json
from pathlib import Path, PurePosixPath
import re
import tarfile
import tempfile
import urllib.request

from editor_assets import ROOT, import_assets, verify

LOCK = ROOT / "editor-release.json"
PUBLIC_REPOSITORY = "https://github.com/terraphim/terraphim-editor"
PROVENANCE_FIELDS = ("sourceRepository", "cargoLockSha256")


def checked(data, digest):
Expand All @@ -21,9 +24,37 @@ def checked(data, digest):
return data


def release_manifest(raw, source):
"""Bind archive metadata to the reviewed source pin before writing assets."""
manifest = json.loads(raw)
if not isinstance(manifest, dict) or not isinstance(source, dict):
raise ValueError("Invalid released editor manifest or source pin")
head = source.get("sourceCommit")
assets = manifest.get("assets")
if (type(manifest.get("schema")) is not int or manifest["schema"] != 1
or not isinstance(head, str) or re.fullmatch(r"[0-9a-f]{40}", head) is None
or manifest.get("sourceHead") != head
or not isinstance(assets, dict) or not assets
or any(not isinstance(digest, str) or re.fullmatch(r"[0-9a-f]{64}", digest) is None
for digest in assets.values())):
raise ValueError("Released editor manifest identity or asset digests mismatch")
# Historical RC1 has no public-dependency receipt. A newer manifest must
# carry both fields and match an explicit source pin; do not silently drop
# the Cargo lock identity or relabel older bytes as a public-crates build.
if any(key in manifest or key in source for key in PROVENANCE_FIELDS):
lock = manifest.get("cargoLockSha256")
if (manifest.get("sourceRepository") != PUBLIC_REPOSITORY
or source.get("sourceRepository") != PUBLIC_REPOSITORY
or not isinstance(lock, str) or re.fullmatch(r"[0-9a-f]{64}", lock) is None
or source.get("cargoLockSha256") != lock):
raise ValueError("Released editor public dependency provenance mismatch")
return manifest


def materialize(archive, manifest, bridge, destination, source):
"""Validate the entire archive before writing only regular admitted files."""
assets = json.loads(manifest)["assets"]
metadata = release_manifest(manifest, source)
assets = metadata["assets"]
files = {}
total = 0
with tarfile.open(fileobj=io.BytesIO(archive), mode="r:gz") as bundle:
Expand Down Expand Up @@ -53,6 +84,9 @@ def materialize(archive, manifest, bridge, destination, source):
"assets": {name: hashlib.sha256(data).hexdigest()
for name, data in sorted(files.items())},
"qualification": "Released editor assets; host acceptance is separate"}
for key in PROVENANCE_FIELDS:
if key in metadata:
lock[key] = metadata[key]
(destination / "host-assets.json").write_text(json.dumps(lock, indent=2) + "\n")
verify(destination)

Expand Down
Loading
Loading