orizu 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -13
- package/dist/artifact-archive.js +152 -0
- package/dist/connectors-cli.js +80 -0
- package/dist/credentials.js +4 -1
- package/dist/daytona-slice-rehearsal.js +255 -0
- package/dist/daytona-slice.js +441 -0
- package/dist/egress-allowlist-cli.js +132 -0
- package/dist/egress-policy.js +159 -0
- package/dist/git-credential.js +131 -0
- package/dist/github-setup.js +226 -0
- package/dist/help.js +271 -16
- package/dist/hosted-bootstrap-rehearsal.js +235 -0
- package/dist/hosted-bootstrap.js +365 -0
- package/dist/hosted-broker-server.js +220 -0
- package/dist/hosted-git-http-server.js +136 -0
- package/dist/hosted-harness-claude.js +493 -0
- package/dist/hosted-harness-opencode.js +729 -0
- package/dist/hosted-harness.js +60 -0
- package/dist/hosted-loop.js +477 -0
- package/dist/hosted-run-event-sink.js +499 -0
- package/dist/hosted-runtime-assets.js +216 -0
- package/dist/hosted-session-cli.js +642 -0
- package/dist/index.js +855 -237
- package/dist/kill-switch-cli.js +89 -0
- package/dist/manifests-cli.js +143 -0
- package/dist/preview-runtime.js +4 -1
- package/dist/sandbox-provider.js +238 -0
- package/dist/secret-redaction.js +112 -0
- package/dist/session-timeline.js +103 -0
- package/dist/setup-prompt.js +4 -2
- package/dist/skill-installer.js +9 -1
- package/dist/smoke.js +250 -0
- package/dist/task-assignment-manifest.js +39 -2
- package/dist/vercel-sandbox-provider.js +260 -0
- package/dist/workbench-cli.js +493 -0
- package/dist/workspace-sync.js +924 -0
- package/dist/workspace.js +868 -57
- package/package.json +4 -1
- package/src/artifact-archive.ts +182 -0
- package/src/connectors-cli.ts +115 -0
- package/src/credentials.ts +6 -2
- package/src/daytona-slice-rehearsal.ts +320 -0
- package/src/daytona-slice.ts +598 -0
- package/src/egress-allowlist-cli.ts +147 -0
- package/src/egress-policy.ts +188 -0
- package/src/git-credential.ts +155 -0
- package/src/github-setup.ts +366 -0
- package/src/help.ts +272 -16
- package/src/hosted-bootstrap-rehearsal.ts +312 -0
- package/src/hosted-bootstrap.ts +571 -0
- package/src/hosted-broker-server.ts +278 -0
- package/src/hosted-git-http-server.ts +164 -0
- package/src/hosted-harness-claude.ts +621 -0
- package/src/hosted-harness-opencode.ts +823 -0
- package/src/hosted-harness.ts +124 -0
- package/src/hosted-loop.ts +680 -0
- package/src/hosted-run-event-sink.ts +632 -0
- package/src/hosted-runtime-assets.ts +272 -0
- package/src/hosted-session-cli.ts +844 -0
- package/src/index.ts +987 -296
- package/src/kill-switch-cli.ts +113 -0
- package/src/manifests-cli.ts +168 -0
- package/src/preview-runtime.ts +14 -9
- package/src/sandbox-provider.ts +440 -0
- package/src/secret-redaction.ts +124 -0
- package/src/session-timeline.ts +152 -0
- package/src/setup-prompt.ts +4 -2
- package/src/skill-installer.ts +13 -1
- package/src/smoke.ts +342 -0
- package/src/task-assignment-manifest.ts +70 -2
- package/src/vercel-sandbox-provider.ts +388 -0
- package/src/workbench-cli.ts +701 -0
- package/src/workspace-sync.ts +1148 -0
- package/src/workspace.ts +1051 -64
- package/vendor/skills/orizu-cli/SKILL.md +3 -1
- package/vendor/skills/orizu-cli/references/cli-reference.md +3 -3
package/dist/help.js
CHANGED
|
@@ -16,6 +16,11 @@ const GROUPS = [
|
|
|
16
16
|
{ name: 'Apps', summary: 'Create, preview, update, inspect, and export review apps.' },
|
|
17
17
|
{ name: 'Tasks', summary: 'Create review tasks, mutate task status, assign reviewers, and export labels.' },
|
|
18
18
|
{ name: 'Datasets', summary: 'Upload, version, split, mutate, export, lock, clone, and delete datasets.' },
|
|
19
|
+
{ name: 'Workspace', summary: 'Metadata-first sync of the workbench contract: inspect status, reconcile, pull, and apply.' },
|
|
20
|
+
{ name: 'Sessions', summary: 'Start, inspect, and end durable workspace sessions for agent/operator work.' },
|
|
21
|
+
{ name: 'Workbench runs', summary: 'Start, inspect, tail, and finish resumable workbench runs.' },
|
|
22
|
+
{ name: 'Connectors', summary: 'Inspect project connector/integration readiness (read-only; secrets redacted).' },
|
|
23
|
+
{ name: 'Promotion manifests', summary: 'List, inspect, approve, reject, and idempotently apply promotion manifests.' },
|
|
19
24
|
];
|
|
20
25
|
export const COMMAND_DOCS = [
|
|
21
26
|
{
|
|
@@ -54,28 +59,36 @@ export const COMMAND_DOCS = [
|
|
|
54
59
|
},
|
|
55
60
|
{
|
|
56
61
|
path: ['setup'],
|
|
57
|
-
usage: 'orizu setup [--agent <claude|codex>]... [--
|
|
58
|
-
summary: 'Guided onboarding: sign in,
|
|
62
|
+
usage: 'orizu setup [--team <slug>] [--agent <claude|codex>]... [--workspace [path]|--no-workspace] [--validate] [--fix] [--no-symlinks] [--verbose] [--no-install] [--handoff|--no-handoff] [--launch <claude|codex>] [--skip-login] [--yes] [--dry-run] [--no-input|--non-interactive] [--json]',
|
|
63
|
+
summary: 'Guided onboarding: sign in, initialize the workbench contract, and install agent skills.',
|
|
59
64
|
group: 'Agent setup',
|
|
60
65
|
options: [
|
|
61
|
-
{ name: '--
|
|
62
|
-
{ name: '--
|
|
63
|
-
{ name: '--
|
|
64
|
-
{ name: '--workspace', help: '
|
|
65
|
-
{ name: '--
|
|
66
|
-
{ name: '--
|
|
67
|
-
{ name: '--no-
|
|
66
|
+
{ name: '--team <slug>', help: 'Team/workbench slug. Authenticated setup materializes all projects in this team.' },
|
|
67
|
+
{ name: '--workspace [path]', help: 'Initialize or validate a workspace path, or the current directory when no path is provided. If provided, the value must be a filesystem path.' },
|
|
68
|
+
{ name: '--service-origin <url>', help: 'Service origin written to setup metadata. Defaults to the active CLI server.' },
|
|
69
|
+
{ name: '--attach-workspace <id>', help: 'Record an existing Orizu workspace id for future attachment.' },
|
|
70
|
+
{ name: '--validate', help: 'Inspect the workspace contract without writing files.' },
|
|
71
|
+
{ name: '--fix', help: 'Apply safe idempotent repairs only.' },
|
|
72
|
+
{ name: '--no-symlinks', help: 'Write CLAUDE.md as a pointer file instead of a symlink to AGENTS.md.' },
|
|
73
|
+
{ name: '--verbose', help: 'Show per-file setup actions. Default setup output is summary-oriented.' },
|
|
74
|
+
{ name: '--agent <agent>', help: 'Install the global Orizu skill for this coding agent after workspace setup. Repeat for multiple agents.', repeatable: true, choices: ['claude', 'codex'] },
|
|
75
|
+
{ name: '--no-workspace', help: 'Skip workspace creation during guided setup. `--validate` and `--fix` still inspect or repair the workspace contract.' },
|
|
76
|
+
{ name: '--no-install', help: 'Skip the coding-agent skill install step.' },
|
|
77
|
+
{ name: '--handoff', help: 'Print the coding-agent setup prompt after setup. By default, setup points to `orizu setup prompt` instead of printing it inline.' },
|
|
78
|
+
{ name: '--no-handoff', help: 'Compatibility flag; suppresses --handoff/--launch. Setup does not print the handoff prompt by default.' },
|
|
68
79
|
{ name: '--launch <agent>', help: 'Launch a detected coding agent with the setup prompt (interactive terminals only).', choices: ['claude', 'codex'] },
|
|
69
80
|
{ name: '--skip-login', help: 'Skip the authentication phase.' },
|
|
70
|
-
{ name: '--yes', help: '
|
|
81
|
+
{ name: '--yes', help: 'Replace existing managed skill links without prompting.' },
|
|
71
82
|
{ name: '--dry-run', help: 'Preview every planned change without writing.' },
|
|
72
83
|
{ name: '--no-input', help: 'Never prompt; behave as in a non-interactive terminal.' },
|
|
84
|
+
{ name: '--non-interactive', help: 'Alias for --no-input.' },
|
|
73
85
|
{ name: '--json', help: 'Emit the setup summary as JSON.' },
|
|
74
86
|
],
|
|
75
87
|
examples: [
|
|
76
88
|
'orizu setup',
|
|
77
|
-
'orizu setup --
|
|
78
|
-
'orizu setup --
|
|
89
|
+
'orizu setup --team highlight',
|
|
90
|
+
'orizu setup --team highlight --agent codex --agent claude --non-interactive --yes',
|
|
91
|
+
'orizu setup --validate --workspace ./workbench',
|
|
79
92
|
],
|
|
80
93
|
},
|
|
81
94
|
{
|
|
@@ -88,7 +101,7 @@ export const COMMAND_DOCS = [
|
|
|
88
101
|
{
|
|
89
102
|
path: ['install-skill'],
|
|
90
103
|
usage: 'orizu install-skill [--agent <claude|codex>]... [--scope global|project] [--mode auto|link|copy] [--target <target>]... [--yes] [--dry-run]',
|
|
91
|
-
summary: '
|
|
104
|
+
summary: 'Install or repair the Orizu coding-agent skill.',
|
|
92
105
|
group: 'Agent setup',
|
|
93
106
|
aliases: [['skills', 'install']],
|
|
94
107
|
options: [
|
|
@@ -112,7 +125,7 @@ export const COMMAND_DOCS = [
|
|
|
112
125
|
name: '--target <target>',
|
|
113
126
|
help: 'Advanced: explicit install destination ID. Repeat for multiple targets.',
|
|
114
127
|
repeatable: true,
|
|
115
|
-
choices: ['agent-user', 'agents-project', 'codex-project', 'claude-user', 'claude-project', 'agents-md'],
|
|
128
|
+
choices: ['codex-user', 'agent-user', 'agents-project', 'codex-project', 'claude-user', 'claude-project', 'agents-md'],
|
|
116
129
|
},
|
|
117
130
|
{ name: '--yes', help: 'Replace an existing managed skill or AGENTS.md section without prompting.' },
|
|
118
131
|
{ name: '--dry-run', help: 'Show planned writes without changing files.' },
|
|
@@ -201,7 +214,7 @@ export const COMMAND_DOCS = [
|
|
|
201
214
|
},
|
|
202
215
|
{
|
|
203
216
|
path: ['teams', 'members', 'role'],
|
|
204
|
-
usage: 'orizu teams members role --team <teamSlug> --email <email> --role <admin|
|
|
217
|
+
usage: 'orizu teams members role --team <teamSlug> --email <email> --role <admin|curator|judge>',
|
|
205
218
|
summary: 'Change a member role.',
|
|
206
219
|
group: 'Teams',
|
|
207
220
|
},
|
|
@@ -454,6 +467,18 @@ export const COMMAND_DOCS = [
|
|
|
454
467
|
summary: 'Create a draft review task by default, with auto distribution or an explicit row-assignment JSONL file.',
|
|
455
468
|
group: 'Tasks',
|
|
456
469
|
},
|
|
470
|
+
{
|
|
471
|
+
path: ['tasks', 'update'],
|
|
472
|
+
usage: 'orizu tasks update --task <taskId> [--title <text>] [--description <text>|--description-file <path>] [--instructions <text>|--instructions-file <path>] [--dataset <datasetId>] [--app <appId> [--version <n>]] [--labels-per-item <n>] [--assignees <userIdOrEmail1,userIdOrEmail2> | --assignment-file <path>] [--json]',
|
|
473
|
+
summary: 'Update a draft review task before publishing.',
|
|
474
|
+
group: 'Tasks',
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
path: ['tasks', 'discard'],
|
|
478
|
+
usage: 'orizu tasks discard --task <taskId> [--yes] [--json]',
|
|
479
|
+
summary: 'Permanently discard a draft review task.',
|
|
480
|
+
group: 'Tasks',
|
|
481
|
+
},
|
|
457
482
|
{
|
|
458
483
|
path: ['tasks', 'publish'],
|
|
459
484
|
usage: 'orizu tasks publish --task <taskId> (--assignees <userId1,userId2> | --assignment-file <path>) [--json]',
|
|
@@ -501,6 +526,12 @@ export const COMMAND_DOCS = [
|
|
|
501
526
|
summary: 'Resume a paused task.',
|
|
502
527
|
group: 'Tasks',
|
|
503
528
|
},
|
|
529
|
+
{
|
|
530
|
+
path: ['tasks', 'complete'],
|
|
531
|
+
usage: 'orizu tasks complete --task <taskId>',
|
|
532
|
+
summary: 'Mark an active or paused task completed.',
|
|
533
|
+
group: 'Tasks',
|
|
534
|
+
},
|
|
504
535
|
{
|
|
505
536
|
path: ['tasks', 'export'],
|
|
506
537
|
usage: 'orizu tasks export [--task <taskId>] [--format <csv|json|jsonl>] [--out <path>]',
|
|
@@ -579,6 +610,230 @@ export const COMMAND_DOCS = [
|
|
|
579
610
|
summary: 'Clone a dataset.',
|
|
580
611
|
group: 'Datasets',
|
|
581
612
|
},
|
|
613
|
+
{
|
|
614
|
+
path: ['workspace', 'status'],
|
|
615
|
+
usage: 'orizu workspace status [--remote] [--json]',
|
|
616
|
+
summary: 'Show tracked-resource status: local dirtiness vs the last-sync cache, plus missing and untracked files; --remote adds server statuses via a server-side reconciliation.',
|
|
617
|
+
group: 'Workspace',
|
|
618
|
+
options: [
|
|
619
|
+
{ name: '--remote', help: 'Attach server statuses. This performs the same server-side reconciliation as `orizu workspace sync` — it registers and updates tracked-resource records; there is no read-only remote status in v0. The local cache is never advanced.' },
|
|
620
|
+
{ name: '--json', help: 'Emit the machine-readable status result.' },
|
|
621
|
+
],
|
|
622
|
+
examples: ['orizu workspace status', 'orizu workspace status --remote --json'],
|
|
623
|
+
},
|
|
624
|
+
{
|
|
625
|
+
path: ['workspace', 'sync'],
|
|
626
|
+
usage: 'orizu workspace sync [--json]',
|
|
627
|
+
summary: 'Metadata-first reconcile of the whole workbench. Attaches the workspace on first run; advances the cache base only on a clean convergence.',
|
|
628
|
+
group: 'Workspace',
|
|
629
|
+
options: [
|
|
630
|
+
{ name: '--json', help: 'Emit the machine-readable per-resource status list.' },
|
|
631
|
+
],
|
|
632
|
+
examples: ['orizu workspace sync', 'orizu workspace sync --json'],
|
|
633
|
+
},
|
|
634
|
+
{
|
|
635
|
+
path: ['workspace', 'pull'],
|
|
636
|
+
usage: 'orizu workspace pull <path> [--json]',
|
|
637
|
+
summary: 'Fast-forward a resource to the server truth (v0: manifest canonical block + cache only). Refuses when local edits are ahead and no-ops when the server has no truth (local-only/stale). Bulk content materializes via the primitive command (e.g. orizu prompts pull).',
|
|
638
|
+
group: 'Workspace',
|
|
639
|
+
options: [
|
|
640
|
+
{ name: '--json', help: 'Emit the machine-readable pull result.' },
|
|
641
|
+
],
|
|
642
|
+
examples: ['orizu workspace pull projects/hip/prompts/judge/orizu.prompt.json'],
|
|
643
|
+
},
|
|
644
|
+
{
|
|
645
|
+
path: ['workspace', 'apply'],
|
|
646
|
+
usage: 'orizu workspace apply <path> [--json]',
|
|
647
|
+
summary: 'Promote a repo-owned resource to the server, addressed by the row id recorded by sync. Refuses (409) DB-native/object-storage owners, conflicts, remote-newer, and lost compare-and-set races — on any refusal, run `orizu workspace sync`, converge, then retry.',
|
|
648
|
+
group: 'Workspace',
|
|
649
|
+
options: [
|
|
650
|
+
{ name: '--json', help: 'Emit the machine-readable apply result.' },
|
|
651
|
+
],
|
|
652
|
+
examples: ['orizu workspace apply projects/hip/prompts/judge/orizu.prompt.json'],
|
|
653
|
+
},
|
|
654
|
+
{
|
|
655
|
+
path: ['session', 'start'],
|
|
656
|
+
usage: 'orizu session start [--project <team/project>] [--json]',
|
|
657
|
+
summary: 'Start a durable workspace session for the attached workspace and print the session id for later resume.',
|
|
658
|
+
group: 'Sessions',
|
|
659
|
+
options: [
|
|
660
|
+
{ name: '--project <team/project>', help: 'Optionally scope the session to a project in the attached workspace.' },
|
|
661
|
+
{ name: '--json', help: 'Emit the machine-readable session payload.' },
|
|
662
|
+
],
|
|
663
|
+
examples: ['orizu session start', 'orizu session start --project highlight/hip --json'],
|
|
664
|
+
},
|
|
665
|
+
{
|
|
666
|
+
path: ['session', 'status'],
|
|
667
|
+
usage: 'orizu session status [--session <id> | --status active|ended] [--json]',
|
|
668
|
+
summary: 'Inspect one session by id, including run summaries, or list sessions for the attached workspace.',
|
|
669
|
+
group: 'Sessions',
|
|
670
|
+
options: [
|
|
671
|
+
{ name: '--session <id>', help: 'Resume by session id; does not require the original terminal.' },
|
|
672
|
+
{ name: '--status <status>', help: 'Filter attached-workspace sessions when --session is omitted.', choices: ['active', 'ended'] },
|
|
673
|
+
{ name: '--json', help: 'Emit the machine-readable session or session-list payload.' },
|
|
674
|
+
],
|
|
675
|
+
examples: ['orizu session status --session sess_123 --json', 'orizu session status --status active'],
|
|
676
|
+
},
|
|
677
|
+
{
|
|
678
|
+
path: ['session', 'end'],
|
|
679
|
+
usage: 'orizu session end --session <id> [--json]',
|
|
680
|
+
summary: 'Mark a durable workspace session ended.',
|
|
681
|
+
group: 'Sessions',
|
|
682
|
+
options: [
|
|
683
|
+
{ name: '--session <id>', help: 'Session id to end.', required: true },
|
|
684
|
+
{ name: '--json', help: 'Emit the machine-readable ended session payload.' },
|
|
685
|
+
],
|
|
686
|
+
examples: ['orizu session end --session sess_123'],
|
|
687
|
+
},
|
|
688
|
+
{
|
|
689
|
+
path: ['session', 'finish'],
|
|
690
|
+
usage: 'orizu session finish --session <id> [--project <team/project>] [--json]',
|
|
691
|
+
summary: 'Finish a hosted session branch: no changes deletes the branch; changes create a repo_merge promotion manifest to review and approve (no GitHub PR).',
|
|
692
|
+
group: 'Sessions',
|
|
693
|
+
options: [
|
|
694
|
+
{ name: '--session <id>', help: 'Session id whose branch to finish.', required: true },
|
|
695
|
+
{ name: '--project <team/project>', help: 'Project scope for the manifest when the session is not already project-scoped.' },
|
|
696
|
+
{ name: '--json', help: 'Emit the machine-readable outcome (no-changes or the created manifest).' },
|
|
697
|
+
],
|
|
698
|
+
examples: ['orizu session finish --session sess_123', 'orizu session finish --session sess_123 --project highlight/hip --json'],
|
|
699
|
+
},
|
|
700
|
+
{
|
|
701
|
+
path: ['run', 'start'],
|
|
702
|
+
usage: 'orizu run start --session <id> --title <title> [--project <team/project>] [--json]',
|
|
703
|
+
summary: 'Start a resumable workbench run inside a workspace session and print the run id.',
|
|
704
|
+
group: 'Workbench runs',
|
|
705
|
+
options: [
|
|
706
|
+
{ name: '--session <id>', help: 'Workspace session id.', required: true },
|
|
707
|
+
{ name: '--title <title>', help: 'Human-readable run title.', required: true },
|
|
708
|
+
{ name: '--project <team/project>', help: 'Optionally override the session project scope.' },
|
|
709
|
+
{ name: '--json', help: 'Emit the machine-readable run payload.' },
|
|
710
|
+
],
|
|
711
|
+
examples: ['orizu run start --session sess_123 --title "Fix evaluator drift" --json'],
|
|
712
|
+
},
|
|
713
|
+
{
|
|
714
|
+
path: ['run', 'status'],
|
|
715
|
+
usage: 'orizu run status --run <id> [--json]',
|
|
716
|
+
summary: 'Inspect a workbench run by id, including evidence and latest event sequence.',
|
|
717
|
+
group: 'Workbench runs',
|
|
718
|
+
options: [
|
|
719
|
+
{ name: '--run <id>', help: 'Workbench run id.', required: true },
|
|
720
|
+
{ name: '--json', help: 'Emit the machine-readable run payload.' },
|
|
721
|
+
],
|
|
722
|
+
examples: ['orizu run status --run run_123 --json'],
|
|
723
|
+
},
|
|
724
|
+
{
|
|
725
|
+
path: ['run', 'tail'],
|
|
726
|
+
usage: 'orizu run tail --run <id> [--after <seq>] [--interval <seconds>] [--once] [--json]',
|
|
727
|
+
summary: 'Cursor-poll a workbench run event log; JSON mode emits one event object per line.',
|
|
728
|
+
group: 'Workbench runs',
|
|
729
|
+
options: [
|
|
730
|
+
{ name: '--run <id>', help: 'Workbench run id.', required: true },
|
|
731
|
+
{ name: '--after <seq>', help: 'Start after this event sequence. Defaults to 0.' },
|
|
732
|
+
{ name: '--interval <seconds>', help: 'Polling interval for non-terminal runs. Defaults to 2.' },
|
|
733
|
+
{ name: '--once', help: 'Fetch one page and exit; useful for tests and agents.' },
|
|
734
|
+
{ name: '--json', help: 'Emit JSONL, one event object per line.' },
|
|
735
|
+
],
|
|
736
|
+
examples: ['orizu run tail --run run_123', 'orizu run tail --run run_123 --after 42 --once --json'],
|
|
737
|
+
},
|
|
738
|
+
{
|
|
739
|
+
path: ['run', 'complete'],
|
|
740
|
+
usage: 'orizu run complete --run <id> [--summary <text>] [--json]',
|
|
741
|
+
summary: 'Mark a workbench run succeeded.',
|
|
742
|
+
group: 'Workbench runs',
|
|
743
|
+
options: [
|
|
744
|
+
{ name: '--run <id>', help: 'Workbench run id.', required: true },
|
|
745
|
+
{ name: '--summary <text>', help: 'Optional note stored in the run summary.' },
|
|
746
|
+
{ name: '--json', help: 'Emit the machine-readable run payload.' },
|
|
747
|
+
],
|
|
748
|
+
examples: ['orizu run complete --run run_123 --summary "All gates passed"'],
|
|
749
|
+
},
|
|
750
|
+
{
|
|
751
|
+
path: ['run', 'fail'],
|
|
752
|
+
usage: 'orizu run fail --run <id> [--summary <text>] [--json]',
|
|
753
|
+
summary: 'Mark a workbench run failed.',
|
|
754
|
+
group: 'Workbench runs',
|
|
755
|
+
options: [
|
|
756
|
+
{ name: '--run <id>', help: 'Workbench run id.', required: true },
|
|
757
|
+
{ name: '--summary <text>', help: 'Optional note stored in the run summary.' },
|
|
758
|
+
{ name: '--json', help: 'Emit the machine-readable run payload.' },
|
|
759
|
+
],
|
|
760
|
+
examples: ['orizu run fail --run run_123 --summary "Lint failed"'],
|
|
761
|
+
},
|
|
762
|
+
{
|
|
763
|
+
path: ['run', 'cancel'],
|
|
764
|
+
usage: 'orizu run cancel --run <id> [--summary <text>] [--json]',
|
|
765
|
+
summary: 'Mark a workbench run cancelled.',
|
|
766
|
+
group: 'Workbench runs',
|
|
767
|
+
options: [
|
|
768
|
+
{ name: '--run <id>', help: 'Workbench run id.', required: true },
|
|
769
|
+
{ name: '--summary <text>', help: 'Optional note stored in the run summary.' },
|
|
770
|
+
{ name: '--json', help: 'Emit the machine-readable run payload.' },
|
|
771
|
+
],
|
|
772
|
+
examples: ['orizu run cancel --run run_123 --summary "Superseded by run_456"'],
|
|
773
|
+
},
|
|
774
|
+
{
|
|
775
|
+
path: ['connectors', 'status'],
|
|
776
|
+
usage: 'orizu connectors [status] [--project <team/project>] [--json]',
|
|
777
|
+
summary: 'Show project connector readiness (configured/missing/stale/unauthorized/unsupported/unknown) derived read-only from stored integration state. Secrets are always redacted.',
|
|
778
|
+
group: 'Connectors',
|
|
779
|
+
options: [
|
|
780
|
+
{ name: '--project <team/project>', help: 'Project whose connector readiness to inspect.' },
|
|
781
|
+
{ name: '--json', help: 'Emit the machine-readable connector readiness payload.' },
|
|
782
|
+
],
|
|
783
|
+
examples: ['orizu connectors', 'orizu connectors status --project highlight/hip --json'],
|
|
784
|
+
},
|
|
785
|
+
{
|
|
786
|
+
path: ['manifests', 'list'],
|
|
787
|
+
usage: 'orizu manifests list [--project <team/project>] [--status <status>] [--json]',
|
|
788
|
+
summary: 'List promotion manifests for a project, newest first, optionally filtered by status.',
|
|
789
|
+
group: 'Promotion manifests',
|
|
790
|
+
options: [
|
|
791
|
+
{ name: '--project <team/project>', help: 'Project whose manifests to list.' },
|
|
792
|
+
{ name: '--status <status>', help: 'Filter by status.', choices: ['draft', 'pending_approval', 'approved', 'applied', 'rejected'] },
|
|
793
|
+
{ name: '--json', help: 'Emit the machine-readable manifest list.' },
|
|
794
|
+
],
|
|
795
|
+
examples: ['orizu manifests list --project highlight/hip --status pending_approval'],
|
|
796
|
+
},
|
|
797
|
+
{
|
|
798
|
+
path: ['manifests', 'show'],
|
|
799
|
+
usage: 'orizu manifests show <id> [--json]',
|
|
800
|
+
summary: 'Show one promotion manifest, including current/proposed state, evidence, outcome, and approver.',
|
|
801
|
+
group: 'Promotion manifests',
|
|
802
|
+
options: [
|
|
803
|
+
{ name: '--json', help: 'Emit the machine-readable manifest payload.' },
|
|
804
|
+
],
|
|
805
|
+
examples: ['orizu manifests show manifest_123 --json'],
|
|
806
|
+
},
|
|
807
|
+
{
|
|
808
|
+
path: ['manifests', 'approve'],
|
|
809
|
+
usage: 'orizu manifests approve <id> [--json]',
|
|
810
|
+
summary: 'Approve a draft or pending_approval manifest; records the approver principal separately from the author.',
|
|
811
|
+
group: 'Promotion manifests',
|
|
812
|
+
options: [
|
|
813
|
+
{ name: '--json', help: 'Emit the machine-readable manifest payload.' },
|
|
814
|
+
],
|
|
815
|
+
examples: ['orizu manifests approve manifest_123'],
|
|
816
|
+
},
|
|
817
|
+
{
|
|
818
|
+
path: ['manifests', 'reject'],
|
|
819
|
+
usage: 'orizu manifests reject <id> [--json]',
|
|
820
|
+
summary: 'Reject a manifest so it can no longer be applied.',
|
|
821
|
+
group: 'Promotion manifests',
|
|
822
|
+
options: [
|
|
823
|
+
{ name: '--json', help: 'Emit the machine-readable manifest payload.' },
|
|
824
|
+
],
|
|
825
|
+
examples: ['orizu manifests reject manifest_123'],
|
|
826
|
+
},
|
|
827
|
+
{
|
|
828
|
+
path: ['manifests', 'apply'],
|
|
829
|
+
usage: 'orizu manifests apply <id> [--json]',
|
|
830
|
+
summary: 'Apply an approved manifest. Idempotent: re-applying returns the stored outcome with no second effect. v0 records the outcome and links evidence; content promotion still flows through the primitive commands.',
|
|
831
|
+
group: 'Promotion manifests',
|
|
832
|
+
options: [
|
|
833
|
+
{ name: '--json', help: 'Emit the machine-readable manifest payload.' },
|
|
834
|
+
],
|
|
835
|
+
examples: ['orizu manifests apply manifest_123 --json'],
|
|
836
|
+
},
|
|
582
837
|
];
|
|
583
838
|
function groupByName(name) {
|
|
584
839
|
return GROUPS.find(group => group.name === name);
|
|
@@ -625,7 +880,7 @@ export function renderRootHelp() {
|
|
|
625
880
|
lines.push(` ${doc.usage}`);
|
|
626
881
|
}
|
|
627
882
|
}
|
|
628
|
-
lines.push('', 'Examples:', ' orizu install-skill --target
|
|
883
|
+
lines.push('', 'Examples:', ' orizu install-skill --target codex-user --yes', ' orizu apps preview --file ./App.tsx --input-schema ./input.json --output-schema ./output.json --sample-row ./row.json --screenshot ./preview.png', ' orizu tasks create --project core/evals --dataset <datasetId> --app <appId> --title "Review"', ' orizu tasks publish --task <taskId> --assignees <userId1,userId2>', '', 'More:', ' orizu <group> --help', ' orizu <command> --help', ' orizu capabilities --json', ' https://docs.orizu.ai');
|
|
629
884
|
return lines.join('\n');
|
|
630
885
|
}
|
|
631
886
|
export function renderGroupHelp(args) {
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Self-contained rehearsal for the hosted bootstrap (ALI-925), extending the
|
|
3
|
+
* ALI-973 `daytona-slice-rehearsal` pattern.
|
|
4
|
+
*
|
|
5
|
+
* The whole `bootstrapHostedSandbox` flow runs against the local-sim provider
|
|
6
|
+
* with NO Daytona and NO GitHub: a REAL bare git repo backs the session branch,
|
|
7
|
+
* and a REAL HTTP broker (`hosted-broker-server.ts`) stands in for the Orizu
|
|
8
|
+
* control plane (per-repo token broker + RunAPI event ingest).
|
|
9
|
+
*
|
|
10
|
+
* The broker runs as a SEPARATE PROCESS on purpose: local-sim's `exec` blocks on
|
|
11
|
+
* `spawnSync`, and the in-sandbox credential helper it runs calls the broker over
|
|
12
|
+
* the network — an in-process server could not answer while the test thread is
|
|
13
|
+
* blocked. The broker journals events/tokens to files the rehearsal reads back.
|
|
14
|
+
*/
|
|
15
|
+
import { spawnSync } from 'child_process';
|
|
16
|
+
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'fs';
|
|
17
|
+
import { tmpdir } from 'os';
|
|
18
|
+
import { basename, join } from 'path';
|
|
19
|
+
import { fileURLToPath } from 'url';
|
|
20
|
+
import { seedLocalBareRepo } from './daytona-slice-rehearsal.js';
|
|
21
|
+
import { createLocalSimProvider } from './sandbox-provider.js';
|
|
22
|
+
import { gitHttpEnv } from './hosted-git-http-server.js';
|
|
23
|
+
/** The loopback host the git server binds; the helper is scoped to it. */
|
|
24
|
+
const LOOPBACK_HOST = '127.0.0.1';
|
|
25
|
+
function git(args, cwd) {
|
|
26
|
+
const env = { ...process.env, GIT_CONFIG_NOSYSTEM: '1', GIT_TERMINAL_PROMPT: '0' };
|
|
27
|
+
delete env.GIT_DIR;
|
|
28
|
+
delete env.GIT_WORK_TREE;
|
|
29
|
+
delete env.GIT_INDEX_FILE;
|
|
30
|
+
delete env.GIT_OBJECT_DIRECTORY;
|
|
31
|
+
delete env.GIT_COMMON_DIR;
|
|
32
|
+
const res = spawnSync('git', args, { cwd, encoding: 'utf8', env });
|
|
33
|
+
return { stdout: res.stdout ?? '', stderr: res.stderr ?? '', status: res.status ?? 1 };
|
|
34
|
+
}
|
|
35
|
+
function gitOrThrow(args, cwd) {
|
|
36
|
+
const r = git(args, cwd);
|
|
37
|
+
if (r.status !== 0)
|
|
38
|
+
throw new Error(`git ${args.join(' ')} failed: ${r.stderr.trim() || `exit ${r.status}`}`);
|
|
39
|
+
return r.stdout;
|
|
40
|
+
}
|
|
41
|
+
function bunSpawn() {
|
|
42
|
+
const b = globalThis.Bun;
|
|
43
|
+
if (!b?.spawn)
|
|
44
|
+
throw new Error('Bun.spawn is required for the hosted-bootstrap rehearsal (run under bun test)');
|
|
45
|
+
return b;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Env keys the broker server reads (kept here so callers do not hand-roll them).
|
|
49
|
+
*/
|
|
50
|
+
export function brokerEnv(config) {
|
|
51
|
+
const env = { HB_BEARER: config.bearer, HB_REPO: config.repo };
|
|
52
|
+
if (config.eventsFile)
|
|
53
|
+
env.HB_EVENTS_FILE = config.eventsFile;
|
|
54
|
+
if (config.tokensFile)
|
|
55
|
+
env.HB_TOKENS_FILE = config.tokensFile;
|
|
56
|
+
if (config.sessionId)
|
|
57
|
+
env.HB_SESSION_ID = config.sessionId;
|
|
58
|
+
if (config.sessionBranch)
|
|
59
|
+
env.HB_SESSION_BRANCH = config.sessionBranch;
|
|
60
|
+
if (config.repoTokenStatus)
|
|
61
|
+
env.HB_REPO_TOKEN_STATUS = String(config.repoTokenStatus);
|
|
62
|
+
if (config.eventsStatus)
|
|
63
|
+
env.HB_EVENTS_STATUS = String(config.eventsStatus);
|
|
64
|
+
if (config.denyWrite)
|
|
65
|
+
env.HB_DENY_WRITE = '1';
|
|
66
|
+
if (config.fullRunApi)
|
|
67
|
+
env.HB_FULL_RUN_API = '1';
|
|
68
|
+
return env;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Spawn the broker server as its own process and resolve once it prints
|
|
72
|
+
* `LISTENING <port>` on stdout.
|
|
73
|
+
*/
|
|
74
|
+
export async function spawnBrokerProcess(config) {
|
|
75
|
+
const brokerPath = fileURLToPath(new URL('./hosted-broker-server.ts', import.meta.url));
|
|
76
|
+
const proc = bunSpawn().spawn({
|
|
77
|
+
cmd: ['bun', brokerPath],
|
|
78
|
+
env: { ...process.env, ...brokerEnv(config) },
|
|
79
|
+
stdout: 'pipe',
|
|
80
|
+
stderr: 'inherit',
|
|
81
|
+
});
|
|
82
|
+
const decoder = new TextDecoder();
|
|
83
|
+
const reader = proc.stdout.getReader();
|
|
84
|
+
let buffered = '';
|
|
85
|
+
const deadline = Date.now() + 10_000;
|
|
86
|
+
while (Date.now() <= deadline) {
|
|
87
|
+
const { done, value } = await reader.read();
|
|
88
|
+
if (done)
|
|
89
|
+
break;
|
|
90
|
+
if (value)
|
|
91
|
+
buffered += decoder.decode(value, { stream: true });
|
|
92
|
+
const match = buffered.match(/LISTENING (\d+)/);
|
|
93
|
+
if (match) {
|
|
94
|
+
reader.releaseLock();
|
|
95
|
+
const port = Number.parseInt(match[1], 10);
|
|
96
|
+
return { apiBaseUrl: `http://127.0.0.1:${port}`, port, stop: () => proc.kill() };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
reader.releaseLock();
|
|
100
|
+
proc.kill();
|
|
101
|
+
throw new Error('broker server did not report a listening port in time');
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Spawn the authenticated smart-HTTP git server as its own process (same
|
|
105
|
+
* separate-process rationale as the broker) and resolve once it prints
|
|
106
|
+
* `LISTENING <port>`. `baseUrl` is the clone URL root; append the repo segment.
|
|
107
|
+
*/
|
|
108
|
+
export async function spawnGitHttpProcess(config) {
|
|
109
|
+
const serverPath = fileURLToPath(new URL('./hosted-git-http-server.ts', import.meta.url));
|
|
110
|
+
const proc = bunSpawn().spawn({
|
|
111
|
+
cmd: ['bun', serverPath],
|
|
112
|
+
env: { ...process.env, ...gitHttpEnv(config) },
|
|
113
|
+
stdout: 'pipe',
|
|
114
|
+
stderr: 'inherit',
|
|
115
|
+
});
|
|
116
|
+
const decoder = new TextDecoder();
|
|
117
|
+
const reader = proc.stdout.getReader();
|
|
118
|
+
let buffered = '';
|
|
119
|
+
const deadline = Date.now() + 10_000;
|
|
120
|
+
while (Date.now() <= deadline) {
|
|
121
|
+
const { done, value } = await reader.read();
|
|
122
|
+
if (done)
|
|
123
|
+
break;
|
|
124
|
+
if (value)
|
|
125
|
+
buffered += decoder.decode(value, { stream: true });
|
|
126
|
+
const match = buffered.match(/LISTENING (\d+)/);
|
|
127
|
+
if (match) {
|
|
128
|
+
reader.releaseLock();
|
|
129
|
+
const port = Number.parseInt(match[1], 10);
|
|
130
|
+
return { baseUrl: `http://127.0.0.1:${port}`, port, stop: () => proc.kill() };
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
reader.releaseLock();
|
|
134
|
+
proc.kill();
|
|
135
|
+
throw new Error('git http server did not report a listening port in time');
|
|
136
|
+
}
|
|
137
|
+
function readJsonl(file) {
|
|
138
|
+
let raw = '';
|
|
139
|
+
try {
|
|
140
|
+
raw = readFileSync(file, 'utf8');
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return [];
|
|
144
|
+
}
|
|
145
|
+
return raw
|
|
146
|
+
.split('\n')
|
|
147
|
+
.filter(line => line.length > 0)
|
|
148
|
+
.map(line => JSON.parse(line));
|
|
149
|
+
}
|
|
150
|
+
function readLines(file) {
|
|
151
|
+
try {
|
|
152
|
+
return readFileSync(file, 'utf8').split('\n').filter(line => line.length > 0);
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
return [];
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
export async function createHostedBootstrapRehearsal(options = {}) {
|
|
159
|
+
const bearer = options.bearer ?? 'pat_rehearsal_bearer_do_not_log';
|
|
160
|
+
const base = mkdtempSync(join(tmpdir(), 'orizu-hosted-boot-'));
|
|
161
|
+
const repo = seedLocalBareRepo(base, {
|
|
162
|
+
teamSlug: 'acme',
|
|
163
|
+
projectSlug: 'support-bot',
|
|
164
|
+
workspaceSlug: 'support-bot-hosted',
|
|
165
|
+
});
|
|
166
|
+
const workspaceId = 'ws-hosted-1';
|
|
167
|
+
const sessionId = 'sess-hosted-1';
|
|
168
|
+
const runId = 'run-hosted-1';
|
|
169
|
+
const sessionBranch = `orizu/session-${sessionId}`;
|
|
170
|
+
// Cut the session branch off main on the real bare repo.
|
|
171
|
+
gitOrThrow(['--git-dir', repo.gitDir, 'branch', sessionBranch, repo.defaultBranch]);
|
|
172
|
+
// Optionally seed a customer setup hook onto the session branch. `.orizu/` is
|
|
173
|
+
// git-ignored by the workbench contract, so the hook is force-added — an open
|
|
174
|
+
// question flagged in the secrets-policy doc.
|
|
175
|
+
if (options.setupHookBody) {
|
|
176
|
+
const work = mkdtempSync(join(base, 'hook-'));
|
|
177
|
+
gitOrThrow(['clone', '--branch', sessionBranch, repo.gitDir, work]);
|
|
178
|
+
mkdirSync(join(work, '.orizu'), { recursive: true });
|
|
179
|
+
writeFileSync(join(work, '.orizu', 'setup.sh'), options.setupHookBody);
|
|
180
|
+
const ident = ['-c', 'user.email=hook@orizu.local', '-c', 'user.name=Hook'];
|
|
181
|
+
gitOrThrow([...ident, '-C', work, 'add', '-f', '.orizu/setup.sh']);
|
|
182
|
+
gitOrThrow([...ident, '-C', work, 'commit', '-m', 'seed setup hook']);
|
|
183
|
+
gitOrThrow(['-C', work, 'push', 'origin', sessionBranch]);
|
|
184
|
+
rmSync(work, { recursive: true, force: true });
|
|
185
|
+
}
|
|
186
|
+
const eventsFile = join(base, 'events.jsonl');
|
|
187
|
+
const tokensFile = join(base, 'tokens.txt');
|
|
188
|
+
const authLogFile = join(base, 'git-auth.jsonl');
|
|
189
|
+
writeFileSync(eventsFile, '');
|
|
190
|
+
writeFileSync(tokensFile, '');
|
|
191
|
+
writeFileSync(authLogFile, '');
|
|
192
|
+
const broker = await spawnBrokerProcess({
|
|
193
|
+
bearer,
|
|
194
|
+
repo: repo.repoFullName,
|
|
195
|
+
eventsFile,
|
|
196
|
+
tokensFile,
|
|
197
|
+
repoTokenStatus: options.repoTokenStatus,
|
|
198
|
+
eventsStatus: options.eventsStatus,
|
|
199
|
+
fullRunApi: options.fullRunApi,
|
|
200
|
+
sessionId,
|
|
201
|
+
sessionBranch,
|
|
202
|
+
});
|
|
203
|
+
// Real authenticated smart-HTTP git server on loopback: this is what makes the
|
|
204
|
+
// clone go git → credential helper → broker → token → Basic auth → served repo,
|
|
205
|
+
// instead of a filesystem clone that bypasses the helper entirely.
|
|
206
|
+
const gitServer = await spawnGitHttpProcess({ repoDir: repo.gitDir, authLogFile });
|
|
207
|
+
// git includes the (non-standard) port in the credential `host` field, so the
|
|
208
|
+
// helper must be scoped to `127.0.0.1:<port>`, not the bare loopback host.
|
|
209
|
+
const host = `${LOOPBACK_HOST}:${gitServer.port}`;
|
|
210
|
+
const insecureHttpHosts = [host];
|
|
211
|
+
const cloneUrl = `${gitServer.baseUrl}/${basename(repo.gitDir)}`;
|
|
212
|
+
const provider = createLocalSimProvider({ rootDir: join(base, 'sandboxes'), keepOnDestroy: Boolean(options.keep) });
|
|
213
|
+
return {
|
|
214
|
+
apiBaseUrl: broker.apiBaseUrl,
|
|
215
|
+
bearer,
|
|
216
|
+
workspaceId,
|
|
217
|
+
sessionId,
|
|
218
|
+
runId,
|
|
219
|
+
sessionBranch,
|
|
220
|
+
repoFullName: repo.repoFullName,
|
|
221
|
+
provider,
|
|
222
|
+
resolveCloneUrl: () => cloneUrl,
|
|
223
|
+
host,
|
|
224
|
+
insecureHttpHosts,
|
|
225
|
+
events: () => readJsonl(eventsFile),
|
|
226
|
+
tokensIssued: () => readLines(tokensFile),
|
|
227
|
+
basicAuthPasswords: () => readJsonl(authLogFile).map(entry => entry.pass),
|
|
228
|
+
cleanup: async () => {
|
|
229
|
+
broker.stop();
|
|
230
|
+
gitServer.stop();
|
|
231
|
+
if (!options.keep)
|
|
232
|
+
rmSync(base, { recursive: true, force: true });
|
|
233
|
+
},
|
|
234
|
+
};
|
|
235
|
+
}
|