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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ Most of us aren't really writing code anymore, we're directing agents that do. B

Piyaz replaces that cycle. It's not just a context layer your agents read from, it's an end-to-end project management tool that agents operate natively. Piyaz creates tasks, refines them, plans implementations, provides the right context at the right stage, and tracks everything that happens. Your agent harness doesn't need a briefing. It walks into every session knowing exactly what to do next and why.

Full setup, guides, and reference live at **[docs.piyaz.ai](https://docs.piyaz.ai)**.

---

## Use the hosted version (no clone)
Expand Down
42 changes: 20 additions & 22 deletions components/home/GetStartedModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,8 @@ const SELF_HOST_CLI_INSTALLS: readonly CliInstall[] = [
},
];

const HOSTED_README_SETUP_URL =
"https://github.com/FrkAk/piyaz#use-the-hosted-version-no-clone";
const SELF_HOST_README_SETUP_URL =
"https://github.com/FrkAk/piyaz#self-host-contribute";
const HOSTED_DOCS_SETUP_URL = "https://docs.piyaz.ai/docs/get-started/install";
const SELF_HOST_DOCS_SETUP_URL = "https://docs.piyaz.ai/docs/guides/self-host";

const SECTION_LABEL_CLASS =
"font-mono text-[10px] font-semibold uppercase tracking-wider text-text-muted";
Expand All @@ -92,13 +90,13 @@ const MULTI_TEAM_HINT =
interface FirstTimeBodyProps {
/** Target-specific install snippets to render. */
cliInstalls: readonly CliInstall[];
/** Target-specific README setup anchor. */
readmeSetupUrl: string;
/** Target-specific docs setup URL. */
docsSetupUrl: string;
}

interface ReturningBodyProps {
/** Target-specific README setup anchor. */
readmeSetupUrl: string;
/** Target-specific docs setup URL. */
docsSetupUrl: string;
}

/**
Expand All @@ -115,16 +113,16 @@ export function getCliInstalls(
}

/**
* Select the setup guide anchor for the active deploy target.
* Select the docs setup URL for the active deploy target.
* @param deployTarget - Build-time deploy target exposed to client bundles.
* @returns Hosted or self-host README setup URL.
* @returns Hosted or self-host docs setup URL.
*/
export function getReadmeSetupUrl(
export function getDocsSetupUrl(
deployTarget = process.env.NEXT_PUBLIC_DEPLOY_TARGET ?? "",
): string {
return deployTarget === HOSTED_DEPLOY_TARGET
? HOSTED_README_SETUP_URL
: SELF_HOST_README_SETUP_URL;
? HOSTED_DOCS_SETUP_URL
: SELF_HOST_DOCS_SETUP_URL;
}

/**
Expand All @@ -133,7 +131,7 @@ export function getReadmeSetupUrl(
* @param props - Target-specific install copy.
* @returns First-time install instructions.
*/
function FirstTimeBody({ cliInstalls, readmeSetupUrl }: FirstTimeBodyProps) {
function FirstTimeBody({ cliInstalls, docsSetupUrl }: FirstTimeBodyProps) {
return (
<>
<p className="text-sm leading-relaxed text-text-secondary">
Expand Down Expand Up @@ -172,12 +170,12 @@ function FirstTimeBody({ cliInstalls, readmeSetupUrl }: FirstTimeBodyProps) {
<p className="text-xs leading-relaxed text-text-muted">
Full setup details (auth, updates, self-hosting) in the{" "}
<a
href={readmeSetupUrl}
href={docsSetupUrl}
target="_blank"
rel="noreferrer"
className="text-accent underline-offset-2 hover:underline"
>
project README
documentation
</a>
.
</p>
Expand All @@ -191,7 +189,7 @@ function FirstTimeBody({ cliInstalls, readmeSetupUrl }: FirstTimeBodyProps) {
* @param props - Target-specific setup link.
* @returns Returning-user "go talk to your agent" hint.
*/
function ReturningBody({ readmeSetupUrl }: ReturningBodyProps) {
function ReturningBody({ docsSetupUrl }: ReturningBodyProps) {
return (
<>
<p className="text-sm leading-relaxed text-text-secondary">
Expand All @@ -214,12 +212,12 @@ function ReturningBody({ readmeSetupUrl }: ReturningBodyProps) {
Setting up another tool, or starting from a fresh machine? Install
commands live in the{" "}
<a
href={readmeSetupUrl}
href={docsSetupUrl}
target="_blank"
rel="noreferrer"
className="text-accent underline-offset-2 hover:underline"
>
project README
documentation
</a>
.
</p>
Expand All @@ -240,7 +238,7 @@ export function GetStartedModal({
hasProjects = false,
}: GetStartedModalProps) {
const cliInstalls = getCliInstalls();
const readmeSetupUrl = getReadmeSetupUrl();
const docsSetupUrl = getDocsSetupUrl();

return (
<Modal
Expand All @@ -251,11 +249,11 @@ export function GetStartedModal({
>
<div className="max-h-[70vh] space-y-5 overflow-y-auto pr-1">
{hasProjects ? (
<ReturningBody readmeSetupUrl={readmeSetupUrl} />
<ReturningBody docsSetupUrl={docsSetupUrl} />
) : (
<FirstTimeBody
cliInstalls={cliInstalls}
readmeSetupUrl={readmeSetupUrl}
docsSetupUrl={docsSetupUrl}
/>
)}
</div>
Expand Down
18 changes: 18 additions & 0 deletions components/layout/TopBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@ import { useCommandPalette } from "@/components/layout/CommandPaletteProvider";
import { useMobileNav } from "@/components/layout/MobileNav";
import { Kbd } from "@/components/shared/Kbd";
import {
IconDoc,
IconMenu,
IconMoon,
IconSearch,
IconSun,
} from "@/components/shared/icons";

const DOCS_URL = "https://docs.piyaz.ai";

interface TopBarProps {
/** @param projectName - Optional project crumb label. When set, renders the project breadcrumb pill. */
projectName?: string;
Expand Down Expand Up @@ -116,6 +119,21 @@ export function TopBar({
aria-hidden="true"
className="mx-1 hidden h-4 w-px bg-border md:inline-block"
/>
<a
href={DOCS_URL}
target="_blank"
rel="noreferrer"
aria-label="Documentation (opens in a new tab)"
title="Documentation"
className="flex h-7 cursor-pointer items-center gap-1.5 rounded-md px-2.5 text-[12px] font-medium text-text-muted transition-colors hover:bg-surface-hover hover:text-text-secondary"
>
<IconDoc size={12} />
<span className="hidden sm:inline">Docs</span>
</a>
<span
aria-hidden="true"
className="mx-1 hidden h-4 w-px bg-border md:inline-block"
/>
<button
type="button"
onClick={toggleTheme}
Expand Down
22 changes: 10 additions & 12 deletions tests/ui/get-started-modal.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ interface CliInstall {

interface GetStartedModalModule {
getCliInstalls?: (deployTarget?: string) => readonly CliInstall[];
getReadmeSetupUrl?: (deployTarget?: string) => string;
getDocsSetupUrl?: (deployTarget?: string) => string;
}

/**
Expand All @@ -18,20 +18,20 @@ interface GetStartedModalModule {
*/
async function loadGetStartedModalModule(): Promise<{
getCliInstalls: NonNullable<GetStartedModalModule["getCliInstalls"]>;
getReadmeSetupUrl: NonNullable<GetStartedModalModule["getReadmeSetupUrl"]>;
getDocsSetupUrl: NonNullable<GetStartedModalModule["getDocsSetupUrl"]>;
}> {
const modal = (await import(
"@/components/home/GetStartedModal"
)) as GetStartedModalModule;

expect(typeof modal.getCliInstalls).toBe("function");
expect(typeof modal.getReadmeSetupUrl).toBe("function");
expect(typeof modal.getDocsSetupUrl).toBe("function");
return {
getCliInstalls: modal.getCliInstalls as NonNullable<
GetStartedModalModule["getCliInstalls"]
>,
getReadmeSetupUrl: modal.getReadmeSetupUrl as NonNullable<
GetStartedModalModule["getReadmeSetupUrl"]
getDocsSetupUrl: modal.getDocsSetupUrl as NonNullable<
GetStartedModalModule["getDocsSetupUrl"]
>,
};
}
Expand All @@ -47,8 +47,7 @@ function installText(installs: readonly CliInstall[]): string {
}

test("hosted deploy shows hosted setup snippets without local checkout paths", async () => {
const { getCliInstalls, getReadmeSetupUrl } =
await loadGetStartedModalModule();
const { getCliInstalls, getDocsSetupUrl } = await loadGetStartedModalModule();
const installs = getCliInstalls("cloudflare");
const text = installText(installs);

Expand All @@ -66,14 +65,13 @@ test("hosted deploy shows hosted setup snippets without local checkout paths", a
expect(text).not.toContain("./plugins");
expect(text).not.toContain("localhost");
expect(text).not.toContain("piyaz-local");
expect(getReadmeSetupUrl("cloudflare")).toContain(
"#use-the-hosted-version-no-clone",
expect(getDocsSetupUrl("cloudflare")).toContain(
"docs.piyaz.ai/docs/get-started/install",
);
});

test("self-host deploy keeps local plugin install commands", async () => {
const { getCliInstalls, getReadmeSetupUrl } =
await loadGetStartedModalModule();
const { getCliInstalls, getDocsSetupUrl } = await loadGetStartedModalModule();
const installs = getCliInstalls("");
const text = installText(installs);

Expand All @@ -84,5 +82,5 @@ test("self-host deploy keeps local plugin install commands", async () => {
expect(text).toContain("piyaz-local");
expect(text).toContain("localhost");
expect(text).not.toContain("FrkAk/piyaz");
expect(getReadmeSetupUrl("")).toContain("#self-host-contribute");
expect(getDocsSetupUrl("")).toContain("docs.piyaz.ai/docs/guides/self-host");
});