Skip to content
Closed
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
69 changes: 69 additions & 0 deletions .github/workflows/dimcode-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: dimcode prerelease

on:
push:
tags: ['dimcode-v*-next.*']
workflow_dispatch:

permissions:
contents: read

concurrency:
group: dimcode-prerelease
cancel-in-progress: false

jobs:
check:
strategy:
matrix:
os: [ubuntu-latest, macos-15]
runs-on: ${{ matrix.os }}
defaults:
run:
working-directory: agent
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v5
with:
node-version: '24'
cache: npm
cache-dependency-path: agent/npm-shrinkwrap.json
- run: npm ci
- run: npm run check
- run: sh -n install.sh

publish:
needs: check
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
defaults:
run:
working-directory: agent
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v5
with:
node-version: '24'
registry-url: https://registry.npmjs.org
- name: Validate release identity
run: |
node --input-type=module -e '
import fs from "node:fs";
const p = JSON.parse(fs.readFileSync("package.json"));
if (p.name !== "@spomichter/dimcode" || !/^\d+\.\d+\.\d+-next\.\d+$/.test(p.version) || process.env.GITHUB_REF !== `refs/tags/dimcode-v${p.version}`) process.exit(1);
'
- run: npm ci && npm run build
- run: npm pack
- name: Publish npm next
run: npm publish ./spomichter-dimcode-*.tgz --tag next --access public --provenance
env:
NODE_AUTH_TOKEN: ${{ secrets.DIMCODE_NPM_TOKEN }}
- name: Publish installer and package
run: |
gh release create "$GITHUB_REF_NAME" ./spomichter-dimcode-*.tgz install.sh \
--title "dimcode ${GITHUB_REF_NAME#dimcode-v}" --prerelease \
--notes 'Dimcode test release: private Node bootstrap, agent-led DimOS installation, persistent Pi sessions and inline memory visualization. Linux x64/arm64 and Apple Silicon installer; Linux and macOS package checks run before publication.'
env:
GH_TOKEN: ${{ github.token }}
47 changes: 47 additions & 0 deletions .github/workflows/dimcode.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: dimcode

on:
pull_request:
paths:
- 'agent/**'
- 'web/sdk/**'
- 'web/shared/**'
- 'web/relay/**'
- '.github/workflows/dimcode.yml'
push:
branches: [main]
paths:
- 'agent/**'
- 'web/sdk/**'
- 'web/shared/**'
- 'web/relay/**'
- '.github/workflows/dimcode.yml'

permissions: {}

jobs:
check:
runs-on: ubuntu-22.04
timeout-minutes: 15
permissions:
contents: read
defaults:
run:
working-directory: agent
steps:
- uses: actions/checkout@v7
with:
lfs: false
- uses: actions/setup-node@v7
with:
node-version: 24
cache: npm
cache-dependency-path: agent/npm-shrinkwrap.json
- uses: denoland/setup-deno@v2
with:
deno-version: v2.6.10
- run: npm ci
- run: npm run check
env:
DIMCODE_TEST_DENO: deno
Comment on lines +44 to +46

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Run Python MCP Coverage

The workflow sets DIMCODE_TEST_DENO but not DIMCODE_TEST_PYTHON, so the real DimOS MCP image and error interoperability test is skipped. It also does not run for dimos/** changes. This is non-blocking, but changes at the Node/Python MCP boundary can merge without exercising their integration; provision Python, set DIMCODE_TEST_PYTHON, and include the relevant DimOS paths.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Artifacts

Evidence from the check

  • The authored non-product shell harness compiles the checked-in test, runs its workflow-equivalent and Python-enabled variants, and evaluates the literal workflow paths; it provides reproducible validation.

Command output from the check

  • The focused Node test ran from `agent` with Deno set and Python unset, matching the workflow's integration environment; it reports one skipped test, proving the Python MCP coverage does not execute.

Command output from the check

  • The same Node test ran with the repository Python image and passed the real DimOS handlers, image, and isError flow; the appended workflow check shows a DimOS MCP source change does not match configured paths.

View artifacts

T-Rex Ran code and verified through T-Rex

- run: npm pack
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
[Hardware](#hardware) •
[Installation](#installation) •
[Agent CLI & MCP](#agent-cli-and-mcp) •
[dimcode terminal agent](agent/README.md) •
[Blueprints](#blueprints) •
[dimTELE: Remote Teleop](#dimtele-remote-teleop) •
[Development](#development)
Expand Down
1 change: 1 addition & 0 deletions agent/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
npm-shrinkwrap.json -diff linguist-generated
4 changes: 4 additions & 0 deletions agent/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules/
dist/
*.tgz
.test/
17 changes: 17 additions & 0 deletions agent/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/

Copyright 2025 Dimensional Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
176 changes: 176 additions & 0 deletions agent/README.md

Large diffs are not rendered by default.

23 changes: 23 additions & 0 deletions agent/build.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { build } from "esbuild";
import { chmod, mkdir, rm } from "node:fs/promises";
import { resolve } from "node:path";

await rm("dist", { recursive: true, force: true });
await mkdir("dist", { recursive: true });
await build({
entryPoints: ["src/main.ts"],
outdir: "dist",
bundle: true,
platform: "node",
target: "node24",
format: "esm",
packages: "external",
sourcemap: true,
alias: {
"@dimos/sdk": resolve("../web/sdk/src/index.ts"),
"@dimos/shared/manifest": resolve("../web/shared/manifest.ts"),
"@dimos/shared": resolve("../web/shared/protocol.ts"),
},
banner: { js: "#!/usr/bin/env node" },
});
await chmod("dist/main.js", 0o755);
96 changes: 96 additions & 0 deletions agent/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#!/bin/sh
# Installs the harness only. DimOS installation belongs to the agent's skill.
set -eu

main() {
package='@spomichter/dimcode'
version=${DIMCODE_VERSION:-next}
data=${DIMCODE_INSTALL_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/dimcode}
bin=${DIMCODE_BIN_DIR:-$HOME/.local/bin}
case "$data:$bin" in /*:/*) ;; *) echo 'Install directories must be absolute.' >&2; exit 1 ;; esac
case "$(uname -s)-$(uname -m)" in
Linux-x86_64) platform=linux-x64 ;;
Linux-aarch64|Linux-arm64) platform=linux-arm64 ;;
Darwin-arm64) platform=darwin-arm64 ;;
*) echo 'This prerelease supports Linux x64/arm64 and Apple Silicon.' >&2; exit 1 ;;
esac
case "$version" in ''|*[!a-zA-Z0-9._-]*) echo 'Invalid DIMCODE_VERSION.' >&2; exit 1 ;; esac
command -v curl >/dev/null || { echo 'curl is required.' >&2; exit 1; }
mkdir -p "$data" "$bin"
staging=$(mktemp -d "$data/.install.XXXXXX")
trap 'rm -rf "$staging"' EXIT
trap 'exit 130' INT
trap 'exit 143' TERM
printf '\ndimcode · Install your Dimensional agent\n\n'

node="$data/node/bin/node"
if ! "$node" -e 'process.exit(+process.versions.node.split(".")[0] === 24 ? 0 : 1)' 2>/dev/null; then
dist=https://nodejs.org/dist/latest-v24.x
printf 'Installing a private Node 24 runtime…\n'
curl -fsSL "$dist/SHASUMS256.txt" -o "$staging/checksums"
archive=$(awk -v suffix="-$platform.tar.gz" '$2 ~ /^node-v[0-9.]+-/ && substr($2,length($2)-length(suffix)+1)==suffix {print $2; exit}' "$staging/checksums")
[ -n "$archive" ] || { echo 'No compatible Node archive found.' >&2; exit 1; }
curl -fsSL "$dist/$archive" -o "$staging/$archive"
awk -v file="$archive" '$2==file {print}' "$staging/checksums" > "$staging/selected.sha256"
if command -v sha256sum >/dev/null 2>&1; then
(cd "$staging" && sha256sum -c selected.sha256)
elif command -v shasum >/dev/null 2>&1; then
(cd "$staging" && shasum -a 256 -c selected.sha256)
else
echo 'sha256sum or shasum is required to verify Node.' >&2; exit 1
fi
tar -xzf "$staging/$archive" -C "$staging"
if [ -e "$data/node" ] || [ -L "$data/node" ]; then
echo "Existing runtime at $data/node is unusable; choose another DIMCODE_INSTALL_DIR." >&2
exit 1
fi
mv "$staging/${archive%.tar.gz}" "$data/node"
fi
PATH="$data/node/bin:$PATH"
export PATH
npm="$data/node/bin/npm"
curl -fsSL "https://registry.npmjs.org/$package/$version" -o "$staging/metadata.json"
resolved=$("$node" -p 'JSON.parse(require("node:fs").readFileSync(process.argv[1])).version' "$staging/metadata.json")
case "$resolved" in ''|*[!a-zA-Z0-9._-]*) echo 'Invalid package version from registry.' >&2; exit 1 ;; esac
release="$data/releases/$resolved"
entry="$release/node_modules/$package/dist/main.js"
if [ ! -f "$entry" ]; then
printf 'Installing %s@%s…\n' "$package" "$resolved"
tarball=$("$node" -p 'JSON.parse(require("node:fs").readFileSync(process.argv[1])).dist.tarball' "$staging/metadata.json")
case "$tarball" in https://registry.npmjs.org/*) ;; *) echo 'Unexpected package registry.' >&2; exit 1 ;; esac
curl -fsSL "$tarball" -o "$staging/dimcode.tgz"
"$node" - "$staging/metadata.json" "$staging/dimcode.tgz" "$package" <<'NODE'
const fs = require('node:fs');
const crypto = require('node:crypto');
const metadata = JSON.parse(fs.readFileSync(process.argv[2]));
const actual = 'sha512-' + crypto.createHash('sha512').update(fs.readFileSync(process.argv[3])).digest('base64');
if (metadata.name !== process.argv[4] || actual !== metadata.dist.integrity) throw new Error('Package integrity check failed');
NODE
"$npm" install --prefix "$staging/package" --ignore-scripts --min-release-age=0 --omit=dev --no-audit --no-fund "$staging/dimcode.tgz"
"$node" "$staging/package/node_modules/$package/dist/main.js" --help >/dev/null
mkdir -p "$data/releases"
[ ! -e "$release" ] || { echo "Incomplete release at $release; choose another DIMCODE_INSTALL_DIR." >&2; exit 1; }
mv "$staging/package" "$release"
fi
"$node" - "$bin/dimcode" "$node" "$entry" <<'NODE'
const fs = require('node:fs');
const [dest, node, entry] = process.argv.slice(2);
const quote = (value) => "'" + value.replaceAll("'", "'\\''") + "'";
const temporary = `${dest}.install-${process.pid}`;
fs.writeFileSync(temporary, `#!/bin/sh\nexec ${quote(node)} ${quote(entry)} "$@"\n`, { mode: 0o755, flag: 'wx' });
fs.renameSync(temporary, dest);
NODE
printf '\nInstalled %s@%s\n' "$package" "$resolved"
case ":${PATH}:" in
*":$bin:"*) printf 'Run: dimcode setup\nThen: dimcode\n' ;;
*) printf 'Run: %s/dimcode setup\nAdd %s to your shell PATH to use the short command.\n' "$bin" "$bin" ;;
esac
printf 'No daemon or robot was started. Setup asks about gateway startup.\n'
if [ "${DIMCODE_SETUP:-1}" = 1 ] && ( : </dev/tty ) 2>/dev/null; then
printf '\nOpen interactive setup now? [Y/n] ' >/dev/tty
IFS= read -r answer </dev/tty || answer=n
case "$answer" in n|N|no|NO) ;; *) "$bin/dimcode" setup </dev/tty ;; esac
fi
}

main "$@"
Loading
Loading