Skip to content
Open
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
4 changes: 3 additions & 1 deletion docs/README-python-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,7 @@ asyncio.run(main())
The `rocketride` command is installed automatically with the package.

```bash
rocketride init # Scaffold .rocketride/ in the current directory
rocketride start pipeline.json # Start a pipeline
rocketride upload *.pdf --token <token> # Upload files to a running pipeline
rocketride status --token <token> # Monitor task progress
Expand All @@ -536,7 +537,8 @@ rocketride events ALL --token <token> # Stream task events
rocketride rrext_store get_all_projects # List stored projects
```

All commands accept `--uri` and `--apikey` flags, or read from environment variables.
`rocketride init` runs entirely offline — it creates `.rocketride/docs/`, installs agent stubs (CLAUDE.md, cursor rules, etc.) for any detected coding agents, and adds `.rocketride/` to `.gitignore`. Pass `--agent <name>` to force a specific stub or `--no-agents` to skip them.
All other commands accept `--uri` and `--apikey` flags, or read from environment variables.

## Configuration

Expand Down
6 changes: 5 additions & 1 deletion packages/client-python/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,8 @@ where = ["src"]
include = ["rocketride*"]

[tool.setuptools.package-data]
rocketride = ["py.typed"]
rocketride = [
"py.typed",
"cli/templates/docs/*.md",
"cli/templates/stubs/*",
]
68 changes: 62 additions & 6 deletions packages/client-python/scripts/tasks.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@
* clean - Remove build artifacts
*/
const path = require('path');
const { execCommand, syncDir, formatSyncStats, removeDirs, removeMatching, removeDirAndParents, PROJECT_ROOT, BUILD_ROOT, DIST_ROOT, mkdir, copyFile, exists, startServer, stopServer, bracket, parallel, hasSourceChanged, saveSourceHash, setState } = require('../../../scripts/lib');
const crypto = require('crypto');
const fsp = require('fs').promises;
const { execCommand, syncDir, formatSyncStats, removeDirs, removeMatching, removeDirAndParents, PROJECT_ROOT, BUILD_ROOT, DIST_ROOT, mkdir, copyFile, exists, startServer, stopServer, bracket, parallel, fingerprint, saveSourceHash, getState, setState } = require('../../../scripts/lib');

const PACKAGE_DIR = path.join(__dirname, '..');
const SRC_DIR = path.join(PACKAGE_DIR, 'src', 'rocketride');
Expand All @@ -52,6 +54,13 @@ const DOCS_DIR = path.join(PROJECT_ROOT, 'docs');
const README_SRC = path.join(DOCS_DIR, 'README-python-client.md');
const README_DEST = path.join(BUILD_DIR, 'README.md');

// Init ships the agent docs and stubs as wheel package data;
// Source of truth lives in the repo at docs/agents/ + docs/stubs/; the build
// copies them into BUILD_DIR so they end up at the package_data path declared
const AGENT_DOCS_SRC = path.join(DOCS_DIR, 'agents');
const AGENT_STUBS_SRC = path.join(DOCS_DIR, 'stubs');
const TEMPLATES_DEST_BASE = path.join(BUILD_DIR, 'src', 'rocketride', 'cli', 'templates');

// ============================================================================
// Action Factories
// ============================================================================
Expand All @@ -65,6 +74,16 @@ function makeCopyReadmeAction() {
};
}

function makeCopyInitTemplatesAction() {
return {
run: async (ctx, task) => {
const docsStats = await syncDir(AGENT_DOCS_SRC, path.join(TEMPLATES_DEST_BASE, 'docs'), { package: true });
const stubsStats = await syncDir(AGENT_STUBS_SRC, path.join(TEMPLATES_DEST_BASE, 'stubs'), { package: true });
task.output = `docs: ${formatSyncStats(docsStats)} | stubs: ${formatSyncStats(stubsStats)}`;
},
Comment on lines +79 to +83
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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Prefix the unused action context with _.

ctx is never read in this action, so the new code drifts from the repo’s JS convention for unused variables.

♻️ Proposed fix
-		run: async (ctx, task) => {
+		run: async (_ctx, task) => {

As per coding guidelines, "Unused variables must be prefixed with underscore (_)."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/client-python/scripts/tasks.js` around lines 79 - 83, The action
callback parameter `ctx` is unused and should follow the repo convention for
unused variables; rename the parameter in the `run` async function from `ctx` to
`_ctx` (i.e., change `run: async (ctx, task) => { ... }` to `run: async (_ctx,
task) => { ... }`) and ensure there are no remaining references to `ctx` in the
function body so linters pass.

};
}

function makeSyncClientPythonAction() {
return {
run: async (ctx, task) => {
Expand All @@ -88,14 +107,50 @@ function makeWheelSourceAction() {
// State key for source fingerprint
const SRC_HASH_KEY = 'client-python.srcHash';

// Inputs that affect wheel contents — keep in sync with the wheel-build steps.
// SRC_DIR is the package source; AGENT_DOCS_SRC + AGENT_STUBS_SRC are bundled
// into the wheel as `cli/templates/` package data; README_SRC is copied to
// BUILD_DIR/README.md before `python -m build` runs; pyproject.toml + LICENSE
// are top-level packaging metadata copied via wheel-source's syncDir(PACKAGE_DIR).
const WHEEL_INPUT_DIRS = [SRC_DIR, AGENT_DOCS_SRC, AGENT_STUBS_SRC];
const WHEEL_INPUT_FILES = [README_SRC, path.join(PACKAGE_DIR, 'pyproject.toml'), path.join(PACKAGE_DIR, 'LICENSE')];

async function computeWheelInputsHash() {
const dirHashes = await Promise.all(WHEEL_INPUT_DIRS.map((d) => fingerprint(d)));
const fileStats = await Promise.all(
WHEEL_INPUT_FILES.map(async (f) => {
try {
const s = await fsp.stat(f);
return `${path.basename(f)}:${s.size}:${s.mtimeMs}`;
} catch {
return `${path.basename(f)}:missing`;
}
})
);
const combined = [...dirHashes.map((h) => h ?? 'missing'), ...fileStats].join('|');
return crypto.createHash('md5').update(combined).digest('hex');
}

// True only if DIST_DIR contains at least one wheel or sdist artifact;
// guards against an empty/half-built dist dir from a previously failed build.
async function hasWheelArtifacts() {
try {
const entries = await fsp.readdir(DIST_DIR);
return entries.some((name) => name.endsWith('.whl') || name.endsWith('.tar.gz'));
} catch {
return false;
}
}

function makeWheelBuildAction() {
return {
run: async (ctx, task) => {
// Check if source changed
const { changed, hash } = await hasSourceChanged(SRC_DIR, SRC_HASH_KEY);
const outputExists = await exists(DIST_DIR);
// Check if any wheel input (src, agent docs/stubs, README) changed
const hash = await computeWheelInputsHash();
const savedHash = await getState(SRC_HASH_KEY);
const artifactsExist = await hasWheelArtifacts();

if (!changed && outputExists) {
if (hash === savedHash && artifactsExist) {
task.output = 'No changes detected';
Comment thread
coderabbitai[bot] marked this conversation as resolved.
return;
}
Expand Down Expand Up @@ -223,6 +278,7 @@ module.exports = {
actions: [
// Internal actions
{ name: 'client-python:copy-readme', action: makeCopyReadmeAction },
{ name: 'client-python:copy-init-templates', action: makeCopyInitTemplatesAction },
{ name: 'client-python:sync-source', action: makeSyncClientPythonAction },
{ name: 'client-python:wheel-source', action: makeWheelSourceAction },
{ name: 'client-python:wheel-build', action: makeWheelBuildAction },
Expand All @@ -236,7 +292,7 @@ module.exports = {
name: 'client-python:build',
action: () => ({
description: 'Build Python client',
steps: ['server:build', 'client-python:sync-source', 'client-python:wheel-source', 'client-python:copy-readme', 'client-python:wheel-build', 'client-python:sync'],
steps: ['server:build', 'client-python:sync-source', 'client-python:wheel-source', 'client-python:copy-readme', 'client-python:copy-init-templates', 'client-python:wheel-build', 'client-python:sync'],
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}),
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
from .events import EventsCommand
from .list import ListCommand
from .store import StoreCommand
from .init import InitCommand

__all__ = [
'StartCommand',
Expand All @@ -52,4 +53,5 @@
'EventsCommand',
'ListCommand',
'StoreCommand',
'InitCommand',
]
Loading
Loading