# WriteUserScript

Creates or overwrites a script in the caller's user folder.

Two destinations are supported:

| kind | directory | runtime | signature |
|------|-----------|---------|-----------|
| `'script'` (default) | `scripts/` | plain Node.js | `main({ params })` |
| `'browser-macro'` | `browser-macros/` | Playwright — Chromium | `main({ context, params })` |

## Input

```ts
{
  name: string,                        // slug — '.js' appended if absent
  content: string,                     // full file text (frontmatter + main())
  kind?: 'script' | 'browser-macro',  // default: 'script'
  overwrite?: boolean                  // default: false — error if file exists
}
```

## Required file structure

The content must define a `main` function. The following forms are all accepted:

```js
// ES function declaration
async function main({ params }) { … }

// Arrow / assigned function
const main = async ({ params }) => { … };

// CommonJS export
module.exports = async function main({ params }) { … };
exports.main = async function({ params }) { … };
```

If none of these patterns is found the tool returns `isError: true` with a
hint to add a `main` definition.

## YAML frontmatter (recommended)

```yaml
---
description: One-line human-readable description shown in ListUserAssets
params:
  - name: url
    type: string
  - name: limit
    type: number
    default: 10
---
```

Frontmatter is parsed by `RunUserScript` for param validation. Scripts without
frontmatter still run, but param validation is skipped.

Browser macros may additionally declare `session_profile_id: <N>` to auto-load
a saved login session (see `RunUserScript` docs).

## Size limit

256 KB (UTF-8 encoded). Exceeding the limit returns `isError: true`.

## Overwrite semantics

By default (`overwrite: false`) writing to an existing file is an error.
Pass `overwrite: true` to replace the existing file atomically.

## When to use

- You discovered a useful reusable pattern during a task — save it for next time.
- The user asks you to create or update a script they can run later via `RunUserScript`.
- You want to prototype a browser automation without going through the UI.

## Examples

### Plain Node script

```js
WriteUserScript({
  name: "fetch-and-clean",
  kind: "script",
  content: `---
description: Fetch a URL and return cleaned JSON
params:
  - name: url
    type: string
---
const https = require('https');

async function main({ params }) {
  const res = await fetch(params.url);
  const json = await res.json();
  return { items: json.items ?? [] };
}
`
})
```

### Browser macro

```js
WriteUserScript({
  name: "screenshot-dashboard",
  kind: "browser-macro",
  content: `---
description: Take a screenshot of the dashboard
params:
  - name: url
    type: string
---
async function main({ context, params }) {
  const page = await context.newPage();
  await page.goto(params.url);
  const buf = await page.screenshot({ fullPage: true });
  return { screenshotBase64: buf.toString('base64') };
}
`
})
```

## Error cases

| Situation | `isError` | message contains |
|-----------|-----------|-----------------|
| No authenticated user | true | "authenticated" |
| `name` missing / empty | true | `"name"` |
| `name` contains `/`, space, etc. | true | "alphanumeric" |
| `content` missing `main` | true | "main" |
| Content exceeds 256 KB | true | "bytes" |
| File exists, `overwrite` not set | true | "overwrite" |

## Notes

- `WriteUserScript` is a META_TOOL — available in every movement without listing it in `allowed_tools`.
- After writing, use `RunUserScript` to immediately execute and verify the script.
- Use `ListUserAssets` to see all scripts currently in the folder.
