Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
3c6d28b
feat(install): add Codex CLI and plugin preflight checks for --agent …
May 23, 2026
d610d60
feat(install): add codex-checks module with CLI/npm/registration checks
May 23, 2026
521d0f6
feat(install): add resolvePluginId shared utility to codex-checks
May 23, 2026
3ca2006
feat(doctor): export Check, CHECK_REGISTRY, and runDoctorChecks helper
May 23, 2026
cae25cb
feat(install): extend AgentName with codex, add stepRegisterCodexPlugin
May 23, 2026
06d7a66
feat(codex): add switchbot codex doctor subcommand
May 23, 2026
9545ad9
feat(install): add codex agent path routing to stepRegisterCodexPlugin
May 23, 2026
0e4c28c
feat(codex): add switchbot codex repair subcommand
May 23, 2026
7582361
feat(codex): register codex command in program-builder and add COMMAN…
May 23, 2026
8013bda
refactor(codex): extract credentialsPresent helper, share resolveCode…
May 23, 2026
c066238
feat(codex): hint repair command when doctor reports warn or fail
May 23, 2026
0582d75
docs(spec): codex install paths design — setup subcommand + AGENTS.md…
May 23, 2026
4e3050c
docs(spec): fix 4 consistency issues in codex-commands design
May 23, 2026
a4bab08
docs(spec): fix 5 remaining consistency issues + add 3 test cases in …
May 23, 2026
c7a5723
docs(codex): align spec drift on doctor-verify, auth argv, register h…
May 23, 2026
4d73f53
fix(codex): tighten install warnings and extract registerCodexPlugin …
May 23, 2026
c760cec
feat(codex): add codex setup subcommand and route repair through shar…
May 23, 2026
9d67815
docs(readme): add Codex integration quick start section
May 23, 2026
5bd10f5
docs(spec): monorepo migration design — absorb codex-plugin and openc…
May 23, 2026
e2684b8
docs(spec): fix 3 design issues in monorepo migration — workspace:*, …
May 23, 2026
c5fbacd
feat(monorepo): consolidate codex-plugin via npm workspaces
May 23, 2026
e79a991
feat(monorepo): import openclaw-skill as workspace package
May 23, 2026
685b755
ci(publish): per-package matrix and detect-versions gate for monorepo
May 23, 2026
a577cab
ci(publish): defer @switchbot/openclaw-skill npm publish
May 23, 2026
71851c0
feat(codex): 6-step setup adds install-codex-plugin; onInstall is bes…
May 23, 2026
86a449e
fix(codex): junction workaround for @-path; ship corrected marketplac…
May 23, 2026
1cf02cb
test(codex): add pack-install smoke for codex plugin tarball
May 23, 2026
2a75c94
fix(codex): stable Windows junction alias; add stage field to Registr…
May 23, 2026
75f5b4a
fix(codex): relocate Windows alias to LOCALAPPDATA and repair stale j…
May 23, 2026
1e3945a
fix(codex-plugin): mirror alias-relocation logic in install.js
May 23, 2026
99fa2a5
docs(changelog): describe final alias path and repair behavior
May 23, 2026
8ada5e5
test(openclaw-skill): use 127.0.0.1 in policy-editor fetch URLs
May 23, 2026
73ec2f0
fix: publish openclaw-skill and fix Windows .cmd shim invocations
May 23, 2026
e9b8bf6
fix(auth): release callback port immediately when open() throws
May 23, 2026
12c1dea
fix(codex): pre-remove plugin before add to avoid Windows backup ACCE…
May 23, 2026
b187e03
test(codex-checks): add plugin-remove mock slot in registration tests
May 23, 2026
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
32 changes: 1 addition & 31 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ jobs:
exit 1
fi
- run: npm test
- run: npm run test:workspaces

bundle-smoke:
name: esbuild bundle smoke test (Node ${{ matrix.node-version }})
Expand Down Expand Up @@ -145,34 +146,3 @@ jobs:
- run: npm run build
- name: npm pack -> npm install tarball -> switchbot --version / policy new / policy validate
run: npm run smoke:pack-install

policy-schema-sync:
name: Policy schema sync with skill repo
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v4
- name: Fetch skill repo's mirrored schema
run: |
HTTP=$(curl -o /tmp/skill-policy.schema.json -w "%{http_code}" -fsSL --retry 3 \
https://raw.githubusercontent.com/OpenWonderLabs/openclaw-switchbot-skill/main/examples/policy.schema.json \
2>/dev/null || echo "000")
if [ "$HTTP" = "404" ] || [ "$HTTP" = "000" ]; then
echo "SKIP: skill repo schema not yet published (HTTP $HTTP). Skipping drift check."
exit 0
fi
if [ "$HTTP" != "200" ]; then
echo "WARN: unexpected HTTP $HTTP fetching skill schema. Skipping drift check."
exit 0
fi
echo "Fetched skill schema (HTTP $HTTP). Diffing against CLI v0.2 source of truth..."
if ! diff -u /tmp/skill-policy.schema.json src/policy/schema/v0.2.json; then
echo ""
echo "FAIL: policy schema drift detected."
echo " CLI source: src/policy/schema/v0.2.json"
echo " Skill copy: https://github.com/OpenWonderLabs/openclaw-switchbot-skill/blob/main/examples/policy.schema.json"
echo ""
echo "Sync the skill's examples/policy.schema.json from the CLI file and cut a matching skill release."
exit 1
fi
echo "OK: policy schema matches skill repo."
143 changes: 115 additions & 28 deletions .github/workflows/npm-published-smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ on:
types: [completed]
workflow_dispatch:
inputs:
package:
description: 'Package to verify (defaults: matrix runs all published packages)'
required: false
version:
description: 'Published npm version to verify (defaults to package.json from checked-out commit)'
required: false
Expand All @@ -19,6 +22,16 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
fail-fast: false
matrix:
include:
- package: '@switchbot/openapi-cli'
version_path: 'package.json'
kind: cli
- package: '@switchbot/codex-plugin'
version_path: 'packages/codex-plugin/package.json'
kind: plugin
steps:
- uses: actions/checkout@v4
with:
Expand All @@ -29,81 +42,110 @@ jobs:
node-version: 20.x
registry-url: https://registry.npmjs.org

- name: Verify credentials present
- name: Verify npm token present
env:
TOKEN: ${{ secrets.SWITCHBOT_TOKEN }}
SECRET: ${{ secrets.SWITCHBOT_SECRET }}
TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
if [ -z "$TOKEN" ] || [ -z "$SECRET" ]; then
echo "SWITCHBOT_TOKEN / SWITCHBOT_SECRET not set in repo secrets"
if [ -z "$TOKEN" ]; then
echo "NPM_TOKEN not set in repo secrets"
exit 1
fi

- name: Verify npm token present
- name: Verify SwitchBot credentials present (cli only)
if: matrix.kind == 'cli'
env:
TOKEN: ${{ secrets.NPM_TOKEN }}
TOKEN: ${{ secrets.SWITCHBOT_TOKEN }}
SECRET: ${{ secrets.SWITCHBOT_SECRET }}
run: |
if [ -z "$TOKEN" ]; then
echo "NPM_TOKEN not set in repo secrets"
if [ -z "$TOKEN" ] || [ -z "$SECRET" ]; then
echo "SWITCHBOT_TOKEN / SWITCHBOT_SECRET not set in repo secrets (required for cli live smoke)"
exit 1
fi

- name: Resolve target version
id: version
env:
VERSION_PATH: ${{ matrix.version_path }}
INPUT_VERSION: ${{ inputs.version }}
INPUT_PACKAGE: ${{ inputs.package }}
MATRIX_PACKAGE: ${{ matrix.package }}
run: |
if [ -n "${{ inputs.version }}" ]; then
VERSION="${{ inputs.version }}"
# workflow_dispatch with explicit package: skip other matrix entries.
if [ -n "$INPUT_PACKAGE" ] && [ "$INPUT_PACKAGE" != "$MATRIX_PACKAGE" ]; then
echo "skip=true" >> "$GITHUB_OUTPUT"
echo "Skipping $MATRIX_PACKAGE — workflow_dispatch targeted $INPUT_PACKAGE"
exit 0
fi
if [ -n "$INPUT_VERSION" ] && [ -n "$INPUT_PACKAGE" ]; then
VERSION="$INPUT_VERSION"
else
VERSION=$(node -p "require('./package.json').version")
VERSION=$(node -p "require('./$VERSION_PATH').version")
fi
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "target_version=$VERSION"
echo "skip=false" >> "$GITHUB_OUTPUT"
echo "target_version=$VERSION ($MATRIX_PACKAGE)"

- name: Resolve current latest dist-tag
if: steps.version.outputs.skip != 'true'
id: latest
env:
PACKAGE: ${{ matrix.package }}
run: |
LATEST=$(npm view @switchbot/openapi-cli dist-tags.latest)
LATEST=$(npm view "$PACKAGE" dist-tags.latest 2>/dev/null || echo "")
echo "version=$LATEST" >> "$GITHUB_OUTPUT"
echo "current_latest=$LATEST"

- name: Wait for npm package to become available
if: steps.version.outputs.skip != 'true'
id: wait_package
env:
VERSION: ${{ steps.version.outputs.version }}
PACKAGE: ${{ matrix.package }}
run: |
for i in $(seq 1 24); do
if [ "${{ github.event_name }}" = "workflow_run" ]; then
FOUND=$(npm view "@switchbot/openapi-cli@next" version 2>/dev/null || true)
FOUND=$(npm view "${PACKAGE}@next" version 2>/dev/null || true)
if [ "$FOUND" = "$VERSION" ]; then
echo "npm package is available on next: $FOUND"
exit 0
fi
echo "waiting for @switchbot/openapi-cli@$VERSION to appear on npm dist-tag next ($i/24); current next=$FOUND"
# Tolerate the case where this matrix entry's package wasn't republished
# in this release (publish.yml's detect-versions step skipped it).
FOUND_AT_VERSION=$(npm view "${PACKAGE}@${VERSION}" version 2>/dev/null || true)
if [ "$FOUND_AT_VERSION" = "$VERSION" ]; then
echo "npm package version already exists (not republished this release): $FOUND_AT_VERSION — skipping smoke"
echo "skip=true" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "waiting for ${PACKAGE}@${VERSION} on npm dist-tag next ($i/24); current next=$FOUND"
else
FOUND=$(npm view "@switchbot/openapi-cli@$VERSION" version 2>/dev/null || true)
FOUND=$(npm view "${PACKAGE}@${VERSION}" version 2>/dev/null || true)
if [ "$FOUND" = "$VERSION" ]; then
echo "npm package version is available: $FOUND"
exit 0
fi
echo "waiting for @switchbot/openapi-cli@$VERSION to appear on npm ($i/24)"
echo "waiting for ${PACKAGE}@${VERSION} to appear on npm ($i/24)"
fi
sleep 10
done
echo "Timed out waiting for @switchbot/openapi-cli@$VERSION on npm"
echo "Timed out waiting for ${PACKAGE}@${VERSION} on npm"
exit 1

- name: Install published package in a clean temp project
if: steps.version.outputs.skip != 'true' && steps.wait_package.outputs.skip != 'true'
id: install_package
env:
VERSION: ${{ steps.version.outputs.version }}
PACKAGE: ${{ matrix.package }}
run: |
TMPDIR=$(mktemp -d)
echo "TMPDIR=$TMPDIR" >> "$GITHUB_ENV"
cd "$TMPDIR"
npm init -y >/dev/null 2>&1
npm install "@switchbot/openapi-cli@$VERSION"
npm install "${PACKAGE}@${VERSION}"

- name: Binary and offline smoke
- name: Binary and offline smoke (cli only)
if: matrix.kind == 'cli' && steps.version.outputs.skip != 'true' && steps.wait_package.outputs.skip != 'true'
id: offline_smoke
env:
TMPDIR: ${{ env.TMPDIR }}
Expand All @@ -116,7 +158,8 @@ jobs:
npx --no-install switchbot schema export --compact >/dev/null
npx --no-install switchbot capabilities --json | jq -e '.data.commandMeta != null' >/dev/null

- name: Live smoke with configured credentials
- name: Live smoke with configured credentials (cli only)
if: matrix.kind == 'cli' && steps.version.outputs.skip != 'true' && steps.wait_package.outputs.skip != 'true'
id: live_smoke
env:
TMPDIR: ${{ env.TMPDIR }}
Expand All @@ -127,30 +170,74 @@ jobs:
npx --no-install switchbot doctor --json | jq -e '.data.summary != null' >/dev/null
npx --no-install switchbot devices list --json | jq -e '.data.deviceList != null or .data.infraredRemoteList != null' >/dev/null

- name: Plugin tarball-shape smoke (plugins only)
if: matrix.kind == 'plugin' && steps.version.outputs.skip != 'true' && steps.wait_package.outputs.skip != 'true'
id: plugin_smoke
env:
TMPDIR: ${{ env.TMPDIR }}
PACKAGE: ${{ matrix.package }}
VERSION: ${{ steps.version.outputs.version }}
run: |
cd "$TMPDIR"
MANIFEST="node_modules/${PACKAGE}/package.json"
if [ ! -f "$MANIFEST" ]; then
echo "FAIL: $MANIFEST missing"
exit 1
fi
# peerDep must be a concrete range, not a workspace:* leak
PEER=$(node -p "require('./$MANIFEST').peerDependencies?.['@switchbot/openapi-cli'] || ''")
if [ -z "$PEER" ] || echo "$PEER" | grep -q "workspace:"; then
echo "FAIL: $PACKAGE peerDep missing or unrewritten — got: '$PEER'"
exit 1
fi
echo "OK: $PACKAGE peerDep = '$PEER'"
# All declared bin entries must point to readable files
node -e "
const pkg = require('./$MANIFEST');
const fs = require('fs');
const path = require('path');
const root = path.dirname('$MANIFEST');
const bins = pkg.bin || {};
for (const [name, target] of Object.entries(bins)) {
const p = path.join(root, target);
fs.accessSync(p);
console.log('OK: bin ' + name + ' -> ' + target);
}
"

- name: Promote verified version to latest
if: success()
if: success() && steps.version.outputs.skip != 'true' && steps.wait_package.outputs.skip != 'true'
env:
VERSION: ${{ steps.version.outputs.version }}
PACKAGE: ${{ matrix.package }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
npm dist-tag add "@switchbot/openapi-cli@$VERSION" latest
echo "Promoted @switchbot/openapi-cli@$VERSION to dist-tag latest"
npm dist-tag add "${PACKAGE}@${VERSION}" latest
echo "Promoted ${PACKAGE}@${VERSION} to dist-tag latest"

- name: Deprecate failed version
if: >
failure() &&
steps.wait_package.outcome == 'success' &&
steps.wait_package.outputs.skip != 'true' &&
(
steps.install_package.outcome == 'failure' ||
steps.offline_smoke.outcome == 'failure'
steps.offline_smoke.outcome == 'failure' ||
steps.plugin_smoke.outcome == 'failure'
)
env:
VERSION: ${{ steps.version.outputs.version }}
PREVIOUS_LATEST: ${{ steps.latest.outputs.version }}
PACKAGE: ${{ matrix.package }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
npm deprecate "@switchbot/openapi-cli@$VERSION" "Published to dist-tag next but failed package smoke tests. Install @switchbot/openapi-cli@${PREVIOUS_LATEST} or use dist-tag latest."
echo "Deprecated @switchbot/openapi-cli@$VERSION after package smoke failure"
if [ -n "$PREVIOUS_LATEST" ]; then
MSG="Published to dist-tag next but failed package smoke tests. Install ${PACKAGE}@${PREVIOUS_LATEST} or use dist-tag latest."
else
MSG="Published to dist-tag next but failed package smoke tests. No prior latest exists; investigate before re-publishing."
fi
npm deprecate "${PACKAGE}@${VERSION}" "$MSG"
echo "Deprecated ${PACKAGE}@${VERSION} after package smoke failure"

- name: Cleanup temp project
if: always()
Expand Down
Loading
Loading