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
32 changes: 31 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,34 @@ if (container) {
python jules-scratch/verification/verify_introspection_tool.py
```

By following these instructions, you can avoid the common pitfalls of this unique environment and ensure that your contributions are successful.
By following these instructions, you can avoid the common pitfalls of this unique environment and ensure that your contributions are successful.

## Development Tools

To streamline the development process, a suite of tools has been created in the `tools` directory. You should use these tools to manage components and dependencies.

### Component Manager

Use the `component-manager.js` script to create and manage components.

* **To create a new component:**
```bash
node tools/component-manager.js create-component <ComponentName>
```
This will create a new, self-rendering React component in the `src` directory with the correct boilerplate.

* **To set the active component for testing:**
```bash
node tools/component-manager.js set-active-component <ComponentName>
```
This will automatically update `index.html` to load the specified component.

### Dependency Manager

The `dependency-manager.js` script manages the project's CDN dependencies.

* **To inject/update dependencies:**
```bash
node tools/dependency-manager.js
```
This script reads the `dependencies.json` file and injects the required `<script>` tags into `index.html`. If you need to add or update a dependency, you should modify the `dependencies.json` file and then run this script.
32 changes: 31 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,34 @@ This project operates in a unique, CDN-based environment. It's crucial to unders
* **Global React Object:** React is available as a global variable, `window.React`. All React hooks and methods must be called as properties of this object (e.g., `React.useState`, `React.useCallback`).
* **In-Browser Transpilation:** JSX is transpiled in the browser by Babel, which is loaded from a CDN. This is why the script tag in `index.html` has the type `text/babel`.

These constraints are critical for ensuring that the application runs correctly in its intended environment. Please see the `AGENTS.md` file for more detailed instructions for agent developers.
These constraints are critical for ensuring that the application runs correctly in its intended environment. Please see the `AGENTS.md` file for more detailed instructions for agent developers.

## Development Tools

This repository includes a suite of tools to help automate the development process. These tools are located in the `tools` directory.

### Component Manager

The `component-manager.js` script helps you create and manage components.

* **Create a new component:**
```bash
node tools/component-manager.js create-component <ComponentName>
```
This will create a new, self-rendering React component in the `src` directory.

* **Set the active component:**
```bash
node tools/component-manager.js set-active-component <ComponentName>
```
This will update `index.html` to load and run the specified component.

### Dependency Manager

The `dependency-manager.js` script manages the CDN dependencies for the project.

* **Inject dependencies:**
```bash
node tools/dependency-manager.js
```
This will read the `dependencies.json` file and inject the necessary `<script>` tags into `index.html`.
5 changes: 5 additions & 0 deletions dependencies.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"react": "https://unpkg.com/react@18/umd/react.development.js",
"react-dom": "https://unpkg.com/react-dom@18/umd/react-dom.development.js",
"babel": "https://unpkg.com/@babel/standalone/babel.min.js"
}
9 changes: 4 additions & 5 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@
height: 100%;
}
</style>
<!-- 1. Load React, ReactDOM, and Babel -->
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

<!-- 2. Define global configuration variables (as placeholders) -->
<script>
Expand All @@ -29,12 +25,15 @@
window.__app_id = "canvas-prober-12345";
window.__initial_auth_token = "placeholder.jwt.token";
</script>
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js" crossorigin></script>
</head>
<body>
<div id="root"></div>

<!-- 3. Load the self-rendering component. Babel will transpile and execute it. -->
<script type="text/babel" src="JulesIntrospector.jsx"></script>
<script type="text/babel" src="src/JulesIntrospector.jsx"></script>

</body>
</html>
193 changes: 193 additions & 0 deletions src/JulesIntrospector.jsx

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions src/TestComponent.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

function TestComponent() {
const { useState, useEffect } = React;
return (
<div>
<h1>TestComponent Component</h1>
</div>
);
}

// --- Self-Rendering Logic ---
const container = document.getElementById('root');
if (container) {
const root = ReactDOM.createRoot(container);
root.render(React.createElement(TestComponent));
}
67 changes: 67 additions & 0 deletions tools/component-manager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
const fs = require('fs');
const path = require('path');

const command = process.argv[2];
const componentName = process.argv[3];

const SRC_DIR = 'src';
const INDEX_HTML_PATH = 'index.html';

const componentTemplate = (name) => `
function ${name}() {
const { useState, useEffect } = React;
return (
<div>
<h1>${name} Component</h1>
</div>
);
}

// --- Self-Rendering Logic ---
const container = document.getElementById('root');
if (container) {
const root = ReactDOM.createRoot(container);
root.render(React.createElement(${name}));
}
`;

function createComponent(name) {
if (!name) {
console.error('Error: Component name is required.');
process.exit(1);
}
const componentPath = path.join(SRC_DIR, `${name}.jsx`);
if (fs.existsSync(componentPath)) {
console.error(`Error: Component ${name} already exists.`);
process.exit(1);
}
fs.writeFileSync(componentPath, componentTemplate(name));
console.log(`Component ${name} created at ${componentPath}`);
}

function setActiveComponent(name) {
if (!name) {
console.error('Error: Component name is required.');
process.exit(1);
}
const componentPath = path.join(SRC_DIR, `${name}.jsx`);
if (!fs.existsSync(componentPath)) {
console.error(`Error: Component ${name} does not exist.`);
process.exit(1);
}

let indexHtml = fs.readFileSync(INDEX_HTML_PATH, 'utf8');
indexHtml = indexHtml.replace(/src=".*\.jsx"/, `src="${componentPath}"`);
fs.writeFileSync(INDEX_HTML_PATH, indexHtml);
console.log(`Active component set to ${name}`);
}

if (command === 'create-component') {
createComponent(componentName);
} else if (command === 'set-active-component') {
setActiveComponent(componentName);
} else {
console.log('Usage:');
console.log(' node tools/component-manager.js create-component <ComponentName>');
console.log(' node tools/component-manager.js set-active-component <ComponentName>');
}
34 changes: 34 additions & 0 deletions tools/dependency-manager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const fs = require('fs');
const path = require('path');

const DEPENDENCIES_PATH = 'dependencies.json';
const INDEX_HTML_PATH = 'index.html';
const DEPENDENCY_PLACEHOLDER = '<!-- DEPENDENCIES -->';

function injectDependencies() {
const dependencies = JSON.parse(fs.readFileSync(DEPENDENCIES_PATH, 'utf8'));
let indexHtml = fs.readFileSync(INDEX_HTML_PATH, 'utf8');

// Remove existing dependency scripts to ensure idempotency
const dependencyUrls = Object.values(dependencies);
dependencyUrls.forEach(url => {
const scriptTagRegex = new RegExp(`<script src="${url}" crossorigin></script>\\n?`, 'g');
indexHtml = indexHtml.replace(scriptTagRegex, '');
});

const scriptTags = dependencyUrls
.map(url => `<script src="${url}" crossorigin></script>`)
.join('\n ');

if (indexHtml.includes(DEPENDENCY_PLACEHOLDER)) {
indexHtml = indexHtml.replace(DEPENDENCY_PLACEHOLDER, scriptTags);
} else {
// If the placeholder is not found, inject before the closing </head> tag
indexHtml = indexHtml.replace('</head>', ` ${scriptTags}\n</head>`);
}

fs.writeFileSync(INDEX_HTML_PATH, indexHtml);
console.log('Dependencies injected into index.html');
}

injectDependencies();