orizu 0.5.9 → 0.5.11
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/dist/daytona-slice-rehearsal.js +2 -2
- package/dist/daytona-slice.js +1 -51
- package/dist/git-credential.js +10 -7
- package/dist/github-setup.js +18 -2
- package/dist/help.js +16 -11
- package/dist/hosted-boot.js +713 -0
- package/dist/hosted-bootstrap.js +19 -41
- package/dist/hosted-harness-opencode.js +4 -2
- package/dist/hosted-headless.js +17 -6
- package/dist/hosted-loop-lifecycle.js +172 -0
- package/dist/hosted-loop.js +57 -148
- package/dist/hosted-run-event-sink.js +49 -10
- package/dist/hosted-runtime-assets.js +25 -1
- package/dist/hosted-session-cli.js +101 -8
- package/dist/hosted-skill-staging.js +89 -0
- package/dist/index.js +82 -62
- package/dist/manifests-cli.js +7 -2
- package/dist/preview-runtime.js +21 -4
- package/dist/prompt-draft-push.js +95 -0
- package/dist/report-comments-cli.js +9 -2
- package/dist/sandbox-hygiene.js +60 -0
- package/dist/sandbox-provider.js +15 -3
- package/dist/scorer-draft-push.js +110 -0
- package/dist/team-connectors-cli.js +140 -0
- package/dist/vercel-sandbox-provider.js +7 -1
- package/dist/workbench-cli.js +234 -6
- package/dist/workspace-sync.js +9 -2
- package/dist/workspace.js +15 -43
- package/dist/zip-draft-push.js +125 -0
- package/package.json +6 -6
- package/src/daytona-slice-rehearsal.ts +2 -2
- package/src/daytona-slice.ts +1 -70
- package/src/git-credential.ts +10 -7
- package/src/github-setup.ts +24 -2
- package/src/help.ts +18 -11
- package/src/hosted-boot.ts +946 -0
- package/src/hosted-bootstrap.ts +20 -44
- package/src/hosted-harness-opencode.ts +4 -2
- package/src/hosted-headless.ts +26 -8
- package/src/hosted-loop-lifecycle.ts +298 -0
- package/src/hosted-loop.ts +91 -269
- package/src/hosted-run-event-sink.ts +58 -11
- package/src/hosted-runtime-assets.ts +42 -1
- package/src/hosted-session-cli.ts +130 -8
- package/src/hosted-skill-staging.ts +126 -0
- package/src/index.ts +96 -72
- package/src/manifests-cli.ts +8 -2
- package/src/preview-runtime.ts +27 -4
- package/src/prompt-draft-push.ts +143 -0
- package/src/report-comments-cli.ts +10 -2
- package/src/sandbox-hygiene.ts +79 -0
- package/src/sandbox-provider.ts +15 -3
- package/src/scorer-draft-push.ts +155 -0
- package/src/team-connectors-cli.ts +171 -0
- package/src/vercel-sandbox-provider.ts +7 -1
- package/src/workbench-cli.ts +326 -6
- package/src/workspace-sync.ts +9 -2
- package/src/workspace.ts +15 -45
- package/src/zip-draft-push.ts +177 -0
- package/vendor/skills/orizu-cli/references/building-apps.md +2 -0
|
@@ -51,17 +51,17 @@ export function seedLocalBareRepo(baseDir, config) {
|
|
|
51
51
|
const work = mkdtempSync(join(baseDir, 'seed-'));
|
|
52
52
|
gitOrThrow(['init', '--initial-branch=main', work]);
|
|
53
53
|
const ident = ['-c', 'user.email=seed@orizu.local', '-c', 'user.name=Seed'];
|
|
54
|
+
// ALI-1075: no `canonical`/`repoState` liveness fields — manifests carry
|
|
55
|
+
// machine-readable ids only; the DB label is the sole production pointer.
|
|
54
56
|
const teamManifest = {
|
|
55
57
|
schemaVersion: WORKSPACE_SCHEMA_VERSION,
|
|
56
58
|
kind: 'team',
|
|
57
59
|
slug: config.teamSlug,
|
|
58
|
-
canonical: { owner: 'repo', repoState: 'source', objectRef: null },
|
|
59
60
|
};
|
|
60
61
|
const projectManifest = {
|
|
61
62
|
schemaVersion: WORKSPACE_SCHEMA_VERSION,
|
|
62
63
|
kind: 'project',
|
|
63
64
|
slug: config.projectSlug,
|
|
64
|
-
canonical: { owner: 'repo', repoState: 'draft', objectRef: null },
|
|
65
65
|
};
|
|
66
66
|
writeFileSync(join(work, 'orizu.team.json'), `${JSON.stringify(teamManifest, null, 2)}\n`);
|
|
67
67
|
writeFileSync(join(work, '.gitignore'), '# Orizu workspace policy\n.orizu/\n');
|
package/dist/daytona-slice.js
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* branch → approve → apply via the API, then destroy the sandbox.
|
|
24
24
|
*/
|
|
25
25
|
import { WORKSPACE_SCHEMA_VERSION } from './workspace.js';
|
|
26
|
+
import { sweepForTokenResidue } from './sandbox-hygiene.js';
|
|
26
27
|
const REPO_DIR = 'repo';
|
|
27
28
|
const DEFAULT_GENERATED_FILE = 'orizu-slice-note.md';
|
|
28
29
|
const STEP_PLAN = [
|
|
@@ -118,57 +119,6 @@ async function mintRepoToken(fetcher, workspaceId, purpose, sessionId) {
|
|
|
118
119
|
expiresAt: typeof body.expiresAt === 'string' ? body.expiresAt : null,
|
|
119
120
|
};
|
|
120
121
|
}
|
|
121
|
-
/**
|
|
122
|
-
* The list of places a short-lived git token can leak inside a sandbox after a
|
|
123
|
-
* transient clone+push. List-driven so it is trivial to extend. `${repo}` is
|
|
124
|
-
* substituted with the repo path. Ordered from the repo-local stores outward to
|
|
125
|
-
* global config, the credential cache, the reflog, shell history, and the live
|
|
126
|
-
* process listing / argv — the exact surfaces the Daytona-support question names.
|
|
127
|
-
*/
|
|
128
|
-
export function tokenLeakProbes(repoPath) {
|
|
129
|
-
const R = repoPath;
|
|
130
|
-
return [
|
|
131
|
-
{ location: `${R}/.git/config`, command: `cat ${R}/.git/config 2>/dev/null || true` },
|
|
132
|
-
{ location: `${R}/.git/logs (reflog)`, command: `find ${R}/.git/logs -type f -exec cat {} + 2>/dev/null || true` },
|
|
133
|
-
{ location: '~/.git-credentials', command: 'cat "$HOME/.git-credentials" 2>/dev/null || true' },
|
|
134
|
-
{ location: '~/.gitconfig (global)', command: 'cat "$HOME/.gitconfig" 2>/dev/null || true' },
|
|
135
|
-
{ location: 'git credential cache/store', command: 'cat "$HOME/.cache/git/credential/"* "${XDG_CACHE_HOME:-$HOME/.cache}/git/credential/"* 2>/dev/null || true' },
|
|
136
|
-
{ location: 'shell history', command: 'cat "$HOME/.bash_history" "$HOME/.zsh_history" 2>/dev/null || true' },
|
|
137
|
-
{ location: 'process listing / argv', command: 'ps -eo args 2>/dev/null || ps aux 2>/dev/null || true' },
|
|
138
|
-
{ location: 'process env', command: 'env' },
|
|
139
|
-
];
|
|
140
|
-
}
|
|
141
|
-
/**
|
|
142
|
-
* Grep the sandbox filesystem + process table for token values and the
|
|
143
|
-
* `x-access-token` marker across every known leak surface (see `tokenLeakProbes`).
|
|
144
|
-
* Returns every finding; an empty array means the transient operations left no
|
|
145
|
-
* residue. This is the load-bearing check the whole slice exists to make.
|
|
146
|
-
*
|
|
147
|
-
* NOTE (local-sim): the reflog/config/credential-store/history probes run
|
|
148
|
-
* meaningfully in local-sim, but `ps`/argv coverage is only decisive on the live
|
|
149
|
-
* Daytona run (local-sim runs the git clone via a child process on the host, not
|
|
150
|
-
* inside an isolated PID namespace). The WS-F memo marks that probe live-only.
|
|
151
|
-
*/
|
|
152
|
-
export async function sweepForTokenResidue(session, opts) {
|
|
153
|
-
const markers = opts.markers ?? ['x-access-token'];
|
|
154
|
-
const tokens = opts.tokens.filter(token => token.length > 0);
|
|
155
|
-
const probes = opts.probes ?? tokenLeakProbes(opts.repoPath);
|
|
156
|
-
const findings = [];
|
|
157
|
-
for (const probe of probes) {
|
|
158
|
-
const { stdout } = await session.exec(probe.command);
|
|
159
|
-
for (const token of tokens) {
|
|
160
|
-
if (stdout.includes(token)) {
|
|
161
|
-
findings.push({ location: probe.location, marker: 'token-value' });
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
for (const marker of markers) {
|
|
165
|
-
if (stdout.includes(marker)) {
|
|
166
|
-
findings.push({ location: probe.location, marker });
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
return findings;
|
|
171
|
-
}
|
|
172
122
|
// -- The workflow ------------------------------------------------------------
|
|
173
123
|
/**
|
|
174
124
|
* Run a command in the sandbox and throw on a non-zero (or missing) exit code,
|
package/dist/git-credential.js
CHANGED
|
@@ -45,17 +45,20 @@ export function resolveAttachedWorkspaceId(cwd) {
|
|
|
45
45
|
const manifestPath = join(dir, 'orizu.team.json');
|
|
46
46
|
if (existsSync(manifestPath)) {
|
|
47
47
|
const manifest = readJsonManifest(manifestPath);
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
: null;
|
|
52
|
-
if (typeof serviceId === 'string' && serviceId)
|
|
53
|
-
return serviceId;
|
|
48
|
+
// `setup.attachedWorkspaceId` is the attachment id; `canonical.serviceId`
|
|
49
|
+
// is a legacy duplicate kept only as a read fallback for old repos
|
|
50
|
+
// (ALI-1075: fresh manifests carry no `canonical` block).
|
|
54
51
|
const setup = manifest?.setup;
|
|
55
52
|
const attached = setup && typeof setup === 'object' && !Array.isArray(setup)
|
|
56
53
|
? setup.attachedWorkspaceId
|
|
57
54
|
: null;
|
|
58
|
-
|
|
55
|
+
if (typeof attached === 'string' && attached)
|
|
56
|
+
return attached;
|
|
57
|
+
const canonical = manifest?.canonical;
|
|
58
|
+
const serviceId = canonical && typeof canonical === 'object' && !Array.isArray(canonical)
|
|
59
|
+
? canonical.serviceId
|
|
60
|
+
: null;
|
|
61
|
+
return typeof serviceId === 'string' && serviceId ? serviceId : null;
|
|
59
62
|
}
|
|
60
63
|
const parent = dirname(dir);
|
|
61
64
|
if (parent === dir)
|
package/dist/github-setup.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* is immediately rewritten to a clean origin.
|
|
15
15
|
*/
|
|
16
16
|
import { spawnSync } from 'child_process';
|
|
17
|
-
import { mkdirSync } from 'fs';
|
|
17
|
+
import { existsSync, mkdirSync } from 'fs';
|
|
18
18
|
import { join } from 'path';
|
|
19
19
|
import { authedFetch } from './http.js';
|
|
20
20
|
import { assertWorkspaceDirUsable } from './workspace.js';
|
|
@@ -196,6 +196,23 @@ export async function runHostedAttach(options, io) {
|
|
|
196
196
|
}
|
|
197
197
|
}
|
|
198
198
|
const cleanUrl = `https://github.com/${repoFullName}.git`;
|
|
199
|
+
const ensureOrizuDir = io.ensureOrizuDir ?? ((repoDir) => mkdirSync(join(repoDir, '.orizu'), { recursive: true }));
|
|
200
|
+
// Idempotent re-run (ALI-1069): `orizu setup` in an ALREADY-attached workspace
|
|
201
|
+
// reaches here with `targetDir` holding the prior clone (its `.git` plus the
|
|
202
|
+
// committed orizu.team.json — `assertWorkspaceDirUsable` deliberately exempts
|
|
203
|
+
// that dir as the idempotent case). `git clone` refuses ANY non-empty dir, so
|
|
204
|
+
// an unconditional clone would abort the re-run with a misleading "not an empty
|
|
205
|
+
// directory" error. Short-circuit: re-affirm the credential helper config
|
|
206
|
+
// (idempotent) and return without recloning.
|
|
207
|
+
const repoAlreadyCloned = io.repoAlreadyCloned ?? ((dir) => existsSync(join(dir, '.git')));
|
|
208
|
+
if (repoAlreadyCloned(options.targetDir)) {
|
|
209
|
+
io.print(' Workbench repo already attached — skipping clone.');
|
|
210
|
+
gitOrThrow(io.git, ['config', 'credential.helper', CREDENTIAL_HELPER], { cwd: options.targetDir });
|
|
211
|
+
gitOrThrow(io.git, ['config', 'credential.useHttpPath', 'true'], { cwd: options.targetDir });
|
|
212
|
+
ensureOrizuDir(options.targetDir);
|
|
213
|
+
io.print(' Attached. Configured the Orizu credential helper for git.');
|
|
214
|
+
return { repoFullName, provisioned, targetDir: options.targetDir };
|
|
215
|
+
}
|
|
199
216
|
io.print(` Cloning ${repoFullName}...`);
|
|
200
217
|
// Clone with the helper inline + the workspace id in the env so the token is
|
|
201
218
|
// brokered on demand and never materializes in the URL or on disk.
|
|
@@ -211,7 +228,6 @@ export async function runHostedAttach(options, io) {
|
|
|
211
228
|
// Persist the helper repo-locally for future pull/push (cwd-resolved).
|
|
212
229
|
gitOrThrow(io.git, ['config', 'credential.helper', CREDENTIAL_HELPER], { cwd: options.targetDir });
|
|
213
230
|
gitOrThrow(io.git, ['config', 'credential.useHttpPath', 'true'], { cwd: options.targetDir });
|
|
214
|
-
const ensureOrizuDir = io.ensureOrizuDir ?? ((repoDir) => mkdirSync(join(repoDir, '.orizu'), { recursive: true }));
|
|
215
231
|
ensureOrizuDir(options.targetDir);
|
|
216
232
|
io.print(' Attached. Configured the Orizu credential helper for git.');
|
|
217
233
|
return { repoFullName, provisioned, targetDir: options.targetDir };
|
package/dist/help.js
CHANGED
|
@@ -318,8 +318,8 @@ export const COMMAND_DOCS = [
|
|
|
318
318
|
},
|
|
319
319
|
{
|
|
320
320
|
path: ['prompts', 'push'],
|
|
321
|
-
usage: 'orizu prompts push <dir> [--runner-version <id>] [--project <team/project>] [--parent <version-id>] [--json]',
|
|
322
|
-
summary: 'Push a local prompt artifact directory as a new version.',
|
|
321
|
+
usage: 'orizu prompts push <dir> [--runner-version <id>] [--project <team/project>] [--parent <version-id>] [--session <session-id>] [--json]',
|
|
322
|
+
summary: 'Push a local prompt artifact directory as a new version (with --session: a commit-first git draft).',
|
|
323
323
|
group: 'Prompts and judges',
|
|
324
324
|
},
|
|
325
325
|
{
|
|
@@ -354,8 +354,8 @@ export const COMMAND_DOCS = [
|
|
|
354
354
|
},
|
|
355
355
|
{
|
|
356
356
|
path: ['judges', 'push'],
|
|
357
|
-
usage: 'orizu judges push <dir> [--runner-version <id>] [--project <team/project>] [--parent <version-id>] [--json]',
|
|
358
|
-
summary: 'Push a local judge artifact directory as a new version.',
|
|
357
|
+
usage: 'orizu judges push <dir> [--runner-version <id>] [--project <team/project>] [--parent <version-id>] [--session <session-id>] [--json]',
|
|
358
|
+
summary: 'Push a local judge artifact directory as a new version (with --session: a commit-first git draft).',
|
|
359
359
|
group: 'Prompts and judges',
|
|
360
360
|
},
|
|
361
361
|
{
|
|
@@ -747,23 +747,25 @@ export const COMMAND_DOCS = [
|
|
|
747
747
|
},
|
|
748
748
|
{
|
|
749
749
|
path: ['session', 'start'],
|
|
750
|
-
usage: 'orizu session start [--project <team/project>] [--json]',
|
|
751
|
-
summary: 'Start a durable workspace session
|
|
750
|
+
usage: 'orizu session start [--project <team/project>] [--workspace <dir>] [--json]',
|
|
751
|
+
summary: 'Start a durable workspace session and print the session id. When run inside the workbench clone (or with --workspace), the remote session branch is fetched and checked out locally, and the exact next git commands are printed.',
|
|
752
752
|
group: 'Sessions',
|
|
753
753
|
options: [
|
|
754
754
|
{ name: '--project <team/project>', help: 'Optionally scope the session to a project in the attached workspace.' },
|
|
755
|
+
{ name: '--workspace <dir>', help: 'Workbench clone directory when not running from inside it.' },
|
|
755
756
|
{ name: '--json', help: 'Emit the machine-readable session payload.' },
|
|
756
757
|
],
|
|
757
758
|
examples: ['orizu session start', 'orizu session start --project highlight/hip --json'],
|
|
758
759
|
},
|
|
759
760
|
{
|
|
760
761
|
path: ['session', 'status'],
|
|
761
|
-
usage: 'orizu session status [--session <id> | --status active|ended] [--json]',
|
|
762
|
-
summary: 'Inspect one session by id
|
|
762
|
+
usage: 'orizu session status [--session <id> | --status active|ended] [--workspace <dir>] [--json]',
|
|
763
|
+
summary: 'Inspect one session by id (including run summaries and, when run inside the workbench clone, the session branch with local ahead/behind vs origin), or list sessions for the attached workspace.',
|
|
763
764
|
group: 'Sessions',
|
|
764
765
|
options: [
|
|
765
766
|
{ name: '--session <id>', help: 'Resume by session id; does not require the original terminal.' },
|
|
766
767
|
{ name: '--status <status>', help: 'Filter attached-workspace sessions when --session is omitted.', choices: ['active', 'ended'] },
|
|
768
|
+
{ name: '--workspace <dir>', help: 'Workbench clone directory when not running from inside it.' },
|
|
767
769
|
{ name: '--json', help: 'Emit the machine-readable session or session-list payload.' },
|
|
768
770
|
],
|
|
769
771
|
examples: ['orizu session status --session sess_123 --json', 'orizu session status --status active'],
|
|
@@ -781,15 +783,18 @@ export const COMMAND_DOCS = [
|
|
|
781
783
|
},
|
|
782
784
|
{
|
|
783
785
|
path: ['session', 'finish'],
|
|
784
|
-
usage: 'orizu session finish --session <id> [--project <team/project>] [--json]',
|
|
785
|
-
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).',
|
|
786
|
+
usage: 'orizu session finish --session <id> [--project <team/project>] [--push [--message <text>]] [--workspace <dir>] [--json]',
|
|
787
|
+
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). Warns when your local session-branch checkout has uncommitted/unpushed work; --push stages, commits, and pushes it first.',
|
|
786
788
|
group: 'Sessions',
|
|
787
789
|
options: [
|
|
788
790
|
{ name: '--session <id>', help: 'Session id whose branch to finish.', required: true },
|
|
789
791
|
{ name: '--project <team/project>', help: 'Project scope for the manifest when the session is not already project-scoped.' },
|
|
792
|
+
{ name: '--push', help: 'Opt-in: stage, commit, and push local session-branch work before finishing (raw git stays the default workflow).' },
|
|
793
|
+
{ name: '--message <text>', help: 'Commit message for --push (a default is used when omitted).' },
|
|
794
|
+
{ name: '--workspace <dir>', help: 'Workbench clone directory when not running from inside it.' },
|
|
790
795
|
{ name: '--json', help: 'Emit the machine-readable outcome (no-changes or the created manifest).' },
|
|
791
796
|
],
|
|
792
|
-
examples: ['orizu session finish --session sess_123', 'orizu session finish --session sess_123 --
|
|
797
|
+
examples: ['orizu session finish --session sess_123', 'orizu session finish --session sess_123 --push --message "tune judge prompt"'],
|
|
793
798
|
},
|
|
794
799
|
{
|
|
795
800
|
path: ['run', 'start'],
|