Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
ed8b041
fix: drop Bun globals from the Node bundle path and lint against them
tejaskash Sep 3, 2026
887a81c
fix(io): spawn Windows tools without a shell and quote .cmd wrapper a…
tejaskash Sep 3, 2026
c6809d1
feat(router): pin the host platform on the context
tejaskash Sep 3, 2026
c41b15d
fix(dev): run Python agents with UTF-8, unbuffered stdout
tejaskash Sep 3, 2026
33ddf65
fix: drop shell-specific retry hints from subprocess and create messages
tejaskash Sep 3, 2026
ff8c0a0
test: rekey role policy fixtures for the sha256 policy names
tejaskash Sep 3, 2026
9d1705f
fix(tui): spell the control key ctrl in key hints
tejaskash Sep 3, 2026
d78160b
fix(router): name unknown subcommands instead of reporting excess arg…
tejaskash Sep 3, 2026
df06cd9
fix(project): terminate remove output and emit JSON under --json
tejaskash Sep 3, 2026
258f764
fix(tui): fall back to ASCII glyphs on terminals without Unicode fonts
tejaskash Sep 3, 2026
e894dd8
fix(create): keep wizard input after a failed create and offer retry
tejaskash Sep 3, 2026
231c003
fix(create): refuse Windows project paths that will exceed MAX_PATH
tejaskash Sep 3, 2026
9130d29
docs: add Windows notes for execution policy, conhost, and long paths
tejaskash Sep 3, 2026
1bab4ec
refactor: simplify windows bugbash fixes
tejaskash Sep 3, 2026
ffc3471
refactor: second simplify pass over the windows bugbash fixes
tejaskash Sep 3, 2026
f3d7dab
refactor: share the success reporter and give the OTEL lookup the Pyt…
tejaskash Sep 3, 2026
9b01905
test: drop the underscore from the glyph table test name
tejaskash Sep 3, 2026
3d6951b
fix(create): gate wizard retry on nothing written, let --skip-install…
tejaskash Sep 3, 2026
aeb1431
fix(eval): recognise legacy-suffixed managed roles and warn when a su…
tejaskash Sep 4, 2026
4c73624
fix(io): escape every backslash run before a quote; reset the wizard …
tejaskash Sep 4, 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
16 changes: 15 additions & 1 deletion .oxlintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@
"categories": {
"correctness": "error"
},
"rules": {
"no-restricted-globals": [
"error",
{
"name": "Bun",
"message": "The npm bundle runs under Node. Use node:* APIs in src/ and keep Bun to scripts/, src/testing/, and tests."
}
]
},
"ignorePatterns": ["dist/", "node_modules/", "src/assets/"],
"overrides": []
"overrides": [
{
"files": ["scripts/**", "src/testing/**", "**/*.test.*", "**/*-test-support.ts"],
"rules": { "no-restricted-globals": "off" }
}
]
}
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -916,6 +916,19 @@ npm pack # builds via prepublishOnly, creates the .tgz
npm i -g ./agentcore-1.0.0.tgz
```

## Windows notes

- **`agentcore.ps1 cannot be loaded because running scripts is disabled`**: the
npm shim is a PowerShell script and Windows Server defaults to a `Restricted`
execution policy. Run `Set-ExecutionPolicy -Scope CurrentUser RemoteSigned`
once, or call `agentcore.cmd`. The compiled `.exe` has no shim.
- **The CLI looks frozen in a PowerShell window**: legacy conhost pauses all
output while text is selected (the title bar shows `Select`). Press `Esc`.
Windows Terminal does not do this.
- **`project create` refuses a long path**: Windows caps paths at 260 characters
unless `LongPathsEnabled` is set, and the CDK app's `node_modules` needs about
100 of them. Create the project higher in the tree or enable long paths.

# Build

Run `make` to verify bun is installed, build the Node bundle, and compile all native binaries:
Expand Down
2 changes: 1 addition & 1 deletion src/components/CliOnlyScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export function CliOnlyScreen({ ctx, path }: CliOnlyScreenProps) {
keyHints={[
{ key: "↑↓", label: "scroll" },
{ key: "esc", label: "back" },
{ key: "ctl+c", label: "quit" },
{ key: "ctrl+c", label: "quit" },
]}
>
<Box flexDirection="column" paddingX={1} flexGrow={1} minHeight={0}>
Expand Down
14 changes: 8 additions & 6 deletions src/components/ConfirmAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Spinner } from "./ui/spinner";
import { Confirm } from "./ui/confirm";
import { TaskList, type Task } from "./ui/task-list";
import { KeyValueTable } from "./KeyValueTable";
import { darkTheme } from "./ui/_core.js";
import { darkTheme, glyphs } from "./ui/_core.js";
import { driveProgress, type ProgressEvent } from "../tui/progress";

const theme = darkTheme;
Expand Down Expand Up @@ -127,18 +127,18 @@ export function ConfirmAction({
? [
{ key: "y/n", label: "confirm" },
{ key: "esc", label: "back" },
{ key: "ctl+c", label: "quit" },
{ key: "ctrl+c", label: "quit" },
]
: phase.kind === "success"
? [{ key: "enter", label: doneLabel }]
: phase.kind === "error"
? [
{ key: "esc", label: "back" },
{ key: "ctl+c", label: "quit" },
{ key: "ctrl+c", label: "quit" },
]
: // Nothing listens for esc while the action runs (or is about to):
// an operation in flight is not abandoned by leaving the screen.
[{ key: "ctl+c", label: "quit" }];
[{ key: "ctrl+c", label: "quit" }];

return (
<Layout breadcrumb={breadcrumb} description={description} keyHints={hints}>
Expand Down Expand Up @@ -231,7 +231,7 @@ function SuccessBody({
return (
<Box flexDirection="column">
<Text color={theme.colors.success} bold>
{title}
{glyphs.check} {title}
</Text>
{Object.keys(rows).length > 0 && (
<Box flexDirection="column" marginTop={1} marginLeft={2}>
Expand Down Expand Up @@ -262,7 +262,9 @@ function ErrorBody({ message, onBack }: { message: string; onBack: () => void })

return (
<Box flexDirection="column">
<Text color={theme.colors.error}>✗ {message}</Text>
<Text color={theme.colors.error}>
{glyphs.cross} {message}
</Text>
<Box marginTop={1}>
<Text color={theme.colors.muted}>press esc to go back</Text>
</Box>
Expand Down
28 changes: 9 additions & 19 deletions src/components/EndpointWizard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ import { coreOptsFromCtx } from "../handlers/utils";
import { Layout } from "./Layout";
import { FormRadioGroup, type FormRadioOption } from "./FormRadioGroup";
import { FormTextInput } from "./FormTextInput";
import { ErrorPanel } from "./ErrorPanel";
import { Stepper, type Step } from "./ui/stepper";
import { Spinner } from "./ui/spinner";
import { CodeBlock } from "./ui/code-block";
import { darkTheme } from "./ui/_core.js";
import { darkTheme, glyphs } from "./ui/_core.js";

const theme = darkTheme;

Expand Down Expand Up @@ -185,16 +186,16 @@ function hintsFor(
phase: WizardPhase,
verb: string,
): { key: string; label: string }[] {
if (phase.kind === "submitting") return [{ key: "ctl+c", label: "quit" }];
if (phase.kind === "submitting") return [{ key: "ctrl+c", label: "quit" }];
if (phase.kind === "success") return [{ key: "enter", label: "continue" }];
if (phase.kind === "error")
return [
{ key: "esc", label: "back" },
{ key: "ctl+c", label: "quit" },
{ key: "ctrl+c", label: "quit" },
];
const base = [
{ key: "esc", label: "back" },
{ key: "ctl+c", label: "quit" },
{ key: "ctrl+c", label: "quit" },
];
if (stepKey === "version") {
return [{ key: "↑↓", label: "choose" }, { key: "enter", label: "continue" }, ...base];
Expand Down Expand Up @@ -321,7 +322,9 @@ function VersionStep({
) : versions.isError ? (
<>
<Question text="which harness version should this endpoint serve?" />
<Text color={theme.colors.error}>✗ {(versions.error as Error).message}</Text>
<Text color={theme.colors.error}>
{glyphs.cross} {(versions.error as Error).message}
</Text>
</>
) : options.length === 0 ? (
<>
Expand Down Expand Up @@ -392,7 +395,7 @@ function SuccessPanel({
return (
<Box flexDirection="column">
<Text color={theme.colors.success} bold>
endpoint {verb}d
{glyphs.check} endpoint {verb}d
</Text>
<Text>
{" "}
Expand All @@ -404,16 +407,3 @@ function SuccessPanel({
</Box>
);
}

function ErrorPanel({ message, onBack }: { message: string; onBack: () => void }) {
useInput((_input, key) => {
if (key.escape || key.return) onBack();
});

return (
<Box flexDirection="column">
<Text color={theme.colors.error}>✗ {message}</Text>
<Text color={theme.colors.muted}>{" esc returns to the form"}</Text>
</Box>
);
}
19 changes: 15 additions & 4 deletions src/components/ErrorPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
import { Box, Text, useInput } from "ink";
import { darkTheme } from "./ui/_core.js";
import { darkTheme, glyphs } from "./ui/_core.js";

const theme = darkTheme;

export function ErrorPanel({ message, onBack }: { message: string; onBack: () => void }) {
useInput((_input, key) => {
export function ErrorPanel({
message,
onBack,
onRetry,
}: {
message: string;
onBack: () => void;
onRetry?: () => void;
}) {
useInput((input, key) => {
if (key.escape || key.return) onBack();
if (input === "r" && onRetry) onRetry();
});

return (
<Box flexDirection="column">
<Text color={theme.colors.error}>✗ {message}</Text>
<Text color={theme.colors.error}>
{glyphs.cross} {message}
</Text>
<Text color={theme.colors.muted}>{" esc returns to the form"}</Text>
</Box>
);
Expand Down
6 changes: 3 additions & 3 deletions src/components/FormCheckboxMultiSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Box, Text } from "ink";
import { darkTheme } from "./ui/_core.js";
import { darkTheme, glyphs } from "./ui/_core.js";

const theme = darkTheme;

Expand Down Expand Up @@ -46,10 +46,10 @@ export function FormCheckboxMultiSelect({
return (
<Box key={option.label}>
<Text color={isCursor ? theme.colors.focus : theme.colors.muted}>
{isCursor ? "❯ " : " "}
{isCursor ? `${glyphs.pointer} ` : " "}
</Text>
<Text color={option.checked ? theme.colors.success : theme.colors.muted}>
{option.checked ? "[✓] " : "[ ] "}
{option.checked ? `[${glyphs.done}] ` : "[ ] "}
</Text>
<Text bold={isCursor} color={isCursor ? theme.colors.focus : theme.colors.text}>
{option.label.padEnd(columnWidth)}
Expand Down
12 changes: 6 additions & 6 deletions src/components/HarnessWizard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { Stepper, type Step } from "./ui/stepper";
import { Spinner } from "./ui/spinner";
import { CodeBlock } from "./ui/code-block";
import { ScrollView } from "ink-scroll-view";
import { darkTheme } from "./ui/_core.js";
import { darkTheme, glyphs } from "./ui/_core.js";
import { Divider } from "./ui/divider/Divider.js";
import { KeyValueTable } from "./KeyValueTable.js";

Expand Down Expand Up @@ -392,16 +392,16 @@ function hintsFor(
phase: WizardPhase,
verb: string,
): { key: string; label: string }[] {
if (phase.kind === "submitting") return [{ key: "ctl+c", label: "quit" }];
if (phase.kind === "submitting") return [{ key: "ctrl+c", label: "quit" }];
if (phase.kind === "success") return [{ key: "enter", label: "continue" }];
if (phase.kind === "error")
return [
{ key: "esc", label: "back" },
{ key: "ctl+c", label: "quit" },
{ key: "ctrl+c", label: "quit" },
];
const base = [
{ key: "esc", label: "back" },
{ key: "ctl+c", label: "quit" },
{ key: "ctrl+c", label: "quit" },
];
switch (stepKey) {
case "name":
Expand All @@ -417,7 +417,7 @@ function hintsFor(
...base,
];
case "prompt":
return [{ key: "enter", label: "newline" }, { key: "ctl+d", label: "continue" }, ...base];
return [{ key: "enter", label: "newline" }, { key: "ctrl+d", label: "continue" }, ...base];
case "review":
return [{ key: "enter", label: verb }, { key: "↑↓", label: "scroll" }, ...base];
default:
Expand Down Expand Up @@ -1165,7 +1165,7 @@ function SuccessPanel({
return (
<Box flexDirection="column" paddingX={1}>
<Text color={theme.colors.success} bold>
harness {mode === "create" ? "created" : "updated"}
{glyphs.check} harness {mode === "create" ? "created" : "updated"}
</Text>
<Text color={theme.colors.muted}>
{mode === "create"
Expand Down
2 changes: 1 addition & 1 deletion src/components/JsonDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export function JsonDetail({
{ key: "↑↓/kj", label: "navigate" },
...(error && onRetry ? [{ key: "r", label: "retry" }] : []),
{ key: "esc", label: "back" },
{ key: "ctl+c", label: "quit" },
{ key: "ctrl+c", label: "quit" },
]}
>
{isPending ? (
Expand Down
2 changes: 1 addition & 1 deletion src/components/PaginatedTablePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export function PaginatedTablePicker<TItem, TRow extends Record<string, unknown>
...(list.isError && paging.pageIndex > 0 ? [{ key: "←/h", label: "previous page" }] : []),
...(list.isError ? [{ key: "r", label: "retry" }] : []),
{ key: "esc", label: "back" },
{ key: "ctl+c", label: "quit" },
{ key: "ctrl+c", label: "quit" },
]}
>
{list.isPending ? (
Expand Down
8 changes: 5 additions & 3 deletions src/components/ResourceDetailScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Box, Text, useInput } from "ink";
import { useNavigate } from "react-router";
import { KeyValueTable } from "./KeyValueTable.js";
import { Layout } from "./Layout";
import { darkTheme } from "./ui/_core.js";
import { darkTheme, glyphs } from "./ui/_core.js";
import { Divider } from "./ui/divider/Divider.js";
import { Spinner } from "./ui/spinner";

Expand Down Expand Up @@ -69,7 +69,7 @@ export function ResourceDetailScreen({
...(ready && actions.length > 0 ? [{ key: "enter", label: selectLabel }] : []),
...(error && onRetry ? [{ key: "r", label: "retry" }] : []),
{ key: "esc", label: "back" },
{ key: "ctl+c", label: "quit" },
{ key: "ctrl+c", label: "quit" },
]}
>
{isPending ? (
Expand All @@ -91,7 +91,9 @@ export function ResourceDetailScreen({
const selected = actionIndex === selectedIndex;
return (
<Box key={action.name}>
<Text color={darkTheme.colors.focus}>{selected ? "❯ " : " "}</Text>
<Text color={darkTheme.colors.focus}>
{selected ? `${glyphs.pointer} ` : " "}
</Text>
<Text
bold={selected}
color={selected ? darkTheme.colors.focus : darkTheme.colors.text}
Expand Down
6 changes: 3 additions & 3 deletions src/components/RouterScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { CommandKey, isTuiCommandSupported } from "../router";
import { Layout } from "./Layout";
import { Divider } from "./ui/divider";
import { TextInput } from "./ui/text-input";
import { darkTheme } from "./ui/_core.js";
import { darkTheme, glyphs } from "./ui/_core.js";
import type { ScreenProps } from "../handlers/types";

const theme = darkTheme;
Expand Down Expand Up @@ -135,7 +135,7 @@ export function RouterScreen({ ctx, path }: RouterScreenProps) {
{ key: "↑↓", label: "navigate" },
{ key: "enter", label: "select" },
{ key: "esc", label: "back" },
{ key: "ctl+c", label: "quit" },
{ key: "ctrl+c", label: "quit" },
]}
>
<Box flexDirection="column">
Expand Down Expand Up @@ -171,7 +171,7 @@ export function RouterScreen({ ctx, path }: RouterScreenProps) {
<React.Fragment key={o.name}>
{startsCliOnly && <Divider title="command line only" />}
<Box paddingX={1}>
<Text color={theme.colors.focus}>{isHl ? "❯ " : " "}</Text>
<Text color={theme.colors.focus}>{isHl ? `${glyphs.pointer} ` : " "}</Text>
<Text
bold={isHl}
color={
Expand Down
Loading
Loading